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 * All files in this archive are subject to the GNU General Public License.
16 * See the file COPYING in the source tree root for full license agreement.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
24 * This version supports large files directly from internal memory management.
25 * There is a drawback however: It may happen that a song is not completely
26 * loaded when the internal rockbox-ringbuffer (approx. 28MB) is filled up
27 * As a workaround make sure you don't have directories with mods larger
28 * than a total of 28MB
43 #define CHUNK_SIZE (1024*2)
46 /* This codec supports MOD Files:
50 static int32_t samples
[CHUNK_SIZE
] IBSS_ATTR
; /* The sample buffer */
54 /* Sample name / description */
55 /*char description[22];*/
57 /* Sample length in bytes */
58 unsigned short length
;
60 /* Sample finetuning (-8 - +7) */
63 /* Sample volume (0 - 64) */
66 /* Sample Repeat Position */
67 unsigned short repeatoffset
;
69 /* Sample Repeat Length */
70 unsigned short repeatlength
;
72 /* Offset to sample data */
73 unsigned int sampledataoffset
;
78 /* Song name / title description */
81 /* No. of channels in song */
82 unsigned char noofchannels
;
84 /* No. of instruments used (either 15 or 31) */
85 unsigned char noofinstruments
;
87 /* How many patterns are beeing played? */
88 unsigned char songlength
;
90 /* Where to jump after the song end? */
91 unsigned char songendjumpposition
;
93 /* Pointer to the Pattern Order Table */
94 unsigned char *patternordertable
;
96 /* Pointer to the pattern data */
99 /* Pointer to the sample buffer */
100 signed char *sampledata
;
102 /* Instrument data */
103 struct s_instrument instrument
[31];
106 struct s_modchannel
{
110 /* Current Offset to period in PeriodTable of notebeeing played
111 (can be temporarily negative) */
112 short periodtableoffset
;
114 /* Current Period beeing played */
118 unsigned char effect
;
120 /* Current parameters of effect */
121 unsigned char effectparameter
;
123 /* Current Instrument beeing played */
124 unsigned char instrument
;
126 /* Current Vibrato Speed */
127 unsigned char vibratospeed
;
129 /* Current Vibrato Depth */
130 unsigned char vibratodepth
;
132 /* Current Position for Vibrato in SinTable */
133 unsigned char vibratosinpos
;
135 /* Current Tremolo Speed */
136 unsigned char tremolospeed
;
138 /* Current Tremolo Depth */
139 unsigned char tremolodepth
;
141 /* Current Position for Tremolo in SinTable */
142 unsigned char tremolosinpos
;
144 /* Current Speed of Effect "Slide Note up" */
145 unsigned char slideupspeed
;
147 /* Current Speed of Effect "Slide Note down" */
148 unsigned char slidedownspeed
;
150 /* Current Speed of the "Slide to Note" effect */
151 unsigned char slidetonotespeed
;
153 /* Current Period of the "Slide to Note" effect */
154 unsigned short slidetonoteperiod
;
159 unsigned char ticksperline
;
161 /* Beats per Minute */
164 /* Position of the Song in the Pattern Table (0-127) */
165 unsigned char patterntableposition
;
167 /* Current Line (may be temporarily < 0) */
168 signed char currentline
;
171 signed char currenttick
;
173 /* How many samples are required to calculate for each tick? */
174 unsigned int samplespertick
;
176 /* Information about the channels */
177 struct s_modchannel modchannel
[8];
179 /* The Amiga Period Table
180 (+1 because we use index 0 for period 0 = no new note) */
181 unsigned short periodtable
[37*8+1];
183 /* The sinus table [-255,255] */
184 signed short sintable
[0x40];
186 /* Is the glissando effect enabled? */
187 bool glissandoenabled
;
189 /* Is the Amiga Filter enabled? */
190 bool amigafilterenabled
;
192 /* The pattern-line where the loop is carried out (set with e6 command) */
193 unsigned char loopstartline
;
195 /* Number of times to loop */
196 unsigned char looptimes
;
200 /* Panning (0 = left, 16 = right) */
201 unsigned char panning
;
203 /* Sample frequency of the channel */
204 unsigned short frequency
;
206 /* Position of the sample currently played */
207 unsigned int samplepos
;
209 /* Fractual Position of the sample currently player */
210 unsigned int samplefractpos
;
215 /* Loop Position Start */
216 unsigned int loopstart
;
218 /* Loop Position End */
219 unsigned int loopend
;
221 /* Is The channel beeing played? */
224 /* The Volume (0..64) */
227 /* The last sampledata beeing played (required for interpolation) */
228 signed short lastsampledata
;
233 struct s_channel channel
[32];
236 struct s_song modsong IDATA_ATTR
; /* The Song */
237 struct s_modplayer modplayer IDATA_ATTR
; /* The Module Player */
238 struct s_mixer mixer IDATA_ATTR
;
240 const unsigned short mixingrate
= 44100;
242 STATICIRAM
void mixer_playsample(int channel
, int instrument
) ICODE_ATTR
;
243 void mixer_playsample(int channel
, int instrument
)
245 struct s_channel
*p_channel
= &mixer
.channel
[channel
];
246 struct s_instrument
*p_instrument
= &modsong
.instrument
[instrument
];
248 p_channel
->channelactive
= true;
249 p_channel
->samplepos
= p_instrument
->sampledataoffset
;
250 p_channel
->samplefractpos
= 0;
251 p_channel
->loopsample
= (p_instrument
->repeatlength
> 2) ? true : false;
252 if (p_channel
->loopsample
) {
253 p_channel
->loopstart
= p_instrument
->repeatoffset
+
254 p_instrument
->sampledataoffset
;
255 p_channel
->loopend
= p_channel
->loopstart
+
256 p_instrument
->repeatlength
;
258 else p_channel
->loopend
= p_instrument
->length
+
259 p_instrument
->sampledataoffset
;
261 /* Remember the instrument */
262 modplayer
.modchannel
[channel
].instrument
= instrument
;
265 inline void mixer_stopsample(int channel
)
267 mixer
.channel
[channel
].channelactive
= false;
270 inline void mixer_continuesample(int channel
)
272 mixer
.channel
[channel
].channelactive
= true;
275 inline void mixer_setvolume(int channel
, int volume
)
277 mixer
.channel
[channel
].volume
= volume
;
280 inline void mixer_setpanning(int channel
, int panning
)
282 mixer
.channel
[channel
].panning
= panning
;
285 inline void mixer_setamigaperiod(int channel
, int amigaperiod
)
287 /* Just to make sure we don't devide by zero
288 * amigaperiod shouldn't 0 anyway - if it is the case
289 * then something terribly went wrong */
290 if (amigaperiod
== 0)
293 mixer
.channel
[channel
].frequency
= 3579546 / amigaperiod
;
296 /* Initialize the MOD Player with default values and precalc tables */
297 STATICIRAM
void initmodplayer(void) ICODE_ATTR
;
298 void initmodplayer(void)
302 /* Calculate Amiga Period Values
303 * Start with Period 907 (= C-1 with Finetune -8) and work upwards */
305 /* Index 0 stands for no note (and therefore no period) */
306 modplayer
.periodtable
[0] = 0;
309 modplayer
.periodtable
[i
] = (unsigned short) f
;
310 f
/= 1.0072464122237039; /* = pow(2.0f, 1.0f/(12.0f*8.0f)); */
314 * This is a more accurate but also time more consuming approach
315 * to calculate the amiga period table
316 * Commented out for speed purposes
317 const int finetuning = 8;
318 const int octaves = 3;
319 for (int halftone=0;halftone<=finetuning*octaves*12+7;halftone++)
321 float e = pow(2.0f, halftone/(12.0f*8.0f));
323 modplayer.periodtable[halfetone+1] = (int)(f+0.5f);
327 /* Calculate Protracker Vibrato sine table
328 * The routine makes use of the Harmonical Oscillator Approach
329 * for calculating sine tables
330 * (see http://membres.lycos.fr/amycoders/tutorials/sintables.html)
331 * The routine presented here calculates a complete sine wave
332 * with 64 values in range [-255,255]
336 d
= 0.09817475f
; /* = 2*PI/64 */
343 modplayer
.sintable
[i
] = (int)(255*a
);
349 /* Set Default Player Values */
350 modplayer
.currentline
= 0;
351 modplayer
.currenttick
= 0;
352 modplayer
.patterntableposition
= 0;
354 modplayer
.ticksperline
= 6;
355 modplayer
.glissandoenabled
= false; /* Disable glissando */
356 modplayer
.amigafilterenabled
= false; /* Disable the Amiga Filter */
358 /* Default Panning Values */
359 int panningvalues
[8] = {4,12,12,4,4,12,12,4};
362 /* Set Default Panning */
363 mixer_setpanning(c
, panningvalues
[c
]);
364 /* Reset channels in the MOD Player */
365 memset(&modplayer
.modchannel
[c
], 0, sizeof(struct s_modchannel
));
366 /* Don't play anything */
367 mixer
.channel
[c
].channelactive
= false;
372 /* Load the MOD File from memory */
373 STATICIRAM
bool loadmod(void *modfile
) ICODE_ATTR
;
374 bool loadmod(void *modfile
)
377 unsigned char *periodsconverted
;
379 /* We don't support PowerPacker 2.0 Files */
380 if (memcmp((char*) modfile
, "PP20", 4) == 0) return false;
382 /* Get the File Format Tag */
383 char *fileformattag
= (char*)modfile
+ 1080;
385 /* Find out how many channels and instruments are used */
386 if (memcmp(fileformattag
, "2CHN", 4) == 0)
387 {modsong
.noofchannels
= 2; modsong
.noofinstruments
= 31;}
388 else if (memcmp(fileformattag
, "M.K.", 4) == 0)
389 {modsong
.noofchannels
= 4; modsong
.noofinstruments
= 31;}
390 else if (memcmp(fileformattag
, "M!K!", 4) == 0)
391 {modsong
.noofchannels
= 4; modsong
.noofinstruments
= 31;}
392 else if (memcmp(fileformattag
, "4CHN", 4) == 0)
393 {modsong
.noofchannels
= 4; modsong
.noofinstruments
= 31;}
394 else if (memcmp(fileformattag
, "FLT4", 4) == 0)
395 {modsong
.noofchannels
= 4; modsong
.noofinstruments
= 31;}
396 else if (memcmp(fileformattag
, "6CHN", 4) == 0)
397 {modsong
.noofchannels
= 6; modsong
.noofinstruments
= 31;}
398 else if (memcmp(fileformattag
, "8CHN", 4) == 0)
399 {modsong
.noofchannels
= 8; modsong
.noofinstruments
= 31;}
400 else if (memcmp(fileformattag
, "OKTA", 4) == 0)
401 {modsong
.noofchannels
= 8; modsong
.noofinstruments
= 31;}
402 else if (memcmp(fileformattag
, "CD81", 4) == 0)
403 {modsong
.noofchannels
= 8; modsong
.noofinstruments
= 31;}
405 /* The file has no format tag, so most likely soundtracker */
406 modsong
.noofchannels
= 4;
407 modsong
.noofinstruments
= 15;
410 /* Get the Song title
412 * strncpy(modsong.szTitle, (char*)pMODFile, 20); */
414 /* Get the Instrument information */
415 for (i
=0;i
<modsong
.noofinstruments
;i
++)
417 struct s_instrument
*instrument
= &modsong
.instrument
[i
];
418 unsigned char *p
= (unsigned char *)modfile
+ 20 + i
*30;
420 /*strncpy(instrument->description, (char*)p, 22); */
422 instrument
->length
= (((p
[0])<<8) + p
[1]) << 1; p
+=2;
423 instrument
->finetune
= *p
++ & 0x0f;
424 /* Treat finetuning as signed nibble */
425 if (instrument
->finetune
> 7) instrument
->finetune
-= 16;
426 instrument
->volume
= *p
++;
427 instrument
->repeatoffset
= (((p
[0])<<8) + p
[1]) << 1; p
+= 2;
428 instrument
->repeatlength
= (((p
[0])<<8) + p
[1]) << 1;
431 /* Get the pattern information */
432 unsigned char *p
= (unsigned char *)modfile
+ 20 +
433 modsong
.noofinstruments
*30;
434 modsong
.songlength
= *p
++;
435 modsong
.songendjumpposition
= *p
++;
436 modsong
.patternordertable
= p
;
438 /* Find out how many patterns are used within this song */
441 if (modsong
.patternordertable
[i
] > maxpatterns
)
442 maxpatterns
= modsong
.patternordertable
[i
];
445 /* use 'restartposition' (historically set to 127) which is not used here
446 as a marker that periods have already been converted */
448 periodsconverted
= (char*)modfile
+ 20 + modsong
.noofinstruments
*30 + 1;
450 /* Get the pattern data; ST doesn't have fileformattag, so 4 bytes less */
451 modsong
.patterndata
= periodsconverted
+
452 (modsong
.noofinstruments
==15 ? 129 : 133);
454 /* Convert the period values in the mod file to offsets
455 * in our periodtable (but only, if we haven't done this yet) */
456 p
= (unsigned char *) modsong
.patterndata
;
457 if (*periodsconverted
!= 0xfe)
459 int note
, note2
, channel
;
460 for (note
=0;note
<maxpatterns
*64;note
++)
461 for (channel
=0;channel
<modsong
.noofchannels
;channel
++)
463 int period
= ((p
[0] & 0x0f) << 8) | p
[1];
464 int periodoffset
= 0;
466 /* Find the offset of the current period */
467 for (note2
= 1; note2
< 12*3+1; note2
++)
468 if (abs(modplayer
.periodtable
[note2
*8+1]-period
) < 4)
470 periodoffset
= note2
*8+1;
473 /* Write back the period offset */
474 p
[0] = (periodoffset
>> 8) | (p
[0] & 0xf0);
475 p
[1] = periodoffset
& 0xff;
478 /* Remember that we already converted the periods,
479 * in case the file gets reloaded by rewinding
480 * with 0xfe (arbitary magic value > 127) */
481 *periodsconverted
= 0xfe;
485 * Calculation: The Samples come after the pattern data
486 * We know that there are nMaxPatterns and each pattern requires
487 * 4 bytes per note and per channel.
488 * And of course there are always lines in each channel */
489 modsong
.sampledata
= (signed char*) modsong
.patterndata
+
490 maxpatterns
*4*modsong
.noofchannels
*64;
491 int sampledataoffset
= 0;
492 for (i
=0;i
<modsong
.noofinstruments
;i
++)
494 modsong
.instrument
[i
].sampledataoffset
= sampledataoffset
;
495 sampledataoffset
+= modsong
.instrument
[i
].length
;
501 /* Apply vibrato to channel */
502 STATICIRAM
void vibrate(int channel
) ICODE_ATTR
;
503 void vibrate(int channel
)
505 struct s_modchannel
*p_modchannel
= &modplayer
.modchannel
[channel
];
508 * >> 7 is used in the original protracker source code */
509 mixer_setamigaperiod(channel
, p_modchannel
->period
+
510 ((p_modchannel
->vibratodepth
*
511 modplayer
.sintable
[p_modchannel
->vibratosinpos
])>>7));
513 /* Foward in Sine Table */
514 p_modchannel
->vibratosinpos
+= p_modchannel
->vibratospeed
;
515 p_modchannel
->vibratosinpos
&= 0x3f;
518 /* Apply tremolo to channel
519 * (same as vibrato, but only apply on volume instead of pitch) */
520 STATICIRAM
void tremolo(int channel
) ICODE_ATTR
;
521 void tremolo(int channel
)
523 struct s_modchannel
*p_modchannel
= &modplayer
.modchannel
[channel
];
526 * >> 6 is used in the original protracker source code */
527 int volume
= (p_modchannel
->volume
*
528 modplayer
.sintable
[p_modchannel
->tremolosinpos
])>>6;
529 if (volume
> 64) volume
= 64;
530 else if (volume
< 0) volume
= 0;
531 mixer_setvolume(channel
, volume
);
533 /* Foward in Sine Table */
534 p_modchannel
->tremolosinpos
+= p_modchannel
->tremolosinpos
;
535 p_modchannel
->tremolosinpos
&= 0x3f;
538 /* Apply Slide to Note effect to channel */
539 STATICIRAM
void slidetonote(int channel
) ICODE_ATTR
;
540 void slidetonote(int channel
)
542 struct s_modchannel
*p_modchannel
= &modplayer
.modchannel
[channel
];
544 /* If there hasn't been any slide-to note set up, then return */
545 if (p_modchannel
->slidetonoteperiod
== 0) return;
548 if (p_modchannel
->slidetonoteperiod
> p_modchannel
->period
)
550 p_modchannel
->period
+= p_modchannel
->slidetonotespeed
;
551 if (p_modchannel
->period
> p_modchannel
->slidetonoteperiod
)
552 p_modchannel
->period
= p_modchannel
->slidetonoteperiod
;
554 /* Slide note down */
555 else if (p_modchannel
->slidetonoteperiod
< p_modchannel
->period
)
557 p_modchannel
->period
-= p_modchannel
->slidetonotespeed
;
558 if (p_modchannel
->period
< p_modchannel
->slidetonoteperiod
)
559 p_modchannel
->period
= p_modchannel
->slidetonoteperiod
;
561 mixer_setamigaperiod(channel
, p_modchannel
->period
);
564 /* Apply Slide to Note effect on channel,
565 * but this time with glissando enabled */
566 STATICIRAM
void slidetonoteglissando(int channel
) ICODE_ATTR
;
567 void slidetonoteglissando(int channel
)
569 struct s_modchannel
*p_modchannel
= &modplayer
.modchannel
[channel
];
572 if (p_modchannel
->slidetonoteperiod
> p_modchannel
->period
)
574 p_modchannel
->period
=
575 modplayer
.periodtable
[p_modchannel
->periodtableoffset
+=8];
576 if (p_modchannel
->period
> p_modchannel
->slidetonoteperiod
)
577 p_modchannel
->period
= p_modchannel
->slidetonoteperiod
;
579 /* Slide note down */
582 p_modchannel
->period
=
583 modplayer
.periodtable
[p_modchannel
->periodtableoffset
-=8];
584 if (p_modchannel
->period
< p_modchannel
->slidetonoteperiod
)
585 p_modchannel
->period
= p_modchannel
->slidetonoteperiod
;
587 mixer_setamigaperiod(channel
, p_modchannel
->period
);
590 /* Apply Volume Slide */
591 STATICIRAM
void volumeslide(int channel
, int effectx
, int effecty
) ICODE_ATTR
;
592 void volumeslide(int channel
, int effectx
, int effecty
)
594 struct s_modchannel
*p_modchannel
= &modplayer
.modchannel
[channel
];
596 /* If both X and Y Parameters are non-zero, then the y value is ignored */
598 p_modchannel
->volume
+= effectx
;
599 if (p_modchannel
->volume
> 64) p_modchannel
->volume
= 64;
602 p_modchannel
->volume
-= effecty
;
603 if (p_modchannel
->volume
< 0) p_modchannel
->volume
= 0;
606 mixer_setvolume(channel
, p_modchannel
->volume
);
609 /* Play the current line (at tick 0) */
610 STATICIRAM
void playline(int pattern
, int line
) ICODE_ATTR
;
611 void playline(int pattern
, int line
)
615 /* Get pointer to the current pattern */
616 unsigned char *p_line
= (unsigned char*)modsong
.patterndata
;
617 p_line
+= pattern
*64*4*modsong
.noofchannels
;
618 p_line
+= line
*4*modsong
.noofchannels
;
620 /* Only allow one Patternbreak Commando per Line */
621 bool patternbreakdone
= false;
623 for (c
=0;c
<modsong
.noofchannels
;c
++)
625 struct s_modchannel
*p_modchannel
= &modplayer
.modchannel
[c
];
626 unsigned char *p_note
= p_line
+ c
*4;
627 unsigned char samplenumber
= (p_note
[0] & 0xf0) | (p_note
[2] >> 4);
628 short periodtableoffset
= ((p_note
[0] & 0x0f) << 8) | p_note
[1];
630 p_modchannel
->effect
= p_note
[2] & 0x0f;
631 p_modchannel
->effectparameter
= p_note
[3];
633 /* Remember Instrument and set Volume if new Instrument triggered */
634 if (samplenumber
> 0)
636 /* And trigger new sample, if new instrument was set */
637 if (samplenumber
-1 != p_modchannel
->instrument
)
639 /* Advance the new sample to the same offset
640 * the old sample was beeing played */
641 int oldsampleoffset
= mixer
.channel
[c
].samplepos
-
643 p_modchannel
->instrument
].sampledataoffset
;
644 mixer_playsample(c
, samplenumber
-1);
645 mixer
.channel
[c
].samplepos
+= oldsampleoffset
;
648 /* Remember last played instrument on channel */
649 p_modchannel
->instrument
= samplenumber
-1;
651 /* Set Volume to standard instrument volume,
652 * if not overwritten by volume effect */
653 if (p_modchannel
->effect
!= 0x0c)
655 p_modchannel
->volume
= modsong
.instrument
[
656 p_modchannel
->instrument
].volume
;
657 mixer_setvolume(c
, p_modchannel
->volume
);
660 /* Trigger new sample if note available */
661 if (periodtableoffset
> 0)
663 /* Restart instrument only when new sample triggered */
664 if (samplenumber
!= 0)
665 mixer_playsample(c
, (samplenumber
> 0) ?
666 samplenumber
-1 : p_modchannel
->instrument
);
668 /* Set the new amiga period
669 * (but only, if there is no slide to note effect) */
670 if ((p_modchannel
->effect
!= 0x3) &&
671 (p_modchannel
->effect
!= 0x5))
673 /* Apply finetuning to sample */
674 p_modchannel
->periodtableoffset
= periodtableoffset
+
675 modsong
.instrument
[p_modchannel
->instrument
].finetune
;
676 p_modchannel
->period
= modplayer
.periodtable
[
677 p_modchannel
->periodtableoffset
];
678 mixer_setamigaperiod(c
, p_modchannel
->period
);
679 /* When a new note is played without slide to note setup,
680 * then disable slide to note */
681 modplayer
.modchannel
[c
].slidetonoteperiod
=
682 p_modchannel
->period
;
685 int effectx
= p_modchannel
->effectparameter
>>4;
686 int effecty
= p_modchannel
->effectparameter
&0x0f;
688 switch (p_modchannel
->effect
)
690 /* Effect 0: Arpeggio */
692 /* Set the base period on tick 0 */
693 if (p_modchannel
->effectparameter
> 0)
694 mixer_setamigaperiod(c
,
695 modplayer
.periodtable
[
696 p_modchannel
->periodtableoffset
]);
698 /* Slide up (Portamento up) */
700 if (p_modchannel
->effectparameter
> 0)
701 p_modchannel
->slideupspeed
=
702 p_modchannel
->effectparameter
;
705 /* Slide down (Portamento down) */
707 if (p_modchannel
->effectparameter
> 0)
708 p_modchannel
->slidedownspeed
=
709 p_modchannel
->effectparameter
;
714 if (p_modchannel
->effectparameter
> 0)
715 p_modchannel
->slidetonotespeed
=
716 p_modchannel
->effectparameter
;
717 /* Get the slide to note directly from the pattern buffer */
718 if (periodtableoffset
> 0)
719 p_modchannel
->slidetonoteperiod
=
720 modplayer
.periodtable
[periodtableoffset
+
722 p_modchannel
->instrument
].finetune
];
723 /* If glissando is enabled apply the effect directly here */
724 if (modplayer
.glissandoenabled
)
725 slidetonoteglissando(c
);
730 if (effectx
> 0) p_modchannel
->vibratospeed
= effectx
;
731 if (effecty
> 0) p_modchannel
->vibratodepth
= effecty
;
734 /* Effect 0x06: Slide to note */
736 /* Get the slide to note directly from the pattern buffer */
737 if (periodtableoffset
> 0)
738 p_modchannel
->slidetonoteperiod
=
739 modplayer
.periodtable
[periodtableoffset
+
741 p_modchannel
->instrument
].finetune
];
744 /* Effect 0x06 is "Continue Effects" */
745 /* It is not processed on tick 0 */
751 if (effectx
> 0) p_modchannel
->tremolodepth
= effectx
;
752 if (effecty
> 0) p_modchannel
->tremolospeed
= effecty
;
755 /* Set fine panning */
757 /* Internal panning goes from 0..15
758 * Scale the fine panning value to that range */
759 mixer
.channel
[c
].panning
= p_modchannel
->effectparameter
>>4;
762 /* Set Sample Offset */
765 struct s_instrument
*p_instrument
=
766 &modsong
.instrument
[p_modchannel
->instrument
];
767 int sampleoffset
= p_instrument
->sampledataoffset
;
768 if (sampleoffset
> p_instrument
->length
)
769 sampleoffset
= p_instrument
->length
;
770 /* Forward the new offset to the mixer */
771 mixer
.channel
[c
].samplepos
=
772 p_instrument
->sampledataoffset
+
773 (p_modchannel
->effectparameter
<<8);
774 mixer
.channel
[c
].samplefractpos
= 0;
778 /* Effect 0x0a (Volume slide) is not processed on tick 0 */
782 modplayer
.currentline
= -1;
783 modplayer
.patterntableposition
= (effectx
<<4)+effecty
;
788 p_modchannel
->volume
= p_modchannel
->effectparameter
;
789 mixer_setvolume(c
, p_modchannel
->volume
);
794 modplayer
.currentline
= effectx
*10 + effecty
- 1;
795 if (!patternbreakdone
)
797 patternbreakdone
= true;
798 modplayer
.patterntableposition
++;
802 /* Extended Effects */
808 modplayer
.amigafilterenabled
=
809 (effecty
>0) ? false : true;
813 mixer_setamigaperiod(c
, p_modchannel
->period
-=
815 if (p_modchannel
->period
<
816 modplayer
.periodtable
[37*8]) p_modchannel
->period
= 100;
817 /* Find out the new offset in the period table */
818 if (p_modchannel
->periodtableoffset
< 36*8)
819 while (modplayer
.periodtable
[
820 p_modchannel
->periodtableoffset
+8] >= p_modchannel
->period
)
821 p_modchannel
->periodtableoffset
+=8;
825 mixer_setamigaperiod(c
,
826 p_modchannel
->period
+= effecty
);
827 if (p_modchannel
->periodtableoffset
> 8)
828 while (modplayer
.periodtable
[
829 p_modchannel
->periodtableoffset
-8]
830 <= p_modchannel
->period
)
831 p_modchannel
->periodtableoffset
-=8;
833 /* Set glissando on/off */
835 modplayer
.glissandoenabled
=
836 (effecty
> 0) ? true:false;
838 /* Set Vibrato waveform */
840 /* Currently not implemented */
842 /* Set Finetune value */
844 /* Treat as signed nibble */
845 if (effecty
> 7) effecty
-= 16;
847 p_modchannel
->periodtableoffset
+=
850 p_modchannel
->instrument
].finetune
;
851 p_modchannel
->period
=
852 modplayer
.periodtable
[
853 p_modchannel
->periodtableoffset
];
855 p_modchannel
->instrument
].finetune
= effecty
;
860 modplayer
.loopstartline
= line
-1;
863 if (modplayer
.looptimes
== 0)
865 modplayer
.currentline
=
866 modplayer
.loopstartline
;
867 modplayer
.looptimes
= effecty
;
869 else modplayer
.looptimes
--;
870 if (modplayer
.looptimes
> 0)
871 modplayer
.currentline
=
872 modplayer
.loopstartline
;
875 /* Set Tremolo waveform */
877 /* Not yet implemented */
879 /* Enhanced Effect 8 is not used */
882 /* Retrigger sample */
884 /* Only processed on subsequent ticks */
886 /* Fine volume slide up */
888 p_modchannel
->volume
+= effecty
;
889 if (p_modchannel
->volume
> 64)
890 p_modchannel
->volume
= 64;
891 mixer_setvolume(c
, p_modchannel
->volume
);
893 /* Fine volume slide down */
895 p_modchannel
->volume
-= effecty
;
896 if (p_modchannel
->volume
< 0)
897 p_modchannel
->volume
= 0;
898 mixer_setvolume(c
, p_modchannel
->volume
);
902 /* Continue sample */
903 mixer_continuesample(c
);
905 /* Note delay (Usage: $ED + ticks to delay note.) */
907 /* We stop the sample here on tick 0
908 * and restart it later in the effect */
910 mixer
.channel
[c
].channelactive
= false;
917 if (p_modchannel
->effectparameter
< 32)
918 modplayer
.ticksperline
= p_modchannel
->effectparameter
;
920 modplayer
.bpm
= p_modchannel
->effectparameter
;
926 /* Play the current effect of the note (ticks 1..speed) */
927 STATICIRAM
void playeffect(int currenttick
) ICODE_ATTR
;
928 void playeffect(int currenttick
)
932 for (c
=0;c
<modsong
.noofchannels
;c
++)
934 struct s_modchannel
*p_modchannel
= &modplayer
.modchannel
[c
];
936 /* If there is no note active then there are no effects to play */
937 if (p_modchannel
->period
== 0) continue;
939 unsigned char effectx
= p_modchannel
->effectparameter
>>4;
940 unsigned char effecty
= p_modchannel
->effectparameter
&0x0f;
942 switch (p_modchannel
->effect
)
944 /* Effect 0: Arpeggio */
946 if (p_modchannel
->effectparameter
> 0)
948 unsigned short newperiodtableoffset
;
949 switch (currenttick
% 3)
952 mixer_setamigaperiod(c
,
953 modplayer
.periodtable
[
954 p_modchannel
->periodtableoffset
]);
957 newperiodtableoffset
=
958 p_modchannel
->periodtableoffset
+(effectx
<<3);
959 if (newperiodtableoffset
< 37*8)
960 mixer_setamigaperiod(c
,
961 modplayer
.periodtable
[
962 newperiodtableoffset
]);
965 newperiodtableoffset
=
966 p_modchannel
->periodtableoffset
+(effecty
<<3);
967 if (newperiodtableoffset
< 37*8)
968 mixer_setamigaperiod(c
,
969 modplayer
.periodtable
[
970 newperiodtableoffset
]);
976 /* Effect 1: Slide Up */
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
)
986 p_modchannel
->periodtableoffset
++;
987 /* Make sure we don't go out of range */
988 if (p_modchannel
->periodtableoffset
> 37*8)
990 p_modchannel
->periodtableoffset
= 37*8;
996 /* Effect 2: Slide Down */
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
)
1006 p_modchannel
->periodtableoffset
--;
1007 /* Make sure we don't go out of range */
1008 if (p_modchannel
->periodtableoffset
< 1)
1010 p_modchannel
->periodtableoffset
= 1;
1016 /* Effect 3: Slide to Note */
1018 /* Apply smooth sliding, if no glissando is enabled */
1019 if (modplayer
.glissandoenabled
== 0)
1023 /* Effect 4: Vibrato */
1028 /* Effect 5: Continue effect 3:'Slide to note',
1029 * but also do Volume slide */
1032 volumeslide(c
, effectx
, effecty
);
1035 /* Effect 6: Continue effect 4:'Vibrato',
1036 * but also do Volume slide */
1039 volumeslide(c
, effectx
, effecty
);
1042 /* Effect 7: Tremolo */
1047 /* Effect 8 (Set fine panning) is only processed at tick 0 */
1048 /* Effect 9 (Set sample offset) is only processed at tick 0 */
1050 /* Effect A: Volume slide */
1052 volumeslide(c
, effectx
, effecty
);
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) */
1062 /* Retrigger sample ($E9 + Tick to Retrig note at) */
1064 /* Don't device by zero */
1065 if (effecty
== 0) effecty
= 1;
1067 if (currenttick
% effecty
== 0)
1068 mixer_playsample(c
, p_modchannel
->instrument
);
1070 /* Cut note (Usage: $EC + Tick to Cut note at) */
1072 if (currenttick
== effecty
)
1073 mixer_stopsample(c
);
1075 /* Delay note (Usage: $ED + ticks to delay note) */
1077 /* If this is the correct tick,
1078 * we start playing the sample now */
1079 if (currenttick
== effecty
)
1080 mixer
.channel
[c
].channelactive
= true;
1085 /* Effect F (Set Speed) is only processed at tick 0 */
1091 inline int clip(int i
)
1093 if (i
> 32767) return(32767);
1094 else if (i
< -32768) return(-32768);
1098 STATICIRAM
void synthrender(void *renderbuffer
, int samplecount
) ICODE_ATTR
;
1099 void synthrender(void *renderbuffer
, int samplecount
)
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 */
1106 int *p_left
= (int *) renderbuffer
; /* int in rockbox */
1107 int *p_right
= p_left
+1;
1109 int qf_distance
, qf_distance2
;
1115 for (i
=0;i
<samplecount
;i
++)
1118 if ((modplayer
.samplespertick
-- <= 0) &&
1119 (modplayer
.patterntableposition
< 127))
1121 if (modplayer
.currenttick
== 0)
1122 playline(modsong
.patternordertable
[
1123 modplayer
.patterntableposition
], modplayer
.currentline
);
1124 else playeffect(modplayer
.currenttick
);
1126 modplayer
.currenttick
++;
1128 if (modplayer
.currenttick
>= modplayer
.ticksperline
)
1130 modplayer
.currentline
++;
1131 modplayer
.currenttick
= 0;
1132 if (modplayer
.currentline
== 64)
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;
1145 modplayer
.samplespertick
= (20*mixingrate
/modplayer
.bpm
)>>3;
1147 /* Mix buffers from here
1148 * Walk through all channels */
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
++)
1156 /* Only mix the sample,
1157 * if channel there is something played on the channel */
1158 if (!mixer
.channel
[c
].channelactive
) continue;
1160 /* Loop the sample, if requested? */
1161 if (mixer
.channel
[c
].samplepos
>= mixer
.channel
[c
].loopend
)
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;
1170 /* If the sample has stopped playing don't mix it */
1171 if (!mixer
.channel
[c
].channelactive
) continue;
1173 /* Get the sample */
1174 s
= (signed short)(modsong
.sampledata
[
1175 mixer
.channel
[c
].samplepos
]*mixer
.channel
[c
].volume
);
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
)
1182 /* Low precision linear interpolation
1183 * (fast integer based) */
1184 qf_distance
= mixer
.channel
[c
].samplefractpos
<<16 /
1186 qf_distance2
= (1<<16)-qf_distance
;
1187 s
= (qf_distance
*s
+ qf_distance2
*
1188 mixer
.channel
[c
].lastsampledata
)>>16;
1191 /* Save the last played sample for interpolation purposes */
1192 mixer
.channel
[c
].lastsampledata
= s
;
1194 /* Pan the sample */
1195 left
+= s
*(16-mixer
.channel
[c
].panning
)>>3;
1196 right
+= s
*mixer
.channel
[c
].panning
>>3;
1198 /* Advance sample */
1199 mixer
.channel
[c
].samplefractpos
+= mixer
.channel
[c
].frequency
;
1200 while (mixer
.channel
[c
].samplefractpos
> mixingrate
)
1202 mixer
.channel
[c
].samplefractpos
-= mixingrate
;
1203 mixer
.channel
[c
].samplepos
++;
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;
1214 *p_right
= right
<<13;
1222 enum codec_status
codec_main(void)
1225 unsigned char *modfile
;
1226 int old_patterntableposition
;
1230 ci
->configure(CODEC_SET_FILEBUF_WATERMARK
, 1024*512);
1238 while (!*ci
->taginfo_ready
&& !ci
->stop_codec
)
1241 codec_set_replaygain(ci
->id3
);
1245 * This is the save way
1248 unsigned int filesize;
1251 bytesfree=sizeof(modfile);
1252 while ((n = ci->read_filebuf(p, bytesfree)) > 0) {
1258 filesize = p-modfile;
1264 /* Directly use mod in buffer */
1266 modfile
= ci
->request_buffer(&n
, ci
->filesize
);
1267 if (!modfile
|| n
< (size_t)ci
->filesize
) {
1274 /* Make use of 44.1khz */
1275 ci
->configure(DSP_SET_FREQUENCY
, 44100);
1276 /* Sample depth is 28 bit host endian */
1277 ci
->configure(DSP_SET_SAMPLE_DEPTH
, 28);
1279 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_INTERLEAVED
);
1281 /* The main decoder loop */
1284 old_patterntableposition
= 0;
1288 if (ci
->stop_codec
|| ci
->new_track
)
1291 if (ci
->seek_time
) {
1292 /* New time is ready in ci->seek_time */
1293 modplayer
.patterntableposition
= ci
->seek_time
/1000;
1294 modplayer
.currentline
= 0;
1295 ci
->seek_complete();
1298 if(old_patterntableposition
!= modplayer
.patterntableposition
) {
1299 ci
->set_elapsed(modplayer
.patterntableposition
*1000+500);
1300 old_patterntableposition
=modplayer
.patterntableposition
;
1303 synthrender(samples
, CHUNK_SIZE
/2);
1305 bytesdone
+= CHUNK_SIZE
;
1307 ci
->pcmbuf_insert(samples
, NULL
, CHUNK_SIZE
/2);
1311 if (ci
->request_next_track())