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 (+1 because we use index 0 for period 0 = no new note) */
183 unsigned short periodtable
[37*8+1];
185 /* The sinus table [-255,255] */
186 signed short sintable
[0x40];
188 /* Is the glissando effect enabled? */
189 bool glissandoenabled
;
191 /* Is the Amiga Filter enabled? */
192 bool amigafilterenabled
;
194 /* The pattern-line where the loop is carried out (set with e6 command) */
195 unsigned char loopstartline
;
197 /* Number of times to loop */
198 unsigned char looptimes
;
202 /* Panning (0 = left, 16 = right) */
203 unsigned char panning
;
205 /* Sample frequency of the channel */
206 unsigned short frequency
;
208 /* Position of the sample currently played */
209 unsigned int samplepos
;
211 /* Fractual Position of the sample currently player */
212 unsigned int samplefractpos
;
217 /* Loop Position Start */
218 unsigned int loopstart
;
220 /* Loop Position End */
221 unsigned int loopend
;
223 /* Is The channel beeing played? */
226 /* The Volume (0..64) */
229 /* The last sampledata beeing played (required for interpolation) */
230 signed short lastsampledata
;
235 struct s_channel channel
[32];
238 struct s_song modsong IDATA_ATTR
; /* The Song */
239 struct s_modplayer modplayer IDATA_ATTR
; /* The Module Player */
240 struct s_mixer mixer IDATA_ATTR
;
242 const unsigned short mixingrate
= 44100;
244 STATICIRAM
void mixer_playsample(int channel
, int instrument
) ICODE_ATTR
;
245 void mixer_playsample(int channel
, int instrument
)
247 struct s_channel
*p_channel
= &mixer
.channel
[channel
];
248 struct s_instrument
*p_instrument
= &modsong
.instrument
[instrument
];
250 p_channel
->channelactive
= true;
251 p_channel
->samplepos
= p_instrument
->sampledataoffset
;
252 p_channel
->samplefractpos
= 0;
253 p_channel
->loopsample
= (p_instrument
->repeatlength
> 2) ? true : false;
254 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
;
260 else p_channel
->loopend
= p_instrument
->length
+
261 p_instrument
->sampledataoffset
;
263 /* Remember the instrument */
264 modplayer
.modchannel
[channel
].instrument
= instrument
;
267 static inline void mixer_stopsample(int channel
)
269 mixer
.channel
[channel
].channelactive
= false;
272 static inline void mixer_continuesample(int channel
)
274 mixer
.channel
[channel
].channelactive
= true;
277 static inline void mixer_setvolume(int channel
, int volume
)
279 mixer
.channel
[channel
].volume
= volume
;
282 static inline void mixer_setpanning(int channel
, int panning
)
284 mixer
.channel
[channel
].panning
= panning
;
287 static inline void mixer_setamigaperiod(int channel
, int amigaperiod
)
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)
295 mixer
.channel
[channel
].frequency
= 3579546 / amigaperiod
;
298 /* Initialize the MOD Player with default values and precalc tables */
299 STATICIRAM
void initmodplayer(void) ICODE_ATTR
;
300 void initmodplayer(void)
304 /* Calculate Amiga Period Values
305 * Start with Period 907 (= C-1 with Finetune -8) and work upwards */
307 /* Index 0 stands for no note (and therefore no period) */
308 modplayer
.periodtable
[0] = 0;
311 modplayer
.periodtable
[i
] = (unsigned short) f
;
312 f
/= 1.0072464122237039; /* = pow(2.0f, 1.0f/(12.0f*8.0f)); */
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++)
323 float e = pow(2.0f, halftone/(12.0f*8.0f));
325 modplayer.periodtable[halfetone+1] = (int)(f+0.5f);
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]
338 d
= 0.09817475f
; /* = 2*PI/64 */
345 modplayer
.sintable
[i
] = (int)(255*a
);
351 /* Set Default Player Values */
352 modplayer
.currentline
= 0;
353 modplayer
.currenttick
= 0;
354 modplayer
.patterntableposition
= 0;
356 modplayer
.ticksperline
= 6;
357 modplayer
.glissandoenabled
= false; /* Disable glissando */
358 modplayer
.amigafilterenabled
= false; /* Disable the Amiga Filter */
360 /* Default Panning Values */
361 int panningvalues
[8] = {4,12,12,4,4,12,12,4};
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;
374 /* Load the MOD File from memory */
375 STATICIRAM
bool loadmod(void *modfile
) ICODE_ATTR
;
376 bool loadmod(void *modfile
)
379 unsigned char *periodsconverted
;
381 /* We don't support PowerPacker 2.0 Files */
382 if (memcmp((char*) modfile
, "PP20", 4) == 0) return false;
384 /* Get the File Format Tag */
385 char *fileformattag
= (char*)modfile
+ 1080;
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;}
407 /* The file has no format tag, so most likely soundtracker */
408 modsong
.noofchannels
= 4;
409 modsong
.noofinstruments
= 15;
412 /* Get the Song title
414 * strncpy(modsong.szTitle, (char*)pMODFile, 20); */
416 /* Get the Instrument information */
417 for (i
=0;i
<modsong
.noofinstruments
;i
++)
419 struct s_instrument
*instrument
= &modsong
.instrument
[i
];
420 unsigned char *p
= (unsigned char *)modfile
+ 20 + i
*30;
422 /*strncpy(instrument->description, (char*)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;
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
;
440 /* Find out how many patterns are used within this song */
443 if (modsong
.patternordertable
[i
] > maxpatterns
)
444 maxpatterns
= modsong
.patternordertable
[i
];
447 /* use 'restartposition' (historically set to 127) which is not used here
448 as a marker that periods have already been converted */
450 periodsconverted
= (char*)modfile
+ 20 + modsong
.noofinstruments
*30 + 1;
452 /* Get the pattern data; ST doesn't have fileformattag, so 4 bytes less */
453 modsong
.patterndata
= periodsconverted
+
454 (modsong
.noofinstruments
==15 ? 129 : 133);
456 /* 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
;
459 if (*periodsconverted
!= 0xfe)
461 int note
, note2
, channel
;
462 for (note
=0;note
<maxpatterns
*64;note
++)
463 for (channel
=0;channel
<modsong
.noofchannels
;channel
++)
465 int period
= ((p
[0] & 0x0f) << 8) | p
[1];
466 int periodoffset
= 0;
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)
472 periodoffset
= note2
*8+1;
475 /* Write back the period offset */
476 p
[0] = (periodoffset
>> 8) | (p
[0] & 0xf0);
477 p
[1] = periodoffset
& 0xff;
480 /* Remember that we already converted the periods,
481 * in case the file gets reloaded by rewinding
482 * with 0xfe (arbitary magic value > 127) */
483 *periodsconverted
= 0xfe;
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
++)
496 modsong
.instrument
[i
].sampledataoffset
= sampledataoffset
;
497 sampledataoffset
+= modsong
.instrument
[i
].length
;
503 /* Apply vibrato to channel */
504 STATICIRAM
void vibrate(int channel
) ICODE_ATTR
;
505 void vibrate(int channel
)
507 struct s_modchannel
*p_modchannel
= &modplayer
.modchannel
[channel
];
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));
515 /* Foward in Sine Table */
516 p_modchannel
->vibratosinpos
+= p_modchannel
->vibratospeed
;
517 p_modchannel
->vibratosinpos
&= 0x3f;
520 /* Apply tremolo to channel
521 * (same as vibrato, but only apply on volume instead of pitch) */
522 STATICIRAM
void tremolo(int channel
) ICODE_ATTR
;
523 void tremolo(int channel
)
525 struct s_modchannel
*p_modchannel
= &modplayer
.modchannel
[channel
];
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
);
535 /* Foward in Sine Table */
536 p_modchannel
->tremolosinpos
+= p_modchannel
->tremolosinpos
;
537 p_modchannel
->tremolosinpos
&= 0x3f;
540 /* Apply Slide to Note effect to channel */
541 STATICIRAM
void slidetonote(int channel
) ICODE_ATTR
;
542 void slidetonote(int channel
)
544 struct s_modchannel
*p_modchannel
= &modplayer
.modchannel
[channel
];
546 /* If there hasn't been any slide-to note set up, then return */
547 if (p_modchannel
->slidetonoteperiod
== 0) return;
550 if (p_modchannel
->slidetonoteperiod
> p_modchannel
->period
)
552 p_modchannel
->period
+= p_modchannel
->slidetonotespeed
;
553 if (p_modchannel
->period
> p_modchannel
->slidetonoteperiod
)
554 p_modchannel
->period
= p_modchannel
->slidetonoteperiod
;
556 /* Slide note down */
557 else if (p_modchannel
->slidetonoteperiod
< p_modchannel
->period
)
559 p_modchannel
->period
-= p_modchannel
->slidetonotespeed
;
560 if (p_modchannel
->period
< p_modchannel
->slidetonoteperiod
)
561 p_modchannel
->period
= p_modchannel
->slidetonoteperiod
;
563 mixer_setamigaperiod(channel
, p_modchannel
->period
);
566 /* Apply Slide to Note effect on channel,
567 * but this time with glissando enabled */
568 STATICIRAM
void slidetonoteglissando(int channel
) ICODE_ATTR
;
569 void slidetonoteglissando(int channel
)
571 struct s_modchannel
*p_modchannel
= &modplayer
.modchannel
[channel
];
574 if (p_modchannel
->slidetonoteperiod
> p_modchannel
->period
)
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
;
581 /* Slide note down */
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
;
589 mixer_setamigaperiod(channel
, p_modchannel
->period
);
592 /* Apply Volume Slide */
593 STATICIRAM
void volumeslide(int channel
, int effectx
, int effecty
) ICODE_ATTR
;
594 void volumeslide(int channel
, int effectx
, int effecty
)
596 struct s_modchannel
*p_modchannel
= &modplayer
.modchannel
[channel
];
598 /* If both X and Y Parameters are non-zero, then the y value is ignored */
600 p_modchannel
->volume
+= effectx
;
601 if (p_modchannel
->volume
> 64) p_modchannel
->volume
= 64;
604 p_modchannel
->volume
-= effecty
;
605 if (p_modchannel
->volume
< 0) p_modchannel
->volume
= 0;
608 mixer_setvolume(channel
, p_modchannel
->volume
);
611 /* Play the current line (at tick 0) */
612 STATICIRAM
void playline(int pattern
, int line
) ICODE_ATTR
;
613 void playline(int pattern
, int line
)
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
;
622 /* Only allow one Patternbreak Commando per Line */
623 bool patternbreakdone
= false;
625 for (c
=0;c
<modsong
.noofchannels
;c
++)
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];
632 p_modchannel
->effect
= p_note
[2] & 0x0f;
633 p_modchannel
->effectparameter
= p_note
[3];
635 /* Remember Instrument and set Volume if new Instrument triggered */
636 if (samplenumber
> 0)
638 /* And trigger new sample, if new instrument was set */
639 if (samplenumber
-1 != p_modchannel
->instrument
)
641 /* Advance the new sample to the same offset
642 * the old sample was beeing played */
643 int oldsampleoffset
= mixer
.channel
[c
].samplepos
-
645 p_modchannel
->instrument
].sampledataoffset
;
646 mixer_playsample(c
, samplenumber
-1);
647 mixer
.channel
[c
].samplepos
+= oldsampleoffset
;
650 /* Remember last played instrument on channel */
651 p_modchannel
->instrument
= samplenumber
-1;
653 /* Set Volume to standard instrument volume,
654 * if not overwritten by volume effect */
655 if (p_modchannel
->effect
!= 0x0c)
657 p_modchannel
->volume
= modsong
.instrument
[
658 p_modchannel
->instrument
].volume
;
659 mixer_setvolume(c
, p_modchannel
->volume
);
662 /* Trigger new sample if note available */
663 if (periodtableoffset
> 0)
665 /* Restart instrument only when new sample triggered */
666 if (samplenumber
!= 0)
667 mixer_playsample(c
, (samplenumber
> 0) ?
668 samplenumber
-1 : p_modchannel
->instrument
);
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))
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
;
687 int effectx
= p_modchannel
->effectparameter
>>4;
688 int effecty
= p_modchannel
->effectparameter
&0x0f;
690 switch (p_modchannel
->effect
)
692 /* Effect 0: Arpeggio */
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
]);
700 /* Slide up (Portamento up) */
702 if (p_modchannel
->effectparameter
> 0)
703 p_modchannel
->slideupspeed
=
704 p_modchannel
->effectparameter
;
707 /* Slide down (Portamento down) */
709 if (p_modchannel
->effectparameter
> 0)
710 p_modchannel
->slidedownspeed
=
711 p_modchannel
->effectparameter
;
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
+
724 p_modchannel
->instrument
].finetune
];
725 /* If glissando is enabled apply the effect directly here */
726 if (modplayer
.glissandoenabled
)
727 slidetonoteglissando(c
);
732 if (effectx
> 0) p_modchannel
->vibratospeed
= effectx
;
733 if (effecty
> 0) p_modchannel
->vibratodepth
= effecty
;
736 /* Effect 0x06: Slide to note */
738 /* Get the slide to note directly from the pattern buffer */
739 if (periodtableoffset
> 0)
740 p_modchannel
->slidetonoteperiod
=
741 modplayer
.periodtable
[periodtableoffset
+
743 p_modchannel
->instrument
].finetune
];
746 /* Effect 0x06 is "Continue Effects" */
747 /* It is not processed on tick 0 */
753 if (effectx
> 0) p_modchannel
->tremolodepth
= effectx
;
754 if (effecty
> 0) p_modchannel
->tremolospeed
= effecty
;
757 /* Set fine panning */
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;
764 /* Set Sample Offset */
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;
780 /* Effect 0x0a (Volume slide) is not processed on tick 0 */
784 modplayer
.currentline
= -1;
785 modplayer
.patterntableposition
= (effectx
<<4)+effecty
;
790 p_modchannel
->volume
= p_modchannel
->effectparameter
;
791 mixer_setvolume(c
, p_modchannel
->volume
);
796 modplayer
.currentline
= effectx
*10 + effecty
- 1;
797 if (!patternbreakdone
)
799 patternbreakdone
= true;
800 modplayer
.patterntableposition
++;
804 /* Extended Effects */
810 modplayer
.amigafilterenabled
=
811 (effecty
>0) ? false : true;
815 mixer_setamigaperiod(c
, p_modchannel
->period
-=
817 if (p_modchannel
->period
<
818 modplayer
.periodtable
[37*8]) p_modchannel
->period
= 100;
819 /* Find out the new offset in the period table */
820 if (p_modchannel
->periodtableoffset
< 36*8)
821 while (modplayer
.periodtable
[
822 p_modchannel
->periodtableoffset
+8] >= p_modchannel
->period
)
823 p_modchannel
->periodtableoffset
+=8;
827 mixer_setamigaperiod(c
,
828 p_modchannel
->period
+= effecty
);
829 if (p_modchannel
->periodtableoffset
> 8)
830 while (modplayer
.periodtable
[
831 p_modchannel
->periodtableoffset
-8]
832 <= p_modchannel
->period
)
833 p_modchannel
->periodtableoffset
-=8;
835 /* Set glissando on/off */
837 modplayer
.glissandoenabled
=
838 (effecty
> 0) ? true:false;
840 /* Set Vibrato waveform */
842 /* Currently not implemented */
844 /* Set Finetune value */
846 /* Treat as signed nibble */
847 if (effecty
> 7) effecty
-= 16;
849 p_modchannel
->periodtableoffset
+=
852 p_modchannel
->instrument
].finetune
;
853 p_modchannel
->period
=
854 modplayer
.periodtable
[
855 p_modchannel
->periodtableoffset
];
857 p_modchannel
->instrument
].finetune
= effecty
;
862 modplayer
.loopstartline
= line
-1;
865 if (modplayer
.looptimes
== 0)
867 modplayer
.currentline
=
868 modplayer
.loopstartline
;
869 modplayer
.looptimes
= effecty
;
871 else modplayer
.looptimes
--;
872 if (modplayer
.looptimes
> 0)
873 modplayer
.currentline
=
874 modplayer
.loopstartline
;
877 /* Set Tremolo waveform */
879 /* Not yet implemented */
881 /* Enhanced Effect 8 is not used */
884 /* Retrigger sample */
886 /* Only processed on subsequent ticks */
888 /* Fine volume slide up */
890 p_modchannel
->volume
+= effecty
;
891 if (p_modchannel
->volume
> 64)
892 p_modchannel
->volume
= 64;
893 mixer_setvolume(c
, p_modchannel
->volume
);
895 /* Fine volume slide down */
897 p_modchannel
->volume
-= effecty
;
898 if (p_modchannel
->volume
< 0)
899 p_modchannel
->volume
= 0;
900 mixer_setvolume(c
, p_modchannel
->volume
);
904 /* Continue sample */
905 mixer_continuesample(c
);
907 /* Note delay (Usage: $ED + ticks to delay note.) */
909 /* We stop the sample here on tick 0
910 * and restart it later in the effect */
912 mixer
.channel
[c
].channelactive
= false;
919 if (p_modchannel
->effectparameter
< 32)
920 modplayer
.ticksperline
= p_modchannel
->effectparameter
;
922 modplayer
.bpm
= p_modchannel
->effectparameter
;
928 /* Play the current effect of the note (ticks 1..speed) */
929 STATICIRAM
void playeffect(int currenttick
) ICODE_ATTR
;
930 void playeffect(int currenttick
)
934 for (c
=0;c
<modsong
.noofchannels
;c
++)
936 struct s_modchannel
*p_modchannel
= &modplayer
.modchannel
[c
];
938 /* If there is no note active then there are no effects to play */
939 if (p_modchannel
->period
== 0) continue;
941 unsigned char effectx
= p_modchannel
->effectparameter
>>4;
942 unsigned char effecty
= p_modchannel
->effectparameter
&0x0f;
944 switch (p_modchannel
->effect
)
946 /* Effect 0: Arpeggio */
948 if (p_modchannel
->effectparameter
> 0)
950 unsigned short newperiodtableoffset
;
951 switch (currenttick
% 3)
954 mixer_setamigaperiod(c
,
955 modplayer
.periodtable
[
956 p_modchannel
->periodtableoffset
]);
959 newperiodtableoffset
=
960 p_modchannel
->periodtableoffset
+(effectx
<<3);
961 if (newperiodtableoffset
< 37*8)
962 mixer_setamigaperiod(c
,
963 modplayer
.periodtable
[
964 newperiodtableoffset
]);
967 newperiodtableoffset
=
968 p_modchannel
->periodtableoffset
+(effecty
<<3);
969 if (newperiodtableoffset
< 37*8)
970 mixer_setamigaperiod(c
,
971 modplayer
.periodtable
[
972 newperiodtableoffset
]);
978 /* Effect 1: Slide Up */
980 mixer_setamigaperiod(c
,
981 p_modchannel
->period
-= p_modchannel
->slideupspeed
);
982 /* Find out the new offset in the period table */
983 if (p_modchannel
->periodtableoffset
<= 37*8)
984 while (modplayer
.periodtable
[
985 p_modchannel
->periodtableoffset
] >
986 p_modchannel
->period
)
988 p_modchannel
->periodtableoffset
++;
989 /* Make sure we don't go out of range */
990 if (p_modchannel
->periodtableoffset
> 37*8)
992 p_modchannel
->periodtableoffset
= 37*8;
998 /* Effect 2: Slide Down */
1000 mixer_setamigaperiod(c
, p_modchannel
->period
+=
1001 p_modchannel
->slidedownspeed
);
1002 /* Find out the new offset in the period table */
1003 if (p_modchannel
->periodtableoffset
> 8)
1004 while (modplayer
.periodtable
[
1005 p_modchannel
->periodtableoffset
] <
1006 p_modchannel
->period
)
1008 p_modchannel
->periodtableoffset
--;
1009 /* Make sure we don't go out of range */
1010 if (p_modchannel
->periodtableoffset
< 1)
1012 p_modchannel
->periodtableoffset
= 1;
1018 /* Effect 3: Slide to Note */
1020 /* Apply smooth sliding, if no glissando is enabled */
1021 if (modplayer
.glissandoenabled
== 0)
1025 /* Effect 4: Vibrato */
1030 /* Effect 5: Continue effect 3:'Slide to note',
1031 * but also do Volume slide */
1034 volumeslide(c
, effectx
, effecty
);
1037 /* Effect 6: Continue effect 4:'Vibrato',
1038 * but also do Volume slide */
1041 volumeslide(c
, effectx
, effecty
);
1044 /* Effect 7: Tremolo */
1049 /* Effect 8 (Set fine panning) is only processed at tick 0 */
1050 /* Effect 9 (Set sample offset) is only processed at tick 0 */
1052 /* Effect A: Volume slide */
1054 volumeslide(c
, effectx
, effecty
);
1057 /* Effect B (Position jump) is only processed at tick 0 */
1058 /* Effect C (Set Volume) is only processed at tick 0 */
1059 /* Effect D (Pattern Preak) is only processed at tick 0 */
1060 /* Effect E (Enhanced Effect) */
1064 /* Retrigger sample ($E9 + Tick to Retrig note at) */
1066 /* Don't device by zero */
1067 if (effecty
== 0) effecty
= 1;
1069 if (currenttick
% effecty
== 0)
1070 mixer_playsample(c
, p_modchannel
->instrument
);
1072 /* Cut note (Usage: $EC + Tick to Cut note at) */
1074 if (currenttick
== effecty
)
1075 mixer_stopsample(c
);
1077 /* Delay note (Usage: $ED + ticks to delay note) */
1079 /* If this is the correct tick,
1080 * we start playing the sample now */
1081 if (currenttick
== effecty
)
1082 mixer
.channel
[c
].channelactive
= true;
1087 /* Effect F (Set Speed) is only processed at tick 0 */
1093 static inline int clip(int i
)
1095 if (i
> 32767) return(32767);
1096 else if (i
< -32768) return(-32768);
1100 STATICIRAM
void synthrender(int32_t *renderbuffer
, int samplecount
) ICODE_ATTR
;
1101 void synthrender(int32_t *renderbuffer
, int samplecount
)
1103 /* 125bpm equals to 50Hz (= 0.02s)
1104 * => one tick = mixingrate/50,
1105 * samples passing in one tick:
1106 * mixingrate/(bpm/2.5) = 2.5*mixingrate/bpm */
1108 int32_t *p_left
= renderbuffer
; /* int in rockbox */
1109 int32_t *p_right
= p_left
+1;
1111 int qf_distance
, qf_distance2
;
1117 for (i
=0;i
<samplecount
;i
++)
1120 if ((modplayer
.samplespertick
-- <= 0) &&
1121 (modplayer
.patterntableposition
< 127))
1123 if (modplayer
.currenttick
== 0)
1124 playline(modsong
.patternordertable
[
1125 modplayer
.patterntableposition
], modplayer
.currentline
);
1126 else playeffect(modplayer
.currenttick
);
1128 modplayer
.currenttick
++;
1130 if (modplayer
.currenttick
>= modplayer
.ticksperline
)
1132 modplayer
.currentline
++;
1133 modplayer
.currenttick
= 0;
1134 if (modplayer
.currentline
== 64)
1136 modplayer
.patterntableposition
++;
1137 if (modplayer
.patterntableposition
>= modsong
.songlength
)
1138 /* This is for Noise Tracker
1139 * modplayer.patterntableposition =
1140 * modsong.songendjumpposition;
1141 * More compatible approach is restart from 0 */
1142 modplayer
.patterntableposition
=0;
1143 modplayer
.currentline
= 0;
1147 modplayer
.samplespertick
= (20*mixingrate
/modplayer
.bpm
)>>3;
1149 /* Mix buffers from here
1150 * Walk through all channels */
1153 /* If song has not stopped playing */
1154 if (modplayer
.patterntableposition
< 127)
1155 /* Loop through all channels */
1156 for (c
=0;c
<modsong
.noofchannels
;c
++)
1158 /* Only mix the sample,
1159 * if channel there is something played on the channel */
1160 if (!mixer
.channel
[c
].channelactive
) continue;
1162 /* Loop the sample, if requested? */
1163 if (mixer
.channel
[c
].samplepos
>= mixer
.channel
[c
].loopend
)
1165 if (mixer
.channel
[c
].loopsample
)
1166 mixer
.channel
[c
].samplepos
-=
1167 (mixer
.channel
[c
].loopend
-
1168 mixer
.channel
[c
].loopstart
);
1169 else mixer
.channel
[c
].channelactive
= false;
1172 /* If the sample has stopped playing don't mix it */
1173 if (!mixer
.channel
[c
].channelactive
) continue;
1175 /* Get the sample */
1176 s
= (signed short)(modsong
.sampledata
[
1177 mixer
.channel
[c
].samplepos
]*mixer
.channel
[c
].volume
);
1179 /* Interpolate if the sample-frequency is lower
1180 * than the mixing rate
1181 * If you don't want interpolation simply skip this part */
1182 if (mixer
.channel
[c
].frequency
< mixingrate
)
1184 /* Low precision linear interpolation
1185 * (fast integer based) */
1186 qf_distance
= mixer
.channel
[c
].samplefractpos
<<16 /
1188 qf_distance2
= (1<<16)-qf_distance
;
1189 s
= (qf_distance
*s
+ qf_distance2
*
1190 mixer
.channel
[c
].lastsampledata
)>>16;
1193 /* Save the last played sample for interpolation purposes */
1194 mixer
.channel
[c
].lastsampledata
= s
;
1196 /* Pan the sample */
1197 left
+= s
*(16-mixer
.channel
[c
].panning
)>>3;
1198 right
+= s
*mixer
.channel
[c
].panning
>>3;
1200 /* Advance sample */
1201 mixer
.channel
[c
].samplefractpos
+= mixer
.channel
[c
].frequency
;
1202 while (mixer
.channel
[c
].samplefractpos
> mixingrate
)
1204 mixer
.channel
[c
].samplefractpos
-= mixingrate
;
1205 mixer
.channel
[c
].samplepos
++;
1208 /* If we have more than 4 channels
1209 * we have to make sure that we apply clipping */
1210 if (modsong
.noofchannels
> 4) {
1211 *p_left
= clip(left
)<<13;
1212 *p_right
= clip(right
)<<13;
1216 *p_right
= right
<<13;
1224 enum codec_status
codec_main(void)
1227 unsigned char *modfile
;
1228 int old_patterntableposition
;
1237 while (!*ci
->taginfo_ready
&& !ci
->stop_codec
)
1240 codec_set_replaygain(ci
->id3
);
1244 * This is the save way
1247 unsigned int filesize;
1250 bytesfree=sizeof(modfile);
1251 while ((n = ci->read_filebuf(p, bytesfree)) > 0) {
1257 filesize = p-modfile;
1263 /* Directly use mod in buffer */
1265 modfile
= ci
->request_buffer(&n
, ci
->filesize
);
1266 if (!modfile
|| n
< (size_t)ci
->filesize
) {
1273 /* Make use of 44.1khz */
1274 ci
->configure(DSP_SET_FREQUENCY
, 44100);
1275 /* Sample depth is 28 bit host endian */
1276 ci
->configure(DSP_SET_SAMPLE_DEPTH
, 28);
1278 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_INTERLEAVED
);
1280 /* The main decoder loop */
1283 old_patterntableposition
= 0;
1287 if (ci
->stop_codec
|| ci
->new_track
)
1290 if (ci
->seek_time
) {
1291 /* New time is ready in ci->seek_time */
1292 modplayer
.patterntableposition
= ci
->seek_time
/1000;
1293 modplayer
.currentline
= 0;
1294 ci
->seek_complete();
1297 if(old_patterntableposition
!= modplayer
.patterntableposition
) {
1298 ci
->set_elapsed(modplayer
.patterntableposition
*1000+500);
1299 old_patterntableposition
=modplayer
.patterntableposition
;
1302 synthrender(samples
, CHUNK_SIZE
/2);
1304 bytesdone
+= CHUNK_SIZE
;
1306 ci
->pcmbuf_insert(samples
, NULL
, CHUNK_SIZE
/2);
1310 if (ci
->request_next_track())