[Scummvm-cvs-logs] CVS: scummvm/backends/midi/mt32 partial.cpp,1.9,1.10 partial.h,1.5,1.6 synth.cpp,1.21,1.22 tables.cpp,1.2,1.3 tables.h,1.2,1.3

Jerome Fisher kingguppy at users.sourceforge.net
Sun Nov 14 00:06:01 CET 2004


Update of /cvsroot/scummvm/scummvm/backends/midi/mt32
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24882

Modified Files:
	partial.cpp partial.h synth.cpp tables.cpp tables.h 
Log Message:
- Huge cleanup of LUT stuff.
- No longer stores a sawtooth waveform twice, once with each sample negated.
- More graceful handling of truncated waveformcache files.
- Fixed tuning of patterns for non-32KHz sample rates (needs checking).
- Note: Waveform cache format changed, will automatically be rebuilt.


Index: partial.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/partial.cpp,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- partial.cpp	14 Nov 2004 04:40:12 -0000	1.9
+++ partial.cpp	14 Nov 2004 08:04:55 -0000	1.10
@@ -128,6 +128,12 @@
 
 	play = true;
 	initKeyFollow(poly->freqnum); // Initialises noteVal, filtVal and realVal
+	noteLookup = &noteLookups[noteVal];
+
+	// FIXME:KG: I think most places should refer to noteVal/noteLookup instead of these.
+	keyVal = poly->freqnum;
+	keyLookup = &noteLookups[poly->freqnum];
+
 	lfoPos = 0;
 	pulsewidth = patchCache->pulsewidth + pwveltable[patchCache->pwsens][poly->vel];
 	if (pulsewidth > 100) {
@@ -243,7 +249,7 @@
 			pcmWave = &synth->PCMList[patchCache->pcm];
 
 			if (pcmWave->aggSound == -1) {
-				delta = wavtabler[pcmWave->pcmnum][noteVal];
+				delta = noteLookup->wavTable[pcmWave->pcmnum];
 				pcmAddr = pcmWave->addr;
 				len = pcmWave->len;
 				if (partialOff.pcmplace >= len) {
@@ -258,7 +264,7 @@
 				}
 			} else {
 				int tmppcm = LoopPatterns[pcmWave->aggSound][loopPos];
-				delta = looptabler[pcmWave->aggSound][loopPos][noteVal];
+				delta = noteLookup->loopTable[pcmWave->aggSound][loopPos];
 				pcmAddr = synth->PCM[tmppcm].addr;
 				len = synth->PCM[tmppcm].len;
 				if (partialOff.pcmplace >= len) {
@@ -271,7 +277,7 @@
 		} else {
 			// Synthesis partial
 			delta = 0x10707;
-			partialOff.pcmplace %= (Bit16u)(divtable[noteVal] >> 15);
+			partialOff.pcmplace %= (Bit16u)(noteLookup->div << 1);
 		}
 
 		// Build delta for position of next sample
@@ -291,10 +297,6 @@
 				if (delta < 0x10000) {
 					// Linear sound interpolation
 					taddr = pcmAddr + partialOff.pcmplace;
-					if (taddr >= ROMSIZE) {
-						synth->printDebug("Overflow ROMSIZE!");
-						taddr = ROMSIZE - 1;
-					}
 					ra = synth->romfile[taddr];
 					//FIXME:KG: Deal with condition that taddr + 1 is past PCM length
 					rb = synth->romfile[taddr + 1];
@@ -313,7 +315,7 @@
 				}
 			} else {
 				// Render synthesised sample
-				int divis = divtable[noteVal] >> 15;
+				int div = noteLookup->div;
 				int wf = patchCache->waveform;
 				int toff = partialOff.pcmplace;
 				int minorplace = partialOff.pcmoffset >> 14;
@@ -327,25 +329,21 @@
 					// sawtooth waveforms
 					// Pulse width is not yet correct
 					int pa, pb;
-					int hdivis = divis >> 1;
-					int divmark = smalldivtable[noteVal];
+					int divmark = div << 8;
 
-					if (hdivis == 0) {
-						synth->printDebug("ERROR: hdivis=0 generating square wave, this should never happen!");
-						hdivis = 1;
+					if (div == 0) {
+						synth->printDebug("ERROR: div=0 generating square wave, this should never happen!");
+						div = 1;
 					}
-					int ofs = toff % hdivis;
-
-					int ofs3 = toff + ((divmark * pulsetable[pulsewidth]) >> 16);
-					ofs3 = ofs3 % (hdivis);
-
-					pa = waveforms[1][noteVal][(ofs << 2)+minorplace];
-					pb = waveforms[0][noteVal][(ofs3 << 2)+minorplace];
-					ptemp = (pa + pb) * 4;
-
+					int ofsA = toff % div;
+					int ofsB = toff + ((divmark * pulsetable[pulsewidth]) >> 16);
+					ofsB = ofsB % div;
+					pa = noteLookup->waveforms[0][(ofsA << 2) + minorplace];
+					pb = noteLookup->waveforms[0][(ofsB << 2) + minorplace];
+					ptemp = (pa - pb) * 4;
 					// Non-bandlimited squarewave
 					/*
-					ofs = (divis*pulsetable[patchCache->pulsewidth])>>8;
+					ofs = ((div << 1) * pulsetable[patchCache->pulsewidth]) >> 8;
 					if (toff < ofs)
 						ptemp = 1 * WGAMP;
 					else
@@ -356,27 +354,26 @@
 					// to how it looks on the MT-32.  What it really does it takes the
 					// square wave and multiplies it by a full cosine
 					int waveoff = (toff << 2) + minorplace;
-					if (toff < sawtable[noteVal][pulsewidth])
-						ptemp = waveforms[2][noteVal][waveoff % waveformsize[2][noteVal]];
+					if (toff < noteLookup->sawTable[pulsewidth])
+						ptemp = noteLookup->waveforms[1][waveoff % noteLookup->waveformSize[1]];
 					else
-						ptemp = waveforms[3][noteVal][waveoff % waveformsize[3][noteVal]];
+						ptemp = noteLookup->waveforms[2][waveoff % noteLookup->waveformSize[2]];
 					ptemp = ptemp * 4;
 					// This is the correct way
 					// Seems slow to me (though bandlimited) -- doesn't seem to
 					// sound any better though
 					/*
-					hdivis = divis >> 1;
-					int divmark = smalldivtable[noteVal];
+					int divmark = noteLookup->div << 8;
 					//int pw = (patchCache->pulsewidth * pulsemod[filtval]) >> 8;
 
-					ofs = toff % (hdivis);
+					int ofs = toff % div;
 
-					ofs3 = toff + ((divmark*pulsetable[patchCache->pulsewidth])>>16);
-					ofs3 = ofs3 % (hdivis);
+					int ofs3 = toff + ((divmark * pulsetable[patchCache->pulsewidth]) >> 16);
+					ofs3 = ofs3 % div;
 
-					pa = waveforms[0][noteVal][ofs];
-					pb = waveforms[1][noteVal][ofs3];
-					ptemp = ((pa+pb) * waveforms[3][noteVal][toff]) / WGAMP;
+					pa = noteLookup->waveforms[0][ofs];
+					pb = noteLookup->waveforms[0][ofs3];
+					ptemp = ((pa - pb) * noteLookup->waveforms[2][toff]) / WGAMP;
 					ptemp = ptemp *4;
 					*/
 				}
@@ -632,8 +629,6 @@
 	keyfollow = filtVal;
 	realfollow = realVal;
 
-	int fr = poly->freqnum;
-
 	if (tStat->decaying) {
 		reshigh = tStat->envbase;
 		reshigh = (reshigh + ((tStat->envdist * tStat->envpos) / tStat->envsize));
@@ -653,10 +648,11 @@
 					tStat->envbase = patchCache->filtEnv.envlevel[tStat->envstat];
 				tStat->envstat++;
 				tStat->envpos = 0;
-				if (tStat->envstat == 3)
+				if (tStat->envstat == 3) {
 					tStat->envsize = lasttimetable[(int)patchCache->filtEnv.envtime[tStat->envstat]];
-				else
-					tStat->envsize = (envtimetable[(int)patchCache->filtEnv.envtime[tStat->envstat]] * timekeytable[(int)patchCache->filtEnv.envtkf][poly->freqnum]) >> 8;
+				} else {
+					tStat->envsize = (envtimetable[(int)patchCache->filtEnv.envtime[tStat->envstat]] * keyLookup->timekeyTable[(int)patchCache->filtEnv.envtkf]) >> 8;
+				}
 
 				tStat->envsize++;
 				tStat->envdist = patchCache->filtEnv.envlevel[tStat->envstat] - tStat->envbase;
@@ -684,14 +680,14 @@
 	if (bias!=0) {
 		//synth->printDebug("Cutoff before %d", cutoff);
 		if (patchCache->tvfdir == 0) {
-			if (fr < bias) {
-				dist = bias - fr;
+			if (keyVal < bias) {
+				dist = bias - keyVal;
 				cutoff = (cutoff * fbiastable[patchCache->tvfblevel][dist]) >> 8;
 			}
 		} else {
 			// > Bias
-			if (fr > bias) {
-				dist = fr - bias;
+			if (keyVal > bias) {
+				dist = keyVal - bias;
 				cutoff = (cutoff * fbiastable[patchCache->tvfblevel][dist]) >> 8;
 			}
 
@@ -699,7 +695,7 @@
 		//synth->printDebug("Cutoff after %d", cutoff);
 	}
 
-	depth = (depth * fildeptable[patchCache->tvfdepth][fr]) >> 8;
+	depth = (depth * keyLookup->fildepTable[patchCache->tvfdepth]) >> 8;
 	reshigh = (reshigh * depth) >> 7;
 
 	Bit32s tmp;
@@ -718,7 +714,7 @@
 		reshigh = 100;
 	else if (reshigh<0)
 		reshigh = 0;
-	tmp = nfilttable[fr][cutoff][reshigh];
+	tmp = keyLookup->nfiltTable[cutoff][reshigh];
 	//tmp *= keyfollow;
 	//tmp /= realfollow;
 
@@ -784,7 +780,7 @@
 			default:
 				//Spot for timekey follow
 				//Only used in subsquent envelope parameters, including the decay
-				tStat->envsize = (envtimetable[(int)patchCache->ampEnv.envtime[tStat->envstat]] * timekeytable[(int)patchCache->ampEnv.envtkf][poly->freqnum]) >> 8;
+				tStat->envsize = (envtimetable[(int)patchCache->ampEnv.envtime[tStat->envstat]] * keyLookup->timekeyTable[(int)patchCache->ampEnv.envtkf]) >> 8;
 
 				//synth->printDebug("Envstat %d, size %d", tStat->envstat, tStat->envsize);
 				break;
@@ -820,14 +816,14 @@
 			bias = patchCache->ampbias[i];
 			if (patchCache->ampdir[i]==0) {
 				// < Bias
-				if (poly->freqnum < bias) {
-					dist = bias-poly->freqnum;
+				if (keyVal < bias) {
+					dist = bias - keyVal;
 					tc = (tc * ampbiastable[patchCache->ampblevel[i]][dist]) >> 8;
 				}
 			} else {
 				// > Bias
-				if (poly->freqnum > bias) {
-					dist = poly->freqnum-bias;
+				if (keyVal > bias) {
+					dist = keyVal - bias;
 					tc = (tc * ampbiastable[patchCache->ampblevel[i]][dist]) >> 8;
 				}
 			}
@@ -860,11 +856,11 @@
 				tStat->envstat++;
 
 				tStat->envbase = patchCache->pitchEnv.level[tStat->envstat];
-				tStat->envsize = (envtimetable[(int)patchCache->pitchEnv.time[tStat->envstat]] * timekeytable[(int)patchCache->pitchEnv.timekeyfollow][poly->freqnum]) >> 8;
+				tStat->envsize = (envtimetable[(int)patchCache->pitchEnv.time[tStat->envstat]] * keyLookup->timekeyTable[(int)patchCache->pitchEnv.timekeyfollow]) >> 8;
 
 				tStat->envpos = 0;
 				tStat->envsize++;
-				tStat->envdist = patchCache->pitchEnv.level[tStat->envstat+1] - tStat->envbase;
+				tStat->envdist = patchCache->pitchEnv.level[tStat->envstat + 1] - tStat->envbase;
 			}
 			tc = tStat->envbase;
 			tc = (tc + ((tStat->envdist * tStat->envpos) / tStat->envsize));
@@ -891,15 +887,15 @@
 
 	switch(envnum) {
 	case EnvelopeType_amp:
-		tStat->envsize = (decaytimetable[(int)patchCache->ampEnv.envtime[4]] * timekeytable[(int)patchCache->ampEnv.envtkf][poly->freqnum]) >> 8;
+		tStat->envsize = (decaytimetable[(int)patchCache->ampEnv.envtime[4]] * keyLookup->timekeyTable[(int)patchCache->ampEnv.envtkf]) >> 8;
 		tStat->envdist = -startval;
 		break;
 	case EnvelopeType_filt:
-		tStat->envsize = (decaytimetable[(int)patchCache->filtEnv.envtime[4]] * timekeytable[(int)patchCache->filtEnv.envtkf][poly->freqnum]) >> 8;
+		tStat->envsize = (decaytimetable[(int)patchCache->filtEnv.envtime[4]] * keyLookup->timekeyTable[(int)patchCache->filtEnv.envtkf]) >> 8;
 		tStat->envdist = -startval;
 		break;
 	case EnvelopeType_pitch:
-		tStat->envsize = (decaytimetable[(int)patchCache->pitchEnv.time[3]] * timekeytable[(int)patchCache->pitchEnv.timekeyfollow][poly->freqnum]) >> 8 ;
+		tStat->envsize = (decaytimetable[(int)patchCache->pitchEnv.time[3]] * keyLookup->timekeyTable[(int)patchCache->pitchEnv.timekeyfollow]) >> 8 ;
 		tStat->envdist = patchCache->pitchEnv.level[4] - startval;
 		break;
 	default:

Index: partial.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/partial.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- partial.h	14 Nov 2004 04:13:14 -0000	1.5
+++ partial.h	14 Nov 2004 08:04:55 -0000	1.6
@@ -25,6 +25,7 @@
 namespace MT32Emu {
 
 class Synth;
+struct NoteLookup;
 
 enum EnvelopeType {
 	EnvelopeType_amp = 0,
@@ -63,6 +64,10 @@
 
 	// Keyfollowed note value
 	int noteVal;
+	NoteLookup *noteLookup; // Lookup stuff for this noteVal
+
+	int keyVal;
+	NoteLookup *keyLookup;
 
 	// Keyfollowed filter values
 	int realVal;

Index: synth.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/synth.cpp,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- synth.cpp	14 Nov 2004 04:13:14 -0000	1.21
+++ synth.cpp	14 Nov 2004 08:04:55 -0000	1.22
@@ -117,7 +117,7 @@
 	isOpen = false;
 	reverbModel = NULL;
 	partialManager = NULL;
-	memset(waveforms, 0, sizeof(waveforms));
+	memset(noteLookups, 0, sizeof(noteLookups));
 	memset(parts, 0, sizeof(parts));
 }
 
@@ -690,11 +690,12 @@
 	if (!isOpen)
 		return;
 
-	for (int t = 0; t < 4; t++) {
+	for (int t = 0; t < 3; t++) {
 		for (int m = 0; m < NUM_NOTES; m++) {
-			if (waveforms[t][m]!=NULL) {
-				delete[] waveforms[t][m];
-				waveforms[t][m] = NULL;
+			if (noteLookups[m].waveforms[t] != NULL) {
+				delete[] noteLookups[m].waveforms[t];
+				noteLookups[m].waveforms[t] = NULL;
+				noteLookups[m].waveformSize[t] = 0;
 			}
 		}
 	}

Index: tables.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/tables.cpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- tables.cpp	14 Nov 2004 04:13:14 -0000	1.2
+++ tables.cpp	14 Nov 2004 08:04:56 -0000	1.3
@@ -89,24 +89,7 @@
 float ResonFactor[31];
 float ResonInv[31];
 
-// Per-note initialisation tables follow
-
-Bit16s freqtable[NUM_NOTES];
-Bit32s fildeptable[5][NUM_NOTES];
-Bit32s timekeytable[5][NUM_NOTES];
-int filttable[2][NUM_NOTES][201];
-int nfilttable[NUM_NOTES][101][101];
-
-Bit32s divtable[NUM_NOTES];
-Bit32s smalldivtable[NUM_NOTES];
-Bit32u wavtabler[54][NUM_NOTES];
-Bit32u looptabler[9][10][NUM_NOTES];
-Bit32s sawtable[NUM_NOTES][101];
-
-Bit16s *waveforms[4][NUM_NOTES];
-Bit32u waveformsize[4][NUM_NOTES];
-static Bit16s tmpforms[4][65536];
-
+NoteLookup noteLookups[NUM_NOTES];
 
 // Begin filter stuff
 
@@ -236,10 +219,10 @@
 		if (pt < 0)
 			pt = 0;
 
-		pulsetable[lf] = (int)((pt) * 215.04f) + 128;
+		pulsetable[lf] = (int)(pt * 215.04f) + 128;
 
 		// I am certain of this:  Verified by hand LFO log
-		lfotable[lf] = (Bit32u)(((float)samplerate) / (pow(1.088883372f,(float)lf) * 0.021236044f));
+		lfotable[lf] = (Bit32u)(((float)samplerate) / (powf(1.088883372f,(float)lf) * 0.021236044f));
 
 		//LOG(LOG_ERROR|LOG_MISC,"lf %d = lfo %d pulsetable %d", lf, lfotable[lf], pulsetable[lf]);
 	}
@@ -320,6 +303,9 @@
 	for (lf = 0; lf <= 200; lf++) {
 		//FIXME:KG: I'm fairly sure this is wrong... lf=100 should yield no fine-tuning (4096)?
 		finetable[lf] = (int)((powf(2.0f, (((float)lf / 200.0f) - 1.0f) / 12.0f)) * 4096.0f);
+
+		// FIXME:KG: This now gives a range of -1 .. 1 semitone. Should be correct, but check
+		//finetable[lf] = (int)((powf(2.0f, (((float)lf / 100.0f) - 1.0f) / 12.0f)) * 4096.0f);
 	}
 
 	float lff;
@@ -333,9 +319,9 @@
 
 	for (lf = 0; lf < 128; lf++) {
 		// Converts MIDI velocity to volume.
-		voltable[lf] = (int)(127.0 * pow((float)lf / 127.0, DOUBLE_LN));
+		voltable[lf] = (int)(127.0f * powf((float)lf / 127.0f, FLOAT_LN));
 	}
-	for (lf = 0; lf < MAX_SAMPLE_OUTPUT; lf++) {
+	for (unsigned int i = 0; i < MAX_SAMPLE_OUTPUT; i++) {
 		int myRand;
 		myRand = rand();
 		int origRand = myRand;
@@ -343,7 +329,7 @@
 		// This one is slower but works with all values of RAND_MAX
 		myRand = (int)((origRand - RAND_MAX / 2) / (float)RAND_MAX * (WGAMP / 2));
 		//FIXME:KG: Original ultimately set the lowest two bits to 0, for no obvious reason
-		smallnoise[lf] = (Bit16s)myRand;
+		smallnoise[i] = (Bit16s)myRand;
 	}
 
 	float tdist;
@@ -469,115 +455,94 @@
 
 // Per-note table initialisation follows
 
-static void initSaw(int f, Bit32s div) {
+static void initSaw(NoteLookup *noteLookup, Bit32s div) {
 	for (int rsaw = 0; rsaw <= 100; rsaw++) {
 		float fsaw;
 		if (rsaw < 50)
 			fsaw = 50.0f;
 		else
 			fsaw = (float)rsaw;
-		int tmpdiv = div << 1;
+		int tmpdiv = div << 17;
 
 		//(66 - (((A8 - 50) / 50) ^ 0.63) * 50) / 132
 		float sawfact = (66.0f - (powf((fsaw - 50.0f) / 50.0f, 0.63f) * 50.0f)) / 132.0f;
-		sawtable[f][rsaw] = (int)(sawfact * (float)tmpdiv) >> 16;
-		//synth->printDebug("F %d divtable %d saw %d sawtable %d", f, div>>16, rsaw, sawtable[f][rsaw]);
+		noteLookup->sawTable[rsaw] = (int)(sawfact * (float)tmpdiv) >> 16;
+		//synth->printDebug("F %d divtable %d saw %d sawtable %d", f, div, rsaw, sawtable[f][rsaw]);
 	}
 }
 
-static void initDep(int f) {
+static void initDep(NoteLookup *noteLookup, float f) {
 	for (int dep = 0; dep < 5; dep++) {
 		if (dep == 0) {
-			fildeptable[dep][f] = 256;
-			timekeytable[dep][f] = 256;
+			noteLookup->fildepTable[dep] = 256;
+			noteLookup->timekeyTable[dep] = 256;
 		} else {
 			float depfac = 3000.0f;
 			float ff, tempdep;
 			depfac = (float)depexp[dep];
 
-			ff = ((float)f - (float)MIDDLEC) / depfac;
+			ff = (f - (float)MIDDLEC) / depfac;
 			tempdep = powf(2, ff) * 256.0f;
-			fildeptable[dep][f] = (int)tempdep;
+			noteLookup->fildepTable[dep] = (int)tempdep;
 
-			ff = (float)(exp(tkcatconst[dep] * ((float)MIDDLEC-(float)f)) * tkcatmult[dep]);
-			timekeytable[dep][f] = (int)(ff * 256.0f);
+			ff = (float)(exp(tkcatconst[dep] * ((float)MIDDLEC - f)) * tkcatmult[dep]);
+			noteLookup->timekeyTable[dep] = (int)(ff * 256.0f);
 		}
 	}
-	//synth->printDebug("F %d d1 %x d2 %x d3 %x d4 %x d5 %x", f, fildeptable[0][f],fildeptable[1][f],fildeptable[2][f],fildeptable[3][f],fildeptable[4][f]);
+	//synth->printDebug("F %f d1 %x d2 %x d3 %x d4 %x d5 %x", f, noteLookup->fildepTable[0], noteLookup->fildepTable[1], noteLookup->fildepTable[2], noteLookup->fildepTable[3], noteLookup->fildepTable[4]);
 }
 
-void TableInitialiser::initWave(Synth *synth, File *file, bool reading, bool writing, int f, float freq, float rate, double ampsize, Bit32s div) {
-	double sd = (2.0 * DOUBLE_PI) / ((((float)div / 65536.0)) * 4.0);
-	waveformsize[0][f] = div >> 14;
-	waveformsize[1][f] = div >> 14;
-	waveformsize[2][f] = div >> 14;
-	waveformsize[3][f] = div >> 13;
-	for (int i = 0; i < 4; i++)
-		waveforms[i][f] = new Bit16s[waveformsize[i][f]];
-	if (reading) {
-		for (int i = 0; i < 4; i++) {
-			size_t len = waveformsize[i][f] * sizeof(Bit16s);
-			if (file->read(waveforms[i][f], len) != len) {
-				synth->printDebug("Error reading wave file cache!");
-				break;
+File *TableInitialiser::initWave(Synth *synth, NoteLookup *noteLookup, float ampsize, float div, File *file) {
+	int iDiv = (int)div;
+	noteLookup->waveformSize[0] = iDiv << 2;
+	noteLookup->waveformSize[1] = iDiv << 2;
+	noteLookup->waveformSize[2] = iDiv << 3;
+	for (int i = 0; i < 3; i++) {
+		if (noteLookup->waveforms[i] == NULL) {
+			noteLookup->waveforms[i] = new Bit16s[noteLookup->waveformSize[i]];
+		}
+	}
+	if (file != NULL) {
+		for (int i = 0; i < 3 && file != NULL; i++) {
+			size_t len = noteLookup->waveformSize[i];
+			for (unsigned int j = 0; j < len; j++) {
+				if (!file->readBit16u((Bit16u *)&noteLookup->waveforms[i][j])) {
+					synth->printDebug("Error reading wave file cache!");
+					file->close();
+					file = NULL;
+					break;
+				}
 			}
 		}
-	} else {
-		float dumbfire;
-		double saw = 0.0f;
-		double sa = 0.0;
-		int fa = 0;
-		memset(tmpforms, 0,sizeof(tmpforms));
-
-		while (sa <= (2.0 * DOUBLE_PI)) {
-			float sqp;
+	}
+	if (file == NULL) {
+		double sd = DOUBLE_PI / (div * 2.0);
 
-			if (sa < DOUBLE_PI) {
-				sqp = -1;
-				sqp = (float)(sqp + (0.25 * (sa/DOUBLE_PI)));
-			} else {
-				sqp=1;
-				sqp = (float)(sqp - (0.25 * ((sa - DOUBLE_PI)/DOUBLE_PI)));
-			}
+		for (int fa = 0; fa < (iDiv << 2); fa++) {
+			double sa = fa * sd;
 
-			saw = 0;
-			for (int sinus = 1; sinus * freq < rate; sinus++) {
+#if 0
+			//FIXME:KG: Credit Timo Strunk (bastardo on #scummvm) for help with this!
+			float saw = 0.5f * FLOAT_PI - sa / 2;
+#else
+			double saw = 0.0;
+			for (int sinus = 1; sinus < div; sinus++) {
 				double fsinus = (double)sinus;
-				saw += (1 / fsinus) * sin(fsinus * sa);
+				saw += sin(fsinus * sa) / fsinus;
 			}
+#endif
 
-			dumbfire = (float)(sa / 2);
-
-			//This works pretty good
-			tmpforms[0][fa] = (Bit16s)(saw * -ampsize / 2);
-			tmpforms[1][fa] = (Bit16s)(saw * ampsize / 2);
-
-			tmpforms[2][fa] = (Bit16s)(cos(dumbfire) * -ampsize);
-			tmpforms[3][fa * 2] = (Bit16s)(cos(sa - DOUBLE_PI) * -ampsize);
-			tmpforms[3][fa * 2 + 1] = (Bit16s)(cos((sa + (sd / 2)) - DOUBLE_PI) * -ampsize);
-
-			fa++;
-			sa += sd;
-		}
-
-		//synth->printDebug("f num %d freq %f and fa %d, div>>13=%d", f, freq, fa, div>>13);
-
-		for (int i = 0; i < 4; i++)
-			memcpy(waveforms[i][f], tmpforms[i], waveformsize[i][f] * sizeof (Bit16s));
-
-		if (writing) {
-			for (int i = 0; i < 4; i++) {
-				int len = waveformsize[i][f] * sizeof(Bit16s);
-				if (!file->write(waveforms[i][f], len)) {
-					synth->printDebug("Error writing waveform cache file");
-					break;
-				}
-			}
+			// This works pretty well
+			noteLookup->waveforms[0][fa] = (Bit16s)(saw * -ampsize / 2);
+			noteLookup->waveforms[1][fa] = (Bit16s)(cos(sa / 2.0) * -ampsize);
+			noteLookup->waveforms[2][fa * 2] = (Bit16s)(cos(sa - DOUBLE_PI) * -ampsize);
+			noteLookup->waveforms[2][fa * 2 + 1] = (Bit16s)(cos((sa + (sd / 2)) - DOUBLE_PI) * -ampsize);
 		}
 	}
+	return file;
 }
 
-static void initFiltTable(int f, float freq, float rate) {
+static void initFiltTable(NoteLookup *noteLookup, float freq, float rate) {
 	for (int tr = 0; tr <= 200; tr++) {
 		float ftr = (float)tr;
 
@@ -587,18 +552,18 @@
 
 		// I think this is the one
 		float brsq = powf(10.0f, (tr / 50.0f) - 1.0f);
-		filttable[0][f][tr] = (int)((freq * brsq) / (rate / 2) * FILTERGRAN);
-		if (filttable[0][f][tr]>=((FILTERGRAN*15)/16))
-			filttable[0][f][tr] = ((FILTERGRAN*15)/16);
+		noteLookup->filtTable[0][tr] = (int)((freq * brsq) / (rate / 2) * FILTERGRAN);
+		if (noteLookup->filtTable[0][tr]>=((FILTERGRAN*15)/16))
+			noteLookup->filtTable[0][tr] = ((FILTERGRAN*15)/16);
 
 		float brsa = powf(10.0f, ((tr / 55.0f) - 1.0f)) / 2.0f;
-		filttable[1][f][tr] = (int)((freq * brsa) / (rate / 2) * FILTERGRAN);
-		if (filttable[1][f][tr]>=((FILTERGRAN*15)/16))
-			filttable[1][f][tr] = ((FILTERGRAN*15)/16);
+		noteLookup->filtTable[1][tr] = (int)((freq * brsa) / (rate / 2) * FILTERGRAN);
+		if (noteLookup->filtTable[1][tr]>=((FILTERGRAN*15)/16))
+			noteLookup->filtTable[1][tr] = ((FILTERGRAN*15)/16);
 	}
 }
 
-static void initNFiltTable(int f, float freq, float rate) {
+static void initNFiltTable(NoteLookup *noteLookup, float freq, float rate) {
 	for (int cf = 0; cf <= 100; cf++) {
 		float cfmult = (float)cf;
 
@@ -609,53 +574,127 @@
 
 			float freqsum = expf((cfmult + tfadd) / 30.0f) / 4.0f;
 
-			nfilttable[f][cf][tf] = (int)((freq * freqsum) / (rate / 2)*FILTERGRAN);
-			if (nfilttable[f][cf][tf] >= ((FILTERGRAN * 15) / 16))
-				nfilttable[f][cf][tf] = ((FILTERGRAN * 15) / 16);
+			noteLookup->nfiltTable[cf][tf] = (int)((freq * freqsum) / (rate / 2) * FILTERGRAN);
+			if (noteLookup->nfiltTable[cf][tf] >= ((FILTERGRAN * 15) / 16))
+				noteLookup->nfiltTable[cf][tf] = ((FILTERGRAN * 15) / 16);
 		}
 	}
 }
 
-void TableInitialiser::initNotes(Synth *synth, PCMWave pcms[54], float rate) {
-	char filename[32];
+File *TableInitialiser::initNote(Synth *synth, NoteLookup *noteLookup, float note, float rate, float tuning, PCMWave pcmWaves[54], File *file) {
+	float ampsize = WGAMP;
+	float freq = (float)(tuning * pow(2.0, ((double)note - MIDDLEA) / 12.0));
+	float div = rate / freq;
+	noteLookup->div = (int)div;
+
+	initSaw(noteLookup, noteLookup->div);
+	initDep(noteLookup, note);
+
+	//synth->printDebug("Note %f; freq=%f, div=%f", note, freq, rate / freq);
+	file = initWave(synth, noteLookup, ampsize, div, file);
+
+	// Create the pitch tables
+
+	float rateMult = 32000.0f / rate;
+	float tuner = rateMult * freq * 65536.0f;
+	for (int pc = 0; pc < 54; pc++) {
+		noteLookup->wavTable[pc] = (int)(tuner / pcmWaves[pc].tune);
+	}
+	for (int lp = 0; lp < 9; lp++) {
+		for (int ln = 0; ln < 10; ln++) {
+			// FIXME:KG: Surely this needs to be adjusted for the rate?
+			// If not, remove rateMult * from below
+			// (Note: I'm assuming the LoopPatternTuning constants were intended for 32k rate)
+			noteLookup->loopTable[lp][ln] = (int)(rateMult * (float)LoopPatternTuning[lp][ln] * (freq / 220.0f));
+		}
+	}
+
+	initFiltTable(noteLookup, freq, rate);
+	initNFiltTable(noteLookup, freq, rate);
+	return file;
+}
+
+void TableInitialiser::initNotes(Synth *synth, PCMWave pcmWaves[54], float rate, float tuning) {
+	char filename[64];
 	int intRate = (int)rate;
-	sprintf(filename, "waveformcache-%d.raw", intRate);
+	char version[4] = {0, 0, 0, 1};
+	sprintf(filename, "waveformcache-%d-%.1f.raw", intRate, tuning);
 
 	File *file = NULL;
-	bool reading = false, writing = false;
-	char header[16];
+	char header[20];
 	strncpy(header, "MT32WAVE", 8);
 	int pos = 8;
 	// Version...
 	for (int i = 0; i < 4; i++)
-		header[pos++] = 0;
-	header[pos++] = (char)(intRate & 0xFF);
-	header[pos++] = (char)((intRate >> 8) & 0xFF);
+		header[pos++] = version[i];
+	header[pos++] = (char)((intRate >> 24) & 0xFF);
 	header[pos++] = (char)((intRate >> 16) & 0xFF);
-	header[pos] = (char)((intRate >> 24) & 0xFF);
+	header[pos++] = (char)((intRate >> 8) & 0xFF);
+	header[pos++] = (char)(intRate & 0xFF);
+	int intTuning = (int)tuning;
+	header[pos++] = (char)((intTuning >> 8) & 0xFF);
+	header[pos++] = (char)(intTuning & 0xFF);
+	header[pos++] = 0;
+	header[pos] = (char)((tuning - intTuning) * 10);
 #if MT32EMU_WAVECACHEMODE < 2
+	bool reading = false;
 	file = synth->openFile(filename, File::OpenMode_read);
 	if (file != NULL) {
 		char fileHeader[16];
 		if (file->read(fileHeader, 16) == 16) {
 			if (memcmp(fileHeader, header, 16) == 0) {
-				reading = true;
+				Bit16u endianCheck;
+				if (file->readBit16u(&endianCheck)) {
+					if (endianCheck == 1) {
+						reading = true;
+					} else {
+						synth->printDebug("Endian check in %s does not match expected - will generate", filename);
+					}
+				} else {
+					synth->printDebug("Unable to read endian check in %s - will generate", filename);
+				}
 			} else {
 				synth->printDebug("Header of %s does not match expected - will generate", filename);
 			}
 		} else {
 			synth->printDebug("Error reading 16 bytes of %s - will generate", filename);
 		}
+		if (!reading) {
+			file->close();
+			file = NULL;
+		}
 	} else {
 		synth->printDebug("Unable to open %s for reading - will generate", filename);
 	}
 #endif
+
+	//FIXME:KG: may only need to do 12 to 108
+	//12..108 is the range allowed by note on commands, but the key can be modified by pitch keyfollow
+	//and adjustment for timbre pitch, so the results can be outside that range. Do move it (by octave) into
+	// the 12..108 range, or keep it in 0..127 range, or something else altogether?
+	for (int f = 12; f < 109; f++) {
+		NoteLookup *noteLookup = &noteLookups[f];
+		file = initNote(synth, noteLookup, (float)f, rate, tuning, pcmWaves, file);
+	}
+
 #if MT32EMU_WAVECACHEMODE == 0 || MT32EMU_WAVECACHEMODE == 2
-	if (!reading) {
+	if (file == NULL) {
 		file = synth->openFile(filename, File::OpenMode_write);
 		if (file != NULL) {
-			if (file->write(header, 16) == 16) {
-				writing = true;
+			if (file->write(header, 16) == 16 && file->writeBit16u(1)) {
+				for (int f = 12; f < 109 && file != NULL; f++) {
+					for (int i = 0; i < 3 && file != NULL; i++) {
+						int len = noteLookups[f].waveformSize[i];
+						for (int j = 0; j < len; j++) {
+							if (!file->writeBit16u(noteLookups[f].waveforms[i][j])) {
+								synth->printDebug("Error writing waveform cache file");
+								file->close();
+								file = NULL;
+								break;
+							}
+						}
+					}
+				}
 			} else {
 				synth->printDebug("Error writing 16-byte header to %s - won't continue saving", filename);
 			}
@@ -665,35 +704,6 @@
 	}
 #endif
 
-	double ampsize = WGAMP;
-	for (int f = 12; f < 109; f++) {
-		float freq = (float)(TUNING * pow(2.0, ((double)f - 69.0) / 12.0));
-		freqtable[f] = (Bit16s)freq;
-		divtable[f] = (int)(rate / freq);
-		smalldivtable[f] = divtable[f] << 8;
-		divtable[f] = divtable[f] << 16;
-
-		initSaw(f, divtable[f]);
-		initDep(f);
-
-		//synth->printDebug("F %d sd %f div %d", f, sd, divtable[f]);
-		initWave(synth, file, reading, writing, f, freq, rate, ampsize, divtable[f]);
-
-		// Create the pitch tables
-
-		float tuner = (32000.0f / rate) * 65536.0f;
-		for (int pc = 0; pc < 54; pc++)
-			wavtabler[pc][f] = (int)(tuner * (freq / pcms[pc].tune));
-		for (int lp = 0; lp < 9; lp++) {
-			for (int ln = 0; ln < 10; ln++) {
-				// FIXME:KG: Surely this needs to be adjusted for the rate?
-				looptabler[lp][ln][f] = (int)((float)LoopPatternTuning[lp][ln] * (freq / 220.0f));
-			}
-		}
-
-		initFiltTable(f, freq, rate);
-		initNFiltTable(f, freq, rate);
-	}
 	if (file != NULL)
 		synth->closeFile(file);
 }
@@ -710,7 +720,7 @@
 		initialisedSampleRate = sampleRate;
 	}
 	// This always needs to be done, to allocate the waveforms
-	initNotes(synth, pcms, sampleRate);
+	initNotes(synth, pcms, sampleRate, TUNING);
 	return true;
 }
 

Index: tables.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/tables.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- tables.h	14 Nov 2004 04:13:15 -0000	1.2
+++ tables.h	14 Nov 2004 08:04:56 -0000	1.3
@@ -42,7 +42,7 @@
 // FIXME:KG: Keeping it at 440.0f for now, as in original. Check with CC
 const float TUNING = 440.0f;
 
-const int NUM_NOTES = 128; // MIDI supports 128 notes/keys
+const int NUM_NOTES = 128; // Number of slots for note LUT (we actually only use 12..108)
 
 // Amplitude of waveform generator
 const int WGAMP = 7168; // 8192?
@@ -55,17 +55,12 @@
 
 // Some optimization stuff
 extern Bit32s keytable[217];
-extern Bit32s divtable[NUM_NOTES];
-extern Bit32s smalldivtable[NUM_NOTES];
-extern Bit32u wavtabler[54][NUM_NOTES];
-extern Bit32u looptabler[9][10][NUM_NOTES];
 extern Bit16s sintable[65536];
 extern Bit32u lfotable[101];
 extern Bit32s penvtable[16][101];
 extern Bit32s filveltable[128][101];
 extern Bit32s veltkeytable[5][128];
 extern Bit32s pulsetable[101];
-extern Bit32s sawtable[NUM_NOTES][101];
 extern Bit32s ampbiastable[13][128];
 extern Bit32s fbiastable[15][128];
 extern float filtcoeff[FILTERGRAN][31][8];
@@ -79,23 +74,28 @@
 extern Bit32s voltable[128];
 extern float ResonInv[31];
 
-extern Bit16s freqtable[NUM_NOTES];
-extern Bit32s fildeptable[5][NUM_NOTES];
-extern Bit32s timekeytable[5][NUM_NOTES];
-extern int filttable[2][NUM_NOTES][201];
-extern int nfilttable[NUM_NOTES][101][101];
-
-extern const Bit8s LoopPatterns[9][10];
+struct NoteLookup {
+	Bit32s div;
+	Bit32u wavTable[54];
+	Bit32u loopTable[9][10];
+	Bit32s sawTable[101];
+	Bit32s fildepTable[5];
+	Bit32s timekeyTable[5];
+	int filtTable[2][201];
+	int nfiltTable[101][101];
+	Bit16s *waveforms[3];
+	Bit32u waveformSize[3];
+};
 
-extern Bit16s *waveforms[4][NUM_NOTES];
-extern Bit32u waveformsize[4][NUM_NOTES];
+extern NoteLookup noteLookups[NUM_NOTES];
 
 class TableInitialiser {
 	static void initMT32ConstantTables(Synth *synth);
-	static void initWave(Synth *synth, File *file, bool reading, bool writing, int f, float freq, float rate, double ampsize, Bit32s div);
-	static void initNotes(Synth *synth, PCMWave pcms[54], float rate);
+	static File *initWave(Synth *synth, NoteLookup *noteLookup, float ampsize, float div, File *file);
+	static void initNotes(Synth *synth, PCMWave pcms[54], float rate, float tuning);
 public:
 	static bool initMT32Tables(Synth *synth, PCMWave pcms[54], float sampleRate);
+	static File *initNote(Synth *synth, NoteLookup *noteLookup, float note, float rate, float tuning, PCMWave pcmWaves[54], File *file);
 };
 
 }





More information about the Scummvm-git-logs mailing list