Submit initial patch from FS#12176. Adds support for several new game music formats...
[kugel-rb.git] / apps / codecs / mod.c
blob3703ecd304f5084eec6efa1cb6ba7bfa7f03004e
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * MOD Codec for rockbox
12 * Written from scratch by Rainer Sinsch
13 * exclusivly for Rockbox in February 2008
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.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
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 *************/
33 #include "debug.h"
34 #include "codeclib.h"
35 #include <inttypes.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <ctype.h>
43 CODEC_HEADER
45 #define CHUNK_SIZE (1024*2)
48 /* This codec supports MOD Files:
52 static int32_t samples[CHUNK_SIZE] IBSS_ATTR; /* The sample buffer */
54 /* Instrument Data */
55 struct s_instrument {
56 /* Sample name / description */
57 /*char description[22];*/
59 /* Sample length in bytes */
60 unsigned short length;
62 /* Sample finetuning (-8 - +7) */
63 signed char finetune;
65 /* Sample volume (0 - 64) */
66 signed char volume;
68 /* Sample Repeat Position */
69 unsigned short repeatoffset;
71 /* Sample Repeat Length */
72 unsigned short repeatlength;
74 /* Offset to sample data */
75 unsigned int sampledataoffset;
78 /* Song Data */
79 struct s_song {
80 /* Song name / title description */
81 /*char szTitle[20];*/
83 /* No. of channels in song */
84 unsigned char noofchannels;
86 /* No. of instruments used (either 15 or 31) */
87 unsigned char noofinstruments;
89 /* How many patterns are beeing played? */
90 unsigned char songlength;
92 /* Where to jump after the song end? */
93 unsigned char songendjumpposition;
95 /* Pointer to the Pattern Order Table */
96 unsigned char *patternordertable;
98 /* Pointer to the pattern data */
99 void *patterndata;
101 /* Pointer to the sample buffer */
102 signed char *sampledata;
104 /* Instrument data */
105 struct s_instrument instrument[31];
108 struct s_modchannel {
109 /* Current Volume */
110 signed char volume;
112 /* Current Offset to period in PeriodTable of notebeeing played
113 (can be temporarily negative) */
114 short periodtableoffset;
116 /* Current Period beeing played */
117 short period;
119 /* Current effect */
120 unsigned char effect;
122 /* Current parameters of effect */
123 unsigned char effectparameter;
125 /* Current Instrument beeing played */
126 unsigned char instrument;
128 /* Current Vibrato Speed */
129 unsigned char vibratospeed;
131 /* Current Vibrato Depth */
132 unsigned char vibratodepth;
134 /* Current Position for Vibrato in SinTable */
135 unsigned char vibratosinpos;
137 /* Current Tremolo Speed */
138 unsigned char tremolospeed;
140 /* Current Tremolo Depth */
141 unsigned char tremolodepth;
143 /* Current Position for Tremolo in SinTable */
144 unsigned char tremolosinpos;
146 /* Current Speed of Effect "Slide Note up" */
147 unsigned char slideupspeed;
149 /* Current Speed of Effect "Slide Note down" */
150 unsigned char slidedownspeed;
152 /* Current Speed of the "Slide to Note" effect */
153 unsigned char slidetonotespeed;
155 /* Current Period of the "Slide to Note" effect */
156 unsigned short slidetonoteperiod;
159 struct s_modplayer {
160 /* Ticks per Line */
161 unsigned char ticksperline;
163 /* Beats per Minute */
164 unsigned char bpm;
166 /* Position of the Song in the Pattern Table (0-127) */
167 unsigned char patterntableposition;
169 /* Current Line (may be temporarily < 0) */
170 signed char currentline;
172 /* Current Tick */
173 signed char currenttick;
175 /* How many samples are required to calculate for each tick? */
176 unsigned int samplespertick;
178 /* Information about the channels */
179 struct s_modchannel modchannel[8];
181 /* The Amiga Period Table */
182 unsigned short *periodtable;
184 /* The sinus table [-255,255] */
185 signed short *sintable;
187 /* Is the glissando effect enabled? */
188 bool glissandoenabled;
190 /* Is the Amiga Filter enabled? */
191 bool amigafilterenabled;
193 /* The pattern-line where the loop is carried out (set with e6 command) */
194 unsigned char loopstartline;
196 /* Number of times to loop */
197 unsigned char looptimes;
200 struct s_channel {
201 /* Panning (0 = left, 16 = right) */
202 unsigned char panning;
204 /* Sample frequency of the channel */
205 unsigned short frequency;
207 /* Position of the sample currently played */
208 unsigned int samplepos;
210 /* Fractual Position of the sample currently player */
211 unsigned int samplefractpos;
213 /* Loop Sample */
214 bool loopsample;
216 /* Loop Position Start */
217 unsigned int loopstart;
219 /* Loop Position End */
220 unsigned int loopend;
222 /* Is The channel beeing played? */
223 bool channelactive;
225 /* The Volume (0..64) */
226 signed char volume;
228 /* The last sampledata beeing played (required for interpolation) */
229 signed short lastsampledata;
232 struct s_mixer {
233 /* The channels */
234 struct s_channel channel[32];
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;
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};
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};
293 const unsigned short mixingrate = 44100;
295 STATICIRAM void mixer_playsample(int channel, int instrument) ICODE_ATTR;
296 void mixer_playsample(int channel, int instrument)
298 struct s_channel *p_channel = &mixer.channel[channel];
299 struct s_instrument *p_instrument = &modsong.instrument[instrument];
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;
311 else p_channel->loopend = p_instrument->length +
312 p_instrument->sampledataoffset;
314 /* Remember the instrument */
315 modplayer.modchannel[channel].instrument = instrument;
318 static inline void mixer_stopsample(int channel)
320 mixer.channel[channel].channelactive = false;
323 static inline void mixer_continuesample(int channel)
325 mixer.channel[channel].channelactive = true;
328 static inline void mixer_setvolume(int channel, int volume)
330 mixer.channel[channel].volume = volume;
333 static inline void mixer_setpanning(int channel, int panning)
335 mixer.channel[channel].panning = panning;
338 static inline void mixer_setamigaperiod(int channel, int amigaperiod)
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;
346 mixer.channel[channel].frequency = 3579546 / amigaperiod;
349 /* Initialize the MOD Player with default values and precalc tables */
350 STATICIRAM void initmodplayer(void) ICODE_ATTR;
351 void initmodplayer(void)
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. */
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++)
367 modplayer.periodtable[i] = (unsigned short) f;
368 f /= 1.0072464122237039; /* = pow(2.0f, 1.0f/(12.0f*8.0f)); */
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++)
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);
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]
392 float a, b, d, dd;
394 d = 0.09817475f; /* = 2*PI/64 */
395 dd = d*d;
396 a = 0;
397 b = d;
399 for (i=0;i<0x40;i++)
401 modplayer.sintable[i] = (int)(255*a);
403 a = a+b;
404 b = b-dd*a;
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 */
420 /* Default Panning Values */
421 int panningvalues[8] = {4,12,12,4,4,12,12,4};
422 for (c=0;c<8;c++)
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;
434 /* Load the MOD File from memory */
435 STATICIRAM bool loadmod(void *modfile) ICODE_ATTR;
436 bool loadmod(void *modfile)
438 int i;
439 unsigned char *periodsconverted;
441 /* We don't support PowerPacker 2.0 Files */
442 if (memcmp((char*) modfile, "PP20", 4) == 0) return false;
444 /* Get the File Format Tag */
445 char *fileformattag = (char*)modfile + 1080;
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;
472 /* Get the Song title
473 * Skipped here
474 * strncpy(modsong.szTitle, (char*)pMODFile, 20); */
476 /* Get the Instrument information */
477 for (i=0;i<modsong.noofinstruments;i++)
479 struct s_instrument *instrument = &modsong.instrument[i];
480 unsigned char *p = (unsigned char *)modfile + 20 + i*30;
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;
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;
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++;
507 /* use 'restartposition' (historically set to 127) which is not used here
508 as a marker that periods have already been converted */
510 periodsconverted = (char*)modfile + 20 + modsong.noofinstruments*30 + 1;
512 /* Get the pattern data; ST doesn't have fileformattag, so 4 bytes less */
513 modsong.patterndata = periodsconverted +
514 (modsong.noofinstruments==15 ? 129 : 133);
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)
521 int note, note2, channel;
522 for (note=0;note<maxpatterns*64;note++)
523 for (channel=0;channel<modsong.noofchannels;channel++)
525 int period = ((p[0] & 0x0f) << 8) | p[1];
526 int periodoffset = 0;
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)
532 periodoffset = note2*8+1;
533 break;
535 /* Write back the period offset */
536 p[0] = (periodoffset >> 8) | (p[0] & 0xf0);
537 p[1] = periodoffset & 0xff;
538 p += 4;
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;
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++)
556 modsong.instrument[i].sampledataoffset = sampledataoffset;
557 sampledataoffset += modsong.instrument[i].length;
560 return true;
563 /* Apply vibrato to channel */
564 STATICIRAM void vibrate(int channel) ICODE_ATTR;
565 void vibrate(int channel)
567 struct s_modchannel *p_modchannel = &modplayer.modchannel[channel];
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));
575 /* Foward in Sine Table */
576 p_modchannel->vibratosinpos += p_modchannel->vibratospeed;
577 p_modchannel->vibratosinpos &= 0x3f;
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)
585 struct s_modchannel *p_modchannel = &modplayer.modchannel[channel];
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);
595 /* Foward in Sine Table */
596 p_modchannel->tremolosinpos += p_modchannel->tremolosinpos;
597 p_modchannel->tremolosinpos &= 0x3f;
600 /* Apply Slide to Note effect to channel */
601 STATICIRAM void slidetonote(int channel) ICODE_ATTR;
602 void slidetonote(int channel)
604 struct s_modchannel *p_modchannel = &modplayer.modchannel[channel];
606 /* If there hasn't been any slide-to note set up, then return */
607 if (p_modchannel->slidetonoteperiod == 0) return;
609 /* Slide note up */
610 if (p_modchannel->slidetonoteperiod > p_modchannel->period)
612 p_modchannel->period += p_modchannel->slidetonotespeed;
613 if (p_modchannel->period > p_modchannel->slidetonoteperiod)
614 p_modchannel->period = p_modchannel->slidetonoteperiod;
616 /* Slide note down */
617 else if (p_modchannel->slidetonoteperiod < p_modchannel->period)
619 p_modchannel->period -= p_modchannel->slidetonotespeed;
620 if (p_modchannel->period < p_modchannel->slidetonoteperiod)
621 p_modchannel->period = p_modchannel->slidetonoteperiod;
623 mixer_setamigaperiod(channel, p_modchannel->period);
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)
631 struct s_modchannel *p_modchannel = &modplayer.modchannel[channel];
633 /* Slide note up */
634 if (p_modchannel->slidetonoteperiod > p_modchannel->period)
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;
641 /* Slide note down */
642 else
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;
649 mixer_setamigaperiod(channel, p_modchannel->period);
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)
656 struct s_modchannel *p_modchannel = &modplayer.modchannel[channel];
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;
663 else {
664 p_modchannel->volume -= effecty;
665 if (p_modchannel->volume < 0) p_modchannel->volume = 0;
668 mixer_setvolume(channel, p_modchannel->volume);
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)
675 int c;
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;
682 /* Only allow one Patternbreak Commando per Line */
683 bool patternbreakdone = false;
685 for (c=0;c<modsong.noofchannels;c++)
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];
692 p_modchannel->effect = p_note[2] & 0x0f;
693 p_modchannel->effectparameter = p_note[3];
695 /* Remember Instrument and set Volume if new Instrument triggered */
696 if (samplenumber > 0)
698 /* And trigger new sample, if new instrument was set */
699 if (samplenumber-1 != p_modchannel->instrument)
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;
710 /* Remember last played instrument on channel */
711 p_modchannel->instrument = samplenumber-1;
713 /* Set Volume to standard instrument volume,
714 * if not overwritten by volume effect */
715 if (p_modchannel->effect != 0x0c)
717 p_modchannel->volume = modsong.instrument[
718 p_modchannel->instrument].volume;
719 mixer_setvolume(c, p_modchannel->volume);
722 /* Trigger new sample if note available */
723 if (periodtableoffset > 0)
725 /* Restart instrument only when new sample triggered */
726 if (samplenumber != 0)
727 mixer_playsample(c, (samplenumber > 0) ?
728 samplenumber-1 : p_modchannel->instrument);
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))
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;
747 int effectx = p_modchannel->effectparameter>>4;
748 int effecty = p_modchannel->effectparameter&0x0f;
750 switch (p_modchannel->effect)
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;
767 /* Slide down (Portamento down) */
768 case 0x02:
769 if (p_modchannel->effectparameter > 0)
770 p_modchannel->slidedownspeed =
771 p_modchannel->effectparameter;
772 break;
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;
790 /* Set Vibrato */
791 case 0x04:
792 if (effectx > 0) p_modchannel->vibratospeed = effectx;
793 if (effecty > 0) p_modchannel->vibratodepth = effecty;
794 break;
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;
806 /* Effect 0x06 is "Continue Effects" */
807 /* It is not processed on tick 0 */
808 case 0x06:
809 break;
811 /* Set Tremolo */
812 case 0x07:
813 if (effectx > 0) p_modchannel->tremolodepth = effectx;
814 if (effecty > 0) p_modchannel->tremolospeed = effecty;
815 break;
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;
824 /* Set Sample Offset */
825 case 0x09:
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;
840 /* Effect 0x0a (Volume slide) is not processed on tick 0 */
842 /* Position Jump */
843 case 0x0b:
844 modplayer.currentline = -1;
845 modplayer.patterntableposition = (effectx<<4)+effecty;
846 break;
848 /* Set Volume */
849 case 0x0c:
850 p_modchannel->volume = p_modchannel->effectparameter;
851 mixer_setvolume(c, p_modchannel->volume);
852 break;
854 /* Pattern break */
855 case 0x0d:
856 modplayer.currentline = effectx*10 + effecty - 1;
857 if (!patternbreakdone)
859 patternbreakdone = true;
860 modplayer.patterntableposition++;
862 break;
864 /* Extended Effects */
865 case 0x0e:
866 switch (effectx)
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;
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
923 if (modplayer.looptimes == 0)
925 modplayer.currentline =
926 modplayer.loopstartline;
927 modplayer.looptimes = effecty;
929 else modplayer.looptimes--;
930 if (modplayer.looptimes > 0)
931 modplayer.currentline =
932 modplayer.loopstartline;
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;
973 break;
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;
986 /* Play the current effect of the note (ticks 1..speed) */
987 STATICIRAM void playeffect(int currenttick) ICODE_ATTR;
988 void playeffect(int currenttick)
990 int c;
992 for (c=0;c<modsong.noofchannels;c++)
994 struct s_modchannel *p_modchannel = &modplayer.modchannel[c];
996 /* If there is no note active then there are no effects to play */
997 if (p_modchannel->period == 0) continue;
999 unsigned char effectx = p_modchannel->effectparameter>>4;
1000 unsigned char effecty = p_modchannel->effectparameter&0x0f;
1002 switch (p_modchannel->effect)
1004 /* Effect 0: Arpeggio */
1005 case 0x00:
1006 if (p_modchannel->effectparameter > 0)
1008 unsigned short newperiodtableoffset;
1009 switch (currenttick % 3)
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;
1034 break;
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)
1046 p_modchannel->periodtableoffset++;
1047 /* Make sure we don't go out of range */
1048 if (p_modchannel->periodtableoffset > 37*8)
1050 p_modchannel->periodtableoffset = 37*8;
1051 break;
1054 break;
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)
1066 p_modchannel->periodtableoffset--;
1067 /* Make sure we don't go out of range */
1068 if (p_modchannel->periodtableoffset < 1)
1070 p_modchannel->periodtableoffset = 1;
1071 break;
1074 break;
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;
1083 /* Effect 4: Vibrato */
1084 case 0x04:
1085 vibrate(c);
1086 break;
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;
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;
1102 /* Effect 7: Tremolo */
1103 case 0x07:
1104 tremolo(c);
1105 break;
1107 /* Effect 8 (Set fine panning) is only processed at tick 0 */
1108 /* Effect 9 (Set sample offset) is only processed at tick 0 */
1110 /* Effect A: Volume slide */
1111 case 0x0a:
1112 volumeslide(c, effectx, effecty);
1113 break;
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)
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;
1144 break;
1145 /* Effect F (Set Speed) is only processed at tick 0 */
1151 static inline int clip(int i)
1153 if (i > 32767) return(32767);
1154 else if (i < -32768) return(-32768);
1155 else return(i);
1158 STATICIRAM void synthrender(int32_t *renderbuffer, int samplecount) ICODE_ATTR;
1159 void synthrender(int32_t *renderbuffer, int samplecount)
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 */
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;
1171 int i;
1173 int c, left, right;
1175 for (i=0;i<samplecount;i++)
1177 /* New Tick? */
1178 if ((modplayer.samplespertick-- <= 0) &&
1179 (modplayer.patterntableposition < 127))
1181 if (modplayer.currenttick == 0)
1182 playline(modsong.patternordertable[
1183 modplayer.patterntableposition], modplayer.currentline);
1184 else playeffect(modplayer.currenttick);
1186 modplayer.currenttick++;
1188 if (modplayer.currenttick >= modplayer.ticksperline)
1190 modplayer.currentline++;
1191 modplayer.currenttick = 0;
1192 if (modplayer.currentline == 64)
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;
1205 modplayer.samplespertick = (20*mixingrate/modplayer.bpm)>>3;
1207 /* Mix buffers from here
1208 * Walk through all channels */
1209 left=0, right=0;
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++)
1216 /* Only mix the sample,
1217 * if channel there is something played on the channel */
1218 if (!mixer.channel[c].channelactive) continue;
1220 /* Loop the sample, if requested? */
1221 if (mixer.channel[c].samplepos >= mixer.channel[c].loopend)
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;
1230 /* If the sample has stopped playing don't mix it */
1231 if (!mixer.channel[c].channelactive) continue;
1233 /* Get the sample */
1234 s = (signed short)(modsong.sampledata[
1235 mixer.channel[c].samplepos]*mixer.channel[c].volume);
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)
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;
1251 /* Save the last played sample for interpolation purposes */
1252 mixer.channel[c].lastsampledata = s;
1254 /* Pan the sample */
1255 left += s*(16-mixer.channel[c].panning)>>3;
1256 right += s*mixer.channel[c].panning>>3;
1258 /* Advance sample */
1259 mixer.channel[c].samplefractpos += mixer.channel[c].frequency;
1260 while (mixer.channel[c].samplefractpos > mixingrate)
1262 mixer.channel[c].samplefractpos -= mixingrate;
1263 mixer.channel[c].samplepos++;
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;
1272 else {
1273 *p_left = left<<13;
1274 *p_right = right<<13;
1276 p_left+=2;
1277 p_right+=2;
1281 /* this is the codec entry point */
1282 enum codec_status codec_main(enum codec_entry_call_reason reason)
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);
1293 return CODEC_OK;
1296 /* this is called for each file to process */
1297 enum codec_status codec_run(void)
1299 size_t n;
1300 unsigned char *modfile;
1301 int old_patterntableposition;
1302 int bytesdone;
1303 intptr_t param;
1305 if (codec_init()) {
1306 return CODEC_ERROR;
1309 codec_set_replaygain(ci->id3);
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;
1318 initmodplayer();
1319 loadmod(modfile);
1321 /* The main decoder loop */
1322 ci->set_elapsed(0);
1323 bytesdone = 0;
1324 old_patterntableposition = 0;
1326 while (1) {
1327 enum codec_command_action action = ci->get_command(&param);
1329 if (action == CODEC_ACTION_HALT)
1330 break;
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->set_elapsed(modplayer.patterntableposition*1000+500);
1337 ci->seek_complete();
1340 if(old_patterntableposition != modplayer.patterntableposition) {
1341 ci->set_elapsed(modplayer.patterntableposition*1000+500);
1342 old_patterntableposition=modplayer.patterntableposition;
1345 synthrender(samples, CHUNK_SIZE/2);
1347 bytesdone += CHUNK_SIZE;
1349 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE/2);
1353 return CODEC_OK;