From 1f5fb998192f512ac32dfa012586fb78a9a6a72c Mon Sep 17 00:00:00 2001 From: Stepan Moskovchenko Date: Tue, 19 Apr 2005 15:57:07 +0000 Subject: Some shifting optimizations. Working code. 50% realtime. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6323 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/midi/guspat.c | 52 +++++++++++++- apps/plugins/midi/guspat.h | 1 + apps/plugins/midi/midiutil.c | 132 +++++++++++++++-------------------- apps/plugins/midi/sequencer.c | 31 +++++++-- apps/plugins/midi/synth.c | 158 +++++++++++++++++------------------------- apps/plugins/midi2wav.c | 65 ++++++++++------- 6 files changed, 238 insertions(+), 201 deletions(-) diff --git a/apps/plugins/midi/guspat.c b/apps/plugins/midi/guspat.c index f674b64caa..2172072eb1 100644 --- a/apps/plugins/midi/guspat.c +++ b/apps/plugins/midi/guspat.c @@ -66,18 +66,64 @@ struct GWaveform * loadWaveform(int file) wav->res=readData(file, 36); wav->data=readData(file, wav->wavSize); + wav->numSamples = wav->wavSize / 2; int a=0; + return wav; + if(wav->mode & 1 == 0) //Whoops, 8 bit + { + wav->numSamples = wav->wavSize; + + //Allocate a block for the rest of it + //It should end up right after the previous one. + wav->wavSize = wav->wavSize * 2; + void * foo = allocate(wav->wavSize); + + + for(a=0; a<1000; a++) + printf("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + + + for(a=wav->wavSize-1; a>0; a-=2) + { + + } + // int b1=wf->data[s]+((wf->mode & 2) << 6); + // return b1<<8; + } + + /* +//#if !defined(SIMULATOR) + for(a=0; awavSize; a+=2) + { + unsigned char tmp; + tmp = wav->data[2*a]; + wav->data[2*a] = wav->data[2*a+1]; + wav->data[2*a+1] = tmp; + } +//#endif + + if(wav->mode & 2) + { + for(a=0; awavSize/2; a++) + { + ((short *) wav->data)[a] = ((short *) wav->data)[a] - 32767; + } + } +*/ + + + //If we have a 16 bit waveform - if(wav->mode & 1 && (wav->mode & 2)) +/* if(wav->mode & 1 && (wav->mode & 2)) { for(a=0; awavSize; a+=2) //Convert it to { - //wav->data[a]=wav->data[a]; //+((wav->mode & 2) << 6); + wav->data[a]=wav->data[a]+(1 << 7); wav->data[a|1]=wav->data[(a)|1]+(1 << 7); } } - +*/ return wav; } diff --git a/apps/plugins/midi/guspat.h b/apps/plugins/midi/guspat.h index 75bdb2ca01..6e41a85d23 100644 --- a/apps/plugins/midi/guspat.h +++ b/apps/plugins/midi/guspat.h @@ -36,6 +36,7 @@ struct GWaveform unsigned char * name; unsigned char fractions; unsigned int wavSize; + unsigned int numSamples; unsigned int startLoop; unsigned int endLoop; unsigned int sampRate; diff --git a/apps/plugins/midi/midiutil.c b/apps/plugins/midi/midiutil.c index 41a02ae682..bf25d1d277 100644 --- a/apps/plugins/midi/midiutil.c +++ b/apps/plugins/midi/midiutil.c @@ -63,33 +63,26 @@ extern struct plugin_api * rb; +int chVol[16] IDATA_ATTR; //Channel volume +int chPanLeft[16] IDATA_ATTR; //Channel panning +int chPanRight[16] IDATA_ATTR; +int chPat[16]; //Channel patch +int chPW[16]; //Channel pitch wheel, MSB only + + +/* unsigned char chVol[16]; //Channel volume unsigned char chPanLeft[16]; //Channel panning unsigned char chPanRight[16]; unsigned char chPat[16]; //Channel patch unsigned char chPW[16]; //Channel pitch wheel, MSB only - - +*/ struct GPatch * gusload(char *); struct GPatch * patchSet[128]; struct GPatch * drumSet[128]; -struct SynthObject voices[MAX_VOICES]; - -struct SynthObject -{ - int tmp; - struct GWaveform * wf; - unsigned int delta; - unsigned int decay; - unsigned int cp; - unsigned char state, pstate, loopState, loopDir; - unsigned char note, vol, ch, isUsed; - int curRate, curOffset, targetOffset; - int curPoint; -}; - +//char myarray[80] IDATA_ATTR; struct Event { @@ -120,6 +113,34 @@ struct MIDIfile unsigned char patches[128]; int numPatches; }; +/* +struct SynthObject +{ +// int tmp; + struct GWaveform * wf; + unsigned int delta; + unsigned int decay; + unsigned int cp; + unsigned char state, loopState, loopDir; + unsigned char note, vol, ch, isUsed; + int curRate, curOffset, targetOffset; + unsigned int curPoint; +}; +*/ +struct SynthObject +{ +// int tmp; + struct GWaveform * wf; + int delta; + int decay; + int cp; + int state, loopState, loopDir; + int note, vol, ch, isUsed; + int curRate, curOffset, targetOffset; + int curPoint; +}; + +struct SynthObject voices[MAX_VOICES] IDATA_ATTR; @@ -133,13 +154,16 @@ int readVarData(int file); int midimain(void * filename); -//Rick's code void *alloc(int size) { static char *offset = NULL; static int totalSize = 0; char *ret; + int remainder = size % 4; + + size = size + 4-remainder; + if (offset == NULL) { offset = rb->plugin_get_audio_buffer(&totalSize); @@ -157,40 +181,34 @@ void *alloc(int size) totalSize -= size + 4; return ret; } + + +//Rick's code /* -void *ralloc(char *offset, int len) +void *alloc(int size) { - int size; + static char *offset = NULL; + static int totalSize = 0; char *ret; + if (offset == NULL) { - return alloc(len); + offset = rb->plugin_get_audio_buffer(&totalSize); } - size = *((unsigned int *)offset - 4); - - if (size >= 0x02000000) + if (size + 4 > totalSize) { return NULL; } - ret = alloc(len); - - if (len < size) - { - rb->memcpy(ret, offset, len); - } - else - { - rb->memcpy(ret, offset, size); - rb->memset(ret, 0, len - size); - } + ret = offset + 4; + *((unsigned int *)offset) = size; + offset += size + 4; + totalSize -= size + 4; return ret; -} -*/ - +}*/ void * allocate(int size) { return alloc(size); @@ -222,44 +240,6 @@ int eof(int fd) void printf(char *fmt, ...) {fmt=fmt; } -/* -void *audio_bufferbase; -void *audio_bufferpointer; -unsigned int audio_buffer_free; - - - - -void *my_malloc(int size) -{ - - void *alloc; - - if (!audio_bufferbase) - { - audio_bufferbase = audio_bufferpointer - = rb->plugin_get_audio_buffer(&audio_buffer_free); -#if MEM <= 8 && !defined(SIMULATOR) - - if ((unsigned)(ovl_start_addr - (unsigned char *)audio_bufferbase) - < audio_buffer_free) - audio_buffer_free = ovl_start_addr - (unsigned char *)audio_bufferbase; -#endif - } - if (size + 4 > audio_buffer_free) - return 0; - alloc = audio_bufferpointer; - audio_bufferpointer += size + 4; - audio_buffer_free -= size + 4; - return alloc; -} - -void setmallocpos(void *pointer) -{ - audio_bufferpointer = pointer; - audio_buffer_free = audio_bufferpointer - audio_bufferbase; -} -*/ void exit(int code) { code = code; //Stub function, kill warning for now diff --git a/apps/plugins/midi/sequencer.c b/apps/plugins/midi/sequencer.c index f7c6f30376..836866a5df 100644 --- a/apps/plugins/midi/sequencer.c +++ b/apps/plugins/midi/sequencer.c @@ -88,9 +88,30 @@ void setPW(int ch, int msb) void pressNote(int ch, int note, int vol) { +/* + if(ch == 0) return; +// if(ch == 1) return; + if(ch == 2) return; + if(ch == 3) return; + if(ch == 4) return; + if(ch == 5) return; + if(ch == 6) return; + if(ch == 7) return; + if(ch == 8) return; + if(ch == 9) return; + if(ch == 10) return; + if(ch == 11) return; + if(ch == 12) return; + if(ch == 13) return; + if(ch == 14) return; + if(ch == 15) return; +*/ int a=0; for(a=0; amode & 28)) { - voices[a].tmp=40; + // voices[a].tmp=40; // voices[a].state = STATE_RELEASE; //Ramp down // voices[a].state = STATE_RAMPDOWN; //Ramp down - -// voices[a].isUsed = 0; setPoint(&voices[a], 3); } } @@ -281,6 +299,9 @@ int tick(struct MIDIfile * mf) { tempo = (((short)e->evData[0])<<16)|(((short)e->evData[1])<<8)|(e->evData[2]); printf("\nMeta-Event: Tempo Set = %d", tempo); + bpm=mf->div*1000000/tempo; + numberOfSamples=SAMPLE_RATE/bpm; + } } tr->delta = 0; diff --git a/apps/plugins/midi/synth.c b/apps/plugins/midi/synth.c index 99864e557e..bafaf1c7ca 100644 --- a/apps/plugins/midi/synth.c +++ b/apps/plugins/midi/synth.c @@ -16,8 +16,6 @@ * ****************************************************************************/ - - extern struct plugin_api * rb; struct Event * getEvent(struct Track * tr, int evNum) @@ -178,7 +176,20 @@ int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig) -inline signed short int getSample(struct GWaveform * wf, unsigned int s) +int currentVoice IDATA_ATTR; +struct SynthObject * so IDATA_ATTR; +struct GWaveform * wf IDATA_ATTR; +int s IDATA_ATTR; +short s1 IDATA_ATTR; +short s2 IDATA_ATTR; +short sample IDATA_ATTR; //For synthSample +unsigned int cpShifted IDATA_ATTR; + +unsigned char b1 IDATA_ATTR; +unsigned char b2 IDATA_ATTR; + + +inline int getSample(int s) { //16 bit samples @@ -186,24 +197,23 @@ inline signed short int getSample(struct GWaveform * wf, unsigned int s) { if(s<<1 >= wf->wavSize) + { + printf("\n!!!!! %d \t %d", s<<1, wf->wavSize); return 0; - - - /* - * Probably put the signed/unsigned and and 8-16 bit conversion - * into the patch loader and have it run there, once. - */ - + } +// signed short a = ((short *)wf->data)[s]; //Sign conversion moved into guspat.c - unsigned char b1=wf->data[s<<1]; //+((wf->mode & 2) << 6); - unsigned char b2=wf->data[(s<<1)|1]; //+((wf->mode & 2) << 6); + b1=wf->data[s<<1]+((wf->mode & 2) << 6); + b2=wf->data[(s<<1)|1]+((wf->mode & 2) << 6); return (b1 | (b2<<8)) ; + + //Get rid of this sometime } else { //8-bit samples //Do we even have anything 8-bit in our set? - unsigned char b1=wf->data[s]+((wf->mode & 2) << 6); + int b1=wf->data[s]+((wf->mode & 2) << 6); return b1<<8; } } @@ -251,6 +261,12 @@ inline void setPoint(struct SynthObject * so, int pt) */ so->curRate = r<<10; + //Do this here because the patches assume a 44100 sampling rate + //We've halved our sampling rate, ergo the ADSR code will be + //called half the time. Ergo, double the rate to keep stuff + //sounding right. + so->curRate = so->curRate << 1; + so->targetOffset = so->wf->envOffset[pt]<<(20); if(pt==0) @@ -258,8 +274,6 @@ inline void setPoint(struct SynthObject * so, int pt) } -long msi=0; - inline void stopVoice(struct SynthObject * so) { if(so->state == STATE_RAMPDOWN) @@ -269,51 +283,37 @@ inline void stopVoice(struct SynthObject * so) } -int rampDown = 0; -inline signed short int synthVoice(int v) +inline signed short int synthVoice() { - //Probably can combine these 2 lines into one.. - //But for now, this looks more readable -// struct GPatch * pat = patchSet[chPat[voices[v].ch]]; -// struct GWaveform * wf = pat->waveforms[pat->noteTable[voices[v].note]]; - struct SynthObject * so = &voices[v]; - struct GWaveform * wf = so->wf; + so = &voices[currentVoice]; + wf = so->wf; - signed int s; if(so->state != STATE_RAMPDOWN) { - if(so->loopDir==LOOPDIR_FORWARD) - { - so->cp += so->delta; - } - else - { - so->cp -= so->delta; - } + so->cp += so->delta; } - if( (so->cp>>9 >= (wf->wavSize)) && (so->state != STATE_RAMPDOWN)) - stopVoice(so); - - /* - //Original, working, no interpolation - s=getSample(wf, (so->cp>>10)); - */ - + cpShifted = so->cp >> 10; + if( (cpShifted >= (wf->wavSize>>1)) && (so->state != STATE_RAMPDOWN)) + stopVoice(so); - int s2=getSample(wf, (so->cp>>10)+1); + s2 = getSample((cpShifted)+1); - if((wf->mode & (LOOP_REVERSE|LOOP_PINGPONG)) && so->loopState == STATE_LOOPING && (so->cp>>10 <= (wf->startLoop>>1))) + if((wf->mode & (LOOP_REVERSE|LOOP_PINGPONG)) && so->loopState == STATE_LOOPING && (cpShifted <= (wf->startLoop>>1))) { if(wf->mode & LOOP_REVERSE) { so->cp = (wf->endLoop)<<9; - s2=getSample(wf, (so->cp>>10)); + cpShifted = so->cp >> 10; + s2=getSample((cpShifted)); } else + { + so->delta = -so->delta; so->loopDir = LOOPDIR_FORWARD; + } } if((wf->mode & 28) && (so->cp>>10 >= wf->endLoop>>1)) @@ -322,14 +322,21 @@ inline signed short int synthVoice(int v) if((wf->mode & (24)) == 0) { so->cp = (wf->startLoop)<<9; - s2=getSample(wf, (so->cp>>10)); + cpShifted = so->cp >> 10; + s2=getSample((cpShifted)); } else + { + so->delta = -so->delta; so->loopDir = LOOPDIR_REVERSE; + } } //Better, working, linear interpolation - int s1=getSample(wf, (so->cp>>10)); - s = s1 + ((long)((s2 - s1) * (so->cp & 1023))>>10); + s1=getSample((cpShifted)); + s = s1 + ((signed)((s2 - s1) * (so->cp & 1023))>>10); + + +//ADSR COMMENT WOULD GO FROM HERE......... if(so->curRate == 0) stopVoice(so); @@ -366,8 +373,9 @@ inline signed short int synthVoice(int v) so->isUsed=0; //This is OK - s = s * (so->curOffset >> 22); - s = s>>6; + s = (s * (so->curOffset >> 22) >> 6); + +// ............. TO HERE if(so->state == STATE_RAMPDOWN) @@ -377,64 +385,28 @@ inline signed short int synthVoice(int v) so->isUsed=0; } - s = s * so->decay; s = s >> 9; + s = s * so->decay; s = s >> 10; return s*((signed short int)so->vol*(signed short int)chVol[so->ch])>>14; } - -int mhL[16]; -int mhR[16]; -int mp=0; //Mix position, for circular array -// Was stuff for Ghetto Lowpass Filter, now deprecated. - - inline void synthSample(int * mixL, int * mixR) { - int a=0; - signed long int leftMix=0, rightMix=0, sample=0; - for(a=0; a>7; - rightMix += (sample*chPanRight[voices[a].ch])>>7; + sample = synthVoice(currentVoice); + *mixL += (sample*chPanLeft[voices[currentVoice].ch])>>7; + *mixR += (sample*chPanRight[voices[currentVoice].ch])>>7; } } //TODO: Automatic Gain Control, anyone? //Or, should this be implemented on the DSP's output volume instead? - *mixL = leftMix; - *mixR = rightMix; - return; //No more ghetto lowpass filter.. linear intrpolation works well. - - - // HACK HACK HACK - // This is the infamous Ghetto Lowpass Filter - // Now that I have linear interpolation, it should not be needed anymore. - /* - mp++; - if(mp==4) - mp=0; - - mhL[mp]=leftMix; - mhR[mp]=rightMix; - - *mixL = 0; - *mixR = 0; - - - for(a=0; a<4; a++) - { - *mixL += mhL[a]; - *mixR += mhR[a]; - } - *mixL = *mixL>>4; - *mixR = *mixR>>4; - */ - // END HACK END HACK END HACK } diff --git a/apps/plugins/midi2wav.c b/apps/plugins/midi2wav.c index 3cf2866a12..6dc7a626b5 100644 --- a/apps/plugins/midi2wav.c +++ b/apps/plugins/midi2wav.c @@ -16,7 +16,7 @@ * ****************************************************************************/ -#define SAMPLE_RATE 48000 +#define SAMPLE_RATE 22050 #define MAX_VOICES 100 @@ -37,6 +37,12 @@ #include "../../plugin.h" + +#include "lib/xxx2wav.h" + +int numberOfSamples IDATA_ATTR; +long bpm; + #include "midi/midiutil.c" #include "midi/guspat.h" #include "midi/guspat.c" @@ -46,7 +52,6 @@ -#include "lib/xxx2wav.h" int fd=-1; //File descriptor where the output is written @@ -58,6 +63,7 @@ struct plugin_api * rb; + enum plugin_status plugin_start(struct plugin_api* api, void* parameter) { TEST_PLUGIN_API(api); @@ -80,6 +86,14 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) return PLUGIN_OK; } +signed char outputBuffer[3000] IDATA_ATTR; //signed char.. gonna run out of iram ... ! + + +int currentSample IDATA_ATTR; +int outputBufferPosition IDATA_ATTR; +int outputSampleOne IDATA_ATTR; +int outputSampleTwo IDATA_ATTR; + int midimain(void * filename) { @@ -89,9 +103,6 @@ int midimain(void * filename) rb->splash(HZ/5, true, "LOADING MIDI"); struct MIDIfile * mf = loadFile(filename); - long bpm, nsmp, l; - - int bp=0; rb->splash(HZ/5, true, "LOADING PATCHES"); if (initSynth(mf, "/.rockbox/patchset/patchset.cfg", "/.rockbox/patchset/drums.cfg") == -1) @@ -125,7 +136,7 @@ int midimain(void * filename) samp=arg; #else file_info_struct file_info; - file_info.samplerate = 48000; + file_info.samplerate = SAMPLE_RATE; file_info.infile = fd; file_info.channels = 2; file_info.bitspersample = 16; @@ -134,12 +145,11 @@ int midimain(void * filename) #endif - rb->splash(HZ/5, true, " START PLAYING "); + rb->splash(HZ/5, true, " Starting Playback "); - signed char buf[3000]; // tick() will do one MIDI clock tick. Then, there's a loop here that // will generate the right number of samples per MIDI tick. The whole @@ -152,49 +162,56 @@ int midimain(void * filename) printf("\nOkay, starting sequencing"); + + currentSample=0; //Sample counting variable + outputBufferPosition = 0; + + + bpm=mf->div*1000000/tempo; + numberOfSamples=SAMPLE_RATE/bpm; + + + //Tick() will return 0 if there are no more events left to play while(tick(mf)) { //Some annoying math to compute the number of samples //to syntehsize per each MIDI tick. - bpm=mf->div*1000000/tempo; - nsmp=SAMPLE_RATE/bpm; //Yes we need to do this math each time because the tempo //could have changed. // On second thought, this can be moved to the event that //recalculates the tempo, to save a little bit of CPU time. - for(l=0; l>8; //High byte second - bp++; + outputBuffer[outputBufferPosition]=outputSampleOne&0XFF; // Low byte first + outputBufferPosition++; + outputBuffer[outputBufferPosition]=outputSampleOne>>8; //High byte second + outputBufferPosition++; - buf[bp]=s2&0XFF; // Low byte first - bp++; - buf[bp]=s2>>8; //High byte second - bp++; + outputBuffer[outputBufferPosition]=outputSampleTwo&0XFF; // Low byte first + outputBufferPosition++; + outputBuffer[outputBufferPosition]=outputSampleTwo>>8; //High byte second + outputBufferPosition++; //As soon as we produce 2000 bytes of sound, //write it to the sound card. Why 2000? I have //no idea. It's 1 AM and I am dead tired. - if(bp>=2000) + if(outputBufferPosition>=2000) { - rb->write(fd, buf, 2000); - bp=0; + rb->write(fd, outputBuffer, 2000); + outputBufferPosition=0; } } } -- cgit v1.2.3