diff options
Diffstat (limited to 'lib/rbcodec/codecs/mod.c')
-rw-r--r-- | lib/rbcodec/codecs/mod.c | 1353 |
1 files changed, 1353 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/mod.c b/lib/rbcodec/codecs/mod.c new file mode 100644 index 0000000000..5bd64994f1 --- /dev/null +++ b/lib/rbcodec/codecs/mod.c | |||
@@ -0,0 +1,1353 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * MOD Codec for rockbox | ||
11 | * | ||
12 | * Written from scratch by Rainer Sinsch | ||
13 | * exclusivly for Rockbox in February 2008 | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * as published by the Free Software Foundation; either version 2 | ||
18 | * of the License, or (at your option) any later version. | ||
19 | * | ||
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
21 | * KIND, either express or implied. | ||
22 | * | ||
23 | ****************************************************************************/ | ||
24 | |||
25 | /************** | ||
26 | * This version supports large files directly from internal memory management. | ||
27 | * There is a drawback however: It may happen that a song is not completely | ||
28 | * loaded when the internal rockbox-ringbuffer (approx. 28MB) is filled up | ||
29 | * As a workaround make sure you don't have directories with mods larger | ||
30 | * than a total of 28MB | ||
31 | *************/ | ||
32 | |||
33 | #include "debug.h" | ||
34 | #include "codeclib.h" | ||
35 | #include <inttypes.h> | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #include <string.h> | ||
39 | #include <stdlib.h> | ||
40 | #include <ctype.h> | ||
41 | |||
42 | |||
43 | CODEC_HEADER | ||
44 | |||
45 | #define CHUNK_SIZE (1024*2) | ||
46 | |||
47 | |||
48 | /* This codec supports MOD Files: | ||
49 | * | ||
50 | */ | ||
51 | |||
52 | static int32_t samples[CHUNK_SIZE] IBSS_ATTR; /* The sample buffer */ | ||
53 | |||
54 | /* Instrument Data */ | ||
55 | struct s_instrument { | ||
56 | /* Sample name / description */ | ||
57 | /*char description[22];*/ | ||
58 | |||
59 | /* Sample length in bytes */ | ||
60 | unsigned short length; | ||
61 | |||
62 | /* Sample finetuning (-8 - +7) */ | ||
63 | signed char finetune; | ||
64 | |||
65 | /* Sample volume (0 - 64) */ | ||
66 | signed char volume; | ||
67 | |||
68 | /* Sample Repeat Position */ | ||
69 | unsigned short repeatoffset; | ||
70 | |||
71 | /* Sample Repeat Length */ | ||
72 | unsigned short repeatlength; | ||
73 | |||
74 | /* Offset to sample data */ | ||
75 | unsigned int sampledataoffset; | ||
76 | }; | ||
77 | |||
78 | /* Song Data */ | ||
79 | struct s_song { | ||
80 | /* Song name / title description */ | ||
81 | /*char szTitle[20];*/ | ||
82 | |||
83 | /* No. of channels in song */ | ||
84 | unsigned char noofchannels; | ||
85 | |||
86 | /* No. of instruments used (either 15 or 31) */ | ||
87 | unsigned char noofinstruments; | ||
88 | |||
89 | /* How many patterns are beeing played? */ | ||
90 | unsigned char songlength; | ||
91 | |||
92 | /* Where to jump after the song end? */ | ||
93 | unsigned char songendjumpposition; | ||
94 | |||
95 | /* Pointer to the Pattern Order Table */ | ||
96 | unsigned char *patternordertable; | ||
97 | |||
98 | /* Pointer to the pattern data */ | ||
99 | void *patterndata; | ||
100 | |||
101 | /* Pointer to the sample buffer */ | ||
102 | signed char *sampledata; | ||
103 | |||
104 | /* Instrument data */ | ||
105 | struct s_instrument instrument[31]; | ||
106 | }; | ||
107 | |||
108 | struct s_modchannel { | ||
109 | /* Current Volume */ | ||
110 | signed char volume; | ||
111 | |||
112 | /* Current Offset to period in PeriodTable of notebeeing played | ||
113 | (can be temporarily negative) */ | ||
114 | short periodtableoffset; | ||
115 | |||
116 | /* Current Period beeing played */ | ||
117 | short period; | ||
118 | |||
119 | /* Current effect */ | ||
120 | unsigned char effect; | ||
121 | |||
122 | /* Current parameters of effect */ | ||
123 | unsigned char effectparameter; | ||
124 | |||
125 | /* Current Instrument beeing played */ | ||
126 | unsigned char instrument; | ||
127 | |||
128 | /* Current Vibrato Speed */ | ||
129 | unsigned char vibratospeed; | ||
130 | |||
131 | /* Current Vibrato Depth */ | ||
132 | unsigned char vibratodepth; | ||
133 | |||
134 | /* Current Position for Vibrato in SinTable */ | ||
135 | unsigned char vibratosinpos; | ||
136 | |||
137 | /* Current Tremolo Speed */ | ||
138 | unsigned char tremolospeed; | ||
139 | |||
140 | /* Current Tremolo Depth */ | ||
141 | unsigned char tremolodepth; | ||
142 | |||
143 | /* Current Position for Tremolo in SinTable */ | ||
144 | unsigned char tremolosinpos; | ||
145 | |||
146 | /* Current Speed of Effect "Slide Note up" */ | ||
147 | unsigned char slideupspeed; | ||
148 | |||
149 | /* Current Speed of Effect "Slide Note down" */ | ||
150 | unsigned char slidedownspeed; | ||
151 | |||
152 | /* Current Speed of the "Slide to Note" effect */ | ||
153 | unsigned char slidetonotespeed; | ||
154 | |||
155 | /* Current Period of the "Slide to Note" effect */ | ||
156 | unsigned short slidetonoteperiod; | ||
157 | }; | ||
158 | |||
159 | struct s_modplayer { | ||
160 | /* Ticks per Line */ | ||
161 | unsigned char ticksperline; | ||
162 | |||
163 | /* Beats per Minute */ | ||
164 | unsigned char bpm; | ||
165 | |||
166 | /* Position of the Song in the Pattern Table (0-127) */ | ||
167 | unsigned char patterntableposition; | ||
168 | |||
169 | /* Current Line (may be temporarily < 0) */ | ||
170 | signed char currentline; | ||
171 | |||
172 | /* Current Tick */ | ||
173 | signed char currenttick; | ||
174 | |||
175 | /* How many samples are required to calculate for each tick? */ | ||
176 | unsigned int samplespertick; | ||
177 | |||
178 | /* Information about the channels */ | ||
179 | struct s_modchannel modchannel[8]; | ||
180 | |||
181 | /* The Amiga Period Table */ | ||
182 | unsigned short *periodtable; | ||
183 | |||
184 | /* The sinus table [-255,255] */ | ||
185 | signed short *sintable; | ||
186 | |||
187 | /* Is the glissando effect enabled? */ | ||
188 | bool glissandoenabled; | ||
189 | |||
190 | /* Is the Amiga Filter enabled? */ | ||
191 | bool amigafilterenabled; | ||
192 | |||
193 | /* The pattern-line where the loop is carried out (set with e6 command) */ | ||
194 | unsigned char loopstartline; | ||
195 | |||
196 | /* Number of times to loop */ | ||
197 | unsigned char looptimes; | ||
198 | }; | ||
199 | |||
200 | struct s_channel { | ||
201 | /* Panning (0 = left, 16 = right) */ | ||
202 | unsigned char panning; | ||
203 | |||
204 | /* Sample frequency of the channel */ | ||
205 | unsigned short frequency; | ||
206 | |||
207 | /* Position of the sample currently played */ | ||
208 | unsigned int samplepos; | ||
209 | |||
210 | /* Fractual Position of the sample currently player */ | ||
211 | unsigned int samplefractpos; | ||
212 | |||
213 | /* Loop Sample */ | ||
214 | bool loopsample; | ||
215 | |||
216 | /* Loop Position Start */ | ||
217 | unsigned int loopstart; | ||
218 | |||
219 | /* Loop Position End */ | ||
220 | unsigned int loopend; | ||
221 | |||
222 | /* Is The channel beeing played? */ | ||
223 | bool channelactive; | ||
224 | |||
225 | /* The Volume (0..64) */ | ||
226 | signed char volume; | ||
227 | |||
228 | /* The last sampledata beeing played (required for interpolation) */ | ||
229 | signed short lastsampledata; | ||
230 | }; | ||
231 | |||
232 | struct s_mixer { | ||
233 | /* The channels */ | ||
234 | struct s_channel channel[32]; | ||
235 | }; | ||
236 | |||
237 | struct s_song modsong IDATA_ATTR; /* The Song */ | ||
238 | struct s_modplayer modplayer IDATA_ATTR; /* The Module Player */ | ||
239 | struct s_mixer mixer IDATA_ATTR; | ||
240 | |||
241 | /* The Amiga Period Table (+1 because we use index 0 for period 0 = no new note) */ | ||
242 | static unsigned short s_periodtable[37*8+1] IDATA_ATTR = | ||
243 | { 0, 907, 900, 893, 887, 881, 874, 868, | ||
244 | 862, 856, 849, 843, 837, 831, 825, 819, | ||
245 | 813, 808, 802, 796, 790, 785, 779, 773, | ||
246 | 768, 762, 757, 751, 746, 740, 735, 730, | ||
247 | 725, 719, 714, 709, 704, 699, 694, 689, | ||
248 | 684, 679, 674, 669, 664, 660, 655, 650, | ||
249 | 645, 641, 636, 632, 627, 623, 618, 614, | ||
250 | 609, 605, 600, 596, 592, 588, 583, 579, | ||
251 | 575, 571, 567, 563, 559, 555, 551, 547, | ||
252 | 543, 539, 535, 531, 527, 523, 520, 516, | ||
253 | 512, 509, 505, 501, 498, 494, 490, 487, | ||
254 | 483, 480, 477, 473, 470, 466, 463, 460, | ||
255 | 456, 453, 450, 446, 443, 440, 437, 434, | ||
256 | 431, 428, 424, 421, 418, 415, 412, 409, | ||
257 | 406, 404, 401, 398, 395, 392, 389, 386, | ||
258 | 384, 381, 378, 375, 373, 370, 367, 365, | ||
259 | 362, 359, 357, 354, 352, 349, 347, 344, | ||
260 | 342, 339, 337, 334, 332, 330, 327, 325, | ||
261 | 322, 320, 318, 316, 313, 311, 309, 307, | ||
262 | 304, 302, 300, 298, 296, 294, 291, 289, | ||
263 | 287, 285, 283, 281, 279, 277, 275, 273, | ||
264 | 271, 269, 267, 265, 263, 261, 260, 258, | ||
265 | 256, 254, 252, 250, 249, 247, 245, 243, | ||
266 | 241, 240, 238, 236, 235, 233, 231, 230, | ||
267 | 228, 226, 225, 223, 221, 220, 218, 217, | ||
268 | 215, 214, 212, 210, 209, 207, 206, 204, | ||
269 | 203, 202, 200, 199, 197, 196, 194, 193, | ||
270 | 192, 190, 189, 187, 186, 185, 183, 182, | ||
271 | 181, 179, 178, 177, 176, 174, 173, 172, | ||
272 | 171, 169, 168, 167, 166, 165, 163, 162, | ||
273 | 161, 160, 159, 158, 156, 155, 154, 153, | ||
274 | 152, 151, 150, 149, 148, 147, 145, 144, | ||
275 | 143, 142, 141, 140, 139, 138, 137, 136, | ||
276 | 135, 134, 133, 132, 131, 130, 130, 129, | ||
277 | 128, 127, 126, 125, 124, 123, 122, 121, | ||
278 | 120, 120, 119, 118, 117, 116, 115, 115, | ||
279 | 114, 113, 112, 111, 110, 110, 109, 108, | ||
280 | 107}; | ||
281 | |||
282 | /* The sin table */ | ||
283 | static signed short s_sintable[0x40] IDATA_ATTR = | ||
284 | { 0, 25, 49, 74, 97, 120, 141, 162, | ||
285 | 180, 197, 212, 225, 235, 244, 250, 254, | ||
286 | 255, 254, 250, 244, 235, 225, 212, 197, | ||
287 | 180, 161, 141, 120, 97, 73, 49, 24, | ||
288 | 0, -25, -50, -74, -98, -120, -142, -162, | ||
289 | -180, -197, -212, -225, -236, -244, -250, -254, | ||
290 | -255, -254, -250, -244, -235, -224, -211, -197, | ||
291 | -180, -161, -141, -119, -97, -73, -49, -24}; | ||
292 | |||
293 | const unsigned short mixingrate = 44100; | ||
294 | |||
295 | STATICIRAM void mixer_playsample(int channel, int instrument) ICODE_ATTR; | ||
296 | void mixer_playsample(int channel, int instrument) | ||
297 | { | ||
298 | struct s_channel *p_channel = &mixer.channel[channel]; | ||
299 | struct s_instrument *p_instrument = &modsong.instrument[instrument]; | ||
300 | |||
301 | p_channel->channelactive = true; | ||
302 | p_channel->samplepos = p_instrument->sampledataoffset; | ||
303 | p_channel->samplefractpos = 0; | ||
304 | p_channel->loopsample = (p_instrument->repeatlength > 2); | ||
305 | if (p_channel->loopsample) { | ||
306 | p_channel->loopstart = p_instrument->repeatoffset + | ||
307 | p_instrument->sampledataoffset; | ||
308 | p_channel->loopend = p_channel->loopstart + | ||
309 | p_instrument->repeatlength; | ||
310 | } | ||
311 | else p_channel->loopend = p_instrument->length + | ||
312 | p_instrument->sampledataoffset; | ||
313 | |||
314 | /* Remember the instrument */ | ||
315 | modplayer.modchannel[channel].instrument = instrument; | ||
316 | } | ||
317 | |||
318 | static inline void mixer_stopsample(int channel) | ||
319 | { | ||
320 | mixer.channel[channel].channelactive = false; | ||
321 | } | ||
322 | |||
323 | static inline void mixer_continuesample(int channel) | ||
324 | { | ||
325 | mixer.channel[channel].channelactive = true; | ||
326 | } | ||
327 | |||
328 | static inline void mixer_setvolume(int channel, int volume) | ||
329 | { | ||
330 | mixer.channel[channel].volume = volume; | ||
331 | } | ||
332 | |||
333 | static inline void mixer_setpanning(int channel, int panning) | ||
334 | { | ||
335 | mixer.channel[channel].panning = panning; | ||
336 | } | ||
337 | |||
338 | static inline void mixer_setamigaperiod(int channel, int amigaperiod) | ||
339 | { | ||
340 | /* Just to make sure we don't devide by zero | ||
341 | * amigaperiod shouldn't 0 anyway - if it is the case | ||
342 | * then something terribly went wrong */ | ||
343 | if (amigaperiod == 0) | ||
344 | return; | ||
345 | |||
346 | mixer.channel[channel].frequency = 3579546 / amigaperiod; | ||
347 | } | ||
348 | |||
349 | /* Initialize the MOD Player with default values and precalc tables */ | ||
350 | STATICIRAM void initmodplayer(void) ICODE_ATTR; | ||
351 | void initmodplayer(void) | ||
352 | { | ||
353 | unsigned int c; | ||
354 | #if 0 | ||
355 | /* As the calculation of periodtable and sintable uses float and double | ||
356 | * rockbox uses two predefined tables. This reduces the codesize by | ||
357 | * several KB. */ | ||
358 | |||
359 | unsigned int i; | ||
360 | /* Calculate Amiga Period Values | ||
361 | * Start with Period 907 (= C-1 with Finetune -8) and work upwards */ | ||
362 | double f = 907.0f; | ||
363 | /* Index 0 stands for no note (and therefore no period) */ | ||
364 | modplayer.periodtable[0] = 0; | ||
365 | for (i=1;i<297;i++) | ||
366 | { | ||
367 | modplayer.periodtable[i] = (unsigned short) f; | ||
368 | f /= 1.0072464122237039; /* = pow(2.0f, 1.0f/(12.0f*8.0f)); */ | ||
369 | } | ||
370 | |||
371 | /* | ||
372 | * This is a more accurate but also time more consuming approach | ||
373 | * to calculate the amiga period table | ||
374 | * Commented out for speed purposes | ||
375 | const int finetuning = 8; | ||
376 | const int octaves = 3; | ||
377 | for (int halftone=0;halftone<=finetuning*octaves*12+7;halftone++) | ||
378 | { | ||
379 | float e = pow(2.0f, halftone/(12.0f*8.0f)); | ||
380 | float f = 906.55f/e; | ||
381 | modplayer.periodtable[halfetone+1] = (int)(f+0.5f); | ||
382 | } | ||
383 | */ | ||
384 | |||
385 | /* Calculate Protracker Vibrato sine table | ||
386 | * The routine makes use of the Harmonical Oscillator Approach | ||
387 | * for calculating sine tables | ||
388 | * (see http://membres.lycos.fr/amycoders/tutorials/sintables.html) | ||
389 | * The routine presented here calculates a complete sine wave | ||
390 | * with 64 values in range [-255,255] | ||
391 | */ | ||
392 | float a, b, d, dd; | ||
393 | |||
394 | d = 0.09817475f; /* = 2*PI/64 */ | ||
395 | dd = d*d; | ||
396 | a = 0; | ||
397 | b = d; | ||
398 | |||
399 | for (i=0;i<0x40;i++) | ||
400 | { | ||
401 | modplayer.sintable[i] = (int)(255*a); | ||
402 | |||
403 | a = a+b; | ||
404 | b = b-dd*a; | ||
405 | } | ||
406 | #else | ||
407 | /* Point to the predefined tables */ | ||
408 | modplayer.periodtable = s_periodtable; | ||
409 | modplayer.sintable = s_sintable; | ||
410 | #endif | ||
411 | /* Set Default Player Values */ | ||
412 | modplayer.currentline = 0; | ||
413 | modplayer.currenttick = 0; | ||
414 | modplayer.patterntableposition = 0; | ||
415 | modplayer.bpm = 125; | ||
416 | modplayer.ticksperline = 6; | ||
417 | modplayer.glissandoenabled = false; /* Disable glissando */ | ||
418 | modplayer.amigafilterenabled = false; /* Disable the Amiga Filter */ | ||
419 | |||
420 | /* Default Panning Values */ | ||
421 | int panningvalues[8] = {4,12,12,4,4,12,12,4}; | ||
422 | for (c=0;c<8;c++) | ||
423 | { | ||
424 | /* Set Default Panning */ | ||
425 | mixer_setpanning(c, panningvalues[c]); | ||
426 | /* Reset channels in the MOD Player */ | ||
427 | memset(&modplayer.modchannel[c], 0, sizeof(struct s_modchannel)); | ||
428 | /* Don't play anything */ | ||
429 | mixer.channel[c].channelactive = false; | ||
430 | } | ||
431 | |||
432 | } | ||
433 | |||
434 | /* Load the MOD File from memory */ | ||
435 | STATICIRAM bool loadmod(void *modfile) ICODE_ATTR; | ||
436 | bool loadmod(void *modfile) | ||
437 | { | ||
438 | int i; | ||
439 | unsigned char *periodsconverted; | ||
440 | |||
441 | /* We don't support PowerPacker 2.0 Files */ | ||
442 | if (memcmp((char*) modfile, "PP20", 4) == 0) return false; | ||
443 | |||
444 | /* Get the File Format Tag */ | ||
445 | char *fileformattag = (char*)modfile + 1080; | ||
446 | |||
447 | /* Find out how many channels and instruments are used */ | ||
448 | if (memcmp(fileformattag, "2CHN", 4) == 0) | ||
449 | {modsong.noofchannels = 2; modsong.noofinstruments = 31;} | ||
450 | else if (memcmp(fileformattag, "M.K.", 4) == 0) | ||
451 | {modsong.noofchannels = 4; modsong.noofinstruments = 31;} | ||
452 | else if (memcmp(fileformattag, "M!K!", 4) == 0) | ||
453 | {modsong.noofchannels = 4; modsong.noofinstruments = 31;} | ||
454 | else if (memcmp(fileformattag, "4CHN", 4) == 0) | ||
455 | {modsong.noofchannels = 4; modsong.noofinstruments = 31;} | ||
456 | else if (memcmp(fileformattag, "FLT4", 4) == 0) | ||
457 | {modsong.noofchannels = 4; modsong.noofinstruments = 31;} | ||
458 | else if (memcmp(fileformattag, "6CHN", 4) == 0) | ||
459 | {modsong.noofchannels = 6; modsong.noofinstruments = 31;} | ||
460 | else if (memcmp(fileformattag, "8CHN", 4) == 0) | ||
461 | {modsong.noofchannels = 8; modsong.noofinstruments = 31;} | ||
462 | else if (memcmp(fileformattag, "OKTA", 4) == 0) | ||
463 | {modsong.noofchannels = 8; modsong.noofinstruments = 31;} | ||
464 | else if (memcmp(fileformattag, "CD81", 4) == 0) | ||
465 | {modsong.noofchannels = 8; modsong.noofinstruments = 31;} | ||
466 | else { | ||
467 | /* The file has no format tag, so most likely soundtracker */ | ||
468 | modsong.noofchannels = 4; | ||
469 | modsong.noofinstruments = 15; | ||
470 | } | ||
471 | |||
472 | /* Get the Song title | ||
473 | * Skipped here | ||
474 | * strncpy(modsong.szTitle, (char*)pMODFile, 20); */ | ||
475 | |||
476 | /* Get the Instrument information */ | ||
477 | for (i=0;i<modsong.noofinstruments;i++) | ||
478 | { | ||
479 | struct s_instrument *instrument = &modsong.instrument[i]; | ||
480 | unsigned char *p = (unsigned char *)modfile + 20 + i*30; | ||
481 | |||
482 | /*strncpy(instrument->description, (char*)p, 22); */ | ||
483 | p += 22; | ||
484 | instrument->length = (((p[0])<<8) + p[1]) << 1; p+=2; | ||
485 | instrument->finetune = *p++ & 0x0f; | ||
486 | /* Treat finetuning as signed nibble */ | ||
487 | if (instrument->finetune > 7) instrument->finetune -= 16; | ||
488 | instrument->volume = *p++; | ||
489 | instrument->repeatoffset = (((p[0])<<8) + p[1]) << 1; p+= 2; | ||
490 | instrument->repeatlength = (((p[0])<<8) + p[1]) << 1; | ||
491 | } | ||
492 | |||
493 | /* Get the pattern information */ | ||
494 | unsigned char *p = (unsigned char *)modfile + 20 + | ||
495 | modsong.noofinstruments*30; | ||
496 | modsong.songlength = *p++; | ||
497 | modsong.songendjumpposition = *p++; | ||
498 | modsong.patternordertable = p; | ||
499 | |||
500 | /* Find out how many patterns are used within this song */ | ||
501 | int maxpatterns = 0; | ||
502 | for (i=0;i<128;i++) | ||
503 | if (modsong.patternordertable[i] > maxpatterns) | ||
504 | maxpatterns = modsong.patternordertable[i]; | ||
505 | maxpatterns++; | ||
506 | |||
507 | /* use 'restartposition' (historically set to 127) which is not used here | ||
508 | as a marker that periods have already been converted */ | ||
509 | |||
510 | periodsconverted = (char*)modfile + 20 + modsong.noofinstruments*30 + 1; | ||
511 | |||
512 | /* Get the pattern data; ST doesn't have fileformattag, so 4 bytes less */ | ||
513 | modsong.patterndata = periodsconverted + | ||
514 | (modsong.noofinstruments==15 ? 129 : 133); | ||
515 | |||
516 | /* Convert the period values in the mod file to offsets | ||
517 | * in our periodtable (but only, if we haven't done this yet) */ | ||
518 | p = (unsigned char *) modsong.patterndata; | ||
519 | if (*periodsconverted != 0xfe) | ||
520 | { | ||
521 | int note, note2, channel; | ||
522 | for (note=0;note<maxpatterns*64;note++) | ||
523 | for (channel=0;channel<modsong.noofchannels;channel++) | ||
524 | { | ||
525 | int period = ((p[0] & 0x0f) << 8) | p[1]; | ||
526 | int periodoffset = 0; | ||
527 | |||
528 | /* Find the offset of the current period */ | ||
529 | for (note2 = 1; note2 < 12*3+1; note2++) | ||
530 | if (abs(modplayer.periodtable[note2*8+1]-period) < 4) | ||
531 | { | ||
532 | periodoffset = note2*8+1; | ||
533 | break; | ||
534 | } | ||
535 | /* Write back the period offset */ | ||
536 | p[0] = (periodoffset >> 8) | (p[0] & 0xf0); | ||
537 | p[1] = periodoffset & 0xff; | ||
538 | p += 4; | ||
539 | } | ||
540 | /* Remember that we already converted the periods, | ||
541 | * in case the file gets reloaded by rewinding | ||
542 | * with 0xfe (arbitary magic value > 127) */ | ||
543 | *periodsconverted = 0xfe; | ||
544 | } | ||
545 | |||
546 | /* Get the samples | ||
547 | * Calculation: The Samples come after the pattern data | ||
548 | * We know that there are nMaxPatterns and each pattern requires | ||
549 | * 4 bytes per note and per channel. | ||
550 | * And of course there are always lines in each channel */ | ||
551 | modsong.sampledata = (signed char*) modsong.patterndata + | ||
552 | maxpatterns*4*modsong.noofchannels*64; | ||
553 | int sampledataoffset = 0; | ||
554 | for (i=0;i<modsong.noofinstruments;i++) | ||
555 | { | ||
556 | modsong.instrument[i].sampledataoffset = sampledataoffset; | ||
557 | sampledataoffset += modsong.instrument[i].length; | ||
558 | } | ||
559 | |||
560 | return true; | ||
561 | } | ||
562 | |||
563 | /* Apply vibrato to channel */ | ||
564 | STATICIRAM void vibrate(int channel) ICODE_ATTR; | ||
565 | void vibrate(int channel) | ||
566 | { | ||
567 | struct s_modchannel *p_modchannel = &modplayer.modchannel[channel]; | ||
568 | |||
569 | /* Apply Vibrato | ||
570 | * >> 7 is used in the original protracker source code */ | ||
571 | mixer_setamigaperiod(channel, p_modchannel->period+ | ||
572 | ((p_modchannel->vibratodepth * | ||
573 | modplayer.sintable[p_modchannel->vibratosinpos])>>7)); | ||
574 | |||
575 | /* Foward in Sine Table */ | ||
576 | p_modchannel->vibratosinpos += p_modchannel->vibratospeed; | ||
577 | p_modchannel->vibratosinpos &= 0x3f; | ||
578 | } | ||
579 | |||
580 | /* Apply tremolo to channel | ||
581 | * (same as vibrato, but only apply on volume instead of pitch) */ | ||
582 | STATICIRAM void tremolo(int channel) ICODE_ATTR; | ||
583 | void tremolo(int channel) | ||
584 | { | ||
585 | struct s_modchannel *p_modchannel = &modplayer.modchannel[channel]; | ||
586 | |||
587 | /* Apply Tremolo | ||
588 | * >> 6 is used in the original protracker source code */ | ||
589 | int volume = (p_modchannel->volume * | ||
590 | modplayer.sintable[p_modchannel->tremolosinpos])>>6; | ||
591 | if (volume > 64) volume = 64; | ||
592 | else if (volume < 0) volume = 0; | ||
593 | mixer_setvolume(channel, volume); | ||
594 | |||
595 | /* Foward in Sine Table */ | ||
596 | p_modchannel->tremolosinpos += p_modchannel->tremolosinpos; | ||
597 | p_modchannel->tremolosinpos &= 0x3f; | ||
598 | } | ||
599 | |||
600 | /* Apply Slide to Note effect to channel */ | ||
601 | STATICIRAM void slidetonote(int channel) ICODE_ATTR; | ||
602 | void slidetonote(int channel) | ||
603 | { | ||
604 | struct s_modchannel *p_modchannel = &modplayer.modchannel[channel]; | ||
605 | |||
606 | /* If there hasn't been any slide-to note set up, then return */ | ||
607 | if (p_modchannel->slidetonoteperiod == 0) return; | ||
608 | |||
609 | /* Slide note up */ | ||
610 | if (p_modchannel->slidetonoteperiod > p_modchannel->period) | ||
611 | { | ||
612 | p_modchannel->period += p_modchannel->slidetonotespeed; | ||
613 | if (p_modchannel->period > p_modchannel->slidetonoteperiod) | ||
614 | p_modchannel->period = p_modchannel->slidetonoteperiod; | ||
615 | } | ||
616 | /* Slide note down */ | ||
617 | else if (p_modchannel->slidetonoteperiod < p_modchannel->period) | ||
618 | { | ||
619 | p_modchannel->period -= p_modchannel->slidetonotespeed; | ||
620 | if (p_modchannel->period < p_modchannel->slidetonoteperiod) | ||
621 | p_modchannel->period = p_modchannel->slidetonoteperiod; | ||
622 | } | ||
623 | mixer_setamigaperiod(channel, p_modchannel->period); | ||
624 | } | ||
625 | |||
626 | /* Apply Slide to Note effect on channel, | ||
627 | * but this time with glissando enabled */ | ||
628 | STATICIRAM void slidetonoteglissando(int channel) ICODE_ATTR; | ||
629 | void slidetonoteglissando(int channel) | ||
630 | { | ||
631 | struct s_modchannel *p_modchannel = &modplayer.modchannel[channel]; | ||
632 | |||
633 | /* Slide note up */ | ||
634 | if (p_modchannel->slidetonoteperiod > p_modchannel->period) | ||
635 | { | ||
636 | p_modchannel->period = | ||
637 | modplayer.periodtable[p_modchannel->periodtableoffset+=8]; | ||
638 | if (p_modchannel->period > p_modchannel->slidetonoteperiod) | ||
639 | p_modchannel->period = p_modchannel->slidetonoteperiod; | ||
640 | } | ||
641 | /* Slide note down */ | ||
642 | else | ||
643 | { | ||
644 | p_modchannel->period = | ||
645 | modplayer.periodtable[p_modchannel->periodtableoffset-=8]; | ||
646 | if (p_modchannel->period < p_modchannel->slidetonoteperiod) | ||
647 | p_modchannel->period = p_modchannel->slidetonoteperiod; | ||
648 | } | ||
649 | mixer_setamigaperiod(channel, p_modchannel->period); | ||
650 | } | ||
651 | |||
652 | /* Apply Volume Slide */ | ||
653 | STATICIRAM void volumeslide(int channel, int effectx, int effecty) ICODE_ATTR; | ||
654 | void volumeslide(int channel, int effectx, int effecty) | ||
655 | { | ||
656 | struct s_modchannel *p_modchannel = &modplayer.modchannel[channel]; | ||
657 | |||
658 | /* If both X and Y Parameters are non-zero, then the y value is ignored */ | ||
659 | if (effectx > 0) { | ||
660 | p_modchannel->volume += effectx; | ||
661 | if (p_modchannel->volume > 64) p_modchannel->volume = 64; | ||
662 | } | ||
663 | else { | ||
664 | p_modchannel->volume -= effecty; | ||
665 | if (p_modchannel->volume < 0) p_modchannel->volume = 0; | ||
666 | } | ||
667 | |||
668 | mixer_setvolume(channel, p_modchannel->volume); | ||
669 | } | ||
670 | |||
671 | /* Play the current line (at tick 0) */ | ||
672 | STATICIRAM void playline(int pattern, int line) ICODE_ATTR; | ||
673 | void playline(int pattern, int line) | ||
674 | { | ||
675 | int c; | ||
676 | |||
677 | /* Get pointer to the current pattern */ | ||
678 | unsigned char *p_line = (unsigned char*)modsong.patterndata; | ||
679 | p_line += pattern*64*4*modsong.noofchannels; | ||
680 | p_line += line*4*modsong.noofchannels; | ||
681 | |||
682 | /* Only allow one Patternbreak Commando per Line */ | ||
683 | bool patternbreakdone = false; | ||
684 | |||
685 | for (c=0;c<modsong.noofchannels;c++) | ||
686 | { | ||
687 | struct s_modchannel *p_modchannel = &modplayer.modchannel[c]; | ||
688 | unsigned char *p_note = p_line + c*4; | ||
689 | unsigned char samplenumber = (p_note[0] & 0xf0) | (p_note[2] >> 4); | ||
690 | short periodtableoffset = ((p_note[0] & 0x0f) << 8) | p_note[1]; | ||
691 | |||
692 | p_modchannel->effect = p_note[2] & 0x0f; | ||
693 | p_modchannel->effectparameter = p_note[3]; | ||
694 | |||
695 | /* Remember Instrument and set Volume if new Instrument triggered */ | ||
696 | if (samplenumber > 0) | ||
697 | { | ||
698 | /* And trigger new sample, if new instrument was set */ | ||
699 | if (samplenumber-1 != p_modchannel->instrument) | ||
700 | { | ||
701 | /* Advance the new sample to the same offset | ||
702 | * the old sample was beeing played */ | ||
703 | int oldsampleoffset = mixer.channel[c].samplepos - | ||
704 | modsong.instrument[ | ||
705 | p_modchannel->instrument].sampledataoffset; | ||
706 | mixer_playsample(c, samplenumber-1); | ||
707 | mixer.channel[c].samplepos += oldsampleoffset; | ||
708 | } | ||
709 | |||
710 | /* Remember last played instrument on channel */ | ||
711 | p_modchannel->instrument = samplenumber-1; | ||
712 | |||
713 | /* Set Volume to standard instrument volume, | ||
714 | * if not overwritten by volume effect */ | ||
715 | if (p_modchannel->effect != 0x0c) | ||
716 | { | ||
717 | p_modchannel->volume = modsong.instrument[ | ||
718 | p_modchannel->instrument].volume; | ||
719 | mixer_setvolume(c, p_modchannel->volume); | ||
720 | } | ||
721 | } | ||
722 | /* Trigger new sample if note available */ | ||
723 | if (periodtableoffset > 0) | ||
724 | { | ||
725 | /* Restart instrument only when new sample triggered */ | ||
726 | if (samplenumber != 0) | ||
727 | mixer_playsample(c, (samplenumber > 0) ? | ||
728 | samplenumber-1 : p_modchannel->instrument); | ||
729 | |||
730 | /* Set the new amiga period | ||
731 | * (but only, if there is no slide to note effect) */ | ||
732 | if ((p_modchannel->effect != 0x3) && | ||
733 | (p_modchannel->effect != 0x5)) | ||
734 | { | ||
735 | /* Apply finetuning to sample */ | ||
736 | p_modchannel->periodtableoffset = periodtableoffset + | ||
737 | modsong.instrument[p_modchannel->instrument].finetune; | ||
738 | p_modchannel->period = modplayer.periodtable[ | ||
739 | p_modchannel->periodtableoffset]; | ||
740 | mixer_setamigaperiod(c, p_modchannel->period); | ||
741 | /* When a new note is played without slide to note setup, | ||
742 | * then disable slide to note */ | ||
743 | modplayer.modchannel[c].slidetonoteperiod = | ||
744 | p_modchannel->period; | ||
745 | } | ||
746 | } | ||
747 | int effectx = p_modchannel->effectparameter>>4; | ||
748 | int effecty = p_modchannel->effectparameter&0x0f; | ||
749 | |||
750 | switch (p_modchannel->effect) | ||
751 | { | ||
752 | /* Effect 0: Arpeggio */ | ||
753 | case 0x00: | ||
754 | /* Set the base period on tick 0 */ | ||
755 | if (p_modchannel->effectparameter > 0) | ||
756 | mixer_setamigaperiod(c, | ||
757 | modplayer.periodtable[ | ||
758 | p_modchannel->periodtableoffset]); | ||
759 | break; | ||
760 | /* Slide up (Portamento up) */ | ||
761 | case 0x01: | ||
762 | if (p_modchannel->effectparameter > 0) | ||
763 | p_modchannel->slideupspeed = | ||
764 | p_modchannel->effectparameter; | ||
765 | break; | ||
766 | |||
767 | /* Slide down (Portamento down) */ | ||
768 | case 0x02: | ||
769 | if (p_modchannel->effectparameter > 0) | ||
770 | p_modchannel->slidedownspeed = | ||
771 | p_modchannel->effectparameter; | ||
772 | break; | ||
773 | |||
774 | /* Slide to Note */ | ||
775 | case 0x03: | ||
776 | if (p_modchannel->effectparameter > 0) | ||
777 | p_modchannel->slidetonotespeed = | ||
778 | p_modchannel->effectparameter; | ||
779 | /* Get the slide to note directly from the pattern buffer */ | ||
780 | if (periodtableoffset > 0) | ||
781 | p_modchannel->slidetonoteperiod = | ||
782 | modplayer.periodtable[periodtableoffset + | ||
783 | modsong.instrument[ | ||
784 | p_modchannel->instrument].finetune]; | ||
785 | /* If glissando is enabled apply the effect directly here */ | ||
786 | if (modplayer.glissandoenabled) | ||
787 | slidetonoteglissando(c); | ||
788 | break; | ||
789 | |||
790 | /* Set Vibrato */ | ||
791 | case 0x04: | ||
792 | if (effectx > 0) p_modchannel->vibratospeed = effectx; | ||
793 | if (effecty > 0) p_modchannel->vibratodepth = effecty; | ||
794 | break; | ||
795 | |||
796 | /* Effect 0x06: Slide to note */ | ||
797 | case 0x05: | ||
798 | /* Get the slide to note directly from the pattern buffer */ | ||
799 | if (periodtableoffset > 0) | ||
800 | p_modchannel->slidetonoteperiod = | ||
801 | modplayer.periodtable[periodtableoffset + | ||
802 | modsong.instrument[ | ||
803 | p_modchannel->instrument].finetune]; | ||
804 | break; | ||
805 | |||
806 | /* Effect 0x06 is "Continue Effects" */ | ||
807 | /* It is not processed on tick 0 */ | ||
808 | case 0x06: | ||
809 | break; | ||
810 | |||
811 | /* Set Tremolo */ | ||
812 | case 0x07: | ||
813 | if (effectx > 0) p_modchannel->tremolodepth = effectx; | ||
814 | if (effecty > 0) p_modchannel->tremolospeed = effecty; | ||
815 | break; | ||
816 | |||
817 | /* Set fine panning */ | ||
818 | case 0x08: | ||
819 | /* Internal panning goes from 0..15 | ||
820 | * Scale the fine panning value to that range */ | ||
821 | mixer.channel[c].panning = p_modchannel->effectparameter>>4; | ||
822 | break; | ||
823 | |||
824 | /* Set Sample Offset */ | ||
825 | case 0x09: | ||
826 | { | ||
827 | struct s_instrument *p_instrument = | ||
828 | &modsong.instrument[p_modchannel->instrument]; | ||
829 | int sampleoffset = p_instrument->sampledataoffset; | ||
830 | if (sampleoffset > p_instrument->length) | ||
831 | sampleoffset = p_instrument->length; | ||
832 | /* Forward the new offset to the mixer */ | ||
833 | mixer.channel[c].samplepos = | ||
834 | p_instrument->sampledataoffset + | ||
835 | (p_modchannel->effectparameter<<8); | ||
836 | mixer.channel[c].samplefractpos = 0; | ||
837 | break; | ||
838 | } | ||
839 | |||
840 | /* Effect 0x0a (Volume slide) is not processed on tick 0 */ | ||
841 | |||
842 | /* Position Jump */ | ||
843 | case 0x0b: | ||
844 | modplayer.currentline = -1; | ||
845 | modplayer.patterntableposition = (effectx<<4)+effecty; | ||
846 | break; | ||
847 | |||
848 | /* Set Volume */ | ||
849 | case 0x0c: | ||
850 | p_modchannel->volume = p_modchannel->effectparameter; | ||
851 | mixer_setvolume(c, p_modchannel->volume); | ||
852 | break; | ||
853 | |||
854 | /* Pattern break */ | ||
855 | case 0x0d: | ||
856 | modplayer.currentline = effectx*10 + effecty - 1; | ||
857 | if (!patternbreakdone) | ||
858 | { | ||
859 | patternbreakdone = true; | ||
860 | modplayer.patterntableposition++; | ||
861 | } | ||
862 | break; | ||
863 | |||
864 | /* Extended Effects */ | ||
865 | case 0x0e: | ||
866 | switch (effectx) | ||
867 | { | ||
868 | /* Set Filter */ | ||
869 | case 0x0: | ||
870 | modplayer.amigafilterenabled = (effecty == 0); | ||
871 | break; | ||
872 | /* Fineslide up */ | ||
873 | case 0x1: | ||
874 | mixer_setamigaperiod(c, p_modchannel->period -= | ||
875 | effecty); | ||
876 | if (p_modchannel->period < | ||
877 | modplayer.periodtable[37*8]) p_modchannel->period = 100; | ||
878 | /* Find out the new offset in the period table */ | ||
879 | if (p_modchannel->periodtableoffset < 36*8) | ||
880 | while (modplayer.periodtable[ | ||
881 | p_modchannel->periodtableoffset+8] >= p_modchannel->period) | ||
882 | p_modchannel->periodtableoffset+=8; | ||
883 | break; | ||
884 | /* Fineslide down */ | ||
885 | case 0x2: | ||
886 | mixer_setamigaperiod(c, | ||
887 | p_modchannel->period += effecty); | ||
888 | if (p_modchannel->periodtableoffset > 8) | ||
889 | while (modplayer.periodtable[ | ||
890 | p_modchannel->periodtableoffset-8] | ||
891 | <= p_modchannel->period) | ||
892 | p_modchannel->periodtableoffset-=8; | ||
893 | break; | ||
894 | /* Set glissando on/off */ | ||
895 | case 0x3: | ||
896 | modplayer.glissandoenabled = (effecty > 0); | ||
897 | break; | ||
898 | /* Set Vibrato waveform */ | ||
899 | case 0x4: | ||
900 | /* Currently not implemented */ | ||
901 | break; | ||
902 | /* Set Finetune value */ | ||
903 | case 0x5: | ||
904 | /* Treat as signed nibble */ | ||
905 | if (effecty > 7) effecty -= 16; | ||
906 | |||
907 | p_modchannel->periodtableoffset += | ||
908 | effecty - | ||
909 | modsong.instrument[ | ||
910 | p_modchannel->instrument].finetune; | ||
911 | p_modchannel->period = | ||
912 | modplayer.periodtable[ | ||
913 | p_modchannel->periodtableoffset]; | ||
914 | modsong.instrument[ | ||
915 | p_modchannel->instrument].finetune = effecty; | ||
916 | break; | ||
917 | /* Pattern loop */ | ||
918 | case 0x6: | ||
919 | if (effecty == 0) | ||
920 | modplayer.loopstartline = line-1; | ||
921 | else | ||
922 | { | ||
923 | if (modplayer.looptimes == 0) | ||
924 | { | ||
925 | modplayer.currentline = | ||
926 | modplayer.loopstartline; | ||
927 | modplayer.looptimes = effecty; | ||
928 | } | ||
929 | else modplayer.looptimes--; | ||
930 | if (modplayer.looptimes > 0) | ||
931 | modplayer.currentline = | ||
932 | modplayer.loopstartline; | ||
933 | } | ||
934 | break; | ||
935 | /* Set Tremolo waveform */ | ||
936 | case 0x7: | ||
937 | /* Not yet implemented */ | ||
938 | break; | ||
939 | /* Enhanced Effect 8 is not used */ | ||
940 | case 0x8: | ||
941 | break; | ||
942 | /* Retrigger sample */ | ||
943 | case 0x9: | ||
944 | /* Only processed on subsequent ticks */ | ||
945 | break; | ||
946 | /* Fine volume slide up */ | ||
947 | case 0xa: | ||
948 | p_modchannel->volume += effecty; | ||
949 | if (p_modchannel->volume > 64) | ||
950 | p_modchannel->volume = 64; | ||
951 | mixer_setvolume(c, p_modchannel->volume); | ||
952 | break; | ||
953 | /* Fine volume slide down */ | ||
954 | case 0xb: | ||
955 | p_modchannel->volume -= effecty; | ||
956 | if (p_modchannel->volume < 0) | ||
957 | p_modchannel->volume = 0; | ||
958 | mixer_setvolume(c, p_modchannel->volume); | ||
959 | break; | ||
960 | /* Cut sample */ | ||
961 | case 0xc: | ||
962 | /* Continue sample */ | ||
963 | mixer_continuesample(c); | ||
964 | break; | ||
965 | /* Note delay (Usage: $ED + ticks to delay note.) */ | ||
966 | case 0xd: | ||
967 | /* We stop the sample here on tick 0 | ||
968 | * and restart it later in the effect */ | ||
969 | if (effecty > 0) | ||
970 | mixer.channel[c].channelactive = false; | ||
971 | break; | ||
972 | } | ||
973 | break; | ||
974 | |||
975 | /* Set Speed */ | ||
976 | case 0x0f: | ||
977 | if (p_modchannel->effectparameter < 32) | ||
978 | modplayer.ticksperline = p_modchannel->effectparameter; | ||
979 | else | ||
980 | modplayer.bpm = p_modchannel->effectparameter; | ||
981 | break; | ||
982 | } | ||
983 | } | ||
984 | } | ||
985 | |||
986 | /* Play the current effect of the note (ticks 1..speed) */ | ||
987 | STATICIRAM void playeffect(int currenttick) ICODE_ATTR; | ||
988 | void playeffect(int currenttick) | ||
989 | { | ||
990 | int c; | ||
991 | |||
992 | for (c=0;c<modsong.noofchannels;c++) | ||
993 | { | ||
994 | struct s_modchannel *p_modchannel = &modplayer.modchannel[c]; | ||
995 | |||
996 | /* If there is no note active then there are no effects to play */ | ||
997 | if (p_modchannel->period == 0) continue; | ||
998 | |||
999 | unsigned char effectx = p_modchannel->effectparameter>>4; | ||
1000 | unsigned char effecty = p_modchannel->effectparameter&0x0f; | ||
1001 | |||
1002 | switch (p_modchannel->effect) | ||
1003 | { | ||
1004 | /* Effect 0: Arpeggio */ | ||
1005 | case 0x00: | ||
1006 | if (p_modchannel->effectparameter > 0) | ||
1007 | { | ||
1008 | unsigned short newperiodtableoffset; | ||
1009 | switch (currenttick % 3) | ||
1010 | { | ||
1011 | case 0: | ||
1012 | mixer_setamigaperiod(c, | ||
1013 | modplayer.periodtable[ | ||
1014 | p_modchannel->periodtableoffset]); | ||
1015 | break; | ||
1016 | case 1: | ||
1017 | newperiodtableoffset = | ||
1018 | p_modchannel->periodtableoffset+(effectx<<3); | ||
1019 | if (newperiodtableoffset < 37*8) | ||
1020 | mixer_setamigaperiod(c, | ||
1021 | modplayer.periodtable[ | ||
1022 | newperiodtableoffset]); | ||
1023 | break; | ||
1024 | case 2: | ||
1025 | newperiodtableoffset = | ||
1026 | p_modchannel->periodtableoffset+(effecty<<3); | ||
1027 | if (newperiodtableoffset < 37*8) | ||
1028 | mixer_setamigaperiod(c, | ||
1029 | modplayer.periodtable[ | ||
1030 | newperiodtableoffset]); | ||
1031 | break; | ||
1032 | } | ||
1033 | } | ||
1034 | break; | ||
1035 | |||
1036 | /* Effect 1: Slide Up */ | ||
1037 | case 0x01: | ||
1038 | mixer_setamigaperiod(c, | ||
1039 | p_modchannel->period -= p_modchannel->slideupspeed); | ||
1040 | /* Find out the new offset in the period table */ | ||
1041 | if (p_modchannel->periodtableoffset <= 37*8) | ||
1042 | while (modplayer.periodtable[ | ||
1043 | p_modchannel->periodtableoffset] > | ||
1044 | p_modchannel->period) | ||
1045 | { | ||
1046 | p_modchannel->periodtableoffset++; | ||
1047 | /* Make sure we don't go out of range */ | ||
1048 | if (p_modchannel->periodtableoffset > 37*8) | ||
1049 | { | ||
1050 | p_modchannel->periodtableoffset = 37*8; | ||
1051 | break; | ||
1052 | } | ||
1053 | } | ||
1054 | break; | ||
1055 | |||
1056 | /* Effect 2: Slide Down */ | ||
1057 | case 0x02: | ||
1058 | mixer_setamigaperiod(c, p_modchannel->period += | ||
1059 | p_modchannel->slidedownspeed); | ||
1060 | /* Find out the new offset in the period table */ | ||
1061 | if (p_modchannel->periodtableoffset > 8) | ||
1062 | while (modplayer.periodtable[ | ||
1063 | p_modchannel->periodtableoffset] < | ||
1064 | p_modchannel->period) | ||
1065 | { | ||
1066 | p_modchannel->periodtableoffset--; | ||
1067 | /* Make sure we don't go out of range */ | ||
1068 | if (p_modchannel->periodtableoffset < 1) | ||
1069 | { | ||
1070 | p_modchannel->periodtableoffset = 1; | ||
1071 | break; | ||
1072 | } | ||
1073 | } | ||
1074 | break; | ||
1075 | |||
1076 | /* Effect 3: Slide to Note */ | ||
1077 | case 0x03: | ||
1078 | /* Apply smooth sliding, if no glissando is enabled */ | ||
1079 | if (modplayer.glissandoenabled == 0) | ||
1080 | slidetonote(c); | ||
1081 | break; | ||
1082 | |||
1083 | /* Effect 4: Vibrato */ | ||
1084 | case 0x04: | ||
1085 | vibrate(c); | ||
1086 | break; | ||
1087 | |||
1088 | /* Effect 5: Continue effect 3:'Slide to note', | ||
1089 | * but also do Volume slide */ | ||
1090 | case 0x05: | ||
1091 | slidetonote(c); | ||
1092 | volumeslide(c, effectx, effecty); | ||
1093 | break; | ||
1094 | |||
1095 | /* Effect 6: Continue effect 4:'Vibrato', | ||
1096 | * but also do Volume slide */ | ||
1097 | case 0x06: | ||
1098 | vibrate(c); | ||
1099 | volumeslide(c, effectx, effecty); | ||
1100 | break; | ||
1101 | |||
1102 | /* Effect 7: Tremolo */ | ||
1103 | case 0x07: | ||
1104 | tremolo(c); | ||
1105 | break; | ||
1106 | |||
1107 | /* Effect 8 (Set fine panning) is only processed at tick 0 */ | ||
1108 | /* Effect 9 (Set sample offset) is only processed at tick 0 */ | ||
1109 | |||
1110 | /* Effect A: Volume slide */ | ||
1111 | case 0x0a: | ||
1112 | volumeslide(c, effectx, effecty); | ||
1113 | break; | ||
1114 | |||
1115 | /* Effect B (Position jump) is only processed at tick 0 */ | ||
1116 | /* Effect C (Set Volume) is only processed at tick 0 */ | ||
1117 | /* Effect D (Pattern Preak) is only processed at tick 0 */ | ||
1118 | /* Effect E (Enhanced Effect) */ | ||
1119 | case 0x0e: | ||
1120 | switch (effectx) | ||
1121 | { | ||
1122 | /* Retrigger sample ($E9 + Tick to Retrig note at) */ | ||
1123 | case 0x9: | ||
1124 | /* Don't device by zero */ | ||
1125 | if (effecty == 0) effecty = 1; | ||
1126 | /* Apply retrig */ | ||
1127 | if (currenttick % effecty == 0) | ||
1128 | mixer_playsample(c, p_modchannel->instrument); | ||
1129 | break; | ||
1130 | /* Cut note (Usage: $EC + Tick to Cut note at) */ | ||
1131 | case 0xc: | ||
1132 | if (currenttick == effecty) | ||
1133 | mixer_stopsample(c); | ||
1134 | break; | ||
1135 | /* Delay note (Usage: $ED + ticks to delay note) */ | ||
1136 | case 0xd: | ||
1137 | /* If this is the correct tick, | ||
1138 | * we start playing the sample now */ | ||
1139 | if (currenttick == effecty) | ||
1140 | mixer.channel[c].channelactive = true; | ||
1141 | break; | ||
1142 | |||
1143 | } | ||
1144 | break; | ||
1145 | /* Effect F (Set Speed) is only processed at tick 0 */ | ||
1146 | |||
1147 | } | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | static inline int clip(int i) | ||
1152 | { | ||
1153 | if (i > 32767) return(32767); | ||
1154 | else if (i < -32768) return(-32768); | ||
1155 | else return(i); | ||
1156 | } | ||
1157 | |||
1158 | STATICIRAM void synthrender(int32_t *renderbuffer, int samplecount) ICODE_ATTR; | ||
1159 | void synthrender(int32_t *renderbuffer, int samplecount) | ||
1160 | { | ||
1161 | /* 125bpm equals to 50Hz (= 0.02s) | ||
1162 | * => one tick = mixingrate/50, | ||
1163 | * samples passing in one tick: | ||
1164 | * mixingrate/(bpm/2.5) = 2.5*mixingrate/bpm */ | ||
1165 | |||
1166 | int32_t *p_left = renderbuffer; /* int in rockbox */ | ||
1167 | int32_t *p_right = p_left+1; | ||
1168 | signed short s; | ||
1169 | int qf_distance, qf_distance2; | ||
1170 | |||
1171 | int i; | ||
1172 | |||
1173 | int c, left, right; | ||
1174 | |||
1175 | for (i=0;i<samplecount;i++) | ||
1176 | { | ||
1177 | /* New Tick? */ | ||
1178 | if ((modplayer.samplespertick-- <= 0) && | ||
1179 | (modplayer.patterntableposition < 127)) | ||
1180 | { | ||
1181 | if (modplayer.currenttick == 0) | ||
1182 | playline(modsong.patternordertable[ | ||
1183 | modplayer.patterntableposition], modplayer.currentline); | ||
1184 | else playeffect(modplayer.currenttick); | ||
1185 | |||
1186 | modplayer.currenttick++; | ||
1187 | |||
1188 | if (modplayer.currenttick >= modplayer.ticksperline) | ||
1189 | { | ||
1190 | modplayer.currentline++; | ||
1191 | modplayer.currenttick = 0; | ||
1192 | if (modplayer.currentline == 64) | ||
1193 | { | ||
1194 | modplayer.patterntableposition++; | ||
1195 | if (modplayer.patterntableposition >= modsong.songlength) | ||
1196 | /* This is for Noise Tracker | ||
1197 | * modplayer.patterntableposition = | ||
1198 | * modsong.songendjumpposition; | ||
1199 | * More compatible approach is restart from 0 */ | ||
1200 | modplayer.patterntableposition=0; | ||
1201 | modplayer.currentline = 0; | ||
1202 | } | ||
1203 | } | ||
1204 | |||
1205 | modplayer.samplespertick = (20*mixingrate/modplayer.bpm)>>3; | ||
1206 | } | ||
1207 | /* Mix buffers from here | ||
1208 | * Walk through all channels */ | ||
1209 | left=0, right=0; | ||
1210 | |||
1211 | /* If song has not stopped playing */ | ||
1212 | if (modplayer.patterntableposition < 127) | ||
1213 | /* Loop through all channels */ | ||
1214 | for (c=0;c<modsong.noofchannels;c++) | ||
1215 | { | ||
1216 | /* Only mix the sample, | ||
1217 | * if channel there is something played on the channel */ | ||
1218 | if (!mixer.channel[c].channelactive) continue; | ||
1219 | |||
1220 | /* Loop the sample, if requested? */ | ||
1221 | if (mixer.channel[c].samplepos >= mixer.channel[c].loopend) | ||
1222 | { | ||
1223 | if (mixer.channel[c].loopsample) | ||
1224 | mixer.channel[c].samplepos -= | ||
1225 | (mixer.channel[c].loopend- | ||
1226 | mixer.channel[c].loopstart); | ||
1227 | else mixer.channel[c].channelactive = false; | ||
1228 | } | ||
1229 | |||
1230 | /* If the sample has stopped playing don't mix it */ | ||
1231 | if (!mixer.channel[c].channelactive) continue; | ||
1232 | |||
1233 | /* Get the sample */ | ||
1234 | s = (signed short)(modsong.sampledata[ | ||
1235 | mixer.channel[c].samplepos]*mixer.channel[c].volume); | ||
1236 | |||
1237 | /* Interpolate if the sample-frequency is lower | ||
1238 | * than the mixing rate | ||
1239 | * If you don't want interpolation simply skip this part */ | ||
1240 | if (mixer.channel[c].frequency < mixingrate) | ||
1241 | { | ||
1242 | /* Low precision linear interpolation | ||
1243 | * (fast integer based) */ | ||
1244 | qf_distance = mixer.channel[c].samplefractpos<<16 / | ||
1245 | mixingrate; | ||
1246 | qf_distance2 = (1<<16)-qf_distance; | ||
1247 | s = (qf_distance*s + qf_distance2* | ||
1248 | mixer.channel[c].lastsampledata)>>16; | ||
1249 | } | ||
1250 | |||
1251 | /* Save the last played sample for interpolation purposes */ | ||
1252 | mixer.channel[c].lastsampledata = s; | ||
1253 | |||
1254 | /* Pan the sample */ | ||
1255 | left += s*(16-mixer.channel[c].panning)>>3; | ||
1256 | right += s*mixer.channel[c].panning>>3; | ||
1257 | |||
1258 | /* Advance sample */ | ||
1259 | mixer.channel[c].samplefractpos += mixer.channel[c].frequency; | ||
1260 | while (mixer.channel[c].samplefractpos > mixingrate) | ||
1261 | { | ||
1262 | mixer.channel[c].samplefractpos -= mixingrate; | ||
1263 | mixer.channel[c].samplepos++; | ||
1264 | } | ||
1265 | } | ||
1266 | /* If we have more than 4 channels | ||
1267 | * we have to make sure that we apply clipping */ | ||
1268 | if (modsong.noofchannels > 4) { | ||
1269 | *p_left = clip(left)<<13; | ||
1270 | *p_right = clip(right)<<13; | ||
1271 | } | ||
1272 | else { | ||
1273 | *p_left = left<<13; | ||
1274 | *p_right = right<<13; | ||
1275 | } | ||
1276 | p_left+=2; | ||
1277 | p_right+=2; | ||
1278 | } | ||
1279 | } | ||
1280 | |||
1281 | /* this is the codec entry point */ | ||
1282 | enum codec_status codec_main(enum codec_entry_call_reason reason) | ||
1283 | { | ||
1284 | if (reason == CODEC_LOAD) { | ||
1285 | /* Make use of 44.1khz */ | ||
1286 | ci->configure(DSP_SET_FREQUENCY, 44100); | ||
1287 | /* Sample depth is 28 bit host endian */ | ||
1288 | ci->configure(DSP_SET_SAMPLE_DEPTH, 28); | ||
1289 | /* Stereo output */ | ||
1290 | ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); | ||
1291 | } | ||
1292 | |||
1293 | return CODEC_OK; | ||
1294 | } | ||
1295 | |||
1296 | /* this is called for each file to process */ | ||
1297 | enum codec_status codec_run(void) | ||
1298 | { | ||
1299 | size_t n; | ||
1300 | unsigned char *modfile; | ||
1301 | int old_patterntableposition; | ||
1302 | int bytesdone; | ||
1303 | intptr_t param; | ||
1304 | |||
1305 | if (codec_init()) { | ||
1306 | return CODEC_ERROR; | ||
1307 | } | ||
1308 | |||
1309 | codec_set_replaygain(ci->id3); | ||
1310 | |||
1311 | /* Load MOD file */ | ||
1312 | ci->seek_buffer(0); | ||
1313 | modfile = ci->request_buffer(&n, ci->filesize); | ||
1314 | if (!modfile || n < (size_t)ci->filesize) { | ||
1315 | return CODEC_ERROR; | ||
1316 | } | ||
1317 | |||
1318 | initmodplayer(); | ||
1319 | loadmod(modfile); | ||
1320 | |||
1321 | /* The main decoder loop */ | ||
1322 | ci->set_elapsed(0); | ||
1323 | bytesdone = 0; | ||
1324 | old_patterntableposition = 0; | ||
1325 | |||
1326 | while (1) { | ||
1327 | enum codec_command_action action = ci->get_command(¶m); | ||
1328 | |||
1329 | if (action == CODEC_ACTION_HALT) | ||
1330 | break; | ||
1331 | |||
1332 | if (action == CODEC_ACTION_SEEK_TIME) { | ||
1333 | /* New time is ready in param */ | ||
1334 | modplayer.patterntableposition = param/1000; | ||
1335 | modplayer.currentline = 0; | ||
1336 | ci->seek_complete(); | ||
1337 | } | ||
1338 | |||
1339 | if(old_patterntableposition != modplayer.patterntableposition) { | ||
1340 | ci->set_elapsed(modplayer.patterntableposition*1000); | ||
1341 | old_patterntableposition=modplayer.patterntableposition; | ||
1342 | } | ||
1343 | |||
1344 | synthrender(samples, CHUNK_SIZE/2); | ||
1345 | |||
1346 | bytesdone += CHUNK_SIZE; | ||
1347 | |||
1348 | ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE/2); | ||
1349 | |||
1350 | } | ||
1351 | |||
1352 | return CODEC_OK; | ||
1353 | } | ||