summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/mod.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/mod.c')
-rw-r--r--lib/rbcodec/codecs/mod.c1353
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
43CODEC_HEADER
44
45#define CHUNK_SIZE (1024*2)
46
47
48/* This codec supports MOD Files:
49 *
50 */
51
52static int32_t samples[CHUNK_SIZE] IBSS_ATTR; /* The sample buffer */
53
54/* Instrument Data */
55struct 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 */
79struct 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
108struct 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
159struct 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
200struct 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
232struct s_mixer {
233 /* The channels */
234 struct s_channel channel[32];
235};
236
237struct s_song modsong IDATA_ATTR; /* The Song */
238struct s_modplayer modplayer IDATA_ATTR; /* The Module Player */
239struct s_mixer mixer IDATA_ATTR;
240
241/* The Amiga Period Table (+1 because we use index 0 for period 0 = no new note) */
242static 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 */
283static 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
293const unsigned short mixingrate = 44100;
294
295STATICIRAM void mixer_playsample(int channel, int instrument) ICODE_ATTR;
296void 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
318static inline void mixer_stopsample(int channel)
319{
320 mixer.channel[channel].channelactive = false;
321}
322
323static inline void mixer_continuesample(int channel)
324{
325 mixer.channel[channel].channelactive = true;
326}
327
328static inline void mixer_setvolume(int channel, int volume)
329{
330 mixer.channel[channel].volume = volume;
331}
332
333static inline void mixer_setpanning(int channel, int panning)
334{
335 mixer.channel[channel].panning = panning;
336}
337
338static 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 */
350STATICIRAM void initmodplayer(void) ICODE_ATTR;
351void 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 */
435STATICIRAM bool loadmod(void *modfile) ICODE_ATTR;
436bool 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 */
564STATICIRAM void vibrate(int channel) ICODE_ATTR;
565void 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) */
582STATICIRAM void tremolo(int channel) ICODE_ATTR;
583void 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 */
601STATICIRAM void slidetonote(int channel) ICODE_ATTR;
602void 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 */
628STATICIRAM void slidetonoteglissando(int channel) ICODE_ATTR;
629void 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 */
653STATICIRAM void volumeslide(int channel, int effectx, int effecty) ICODE_ATTR;
654void 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) */
672STATICIRAM void playline(int pattern, int line) ICODE_ATTR;
673void 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) */
987STATICIRAM void playeffect(int currenttick) ICODE_ATTR;
988void 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
1151static 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
1158STATICIRAM void synthrender(int32_t *renderbuffer, int samplecount) ICODE_ATTR;
1159void 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 */
1282enum 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 */
1297enum 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(&param);
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}