/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id: $ * * MOD Codec for rockbox * * Sequencer taken from Gravis Ultrasound open source mod player * (forgot the name, if anyone finds out, please insert *g* ) * * Mixer written and ported to rockbox by Rainer Sinsch * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ /************** * This version is quite experimental and support modules up to 486kbyte, only! * Source code is not cleaned and in a very untidy state * Execution should however be efficient, works fine on h320 ******************************/ #include "debug.h" #include "codeclib.h" #include #include #include #include #include CODEC_HEADER #define CHUNK_SIZE (1024*2) struct codec_api *rb; /* This codec supports MOD Files: * */ #ifdef USE_IRAM extern char iramcopy[]; extern char iramstart[]; extern char iramend[]; extern char iedata[]; extern char iend[]; #endif static int32_t samples[CHUNK_SIZE] IBSS_ATTR; /* The sample buffer */ static unsigned char modfile[486*1024]; /* Static buffer for module */ static signed char *sampleMem IDATA_ATTR; /* Pointer to the samples */ unsigned char mute[8] IDATA_ATTR; signed char volume[8] IDATA_ATTR; // volume of channel int freq[8] IDATA_ATTR; // amiga frequency of each channel signed char panval[8] IDATA_ATTR; int midival[8] IDATA_ATTR; // midi value of channel unsigned char lastins[8] IDATA_ATTR; // instrument # for each channel int porto[8] IDATA_ATTR; // note to port to value unsigned char portsp[8] IDATA_ATTR; // porta speed unsigned char vibspe[8] IDATA_ATTR; // vibrato speed unsigned char vibdep[8] IDATA_ATTR; // vibrato depth unsigned char tremspe[8] IDATA_ATTR; // tremolo speed unsigned char tremdep[8] IDATA_ATTR; // tremolo depth unsigned char sinepos[8] IDATA_ATTR; // position in sine wave unsigned char sineneg[8] IDATA_ATTR; // toggle to add or subtract sine value unsigned char geffect[8] IDATA_ATTR; // effect played at the time (for interface) static int freqtab[296] ICONST_ATTR = { // The sorted amiga table. 907,900,894,887,881,875,868,862, // Finetune -8 to -1 856,850,844,838,832,826,820,814, // C-1 to finetune +7 808,802,796,791,785,779,774,768, // C#1 to finetune +7 762,757,752,746,741,736,730,725, // D-1 to finetune +7 720,715,709,704,699,694,689,684, // D#1 to finetune +7 678,675,670,665,660,655,651,646, // E-1 to finetune +7 640,636,632,628,623,619,614,610, // F-1 to finetune +7 604,601,597,592,588,584,580,575, // F#1 to finetune +7 570,567,563,559,555,551,547,543, // G-1 to finetune +7 538,535,532,528,524,520,516,513, // G#1 to finetune +7 508,505,502,498,494,491,487,484, // A-1 to finetune +7 480,477,474,470,467,463,460,457, // A#1 to finetune +7 453,450,447,444,441,437,434,431, // B-1 to finetune +7 428,425,422,419,416,413,410,407, // C-2 to finetune +7 404,401,398,395,392,390,387,384, // C#2 to finetune +7 381,379,376,373,370,368,365,363, // D-2 to finetune +7 360,357,355,352,350,347,345,342, // D#2 to finetune +7 339,337,335,332,330,328,325,323, // E-2 to finetune +7 320,318,316,314,312,309,307,305, // F-2 to finetune +7 302,300,298,296,294,292,290,288, // F#2 to finetune +7 285,284,282,280,278,276,274,272, // G-2 to finetune +7 269,268,266,264,262,260,258,256, // G#2 to finetune +7 254,253,251,249,247,245,244,242, // A-2 to finetune +7 240,238,237,235,233,232,230,228, // A#2 to finetune +7 226,225,223,222,220,219,217,216, // B-2 to finetune +7 214,212,211,209,208,206,205,203, // C-3 to finetune +7 202,200,199,198,196,195,193,192, // C#3 to finetune +7 190,189,188,187,185,184,183,181, // D-3 to finetune +7 180,179,177,176,175,174,172,171, // D#3 to finetune +7 170,169,167,166,165,164,163,161, // E-3 to finetune +7 160,159,158,157,156,155,154,152, // F-3 to finetune +7 151,150,149,148,147,146,145,144, // F#3 to finetune +7 143,142,141,140,139,138,137,136, // G-3 to finetune +7 135,134,133,132,131,130,129,128, // G#3 to finetune +7 127,126,125,125,123,123,122,121, // A-3 to finetune +7 120,119,118,118,117,116,115,114, // A#3 to finetune +7 113,113,112,111,110,109,109,108, // B-3 to finetune +7 }; // This table is for vibrato and contains half a sine wave. static unsigned char sintab[32] ICONST_ATTR = { 0, 24, 49, 74, 97,120,141,161, 180,197,212,224,235,244,250,253, 255,253,250,244,235,224,212,197, 180,161,141,120, 97, 74, 49, 24 }; int speed, bpm, channels IDATA_ATTR; // speed, bpm, channels, figure it out. unsigned char patdelay IDATA_ATTR; // variable storing number of times to delay patn unsigned char patlooprow, patloopno IDATA_ATTR; // pattern loop variables. signed char row; char mastervol IDATA_ATTR; // same here, current row, and master volume int ord IDATA_ATTR; // current order being played // SAMPLE STRUCT typedef struct { char name[23]; // instrument name unsigned short length; // sample length signed char finetune; // sample finetune value unsigned char volume; // sample default volume unsigned short loopstart; // sample loop start unsigned short loopend; // sample loop length unsigned int offset; // offset of sample in dram } Sample; // SONG STRUCT struct { char name[20]; // song name Sample inst[31]; // instrument headers unsigned char songLength; // song length unsigned char numpats; // number of physical patterns unsigned char order[128]; // pattern playing orders } MOD; typedef struct { unsigned char number; // sample being played 5 bits int period; // frequency being played at + 11 bits = 16. unsigned char effect; // effect number + 8 unsigned char eparm; // effect parameter + 8 = 4 bytes! } Note; Note *current IDATA_ATTR; static char *patbuff IDATA_ATTR; // buffer that holds our pattern data static unsigned int offset IDATA_ATTR; // offset of note in pattern data buffer. static const int iMixingRate = 44100; static int iBalance[8] IDATA_ATTR; // Balance static int iFreq[8] IDATA_ATTR; // Frequency static int iSamplePos[8] IDATA_ATTR; // Position des Samplezeigers static int iSampleFractPos[8] IDATA_ATTR; // Fractal position static int iLoopStart[8] IDATA_ATTR; static int iLoopEnd[8] IDATA_ATTR; static int bPlayVoice[8] IDATA_ATTR; static int bLoopVoice[8] IDATA_ATTR; static int tick IDATA_ATTR; static int iSamplesPerTick IDATA_ATTR; // Samples Per Tick static inline void SetVolume(unsigned char iChannel, unsigned char iVolume) { volume[iChannel] = iVolume; } static inline void SetBalance(int iChannel, int iVal) { iBalance[iChannel] = iVal; } static inline void SetFreq(int iChannel, int iVal) { iFreq[iChannel] = 3579546.471f/iVal; } static inline void PlayVoice(unsigned char iChannel, unsigned char iMode , unsigned int iBegin, unsigned int iStart, unsigned int iEnd) { bPlayVoice[iChannel] = 1; iSamplePos[iChannel] = iBegin; iSampleFractPos[iChannel] = 0; iLoopEnd[iChannel] = iEnd; // Loopen? if (iMode) { bLoopVoice[iChannel] = 1; iLoopStart[iChannel] = iStart; } else bLoopVoice[iChannel] = false; } static inline void StopVoice(unsigned char iChannel) { bPlayVoice[iChannel] = false; } static void UpdateNote(void) ICODE_ATTR; static void UpdateNote(void) { unsigned char track, sample, eparmx, eparmy; unsigned short soff; int period; // calculate where in the pattern buffer we should be according to // the pattern number and row. offset = channels*64*sizeof(Note)*MOD.order[ord]+(sizeof(Note)*row*channels); // new row? now we loop through each channel until we have finished for (track=0; track period; // get period sample = current -> number; // get instrument # eparmx = current -> eparm >> 4; // get effect param x eparmy = current -> eparm & 0xF; // get effect param y // for the interface, the next 3 lines just store the effect # to // remember for later geffect[track] = current -> effect; if (geffect[track] == 0xE) geffect[track]+=2+eparmx; if (current->effect == 0 && current -> eparm > 0) geffect[track] = 32; if (sample > 0) { // if instrument > 0 set volume lastins[track] = sample - 1; // remember the sample # volume[track] = MOD.inst[sample-1].volume; // set chan's vol SetVolume(track, volume[track]*mastervol/64); } if (period >= 0) { // if period >= 0 set freq midival[track] = period; // remember the note // if not a porta effect, then set the channels frequency to the // looked up amiga value + or - any finetune if (current->effect != 0x3 && current->effect != 0x5) freq[track]= freqtab[midival[track]+MOD.inst[lastins[track]].finetune]; } soff = 0; // sample offset = nothing now switch (current -> effect) { case 0x0: break; // dont waste my time in here!!! // 0x1: not processed on tick 0 // 0x2: not processed on tick 0 case 0x3: case 0x5: porto[track] = freqtab[midival[track]+MOD.inst[lastins[track]].finetune]; if (current -> eparm > 0 && current->effect == 0x3) portsp[track] = current -> eparm; period = -1; break; case 0x4: if (eparmx > 0) vibspe[track] = eparmx; if (eparmy > 0) vibdep[track] = eparmy; break; // 0x6: not processed on tick 0 case 0x7: if (eparmx > 0) tremspe[track] = eparmx; if (eparmy > 0) tremdep[track] = eparmy; break; case 0x8: if (current -> eparm == 0xa4) panval[track]=7; else panval[track] = (current -> eparm >> 3)-1; if (panval[track] < 0) panval[track] = 0; SetBalance(track, panval[track]); break; case 0x9: soff = current -> eparm << 8; if (soff > MOD.inst[lastins[track]].length) soff = MOD.inst[lastins[track]].length; break; // 0xA: processed in UpdateEffect() (tick based) case 0xB: ord = current->eparm; row = 0; if (ord >= MOD.songLength) ord=0; break; case 0xC: volume[track] = current -> eparm; if (volume[track] < 0) volume[track] = 0; if (volume[track] > 64) volume[track] = 64; SetVolume(track, volume[track]*mastervol/64); break; case 0xD: row = eparmx*10 + eparmy -1; if (row > 63) row =0; ord++; if (ord >= MOD.songLength) ord=0; break; case 0xF: if (current->eparm < 0x20) speed = current->eparm; else bpm = current->eparm; break; case 0xE: switch (eparmx) { case 0x1: freq[track] -= eparmy; break; case 0x2: freq[track] += eparmy; break; // 0x3: not supported (glissando) // 0x4: not supported (set vibrato waveform) case 0x5: MOD.inst[sample-1].finetune = eparmy; if (MOD.inst[sample-1].finetune > 7) MOD.inst[sample-1].finetune -= 16; break; case 0x6: if (eparmy == 0) patlooprow = row; else { if (patloopno == 0) patloopno=eparmy; else patloopno--; if (patloopno > 0) row = patlooprow-1; } break; // 0x6: not supported (set tremolo waveform) case 0x8: panval[track] = eparmy; SetBalance(track, eparmy); break; // 0x9: not processed on tick 0 case 0xA: volume[track] += eparmy; if (volume[track] > 64) volume[track]=64; SetVolume(track, volume[track]*mastervol/64); break; case 0xB: volume[track] -= eparmy; if (volume[track] < 0) volume[track]=0; SetVolume(track, volume[track]*mastervol/64); break; // 0xC: not processed on tick 0 case 0xD: period = -1; break; case 0xE: patdelay = eparmy; break; // 0xF: not supported (Invert loop) }; break; }; // set the frequency on the GUS for the voice, as long as its > 0 if (freq[track] > 0) SetFreq(track, freq[track]); // only play the note if there is a note or there is an effect 9xy if (period >= 0 || soff > 0x00FF) { sinepos[track]=0; // retrig waveform sineneg[track]=0; // if sample has a loop then loop it. if (MOD.inst[lastins[track]].loopend > 2) PlayVoice(track, 8, MOD.inst[lastins[track]].offset+soff, MOD.inst[lastins[track]].offset+MOD.inst[lastins[track]].loopstart, MOD.inst[lastins[track]].offset+MOD.inst[lastins[track]].loopend); // else just play the sample straight and no loop. else PlayVoice(track, 0, MOD.inst[lastins[track]].offset+soff, MOD.inst[lastins[track]].offset, MOD.inst[lastins[track]].offset+MOD.inst[lastins[track]].length); } offset += sizeof(Note); // increment our note pointer. } } /**************************************************************************** * Name : doporta * * Purpose : to carry out a tone portamento to a certain note * * Passed : - * * Returns : - * * Locals : - * ****************************************************************************/ static inline void doporta(unsigned char track) { if (freq[track] < porto[track]) { freq[track] += portsp[track]; if (freq[track] > porto[track]) freq[track]=porto[track]; } if (freq[track] > porto[track]) { freq[track] -= portsp[track]; if (freq[track] < 1) freq[track]=1; if (freq[track] < porto[track]) freq[track]=porto[track]; } SetFreq(track, freq[track]); } /**************************************************************************** * Name : dovibrato * * Purpose : to carry out a vibrato at a certain depth and speed * * Passed : - * * Returns : - * * Locals : int vib - size of delta to add or subtract from period * ****************************************************************************/ static inline void dovibrato(unsigned char track) { int vib; vib = vibdep[track]*sintab[sinepos[track]] >> 7; // div 128 if (sineneg[track] == 0) SetFreq(track, freq[track]+vib); else SetFreq(track, freq[track]-vib); sinepos[track]+=vibspe[track]; if (sinepos[track] > 31) { sinepos[track] -=32; sineneg[track] = ~sineneg[track]; // flip pos/neg flag } } /**************************************************************************** * Name : dotremolo * * Purpose : to carry out a tremolo at a certain depth and speed * * Passed : - * * Returns : - * * Locals : int vib - size of delta to add or subtract from volume * ****************************************************************************/ static inline void dotremolo(unsigned char track) { int vib; vib = tremdep[track]*sintab[sinepos[track]] >> 6; // div64 if (sineneg[track] == 0) { if (volume[track]+vib > 64) vib = 64-volume[track]; SetVolume(track, (volume[track]+vib)*mastervol/64); } else { if (volume[track]-vib < 0) vib = volume[track]; SetVolume(track, (volume[track]-vib)*mastervol/64); } sinepos[track]+= tremspe[track]; if (sinepos[track] > 31) { sinepos[track] -=32; sineneg[track] = ~sineneg[track]; // flip pos/neg flag } } /**************************************************************************** * Name : UpdateEffect * * Purpose : To update any tick based effects after tick 0 * * Passed : int tick - the actual tick number. * * Returns : - * * Locals : int track - the number of the column/track or channel we are in* * int vib - the delta which to vibrate from the frequency with * * byte effect - a temp variable to get the effect number wanted * * byte eparmx - a term variable to get the effect parameter x * * byte eparmy - a term variable to get the effect parameter y * * static byte arpcount - a counter to tell us what to do with * * arpeggio (we dont want to forget it too, so its static) * * Note *current - a temporary note structure to hold the pointed * * to note in the pattern buffer * * Note : To see explanations of effects check out the howto document * ****************************************************************************/ static void UpdateEffect(int tick) ICODE_ATTR; static void UpdateEffect(int tick) { unsigned char track, effect, eparmx, eparmy; if (row < 1) return; // if at row 0 nothing to update offset -= (sizeof(Note) * channels); // go back 4 bytes in buffer // becuase update note did +4 for (track=0; track effect; // grab the effect number eparmx = current -> eparm >> 4; // grab the effect parameter x eparmy = current -> eparm & 0xF; // grab the effect parameter y if (freq[track] == 0) goto skip; switch(effect) { case 0x0: if (current -> eparm > 0) { switch (tick%3) { case 0: SetFreq(track, freq[track]); break; case 1: SetFreq(track, freqtab[midival[track]+(8*eparmx)+MOD.inst[lastins[track]].finetune]); break; case 2: SetFreq(track, freqtab[midival[track]+(8*eparmy)+MOD.inst[lastins[track]].finetune]); break; }; } break; case 0x3: doporta(track); break; case 0x4: dovibrato(track); break; case 0x1: freq[track]-= current -> eparm; // subtract freq SetFreq(track, freq[track]); if (freq[track] < 54) freq[track]=54; // stop at C-5 break; case 0x2: freq[track]+= current -> eparm; SetFreq(track, freq[track]); break; case 0x5: doporta(track); volume[track] += eparmx - eparmy; if (volume[track] < 0) volume[track] = 0; if (volume[track] > 64) volume[track] = 64; SetVolume(track, volume[track]*mastervol/64); break; case 0x6: dovibrato(track); volume[track] += eparmx - eparmy; if (volume[track] < 0) volume[track] = 0; if (volume[track] > 64) volume[track] = 64; SetVolume(track, volume[track]*mastervol/64); break; case 0x7: dotremolo(track); break; case 0xA: volume[track] += eparmx - eparmy; if (volume[track] < 0) volume[track] = 0; if (volume[track] > 64) volume[track] = 64; SetVolume(track, volume[track]*mastervol/64); break; case 0xE: switch(eparmx) { case 0xC: if (eparmy == tick) { volume[track] = 0; SetVolume(track, volume[track]); } break; case 0x9: if (tick % eparmy == 0) { if (MOD.inst[lastins[track]].loopend > 2) PlayVoice(track, 8, MOD.inst[lastins[track]].offset, MOD.inst[lastins[track]].offset+ MOD.inst[lastins[track]].loopstart, MOD.inst[lastins[track]].offset+ MOD.inst[lastins[track]].loopend); else PlayVoice(track, 0, MOD.inst[lastins[track]].offset, MOD.inst[lastins[track]].offset, MOD.inst[lastins[track]].offset+ MOD.inst[lastins[track]].length); } break; case 0xD: if (eparmy==tick) { if (MOD.inst[lastins[track]].loopend > 2) PlayVoice(track, 8, MOD.inst[lastins[track]].offset, MOD.inst[lastins[track]].offset+ MOD.inst[lastins[track]].loopstart, MOD.inst[lastins[track]].offset+ MOD.inst[lastins[track]].loopend); else PlayVoice(track, 0, MOD.inst[lastins[track]].offset, MOD.inst[lastins[track]].offset, MOD.inst[lastins[track]].offset+ MOD.inst[lastins[track]].length); } break; }; break; }; skip: offset+=sizeof(Note); // increment our buffer to next note } } static int LoadMODFromMem(void *pMod) ICODE_ATTR; static int LoadMODFromMem(void *pMod) { unsigned char *part; unsigned char *pbMod = (unsigned char*)pMod; int count=0, count2=0, pattcount, period; unsigned int gusoff, size; //********************** //*** VERIFICATION *** //********************** part = (unsigned char*)(pbMod+1080); // check what MOD format if (rb->strncasecmp((char*)part, "M.K.",4) == 0) channels = 4; else if (rb->strncasecmp((char*)part, "6CHN",4) == 0) channels = 6; else if (rb->strncasecmp((char*)part, "8CHN",4) == 0) channels = 8; else if (rb->strncasecmp((char*)part, "FLT4",4) == 0) channels = 4; else return(false); // not a recognized format //fseek(handle, 20, SEEK_SET); part = (unsigned char*)(pbMod+20); /*********************************/ /*** LOAD SAMPLE INFORMATION ***/ /*********************************/ for (count=0; count<31; count++) { // go through 31 instruments. // Sample Name //fread(MOD.inst[count].name, 22, 1, handle); memcpy(MOD.inst[count].name, part, 22); part+= 22; //part[0] = fgetc(handle); // get samples length //part[1] = fgetc(handle); MOD.inst[count].length = ((part[0] * 0x100) + part[1]) * 2; part+=2; //MOD.inst[count].finetune = fgetc(handle);// get finetune MOD.inst[count].finetune = *part++; // get finetune if (MOD.inst[count].finetune > 7) MOD.inst[count].finetune -= 16; //MOD.inst[count].volume = fgetc(handle); // get sample default volume MOD.inst[count].volume = *part++; // get sample default volume // get sample loop start //MOD.inst[count].loopstart = ((fgetc(handle) << 8)+fgetc(handle))*2; //MOD.inst[count].loopstart = ((*part++<<8) + *part++)*2; MOD.inst[count].loopstart = *part++<<8; MOD.inst[count].loopstart|= *part++; MOD.inst[count].loopstart<<=1; // get sample loop end //MOD.inst[count].loopend = ((fgetc(handle) << 8)+fgetc(handle))*2 + MOD.inst[count].loopstart; //MOD.inst[count].loopend = ((*part++<<8)+ *part++)*2 + MOD.inst[count].loopstart; MOD.inst[count].loopend = *part++<<8; MOD.inst[count].loopend|= *part++; MOD.inst[count].loopend<<=1; MOD.inst[count].loopend+= MOD.inst[count].loopstart; // incase the loopend is past the end of the sample fix it if (MOD.inst[count].loopend > MOD.inst[count].length) MOD.inst[count].loopend = MOD.inst[count].length; } /**************************************/ /*** LOAD ORDER AND SIGNATURE DATA ***/ /**************************************/ MOD.songLength = *part++; // get number of orders. part++; // unused byte, skip it MOD.numpats = 0; // highest pattern is now 0 for (count=0; count<128; count++) { MOD.order[count] = *part++; // get 128 orders. if (MOD.order[count] > MOD.numpats) MOD.numpats = MOD.order[count]; // get highest pattern. } size = channels*sizeof(Note)*64*(MOD.numpats+1); // calculate buffer size // try and allocate memory //if (patbuff) free(patbuff); if ((patbuff = (char *)codec_malloc(size)) == NULL) return(false); // at 1080 again, skip it part = (unsigned char*) (pbMod + 1084); offset =0; // set buffer offset to 0 /**************************/ /*** LOAD PATTERN DATA ***/ /**************************/ for (pattcount=0; pattcount <= MOD.numpats; pattcount++) { for (row=0; row<64; row++) { // loop down through 64 notes. for (count=0; count number = ((part[0] & 0xF0) + (part[2] >> 4)); // get period period = ((part[0] & 0xF) << 8) + part[1]; // do the look up in the table against what is read in. // store note (in midi style format) current -> period = -1; for (count2=1;count2<37; count2++) { if (period > freqtab[count2*8]-3 && period < freqtab[count2*8]+3 ) current -> period = count2*8; } // store effects and arguments current -> effect = part[2] & 0xF; // Effect current -> eparm = part[3]; // parameter offset += sizeof(Note); // increment buffer pos part += 4; } } } /*************************/ /*** LOAD SAMPLE DATA ***/ /*************************/ gusoff =0; sampleMem = (signed char*) part; for (count = 0; count <31; count++) { MOD.inst[count].offset = gusoff; // get offsets in GUS memory gusoff += MOD.inst[count].length; } tick = speed-1; /* Panning values = { 4,12,12, 4, 4,12,12, 4 } */ panval[0] = panval[3] = panval[4] = panval[7] = 4; panval[1] = panval[2] = panval[5] = panval[6] = 12; for (count=0; count 32767) return(32767); else if (i < -32767) return(-32767); else return(i); } static void SynthRender(void *pRenderBuffer, int iSampleCount) ICODE_ATTR; static void SynthRender(void *pRenderBuffer, int iSampleCount) { // 125bpm entspricht 50Hz (= 0.02s) // => ein tick = MixingRate/50, bzw. // samples die fr einen tick vergehen: MixingRate/(bpm/2.5) = 2.5*MixingRate/bpm //static int tick = speed-1; signed int *pLeft = (signed int *) pRenderBuffer; signed int *pRight = pLeft+1; signed short s; int qfDistance, qfDistance2; int i; int c, Left, Right; for (i=0;i= speed) { tick = 0; // set the tick to nothing if (row == 64) { // if end of pattn (64) ord++; // next order if (ord >= MOD.songLength) ord=0; // if end goto 1st order row = 0; // start at top of pattn } if (patdelay == 0) { // if there is no pat delay UpdateNote(); // Update and play the note row++; // increment the row /* for (int count=0;count<4;count++) printf("I%02d V%02d N%3s ", lastins[count]+1, volume[count], notetab[midival[count]/8]); printf("\n"); */ } else patdelay --; // else decrement pat delay } else UpdateEffect(tick); // Else update the effects //iSamplesPerTick = (int) (2.5f*(float)iMixingRate/(float)bpm); iSamplesPerTick = (20*iMixingRate/bpm)>>3; } // ab hier Puffer mischen // Alle Kan�e durchlaufen Left=0, Right=0; static int iLastSample[8] = {0, 0, 0, 0, 0, 0, 0, 0}; for (c=0;c= iLoopEnd[c]) { if (bLoopVoice[c]) iSamplePos[c] -= (iLoopEnd[c]-iLoopStart[c]); else bPlayVoice[c] = false; } if (bPlayVoice[c]) { s = (signed short)(sampleMem[iSamplePos[c]])*volume[c]; // Wenn die Samplefrequenz niedriger als die Mixingfrequenz ist: Interpolien if (iFreq[c] < iMixingRate) { // Lineare Interpolation //fDistance = (float)iSampleFractPos[c]/iMixingRate; //fDistance2 = 1-fDistance; qfDistance = iSampleFractPos[c]<<16 / iMixingRate; qfDistance2 = (1<<16)-qfDistance; //s = (int)(fDistance*s + fDistance2*iLastSample[c]); s = (qfDistance*s + qfDistance2*iLastSample[c])>>16; } // Sample bernehmen Left += s*(16-iBalance[c])>>2; Right += s*iBalance[c]>>2; // Sample weiter rcken iSampleFractPos[c] += iFreq[c]; while (iSampleFractPos[c] > iMixingRate) { iSampleFractPos[c] -= iMixingRate; iSamplePos[c]++; // Zuletzt gespieltes Sample retten (zwecks Interpolation) iLastSample[c] = s; } } } } *pLeft = Clip(Left)<<13; *pRight = Clip(Right)<<13; pLeft+=2; pRight+=2; } } enum codec_status codec_main(void) { size_t n, bytesfree; unsigned char *p; unsigned int filesize; int bytesdone; #ifdef USE_IRAM ci->memcpy(iramstart, iramcopy, iramend - iramstart); ci->memset(iedata, 0, iend - iedata); #endif ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256)); next_track: if (codec_init()) { return CODEC_ERROR; } while (!*ci->taginfo_ready) ci->yield(); /* Load SID file */ p = modfile; bytesfree=sizeof(modfile); while ((n = rb->read_filebuf(p, bytesfree)) > 0) { p += n; bytesfree -= n; } filesize = p-modfile; if (filesize == 0) return CODEC_ERROR; LoadMODFromMem(modfile); /* Make use of 44.1khz */ ci->configure(DSP_SET_FREQUENCY, (long *)44100); /* Sample depth is 28 bit host endian */ ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28); /* Stereo output */ ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED); /* The main decoder loop */ ci->set_elapsed(0); bytesdone = 0; while (1) { ci->yield(); if (ci->stop_codec || ci->new_track) break; if (ci->seek_time) { /* New time is ready in ci->seek_time */ ci->seek_complete(); } SynthRender(samples, CHUNK_SIZE/2); bytesdone += CHUNK_SIZE; while (!ci->pcmbuf_insert((char *)samples, CHUNK_SIZE*sizeof(int))) ci->yield(); ci->set_elapsed(bytesdone*1000LL/44100); } if (ci->request_next_track()) goto next_track; return CODEC_OK; }