Some shifting optimizations. Working code. 50% realtime.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6323 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/plugins/midi/guspat.c b/apps/plugins/midi/guspat.c
index f674b64..2172072 100644
--- a/apps/plugins/midi/guspat.c
+++ b/apps/plugins/midi/guspat.c
@@ -66,18 +66,64 @@
 	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; a<wav->wavSize; 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; a<wav->wavSize/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; a<wav->wavSize; 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 75bdb2c..6e41a85 100644
--- a/apps/plugins/midi/guspat.h
+++ b/apps/plugins/midi/guspat.h
@@ -36,6 +36,7 @@
 	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 41a02ae..bf25d1d 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 @@
 	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 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 @@
 	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);
+	ret = offset + 4;
+	*((unsigned int *)offset) = size;
 
-	if (len < size)
-	{
-		rb->memcpy(ret, offset, len);
-	}
-	else
-	{
-		rb->memcpy(ret, offset, size);
-		rb->memset(ret, 0, len - size);
-	}
-
+	offset += size + 4;
+	totalSize -= size + 4;
 	return ret;
-}
-*/
-
+}*/
 void * allocate(int size)
 {
 	return alloc(size);
@@ -222,44 +240,6 @@
 
 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 f7c6f30..836866a 100644
--- a/apps/plugins/midi/sequencer.c
+++ b/apps/plugins/midi/sequencer.c
@@ -88,9 +88,30 @@
 
 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; a<MAX_VOICES; a++)
 	{
+		if(voices[a].ch == ch && voices[a].note == note)
+			break;
+
 		if(voices[a].isUsed==0)
 			break;
 	}
@@ -107,7 +128,7 @@
 	voices[a].vol=vol;
 	voices[a].cp=0;
 	voices[a].state=STATE_ATTACK;
-	voices[a].pstate=STATE_ATTACK;
+//	voices[a].pstate=STATE_ATTACK;
 	voices[a].decay=255;
 
 
@@ -170,15 +191,12 @@
 	{
 		if(voices[a].ch == ch && voices[a].note == note)
 		{
-			//voices[a].isUsed=0;
 			if((voices[a].wf->mode & 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 @@
 					{
 						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 99864e5..bafaf1c 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 @@
 
 
 
-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 @@
 	{
 
 		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 @@
 	*/
 	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 @@
 }
 
 
-long msi=0;
-
 inline void stopVoice(struct SynthObject * so)
 {
 	if(so->state == STATE_RAMPDOWN)
@@ -269,51 +283,37 @@
 
 }
 
-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))
+	cpShifted = so->cp >> 10;
+
+	if( (cpShifted >= (wf->wavSize>>1)) && (so->state != STATE_RAMPDOWN))
 		stopVoice(so);
 
-        /*
-	//Original, working, no interpolation
-		s=getSample(wf, (so->cp>>10));
-        */
+        s2 = getSample((cpShifted)+1);
 
-
-
-        int s2=getSample(wf, (so->cp>>10)+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 @@
 		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 @@
 		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 @@
 			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<MAX_VOICES; a++)
+//	signed int leftMix=0, rightMix=0,
+	*mixL = 0;
+	*mixR = 0;
+	for(currentVoice=0; currentVoice<MAX_VOICES; currentVoice++)
 	{
-		if(voices[a].isUsed==1)
+		if(voices[currentVoice].isUsed==1)
 		{
-			sample = synthVoice(a);
-
-			leftMix += (sample*chPanLeft[voices[a].ch])>>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 3cf2866..6dc7a62 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 @@
 
 
 
+
 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
 {
 	TEST_PLUGIN_API(api);
@@ -80,6 +86,14 @@
     	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 @@
 	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 @@
         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 @@
 #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 @@
 
 	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<nsmp; l++)
+		for(currentSample=0; currentSample<numberOfSamples; currentSample++)
 		{
-			int s1, s2;
 
-			synthSample(&s1, &s2);
+			synthSample(&outputSampleOne, &outputSampleTwo);
 
 
 			//16-bit audio because, well, it's better
 			// But really because ALSA's OSS emulation sounds extremely
 			//noisy and distorted when in 8-bit mode. I still do not know
 			//why this happens.
-			buf[bp]=s1&0XFF; // Low byte first
-			bp++;
-			buf[bp]=s1>>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;
 			}
 		}
 	}