blob: 3dfaac663f09ed55a473bc98e67cfd1d3431932c [file] [log] [blame]
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001/***************************************************************************
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 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000015 * 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.
Thom Johansenc0f7eb92008-05-21 11:19:58 +000019 *
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 (+1 because we use index 0 for period 0 = no new note) */
183 unsigned short periodtable[37*8+1];
184
185 /* The sinus table [-255,255] */
186 signed short sintable[0x40];
187
188 /* Is the glissando effect enabled? */
189 bool glissandoenabled;
190
191 /* Is the Amiga Filter enabled? */
192 bool amigafilterenabled;
193
194 /* The pattern-line where the loop is carried out (set with e6 command) */
195 unsigned char loopstartline;
196
197 /* Number of times to loop */
198 unsigned char looptimes;
199};
200
201struct s_channel {
202 /* Panning (0 = left, 16 = right) */
203 unsigned char panning;
204
205 /* Sample frequency of the channel */
206 unsigned short frequency;
207
208 /* Position of the sample currently played */
209 unsigned int samplepos;
210
211 /* Fractual Position of the sample currently player */
212 unsigned int samplefractpos;
213
214 /* Loop Sample */
215 bool loopsample;
216
217 /* Loop Position Start */
218 unsigned int loopstart;
219
220 /* Loop Position End */
221 unsigned int loopend;
222
223 /* Is The channel beeing played? */
224 bool channelactive;
225
226 /* The Volume (0..64) */
227 signed char volume;
228
229 /* The last sampledata beeing played (required for interpolation) */
230 signed short lastsampledata;
231};
232
233struct s_mixer {
234 /* The channels */
235 struct s_channel channel[32];
236};
237
238struct s_song modsong IDATA_ATTR; /* The Song */
239struct s_modplayer modplayer IDATA_ATTR; /* The Module Player */
240struct s_mixer mixer IDATA_ATTR;
241
242const unsigned short mixingrate = 44100;
243
244STATICIRAM void mixer_playsample(int channel, int instrument) ICODE_ATTR;
245void mixer_playsample(int channel, int instrument)
246{
247 struct s_channel *p_channel = &mixer.channel[channel];
248 struct s_instrument *p_instrument = &modsong.instrument[instrument];
249
250 p_channel->channelactive = true;
251 p_channel->samplepos = p_instrument->sampledataoffset;
252 p_channel->samplefractpos = 0;
Bertrik Sikken5c4ef782010-01-01 22:47:25 +0000253 p_channel->loopsample = (p_instrument->repeatlength > 2);
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000254 if (p_channel->loopsample) {
255 p_channel->loopstart = p_instrument->repeatoffset +
256 p_instrument->sampledataoffset;
257 p_channel->loopend = p_channel->loopstart +
258 p_instrument->repeatlength;
259 }
260 else p_channel->loopend = p_instrument->length +
261 p_instrument->sampledataoffset;
262
263 /* Remember the instrument */
264 modplayer.modchannel[channel].instrument = instrument;
265}
266
Bertrik Sikken8e22f7f2008-12-29 19:49:48 +0000267static inline void mixer_stopsample(int channel)
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000268{
269 mixer.channel[channel].channelactive = false;
270}
271
Bertrik Sikken8e22f7f2008-12-29 19:49:48 +0000272static inline void mixer_continuesample(int channel)
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000273{
274 mixer.channel[channel].channelactive = true;
275}
276
Bertrik Sikken8e22f7f2008-12-29 19:49:48 +0000277static inline void mixer_setvolume(int channel, int volume)
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000278{
279 mixer.channel[channel].volume = volume;
280}
281
Bertrik Sikken8e22f7f2008-12-29 19:49:48 +0000282static inline void mixer_setpanning(int channel, int panning)
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000283{
284 mixer.channel[channel].panning = panning;
285}
286
Bertrik Sikken8e22f7f2008-12-29 19:49:48 +0000287static inline void mixer_setamigaperiod(int channel, int amigaperiod)
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000288{
289 /* Just to make sure we don't devide by zero
290 * amigaperiod shouldn't 0 anyway - if it is the case
291 * then something terribly went wrong */
292 if (amigaperiod == 0)
293 return;
294
295 mixer.channel[channel].frequency = 3579546 / amigaperiod;
296}
297
298/* Initialize the MOD Player with default values and precalc tables */
299STATICIRAM void initmodplayer(void) ICODE_ATTR;
300void initmodplayer(void)
301{
302 unsigned int i,c;
303
304 /* Calculate Amiga Period Values
305 * Start with Period 907 (= C-1 with Finetune -8) and work upwards */
306 double f = 907.0f;
307 /* Index 0 stands for no note (and therefore no period) */
308 modplayer.periodtable[0] = 0;
309 for (i=1;i<297;i++)
310 {
311 modplayer.periodtable[i] = (unsigned short) f;
312 f /= 1.0072464122237039; /* = pow(2.0f, 1.0f/(12.0f*8.0f)); */
313 }
314
315 /*
316 * This is a more accurate but also time more consuming approach
317 * to calculate the amiga period table
318 * Commented out for speed purposes
319 const int finetuning = 8;
320 const int octaves = 3;
321 for (int halftone=0;halftone<=finetuning*octaves*12+7;halftone++)
322 {
323 float e = pow(2.0f, halftone/(12.0f*8.0f));
324 float f = 906.55f/e;
325 modplayer.periodtable[halfetone+1] = (int)(f+0.5f);
326 }
327 */
328
329 /* Calculate Protracker Vibrato sine table
330 * The routine makes use of the Harmonical Oscillator Approach
331 * for calculating sine tables
332 * (see http://membres.lycos.fr/amycoders/tutorials/sintables.html)
333 * The routine presented here calculates a complete sine wave
334 * with 64 values in range [-255,255]
335 */
336 float a, b, d, dd;
337
338 d = 0.09817475f; /* = 2*PI/64 */
339 dd = d*d;
340 a = 0;
341 b = d;
342
343 for (i=0;i<0x40;i++)
344 {
345 modplayer.sintable[i] = (int)(255*a);
346
347 a = a+b;
348 b = b-dd*a;
349 }
350
351 /* Set Default Player Values */
352 modplayer.currentline = 0;
353 modplayer.currenttick = 0;
354 modplayer.patterntableposition = 0;
355 modplayer.bpm = 125;
356 modplayer.ticksperline = 6;
357 modplayer.glissandoenabled = false; /* Disable glissando */
358 modplayer.amigafilterenabled = false; /* Disable the Amiga Filter */
359
360 /* Default Panning Values */
361 int panningvalues[8] = {4,12,12,4,4,12,12,4};
362 for (c=0;c<8;c++)
363 {
364 /* Set Default Panning */
365 mixer_setpanning(c, panningvalues[c]);
366 /* Reset channels in the MOD Player */
367 memset(&modplayer.modchannel[c], 0, sizeof(struct s_modchannel));
368 /* Don't play anything */
369 mixer.channel[c].channelactive = false;
370 }
371
372}
373
374/* Load the MOD File from memory */
375STATICIRAM bool loadmod(void *modfile) ICODE_ATTR;
376bool loadmod(void *modfile)
377{
378 int i;
Robert Kuklad23f78b2008-05-26 23:00:07 +0000379 unsigned char *periodsconverted;
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000380
381 /* We don't support PowerPacker 2.0 Files */
382 if (memcmp((char*) modfile, "PP20", 4) == 0) return false;
383
384 /* Get the File Format Tag */
385 char *fileformattag = (char*)modfile + 1080;
386
387 /* Find out how many channels and instruments are used */
388 if (memcmp(fileformattag, "2CHN", 4) == 0)
389 {modsong.noofchannels = 2; modsong.noofinstruments = 31;}
390 else if (memcmp(fileformattag, "M.K.", 4) == 0)
391 {modsong.noofchannels = 4; modsong.noofinstruments = 31;}
392 else if (memcmp(fileformattag, "M!K!", 4) == 0)
393 {modsong.noofchannels = 4; modsong.noofinstruments = 31;}
394 else if (memcmp(fileformattag, "4CHN", 4) == 0)
395 {modsong.noofchannels = 4; modsong.noofinstruments = 31;}
396 else if (memcmp(fileformattag, "FLT4", 4) == 0)
397 {modsong.noofchannels = 4; modsong.noofinstruments = 31;}
398 else if (memcmp(fileformattag, "6CHN", 4) == 0)
399 {modsong.noofchannels = 6; modsong.noofinstruments = 31;}
400 else if (memcmp(fileformattag, "8CHN", 4) == 0)
401 {modsong.noofchannels = 8; modsong.noofinstruments = 31;}
402 else if (memcmp(fileformattag, "OKTA", 4) == 0)
403 {modsong.noofchannels = 8; modsong.noofinstruments = 31;}
404 else if (memcmp(fileformattag, "CD81", 4) == 0)
405 {modsong.noofchannels = 8; modsong.noofinstruments = 31;}
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000406 else {
Robert Kuklad23f78b2008-05-26 23:00:07 +0000407 /* The file has no format tag, so most likely soundtracker */
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000408 modsong.noofchannels = 4;
Robert Kuklad23f78b2008-05-26 23:00:07 +0000409 modsong.noofinstruments = 15;
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000410 }
411
412 /* Get the Song title
413 * Skipped here
414 * strncpy(modsong.szTitle, (char*)pMODFile, 20); */
415
416 /* Get the Instrument information */
417 for (i=0;i<modsong.noofinstruments;i++)
418 {
419 struct s_instrument *instrument = &modsong.instrument[i];
420 unsigned char *p = (unsigned char *)modfile + 20 + i*30;
421
422 /*strncpy(instrument->description, (char*)p, 22); */
423 p += 22;
424 instrument->length = (((p[0])<<8) + p[1]) << 1; p+=2;
425 instrument->finetune = *p++ & 0x0f;
426 /* Treat finetuning as signed nibble */
427 if (instrument->finetune > 7) instrument->finetune -= 16;
428 instrument->volume = *p++;
429 instrument->repeatoffset = (((p[0])<<8) + p[1]) << 1; p+= 2;
430 instrument->repeatlength = (((p[0])<<8) + p[1]) << 1;
431 }
432
433 /* Get the pattern information */
434 unsigned char *p = (unsigned char *)modfile + 20 +
435 modsong.noofinstruments*30;
436 modsong.songlength = *p++;
437 modsong.songendjumpposition = *p++;
438 modsong.patternordertable = p;
439
440 /* Find out how many patterns are used within this song */
441 int maxpatterns = 0;
442 for (i=0;i<128;i++)
443 if (modsong.patternordertable[i] > maxpatterns)
444 maxpatterns = modsong.patternordertable[i];
445 maxpatterns++;
446
Robert Kuklad23f78b2008-05-26 23:00:07 +0000447 /* use 'restartposition' (historically set to 127) which is not used here
448 as a marker that periods have already been converted */
449
450 periodsconverted = (char*)modfile + 20 + modsong.noofinstruments*30 + 1;
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000451
Robert Kuklad23f78b2008-05-26 23:00:07 +0000452 /* Get the pattern data; ST doesn't have fileformattag, so 4 bytes less */
453 modsong.patterndata = periodsconverted +
454 (modsong.noofinstruments==15 ? 129 : 133);
455
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000456 /* Convert the period values in the mod file to offsets
457 * in our periodtable (but only, if we haven't done this yet) */
458 p = (unsigned char *) modsong.patterndata;
Robert Kuklad23f78b2008-05-26 23:00:07 +0000459 if (*periodsconverted != 0xfe)
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000460 {
461 int note, note2, channel;
462 for (note=0;note<maxpatterns*64;note++)
463 for (channel=0;channel<modsong.noofchannels;channel++)
464 {
465 int period = ((p[0] & 0x0f) << 8) | p[1];
466 int periodoffset = 0;
467
468 /* Find the offset of the current period */
469 for (note2 = 1; note2 < 12*3+1; note2++)
470 if (abs(modplayer.periodtable[note2*8+1]-period) < 4)
471 {
472 periodoffset = note2*8+1;
473 break;
474 }
475 /* Write back the period offset */
476 p[0] = (periodoffset >> 8) | (p[0] & 0xf0);
477 p[1] = periodoffset & 0xff;
478 p += 4;
479 }
480 /* Remember that we already converted the periods,
Robert Kuklad23f78b2008-05-26 23:00:07 +0000481 * in case the file gets reloaded by rewinding
482 * with 0xfe (arbitary magic value > 127) */
483 *periodsconverted = 0xfe;
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000484 }
485
486 /* Get the samples
487 * Calculation: The Samples come after the pattern data
488 * We know that there are nMaxPatterns and each pattern requires
489 * 4 bytes per note and per channel.
490 * And of course there are always lines in each channel */
491 modsong.sampledata = (signed char*) modsong.patterndata +
492 maxpatterns*4*modsong.noofchannels*64;
493 int sampledataoffset = 0;
494 for (i=0;i<modsong.noofinstruments;i++)
495 {
496 modsong.instrument[i].sampledataoffset = sampledataoffset;
497 sampledataoffset += modsong.instrument[i].length;
498 }
499
500 return true;
501}
502
503/* Apply vibrato to channel */
504STATICIRAM void vibrate(int channel) ICODE_ATTR;
505void vibrate(int channel)
506{
507 struct s_modchannel *p_modchannel = &modplayer.modchannel[channel];
508
509 /* Apply Vibrato
510 * >> 7 is used in the original protracker source code */
511 mixer_setamigaperiod(channel, p_modchannel->period+
512 ((p_modchannel->vibratodepth *
513 modplayer.sintable[p_modchannel->vibratosinpos])>>7));
514
515 /* Foward in Sine Table */
516 p_modchannel->vibratosinpos += p_modchannel->vibratospeed;
517 p_modchannel->vibratosinpos &= 0x3f;
518}
519
520/* Apply tremolo to channel
521 * (same as vibrato, but only apply on volume instead of pitch) */
522STATICIRAM void tremolo(int channel) ICODE_ATTR;
523void tremolo(int channel)
524{
525 struct s_modchannel *p_modchannel = &modplayer.modchannel[channel];
526
527 /* Apply Tremolo
528 * >> 6 is used in the original protracker source code */
529 int volume = (p_modchannel->volume *
530 modplayer.sintable[p_modchannel->tremolosinpos])>>6;
531 if (volume > 64) volume = 64;
532 else if (volume < 0) volume = 0;
533 mixer_setvolume(channel, volume);
534
535 /* Foward in Sine Table */
536 p_modchannel->tremolosinpos += p_modchannel->tremolosinpos;
537 p_modchannel->tremolosinpos &= 0x3f;
538}
539
540/* Apply Slide to Note effect to channel */
541STATICIRAM void slidetonote(int channel) ICODE_ATTR;
542void slidetonote(int channel)
543{
544 struct s_modchannel *p_modchannel = &modplayer.modchannel[channel];
545
546 /* If there hasn't been any slide-to note set up, then return */
547 if (p_modchannel->slidetonoteperiod == 0) return;
548
549 /* Slide note up */
550 if (p_modchannel->slidetonoteperiod > p_modchannel->period)
551 {
552 p_modchannel->period += p_modchannel->slidetonotespeed;
553 if (p_modchannel->period > p_modchannel->slidetonoteperiod)
554 p_modchannel->period = p_modchannel->slidetonoteperiod;
555 }
556 /* Slide note down */
557 else if (p_modchannel->slidetonoteperiod < p_modchannel->period)
558 {
559 p_modchannel->period -= p_modchannel->slidetonotespeed;
560 if (p_modchannel->period < p_modchannel->slidetonoteperiod)
561 p_modchannel->period = p_modchannel->slidetonoteperiod;
562 }
563 mixer_setamigaperiod(channel, p_modchannel->period);
564}
565
566/* Apply Slide to Note effect on channel,
567 * but this time with glissando enabled */
568STATICIRAM void slidetonoteglissando(int channel) ICODE_ATTR;
569void slidetonoteglissando(int channel)
570{
571 struct s_modchannel *p_modchannel = &modplayer.modchannel[channel];
572
573 /* Slide note up */
574 if (p_modchannel->slidetonoteperiod > p_modchannel->period)
575 {
576 p_modchannel->period =
577 modplayer.periodtable[p_modchannel->periodtableoffset+=8];
578 if (p_modchannel->period > p_modchannel->slidetonoteperiod)
579 p_modchannel->period = p_modchannel->slidetonoteperiod;
580 }
581 /* Slide note down */
582 else
583 {
584 p_modchannel->period =
585 modplayer.periodtable[p_modchannel->periodtableoffset-=8];
586 if (p_modchannel->period < p_modchannel->slidetonoteperiod)
587 p_modchannel->period = p_modchannel->slidetonoteperiod;
588 }
589 mixer_setamigaperiod(channel, p_modchannel->period);
590}
591
592/* Apply Volume Slide */
593STATICIRAM void volumeslide(int channel, int effectx, int effecty) ICODE_ATTR;
594void volumeslide(int channel, int effectx, int effecty)
595{
596 struct s_modchannel *p_modchannel = &modplayer.modchannel[channel];
597
598 /* If both X and Y Parameters are non-zero, then the y value is ignored */
599 if (effectx > 0) {
600 p_modchannel->volume += effectx;
601 if (p_modchannel->volume > 64) p_modchannel->volume = 64;
602 }
603 else {
604 p_modchannel->volume -= effecty;
605 if (p_modchannel->volume < 0) p_modchannel->volume = 0;
606 }
607
608 mixer_setvolume(channel, p_modchannel->volume);
609}
610
611/* Play the current line (at tick 0) */
612STATICIRAM void playline(int pattern, int line) ICODE_ATTR;
613void playline(int pattern, int line)
614{
615 int c;
616
617 /* Get pointer to the current pattern */
618 unsigned char *p_line = (unsigned char*)modsong.patterndata;
619 p_line += pattern*64*4*modsong.noofchannels;
620 p_line += line*4*modsong.noofchannels;
621
622 /* Only allow one Patternbreak Commando per Line */
623 bool patternbreakdone = false;
624
625 for (c=0;c<modsong.noofchannels;c++)
626 {
627 struct s_modchannel *p_modchannel = &modplayer.modchannel[c];
628 unsigned char *p_note = p_line + c*4;
629 unsigned char samplenumber = (p_note[0] & 0xf0) | (p_note[2] >> 4);
630 short periodtableoffset = ((p_note[0] & 0x0f) << 8) | p_note[1];
631
632 p_modchannel->effect = p_note[2] & 0x0f;
633 p_modchannel->effectparameter = p_note[3];
634
635 /* Remember Instrument and set Volume if new Instrument triggered */
636 if (samplenumber > 0)
637 {
638 /* And trigger new sample, if new instrument was set */
639 if (samplenumber-1 != p_modchannel->instrument)
640 {
641 /* Advance the new sample to the same offset
642 * the old sample was beeing played */
643 int oldsampleoffset = mixer.channel[c].samplepos -
644 modsong.instrument[
645 p_modchannel->instrument].sampledataoffset;
646 mixer_playsample(c, samplenumber-1);
647 mixer.channel[c].samplepos += oldsampleoffset;
648 }
649
650 /* Remember last played instrument on channel */
651 p_modchannel->instrument = samplenumber-1;
652
653 /* Set Volume to standard instrument volume,
654 * if not overwritten by volume effect */
655 if (p_modchannel->effect != 0x0c)
656 {
657 p_modchannel->volume = modsong.instrument[
658 p_modchannel->instrument].volume;
659 mixer_setvolume(c, p_modchannel->volume);
660 }
661 }
662 /* Trigger new sample if note available */
663 if (periodtableoffset > 0)
664 {
665 /* Restart instrument only when new sample triggered */
666 if (samplenumber != 0)
667 mixer_playsample(c, (samplenumber > 0) ?
668 samplenumber-1 : p_modchannel->instrument);
669
670 /* Set the new amiga period
671 * (but only, if there is no slide to note effect) */
672 if ((p_modchannel->effect != 0x3) &&
673 (p_modchannel->effect != 0x5))
674 {
675 /* Apply finetuning to sample */
676 p_modchannel->periodtableoffset = periodtableoffset +
677 modsong.instrument[p_modchannel->instrument].finetune;
678 p_modchannel->period = modplayer.periodtable[
679 p_modchannel->periodtableoffset];
680 mixer_setamigaperiod(c, p_modchannel->period);
681 /* When a new note is played without slide to note setup,
682 * then disable slide to note */
683 modplayer.modchannel[c].slidetonoteperiod =
684 p_modchannel->period;
685 }
686 }
687 int effectx = p_modchannel->effectparameter>>4;
688 int effecty = p_modchannel->effectparameter&0x0f;
689
690 switch (p_modchannel->effect)
691 {
692 /* Effect 0: Arpeggio */
693 case 0x00:
694 /* Set the base period on tick 0 */
695 if (p_modchannel->effectparameter > 0)
696 mixer_setamigaperiod(c,
697 modplayer.periodtable[
698 p_modchannel->periodtableoffset]);
699 break;
700 /* Slide up (Portamento up) */
701 case 0x01:
702 if (p_modchannel->effectparameter > 0)
703 p_modchannel->slideupspeed =
704 p_modchannel->effectparameter;
705 break;
706
707 /* Slide down (Portamento down) */
708 case 0x02:
709 if (p_modchannel->effectparameter > 0)
710 p_modchannel->slidedownspeed =
711 p_modchannel->effectparameter;
712 break;
713
714 /* Slide to Note */
715 case 0x03:
716 if (p_modchannel->effectparameter > 0)
717 p_modchannel->slidetonotespeed =
718 p_modchannel->effectparameter;
719 /* Get the slide to note directly from the pattern buffer */
720 if (periodtableoffset > 0)
721 p_modchannel->slidetonoteperiod =
722 modplayer.periodtable[periodtableoffset +
723 modsong.instrument[
724 p_modchannel->instrument].finetune];
725 /* If glissando is enabled apply the effect directly here */
726 if (modplayer.glissandoenabled)
727 slidetonoteglissando(c);
728 break;
729
730 /* Set Vibrato */
731 case 0x04:
732 if (effectx > 0) p_modchannel->vibratospeed = effectx;
733 if (effecty > 0) p_modchannel->vibratodepth = effecty;
734 break;
735
736 /* Effect 0x06: Slide to note */
737 case 0x05:
738 /* Get the slide to note directly from the pattern buffer */
739 if (periodtableoffset > 0)
740 p_modchannel->slidetonoteperiod =
741 modplayer.periodtable[periodtableoffset +
742 modsong.instrument[
743 p_modchannel->instrument].finetune];
744 break;
745
746 /* Effect 0x06 is "Continue Effects" */
747 /* It is not processed on tick 0 */
748 case 0x06:
749 break;
750
751 /* Set Tremolo */
752 case 0x07:
753 if (effectx > 0) p_modchannel->tremolodepth = effectx;
754 if (effecty > 0) p_modchannel->tremolospeed = effecty;
755 break;
756
757 /* Set fine panning */
758 case 0x08:
759 /* Internal panning goes from 0..15
760 * Scale the fine panning value to that range */
761 mixer.channel[c].panning = p_modchannel->effectparameter>>4;
762 break;
763
764 /* Set Sample Offset */
765 case 0x09:
766 {
767 struct s_instrument *p_instrument =
768 &modsong.instrument[p_modchannel->instrument];
769 int sampleoffset = p_instrument->sampledataoffset;
770 if (sampleoffset > p_instrument->length)
771 sampleoffset = p_instrument->length;
772 /* Forward the new offset to the mixer */
773 mixer.channel[c].samplepos =
774 p_instrument->sampledataoffset +
775 (p_modchannel->effectparameter<<8);
776 mixer.channel[c].samplefractpos = 0;
777 break;
778 }
779
780 /* Effect 0x0a (Volume slide) is not processed on tick 0 */
781
782 /* Position Jump */
783 case 0x0b:
784 modplayer.currentline = -1;
785 modplayer.patterntableposition = (effectx<<4)+effecty;
786 break;
787
788 /* Set Volume */
789 case 0x0c:
790 p_modchannel->volume = p_modchannel->effectparameter;
791 mixer_setvolume(c, p_modchannel->volume);
792 break;
793
794 /* Pattern break */
795 case 0x0d:
796 modplayer.currentline = effectx*10 + effecty - 1;
797 if (!patternbreakdone)
798 {
799 patternbreakdone = true;
800 modplayer.patterntableposition++;
801 }
802 break;
803
804 /* Extended Effects */
805 case 0x0e:
806 switch (effectx)
807 {
808 /* Set Filter */
809 case 0x0:
Bertrik Sikken5c4ef782010-01-01 22:47:25 +0000810 modplayer.amigafilterenabled = (effecty == 0);
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000811 break;
812 /* Fineslide up */
813 case 0x1:
814 mixer_setamigaperiod(c, p_modchannel->period -=
815 effecty);
816 if (p_modchannel->period <
817 modplayer.periodtable[37*8]) p_modchannel->period = 100;
818 /* Find out the new offset in the period table */
819 if (p_modchannel->periodtableoffset < 36*8)
820 while (modplayer.periodtable[
821 p_modchannel->periodtableoffset+8] >= p_modchannel->period)
822 p_modchannel->periodtableoffset+=8;
823 break;
824 /* Fineslide down */
825 case 0x2:
826 mixer_setamigaperiod(c,
827 p_modchannel->period += effecty);
828 if (p_modchannel->periodtableoffset > 8)
829 while (modplayer.periodtable[
830 p_modchannel->periodtableoffset-8]
831 <= p_modchannel->period)
832 p_modchannel->periodtableoffset-=8;
833 break;
834 /* Set glissando on/off */
835 case 0x3:
Bertrik Sikken5c4ef782010-01-01 22:47:25 +0000836 modplayer.glissandoenabled = (effecty > 0);
Thom Johansenc0f7eb92008-05-21 11:19:58 +0000837 break;
838 /* Set Vibrato waveform */
839 case 0x4:
840 /* Currently not implemented */
841 break;
842 /* Set Finetune value */
843 case 0x5:
844 /* Treat as signed nibble */
845 if (effecty > 7) effecty -= 16;
846
847 p_modchannel->periodtableoffset +=
848 effecty -
849 modsong.instrument[
850 p_modchannel->instrument].finetune;
851 p_modchannel->period =
852 modplayer.periodtable[
853 p_modchannel->periodtableoffset];
854 modsong.instrument[
855 p_modchannel->instrument].finetune = effecty;
856 break;
857 /* Pattern loop */
858 case 0x6:
859 if (effecty == 0)
860 modplayer.loopstartline = line-1;
861 else
862 {
863 if (modplayer.looptimes == 0)
864 {
865 modplayer.currentline =
866 modplayer.loopstartline;
867 modplayer.looptimes = effecty;
868 }
869 else modplayer.looptimes--;
870 if (modplayer.looptimes > 0)
871 modplayer.currentline =
872 modplayer.loopstartline;
873 }
874 break;
875 /* Set Tremolo waveform */
876 case 0x7:
877 /* Not yet implemented */
878 break;
879 /* Enhanced Effect 8 is not used */
880 case 0x8:
881 break;
882 /* Retrigger sample */
883 case 0x9:
884 /* Only processed on subsequent ticks */
885 break;
886 /* Fine volume slide up */
887 case 0xa:
888 p_modchannel->volume += effecty;
889 if (p_modchannel->volume > 64)
890 p_modchannel->volume = 64;
891 mixer_setvolume(c, p_modchannel->volume);
892 break;
893 /* Fine volume slide down */
894 case 0xb:
895 p_modchannel->volume -= effecty;
896 if (p_modchannel->volume < 0)
897 p_modchannel->volume = 0;
898 mixer_setvolume(c, p_modchannel->volume);
899 break;
900 /* Cut sample */
901 case 0xc:
902 /* Continue sample */
903 mixer_continuesample(c);
904 break;
905 /* Note delay (Usage: $ED + ticks to delay note.) */
906 case 0xd:
907 /* We stop the sample here on tick 0
908 * and restart it later in the effect */
909 if (effecty > 0)
910 mixer.channel[c].channelactive = false;
911 break;
912 }
913 break;
914
915 /* Set Speed */
916 case 0x0f:
917 if (p_modchannel->effectparameter < 32)
918 modplayer.ticksperline = p_modchannel->effectparameter;
919 else
920 modplayer.bpm = p_modchannel->effectparameter;
921 break;
922 }
923 }
924}
925
926/* Play the current effect of the note (ticks 1..speed) */
927STATICIRAM void playeffect(int currenttick) ICODE_ATTR;
928void playeffect(int currenttick)
929{
930 int c;
931
932 for (c=0;c<modsong.noofchannels;c++)
933 {
934 struct s_modchannel *p_modchannel = &modplayer.modchannel[c];
935
936 /* If there is no note active then there are no effects to play */
937 if (p_modchannel->period == 0) continue;
938
939 unsigned char effectx = p_modchannel->effectparameter>>4;
940 unsigned char effecty = p_modchannel->effectparameter&0x0f;
941
942 switch (p_modchannel->effect)
943 {
944 /* Effect 0: Arpeggio */
945 case 0x00:
946 if (p_modchannel->effectparameter > 0)
947 {
948 unsigned short newperiodtableoffset;
949 switch (currenttick % 3)
950 {
951 case 0:
952 mixer_setamigaperiod(c,
953 modplayer.periodtable[
954 p_modchannel->periodtableoffset]);
955 break;
956 case 1:
957 newperiodtableoffset =
958 p_modchannel->periodtableoffset+(effectx<<3);
959 if (newperiodtableoffset < 37*8)
960 mixer_setamigaperiod(c,
961 modplayer.periodtable[
962 newperiodtableoffset]);
963 break;
964 case 2:
965 newperiodtableoffset =
966 p_modchannel->periodtableoffset+(effecty<<3);
967 if (newperiodtableoffset < 37*8)
968 mixer_setamigaperiod(c,
969 modplayer.periodtable[
970 newperiodtableoffset]);
971 break;
972 }
973 }
974 break;
975
976 /* Effect 1: Slide Up */
977 case 0x01:
978 mixer_setamigaperiod(c,
979 p_modchannel->period -= p_modchannel->slideupspeed);
980 /* Find out the new offset in the period table */
981 if (p_modchannel->periodtableoffset <= 37*8)
982 while (modplayer.periodtable[
983 p_modchannel->periodtableoffset] >
984 p_modchannel->period)
985 {
986 p_modchannel->periodtableoffset++;
987 /* Make sure we don't go out of range */
988 if (p_modchannel->periodtableoffset > 37*8)
989 {
990 p_modchannel->periodtableoffset = 37*8;
991 break;
992 }
993 }
994 break;
995
996 /* Effect 2: Slide Down */
997 case 0x02:
998 mixer_setamigaperiod(c, p_modchannel->period +=
999 p_modchannel->slidedownspeed);
1000 /* Find out the new offset in the period table */
1001 if (p_modchannel->periodtableoffset > 8)
1002 while (modplayer.periodtable[
1003 p_modchannel->periodtableoffset] <
1004 p_modchannel->period)
1005 {
1006 p_modchannel->periodtableoffset--;
1007 /* Make sure we don't go out of range */
1008 if (p_modchannel->periodtableoffset < 1)
1009 {
1010 p_modchannel->periodtableoffset = 1;
1011 break;
1012 }
1013 }
1014 break;
1015
1016 /* Effect 3: Slide to Note */
1017 case 0x03:
1018 /* Apply smooth sliding, if no glissando is enabled */
1019 if (modplayer.glissandoenabled == 0)
1020 slidetonote(c);
1021 break;
1022
1023 /* Effect 4: Vibrato */
1024 case 0x04:
1025 vibrate(c);
1026 break;
1027
1028 /* Effect 5: Continue effect 3:'Slide to note',
1029 * but also do Volume slide */
1030 case 0x05:
1031 slidetonote(c);
1032 volumeslide(c, effectx, effecty);
1033 break;
1034
1035 /* Effect 6: Continue effect 4:'Vibrato',
1036 * but also do Volume slide */
1037 case 0x06:
1038 vibrate(c);
1039 volumeslide(c, effectx, effecty);
1040 break;
1041
1042 /* Effect 7: Tremolo */
1043 case 0x07:
1044 tremolo(c);
1045 break;
1046
1047 /* Effect 8 (Set fine panning) is only processed at tick 0 */
1048 /* Effect 9 (Set sample offset) is only processed at tick 0 */
1049
1050 /* Effect A: Volume slide */
1051 case 0x0a:
1052 volumeslide(c, effectx, effecty);
1053 break;
1054
1055 /* Effect B (Position jump) is only processed at tick 0 */
1056 /* Effect C (Set Volume) is only processed at tick 0 */
1057 /* Effect D (Pattern Preak) is only processed at tick 0 */
1058 /* Effect E (Enhanced Effect) */
1059 case 0x0e:
1060 switch (effectx)
1061 {
1062 /* Retrigger sample ($E9 + Tick to Retrig note at) */
1063 case 0x9:
1064 /* Don't device by zero */
1065 if (effecty == 0) effecty = 1;
1066 /* Apply retrig */
1067 if (currenttick % effecty == 0)
1068 mixer_playsample(c, p_modchannel->instrument);
1069 break;
1070 /* Cut note (Usage: $EC + Tick to Cut note at) */
1071 case 0xc:
1072 if (currenttick == effecty)
1073 mixer_stopsample(c);
1074 break;
1075 /* Delay note (Usage: $ED + ticks to delay note) */
1076 case 0xd:
1077 /* If this is the correct tick,
1078 * we start playing the sample now */
1079 if (currenttick == effecty)
1080 mixer.channel[c].channelactive = true;
1081 break;
1082
1083 }
1084 break;
1085 /* Effect F (Set Speed) is only processed at tick 0 */
1086
1087 }
1088 }
1089}
1090
Bertrik Sikken8e22f7f2008-12-29 19:49:48 +00001091static inline int clip(int i)
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001092{
1093 if (i > 32767) return(32767);
1094 else if (i < -32768) return(-32768);
1095 else return(i);
1096}
1097
Nils Wallménius13f08d72009-11-29 18:11:49 +00001098STATICIRAM void synthrender(int32_t *renderbuffer, int samplecount) ICODE_ATTR;
1099void synthrender(int32_t *renderbuffer, int samplecount)
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001100{
1101 /* 125bpm equals to 50Hz (= 0.02s)
1102 * => one tick = mixingrate/50,
1103 * samples passing in one tick:
1104 * mixingrate/(bpm/2.5) = 2.5*mixingrate/bpm */
1105
Nils Wallménius13f08d72009-11-29 18:11:49 +00001106 int32_t *p_left = renderbuffer; /* int in rockbox */
1107 int32_t *p_right = p_left+1;
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001108 signed short s;
1109 int qf_distance, qf_distance2;
1110
1111 int i;
1112
1113 int c, left, right;
1114
1115 for (i=0;i<samplecount;i++)
1116 {
1117 /* New Tick? */
1118 if ((modplayer.samplespertick-- <= 0) &&
1119 (modplayer.patterntableposition < 127))
1120 {
1121 if (modplayer.currenttick == 0)
1122 playline(modsong.patternordertable[
1123 modplayer.patterntableposition], modplayer.currentline);
1124 else playeffect(modplayer.currenttick);
1125
1126 modplayer.currenttick++;
1127
1128 if (modplayer.currenttick >= modplayer.ticksperline)
1129 {
1130 modplayer.currentline++;
1131 modplayer.currenttick = 0;
1132 if (modplayer.currentline == 64)
1133 {
1134 modplayer.patterntableposition++;
1135 if (modplayer.patterntableposition >= modsong.songlength)
1136 /* This is for Noise Tracker
1137 * modplayer.patterntableposition =
1138 * modsong.songendjumpposition;
1139 * More compatible approach is restart from 0 */
1140 modplayer.patterntableposition=0;
1141 modplayer.currentline = 0;
1142 }
1143 }
1144
1145 modplayer.samplespertick = (20*mixingrate/modplayer.bpm)>>3;
1146 }
1147 /* Mix buffers from here
1148 * Walk through all channels */
1149 left=0, right=0;
1150
1151 /* If song has not stopped playing */
1152 if (modplayer.patterntableposition < 127)
1153 /* Loop through all channels */
1154 for (c=0;c<modsong.noofchannels;c++)
1155 {
1156 /* Only mix the sample,
1157 * if channel there is something played on the channel */
1158 if (!mixer.channel[c].channelactive) continue;
1159
1160 /* Loop the sample, if requested? */
1161 if (mixer.channel[c].samplepos >= mixer.channel[c].loopend)
1162 {
1163 if (mixer.channel[c].loopsample)
1164 mixer.channel[c].samplepos -=
1165 (mixer.channel[c].loopend-
1166 mixer.channel[c].loopstart);
1167 else mixer.channel[c].channelactive = false;
1168 }
1169
1170 /* If the sample has stopped playing don't mix it */
1171 if (!mixer.channel[c].channelactive) continue;
1172
1173 /* Get the sample */
1174 s = (signed short)(modsong.sampledata[
1175 mixer.channel[c].samplepos]*mixer.channel[c].volume);
1176
1177 /* Interpolate if the sample-frequency is lower
1178 * than the mixing rate
1179 * If you don't want interpolation simply skip this part */
1180 if (mixer.channel[c].frequency < mixingrate)
1181 {
1182 /* Low precision linear interpolation
1183 * (fast integer based) */
1184 qf_distance = mixer.channel[c].samplefractpos<<16 /
1185 mixingrate;
1186 qf_distance2 = (1<<16)-qf_distance;
1187 s = (qf_distance*s + qf_distance2*
1188 mixer.channel[c].lastsampledata)>>16;
1189 }
1190
1191 /* Save the last played sample for interpolation purposes */
1192 mixer.channel[c].lastsampledata = s;
1193
1194 /* Pan the sample */
1195 left += s*(16-mixer.channel[c].panning)>>3;
1196 right += s*mixer.channel[c].panning>>3;
1197
1198 /* Advance sample */
1199 mixer.channel[c].samplefractpos += mixer.channel[c].frequency;
1200 while (mixer.channel[c].samplefractpos > mixingrate)
1201 {
1202 mixer.channel[c].samplefractpos -= mixingrate;
1203 mixer.channel[c].samplepos++;
1204 }
1205 }
1206 /* If we have more than 4 channels
1207 * we have to make sure that we apply clipping */
1208 if (modsong.noofchannels > 4) {
1209 *p_left = clip(left)<<13;
1210 *p_right = clip(right)<<13;
1211 }
1212 else {
1213 *p_left = left<<13;
1214 *p_right = right<<13;
1215 }
1216 p_left+=2;
1217 p_right+=2;
1218 }
1219}
1220
Michael Sevakisc537d592011-04-27 03:08:23 +00001221/* this is the codec entry point */
1222enum codec_status codec_main(enum codec_entry_call_reason reason)
1223{
1224 if (reason == CODEC_LOAD) {
1225 /* Make use of 44.1khz */
1226 ci->configure(DSP_SET_FREQUENCY, 44100);
1227 /* Sample depth is 28 bit host endian */
1228 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
1229 /* Stereo output */
1230 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
1231 }
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001232
Michael Sevakisc537d592011-04-27 03:08:23 +00001233 return CODEC_OK;
1234}
1235
1236/* this is called for each file to process */
1237enum codec_status codec_run(void)
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001238{
1239 size_t n;
1240 unsigned char *modfile;
1241 int old_patterntableposition;
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001242 int bytesdone;
Michael Sevakisc537d592011-04-27 03:08:23 +00001243 intptr_t param;
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001244
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001245 if (codec_init()) {
1246 return CODEC_ERROR;
1247 }
1248
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001249 codec_set_replaygain(ci->id3);
1250
1251 /* Load MOD file */
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001252 ci->seek_buffer(0);
1253 modfile = ci->request_buffer(&n, ci->filesize);
1254 if (!modfile || n < (size_t)ci->filesize) {
1255 return CODEC_ERROR;
1256 }
1257
1258 initmodplayer();
1259 loadmod(modfile);
1260
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001261 /* The main decoder loop */
1262 ci->set_elapsed(0);
1263 bytesdone = 0;
1264 old_patterntableposition = 0;
1265
1266 while (1) {
Michael Sevakisc537d592011-04-27 03:08:23 +00001267 enum codec_command_action action = ci->get_command(&param);
1268
1269 if (action == CODEC_ACTION_HALT)
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001270 break;
1271
Michael Sevakisc537d592011-04-27 03:08:23 +00001272 if (action == CODEC_ACTION_SEEK_TIME) {
1273 /* New time is ready in param */
1274 modplayer.patterntableposition = param/1000;
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001275 modplayer.currentline = 0;
Michael Sevakisc537d592011-04-27 03:08:23 +00001276 ci->set_elapsed(modplayer.patterntableposition*1000+500);
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001277 ci->seek_complete();
1278 }
1279
1280 if(old_patterntableposition != modplayer.patterntableposition) {
1281 ci->set_elapsed(modplayer.patterntableposition*1000+500);
1282 old_patterntableposition=modplayer.patterntableposition;
1283 }
1284
1285 synthrender(samples, CHUNK_SIZE/2);
1286
1287 bytesdone += CHUNK_SIZE;
1288
1289 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE/2);
1290
1291 }
1292
Thom Johansenc0f7eb92008-05-21 11:19:58 +00001293 return CODEC_OK;
1294}