1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
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
45 #define CHUNK_SIZE (1024*2)
48 /* This codec supports MOD Files:
52 static int32_t samples
[CHUNK_SIZE
] IBSS_ATTR
; /* The sample buffer */
56 /* Sample name / description */
57 /*char description[22];*/
59 /* Sample length in bytes */
60 unsigned short length
;
62 /* Sample finetuning (-8 - +7) */
65 /* Sample volume (0 - 64) */
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
;
80 /* Song name / title description */
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 */
101 /* Pointer to the sample buffer */
102 signed char *sampledata
;
104 /* Instrument data */
105 struct s_instrument instrument
[31];
108 struct s_modchannel
{
112 /* Current Offset to period in PeriodTable of notebeeing played
113 (can be temporarily negative) */
114 short periodtableoffset
;
116 /* Current Period beeing played */
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
;
161 unsigned char ticksperline
;
163 /* Beats per Minute */
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
;
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
;
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
;
216 /* Loop Position Start */
217 unsigned int loopstart
;
219 /* Loop Position End */
220 unsigned int loopend
;
222 /* Is The channel beeing played? */
225 /* The Volume (0..64) */
228 /* The last sampledata beeing played (required for interpolation) */
229 signed short lastsampledata
;
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,
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)
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)
355 /* As the calculation of periodtable and sintable uses float and double
356 * rockbox uses two predefined tables. This reduces the codesize by
360 /* Calculate Amiga Period Values
361 * Start with Period 907 (= C-1 with Finetune -8) and work upwards */
363 /* Index 0 stands for no note (and therefore no period) */
364 modplayer
.periodtable
[0] = 0;
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));
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]
394 d
= 0.09817475f
; /* = 2*PI/64 */
401 modplayer
.sintable
[i
] = (int)(255*a
);
407 /* Point to the predefined tables */
408 modplayer
.periodtable
= s_periodtable
;
409 modplayer
.sintable
= s_sintable
;
411 /* Set Default Player Values */
412 modplayer
.currentline
= 0;
413 modplayer
.currenttick
= 0;
414 modplayer
.patterntableposition
= 0;
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};
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
)
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;}
467 /* The file has no format tag, so most likely soundtracker */
468 modsong
.noofchannels
= 4;
469 modsong
.noofinstruments
= 15;
472 /* Get the Song title
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); */
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 */
503 if (modsong
.patternordertable
[i
] > maxpatterns
)
504 maxpatterns
= modsong
.patternordertable
[i
];
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;
535 /* Write back the period offset */
536 p
[0] = (periodoffset
>> 8) | (p
[0] & 0xf0);
537 p
[1] = periodoffset
& 0xff;
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;
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
;
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
];
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
];
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;
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
];
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 */
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 */
660 p_modchannel
->volume
+= effectx
;
661 if (p_modchannel
->volume
> 64) p_modchannel
->volume
= 64;
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
)
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
-
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 */
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
]);
760 /* Slide up (Portamento up) */
762 if (p_modchannel
->effectparameter
> 0)
763 p_modchannel
->slideupspeed
=
764 p_modchannel
->effectparameter
;
767 /* Slide down (Portamento down) */
769 if (p_modchannel
->effectparameter
> 0)
770 p_modchannel
->slidedownspeed
=
771 p_modchannel
->effectparameter
;
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
+
784 p_modchannel
->instrument
].finetune
];
785 /* If glissando is enabled apply the effect directly here */
786 if (modplayer
.glissandoenabled
)
787 slidetonoteglissando(c
);
792 if (effectx
> 0) p_modchannel
->vibratospeed
= effectx
;
793 if (effecty
> 0) p_modchannel
->vibratodepth
= effecty
;
796 /* Effect 0x06: Slide to note */
798 /* Get the slide to note directly from the pattern buffer */
799 if (periodtableoffset
> 0)
800 p_modchannel
->slidetonoteperiod
=
801 modplayer
.periodtable
[periodtableoffset
+
803 p_modchannel
->instrument
].finetune
];
806 /* Effect 0x06 is "Continue Effects" */
807 /* It is not processed on tick 0 */
813 if (effectx
> 0) p_modchannel
->tremolodepth
= effectx
;
814 if (effecty
> 0) p_modchannel
->tremolospeed
= effecty
;
817 /* Set fine panning */
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;
824 /* Set Sample Offset */
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;
840 /* Effect 0x0a (Volume slide) is not processed on tick 0 */
844 modplayer
.currentline
= -1;
845 modplayer
.patterntableposition
= (effectx
<<4)+effecty
;
850 p_modchannel
->volume
= p_modchannel
->effectparameter
;
851 mixer_setvolume(c
, p_modchannel
->volume
);
856 modplayer
.currentline
= effectx
*10 + effecty
- 1;
857 if (!patternbreakdone
)
859 patternbreakdone
= true;
860 modplayer
.patterntableposition
++;
864 /* Extended Effects */
870 modplayer
.amigafilterenabled
= (effecty
== 0);
874 mixer_setamigaperiod(c
, p_modchannel
->period
-=
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;
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;
894 /* Set glissando on/off */
896 modplayer
.glissandoenabled
= (effecty
> 0);
898 /* Set Vibrato waveform */
900 /* Currently not implemented */
902 /* Set Finetune value */
904 /* Treat as signed nibble */
905 if (effecty
> 7) effecty
-= 16;
907 p_modchannel
->periodtableoffset
+=
910 p_modchannel
->instrument
].finetune
;
911 p_modchannel
->period
=
912 modplayer
.periodtable
[
913 p_modchannel
->periodtableoffset
];
915 p_modchannel
->instrument
].finetune
= effecty
;
920 modplayer
.loopstartline
= line
-1;
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
;
935 /* Set Tremolo waveform */
937 /* Not yet implemented */
939 /* Enhanced Effect 8 is not used */
942 /* Retrigger sample */
944 /* Only processed on subsequent ticks */
946 /* Fine volume slide up */
948 p_modchannel
->volume
+= effecty
;
949 if (p_modchannel
->volume
> 64)
950 p_modchannel
->volume
= 64;
951 mixer_setvolume(c
, p_modchannel
->volume
);
953 /* Fine volume slide down */
955 p_modchannel
->volume
-= effecty
;
956 if (p_modchannel
->volume
< 0)
957 p_modchannel
->volume
= 0;
958 mixer_setvolume(c
, p_modchannel
->volume
);
962 /* Continue sample */
963 mixer_continuesample(c
);
965 /* Note delay (Usage: $ED + ticks to delay note.) */
967 /* We stop the sample here on tick 0
968 * and restart it later in the effect */
970 mixer
.channel
[c
].channelactive
= false;
977 if (p_modchannel
->effectparameter
< 32)
978 modplayer
.ticksperline
= p_modchannel
->effectparameter
;
980 modplayer
.bpm
= p_modchannel
->effectparameter
;
986 /* Play the current effect of the note (ticks 1..speed) */
987 STATICIRAM
void playeffect(int currenttick
) ICODE_ATTR
;
988 void playeffect(int currenttick
)
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 */
1006 if (p_modchannel
->effectparameter
> 0)
1008 unsigned short newperiodtableoffset
;
1009 switch (currenttick
% 3)
1012 mixer_setamigaperiod(c
,
1013 modplayer
.periodtable
[
1014 p_modchannel
->periodtableoffset
]);
1017 newperiodtableoffset
=
1018 p_modchannel
->periodtableoffset
+(effectx
<<3);
1019 if (newperiodtableoffset
< 37*8)
1020 mixer_setamigaperiod(c
,
1021 modplayer
.periodtable
[
1022 newperiodtableoffset
]);
1025 newperiodtableoffset
=
1026 p_modchannel
->periodtableoffset
+(effecty
<<3);
1027 if (newperiodtableoffset
< 37*8)
1028 mixer_setamigaperiod(c
,
1029 modplayer
.periodtable
[
1030 newperiodtableoffset
]);
1036 /* Effect 1: Slide Up */
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;
1056 /* Effect 2: Slide Down */
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;
1076 /* Effect 3: Slide to Note */
1078 /* Apply smooth sliding, if no glissando is enabled */
1079 if (modplayer
.glissandoenabled
== 0)
1083 /* Effect 4: Vibrato */
1088 /* Effect 5: Continue effect 3:'Slide to note',
1089 * but also do Volume slide */
1092 volumeslide(c
, effectx
, effecty
);
1095 /* Effect 6: Continue effect 4:'Vibrato',
1096 * but also do Volume slide */
1099 volumeslide(c
, effectx
, effecty
);
1102 /* Effect 7: Tremolo */
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 */
1112 volumeslide(c
, effectx
, effecty
);
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) */
1122 /* Retrigger sample ($E9 + Tick to Retrig note at) */
1124 /* Don't device by zero */
1125 if (effecty
== 0) effecty
= 1;
1127 if (currenttick
% effecty
== 0)
1128 mixer_playsample(c
, p_modchannel
->instrument
);
1130 /* Cut note (Usage: $EC + Tick to Cut note at) */
1132 if (currenttick
== effecty
)
1133 mixer_stopsample(c
);
1135 /* Delay note (Usage: $ED + ticks to delay note) */
1137 /* If this is the correct tick,
1138 * we start playing the sample now */
1139 if (currenttick
== effecty
)
1140 mixer
.channel
[c
].channelactive
= true;
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);
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;
1169 int qf_distance
, qf_distance2
;
1175 for (i
=0;i
<samplecount
;i
++)
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 */
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 /
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;
1274 *p_right
= right
<<13;
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);
1290 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_INTERLEAVED
);
1296 /* this is called for each file to process */
1297 enum codec_status
codec_run(void)
1300 unsigned char *modfile
;
1301 int old_patterntableposition
;
1309 codec_set_replaygain(ci
->id3
);
1313 modfile
= ci
->request_buffer(&n
, ci
->filesize
);
1314 if (!modfile
|| n
< (size_t)ci
->filesize
) {
1321 /* The main decoder loop */
1324 old_patterntableposition
= 0;
1327 enum codec_command_action action
= ci
->get_command(¶m
);
1329 if (action
== CODEC_ACTION_HALT
)
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);