[Scummvm-cvs-logs] CVS: scummvm/backends/midi/mt32 mt32_file.h,1.2,1.3 mt32emu.h,1.7,1.8 part.cpp,1.3,1.4 part.h,1.3,1.4 partial.cpp,1.10,1.11 partial.h,1.6,1.7 partialManager.cpp,1.2,1.3 partialManager.h,1.2,1.3 structures.h,1.10,1.11 synth.cpp,1.23,1.24 synth.h,1.9,1.10 tables.cpp,1.3,1.4 tables.h,1.3,1.4

Jerome Fisher kingguppy at users.sourceforge.net
Sat Nov 27 21:36:10 CET 2004


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

Modified Files:
	mt32_file.h mt32emu.h part.cpp part.h partial.cpp partial.h 
	partialManager.cpp partialManager.h structures.h synth.cpp 
	synth.h tables.cpp tables.h 
Log Message:
- Added graphical representation of initialisation progress. This is quite hacky.
- Initialisation is now interruptible.
- All data is now loaded from MT32_CONTROL.ROM. drumpat.rom, Preset1.syx, Preset2.syx and patchlog.cfg are no longer used.
- Major cleanup. In particular, separated Rhythm part into a new class, instead of dealing with it as a special case everywhere.
- Improved accuracy of pitch key-follow.
- Recaching now happens lazily.
- Changed some right-shifts to divs, due to the former not being arithmetic on some architectures.
- Setting "MT32EMU_ACCURATENOTES" to 1 will generate lookup tables for the exact frequency of every note played. Not recommended.
- Several small bugs fixed.


Index: mt32_file.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/mt32_file.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- mt32_file.h	13 Nov 2004 19:24:37 -0000	1.2
+++ mt32_file.h	28 Nov 2004 05:35:07 -0000	1.3
@@ -41,7 +41,7 @@
 	virtual bool readBit32u(Bit32u *in);
 	virtual size_t write(const void *out, size_t size) = 0;
 	virtual bool writeBit8u(Bit8u out) = 0;
-	// Note: May write some a single byte to the file before failing
+	// Note: May write a single byte to the file before failing
 	virtual bool writeBit16u(Bit16u out);
 	// Note: May write some (<4) bytes to the file before failing
 	virtual bool writeBit32u(Bit32u out);

Index: mt32emu.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/mt32emu.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- mt32emu.h	19 Nov 2004 01:39:16 -0000	1.7
+++ mt32emu.h	28 Nov 2004 05:35:07 -0000	1.8
@@ -27,10 +27,6 @@
 #define MT32EMU_MONITOR_INSTRUMENTS 1
 // Shows number of partials MT-32 is playing, and on which parts
 #define MT32EMU_MONITOR_PARTIALS 0
-// Dump drum patches to syx file for viewing
-#define MT32EMU_DUMP_DRUMS 0
-// Output benchmarks for the filter implementations
-#define MT32EMU_BENCHMARK_FILTERS 0
 // Determines how the waveform cache file is handled (must be regenerated after sampling rate change)
 #define MT32EMU_WAVECACHEMODE 0 // Load existing cache if possible, otherwise generate and save cache
 //#define MT32EMU_WAVECACHEMODE 1 // Load existing cache if possible, otherwise generage but don't save cache

Index: part.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/part.cpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- part.cpp	14 Nov 2004 04:40:12 -0000	1.3
+++ part.cpp	28 Nov 2004 05:35:07 -0000	1.4
@@ -34,16 +34,19 @@
 	0, 1, 0, 1, 1, 0,
 	1, 3, 3, 2, 2, 2, 2 };
 
-// This caches the timbres/settings in use by the rhythm part
-static PatchCache drumCache[94][4];
-static StereoVolume drumPan[64];
+static const float floatKeyfollow[17] = {
+	-1.0f, -1.0f/2.0f, -1.0f/4.0f, 0.0f,
+	1.0f/8.0f, 1.0f/4.0f, 3.0f/8.0f, 1.0f/2.0f, 5.0f/8.0f, 3.0f/4.0f, 7.0f/8.0f, 1.0f,
+	5.0f/4.0f, 3.0f/2.0f, 2.0f,
+	1.0009765625f, 1.0048828125f
+};
 
 //FIXME:KG: Put this dpoly stuff somewhere better
-bool dpoly::isActive() {
+bool dpoly::isActive() const {
 	return partials[0] != NULL || partials[1] != NULL || partials[2] != NULL || partials[3] != NULL;
 }
 
-Bit64s dpoly::getAge() {
+Bit64s dpoly::getAge() const {
 	for (int i = 0; i < 4; i++) {
 		if (partials[i] != NULL) {
 			return partials[i]->age;
@@ -52,36 +55,34 @@
 	return 0;
 }
 
-Part::Part(Synth *useSynth, int usePartNum) {
+RhythmPart::RhythmPart(Synth *useSynth, unsigned int usePartNum): Part(useSynth, usePartNum) {
+	strcpy(name, "Rhythm");
+	rhythmTemp = &synth->mt32ram.rhythmSettings[0];
+	refresh();
+}
+
+Part::Part(Synth *useSynth, unsigned int usePartNum) {
 	this->synth = useSynth;
 	this->partNum = usePartNum;
-	isRhythm = (usePartNum == 8);
+	patchCache[0].dirty = true;
 	holdpedal = false;
-	if (isRhythm) {
-		strcpy(name, "Rhythm");
+	if (usePartNum == 8) {
+		// Nasty hack for rhythm
 		patchTemp = NULL;
 		timbreTemp = NULL;
-		rhythmTemp = &synth->mt32ram.params.rhythmSettings[0];
 	} else {
 		sprintf(name, "Part %d", partNum + 1);
-		patchTemp = &synth->mt32ram.params.patchSettings[partNum];
-		timbreTemp = &synth->mt32ram.params.timbreSettings[partNum];
-		rhythmTemp = NULL;
+		patchTemp = &synth->mt32ram.patchSettings[partNum];
+		timbreTemp = &synth->mt32ram.timbreSettings[partNum];
 	}
 	currentInstr[0] = 0;
 	currentInstr[10] = 0;
-	volume = 102;
+	volume = voltable[102]; //FIXME:KG: Original was just volume=102; I assume this is intended
 	volumesetting.leftvol = 32767;
 	volumesetting.rightvol = 32767;
 	bend = 0.0f;
 	memset(polyTable,0,sizeof(polyTable));
 	memset(patchCache, 0, sizeof(patchCache));
-
-	if (isRhythm) {
-		init = true;
-		refreshDrumCache();
-	}
-	init = false;
 }
 
 void Part::setHoldPedal(bool pedalval) {
@@ -90,16 +91,17 @@
 	holdpedal = pedalval;
 }
 
-void Part::setBend(int midiBend) {
-	if (isRhythm) {
-		synth->printDebug("%s: Setting bend (%d) not supported on rhythm", name, midiBend);
-		return;
-	}
-	// FIXME:KG: Slightly uneven increments, but I wanted min -1.0, centre 0.0 and max 1.0
+void RhythmPart::setBend(unsigned int midiBend) {
+	synth->printDebug("%s: Setting bend (%d) not supported on rhythm", name, midiBend);
+	return;
+}
+
+void Part::setBend(unsigned int midiBend) {
+	// FIXME:KG: Slightly unbalanced increments, but I wanted min -1.0, centre 0.0 and max 1.0
 	if (midiBend <= 0x2000) {
-		bend = (midiBend - 0x2000) / (float)0x2000;
+		bend = ((signed int)midiBend - 0x2000) / (float)0x2000;
 	} else {
-		bend = (midiBend - 0x2000) / (float)0x1FFF;
+		bend = ((signed int)midiBend - 0x2000) / (float)0x1FFF;
 	}
 	// Loop through all partials to update their bend
 	for (int i = 0; i < MT32EMU_MAX_POLY; i++) {
@@ -111,15 +113,15 @@
 	}
 }
 
-void Part::setModulation(int vol) {
-	if (isRhythm) {
-		synth->printDebug("%s: Setting modulation (%d) not supported on rhythm", name, vol);
-		return;
-	}
+void RhythmPart::setModulation(unsigned int midiModulation) {
+	synth->printDebug("%s: Setting modulation (%d) not supported on rhythm", name, midiModulation);
+}
+
+void Part::setModulation(unsigned int midiModulation) {
 	// Just a bloody guess, as always, before I get things figured out
 	for (int t = 0; t < 4; t++) {
 		if (patchCache[t].playPartial) {
-			int newrate = (patchCache[t].modsense * vol) >> 7;
+			int newrate = (patchCache[t].modsense * midiModulation) >> 7;
 			//patchCache[t].lfoperiod = lfotable[newrate];
 			patchCache[t].lfodepth = newrate;
 			//FIXME:KG: timbreTemp->partial[t].lfo.depth =
@@ -127,52 +129,78 @@
 	}
 }
 
-void Part::refreshDrumCache() {
-	if (!isRhythm) {
-		synth->printDebug("ERROR: RefreshDrumCache() called on non-rhythm part");
-	}
-	// Cache drum patches
-	for (int m = 0; m < 64; m++) {
-		int drumTimbre = rhythmTemp[m].timbre;
-		if (drumTimbre >= 94)
+void RhythmPart::refresh() {
+	// (Re-)cache all the mapped timbres ahead of time
+	for (unsigned int drumNum = 0; drumNum < 64; drumNum++) {
+		int drumTimbreNum = rhythmTemp[drumNum].timbre;
+		if (drumTimbreNum >= 94)
 			continue;
-		setPatch(drumTimbre + 128); // This is to cache all the mapped drum timbres ahead of time
-		Bit16s pan = rhythmTemp[m].panpot; // They use R-L 0-14...
+		Bit16s pan = rhythmTemp[drumNum].panpot; // They use R-L 0-14...
+		// FIXME:KG: Panning cache should be backed up to partials using it, too
 		// FIXME:KG: If I don't have left/right mixed up here, it's pure luck
 		if (pan < 7) {
-			drumPan[m].leftvol = 32767;
-			drumPan[m].rightvol = pan * 4681;
+			drumPan[drumNum].leftvol = 32767;
+			drumPan[drumNum].rightvol = pan * 4681;
 		} else {
-			drumPan[m].rightvol = 32767;
-			drumPan[m].leftvol = (14 - pan) * 4681;
+			drumPan[drumNum].rightvol = 32767;
+			drumPan[drumNum].leftvol = (14 - pan) * 4681;
+		}
+		PatchCache *cache = drumCache[drumNum];
+		backupCacheToPartials(cache);
+		for (int t = 0; t < 4; t++) {
+			// Common parameters, stored redundantly
+			cache[t].dirty = true;
+			cache[t].pitchShift = 0.0f;
+			cache[t].benderRange = 0.0f;
+			cache[t].pansetptr = &drumPan[drumNum];
+			cache[t].reverb = rhythmTemp[drumNum].reverbSwitch > 0;
 		}
 	}
 }
 
+void Part::refresh() {
+	backupCacheToPartials(patchCache);
+	for (int t = 0; t < 4; t++) {
+		// Common parameters, stored redundantly
+		patchCache[t].dirty = true;
+		patchCache[t].pitchShift = (patchTemp->patch.keyShift - 24) + (patchTemp->patch.fineTune - 50) / 100.0f;
+		patchCache[t].benderRange = patchTemp->patch.benderRange;
+		patchCache[t].pansetptr = &volumesetting;
+		patchCache[t].reverb = patchTemp->patch.reverbSwitch > 0;
+	}
+	memcpy(currentInstr, timbreTemp->common.name, 10);
+}
+
+void RhythmPart::refreshTimbre(unsigned int absTimbreNum) {
+	for (int m = 0; m < 64; m++) {
+		if (rhythmTemp[m].timbre == absTimbreNum - 128)
+			drumCache[m][0].dirty = true;
+	}
+}
+
+void Part::refreshTimbre(unsigned int absTimbreNum) {
+	if (getAbsTimbreNum() == absTimbreNum) {
+		memcpy(currentInstr, timbreTemp->common.name, 10);
+		patchCache[0].dirty = true;
+	}
+}
+
 int Part::fixBiaslevel(int srcpnt, int *dir) {
-	int noteat = srcpnt & 63;
+	int noteat = srcpnt & 0x3F;
 	int outnote;
-	*dir = 1;
 	if (srcpnt < 64)
 		*dir = 0;
+	else
+		*dir = 1;
 	outnote = 33 + noteat;
 	//synth->printDebug("Bias note %d, dir %d", outnote, *dir);
 
 	return outnote;
 }
 
-int Part::fixKeyfollow(int srckey, int *dir) {
+int Part::fixKeyfollow(int srckey) {
 	if (srckey>=0 && srckey<=16) {
-		//int keyfix[17] = { 256, 128, 64, 0, 32, 64, 96, 128, 128+32, 192, 192+32, 256, 256+64, 256+128, 512, 259, 269 };
-		int keyfix[17] = { 256*16, 128*16, 64*16, 0, 32*16, 64*16, 96*16, 128*16, (128+32)*16, 192*16, (192+32)*16, 256*16, (256+64)*16, (256+128)*16, (512)*16, 4100, 4116};
-
-		if (srckey<3)
-			*dir = -1;
-		else if (srckey==3)
-			*dir = 0;
-		else
-			*dir = 1;
-
+		int keyfix[17] = { -256*16, -128*16, -64*16, 0, 32*16, 64*16, 96*16, 128*16, (128+32)*16, 192*16, (192+32)*16, 256*16, (256+64)*16, (256+128)*16, (512)*16, 4100, 4116};
 		return keyfix[srckey];
 	} else {
 		//LOG(LOG_ERROR|LOG_MISC,"Missed key: %d", srckey);
@@ -180,10 +208,6 @@
 	}
 }
 
-void Part::refreshPatch() {
-	setPatch(-1);
-}
-
 void Part::abortPoly(dpoly *poly) {
 	if (!poly->isPlaying) {
 		return;
@@ -197,7 +221,7 @@
 	poly->isPlaying = false;
 }
 
-void Part::setPatch(PatchParam *patch) {
+void Part::setPatch(const PatchParam *patch) {
 	patchTemp->patch = *patch;
 }
 
@@ -205,187 +229,165 @@
 	*timbreTemp = *timbre;
 }
 
-unsigned int Part::getAbsTimbreNum() {
-	if (isRhythm) {
-		synth->printDebug("%s: Attempted to call getAbsTimbreNum() - doesn't make sense for rhythm");
-		return 0;
-	}
+unsigned int RhythmPart::getAbsTimbreNum() const {
+	synth->printDebug("%s: Attempted to call getAbsTimbreNum() - doesn't make sense for rhythm");
+	return 0;
+}
+
+unsigned int Part::getAbsTimbreNum() const {
 	return (patchTemp->patch.timbreGroup * 64) + patchTemp->patch.timbreNum;
 }
 
-void Part::setPatch(int patchNum) {
-	int absTimbreNum = -1; // Initialised to please compiler
-	const TimbreParam *timbre;
-	if (isRhythm) {
-		// "patchNum" is treated as "timbreNum" for rhythm part
-		if (patchNum < 128) {
-			synth->printDebug("%s: Patch #%d is not valid for rhythm (must be >= 128)", name, patchNum);
-			return;
-		}
-		absTimbreNum = patchNum;
-		timbre = &synth->mt32ram.params.timbres[absTimbreNum].timbre;
-	} else {
-		if (patchNum >= 0) {
-			setPatch(&synth->mt32ram.params.patches[patchNum]);
-		}
-		if (patchNum >= 0) {
-			setTimbre(&synth->mt32ram.params.timbres[getAbsTimbreNum()].timbre);
-		}
-		timbre = timbreTemp;
+void RhythmPart::setProgram(unsigned int patchNum) {
+	synth->printDebug("%s: Attempt to set program (%d) on rhythm is invalid", name, patchNum);
+}
+
+void Part::setProgram(unsigned int patchNum) {
+	setPatch(&synth->mt32ram.patches[patchNum]);
+	setTimbre(&synth->mt32ram.timbres[getAbsTimbreNum()].timbre);
 #if 0
-		// Immediately stop all partials on this part (this is apparently *not* the correct behaviour)
-		for (int m = 0; m < MT32EMU_MAX_POLY; m++) {
-			AbortPoly(poly);
-		}
-#else
-		// check if any partials are still playing with the old patch cache
-		// if so then duplicate the cached data from the part to the partial so that
-		// we can change the part's cache without affecting the partial.
-		// We delay this until now to avoid a copy operation with every note played
-		for (int m = 0; m < MT32EMU_MAX_POLY; m++) {
-			for (int i = 0; i < 4; i++) {
-				Partial *partial = polyTable[m].partials[i];
-				if (partial != NULL && partial->patchCache == &patchCache[i]) {
-					// copy cache data
-					partial->cachebackup = patchCache[i];
-					// update pointers
-					partial->patchCache = &partial->cachebackup;
-				}
+	// Immediately stop all partials on this part (this is apparently *not* the correct behaviour)
+	for (int m = 0; m < MT32EMU_MAX_POLY; m++) {
+		AbortPoly(poly);
+	}
+#endif
+
+	refresh();
+
+	allStop(); //FIXME:KG: Is this correct?
+}
+
+void Part::backupCacheToPartials(PatchCache cache[4]) {
+	// check if any partials are still playing with the old patch cache
+	// if so then duplicate the cached data from the part to the partial so that
+	// we can change the part's cache without affecting the partial.
+	// We delay this until now to avoid a copy operation with every note played
+	for (int m = 0; m < MT32EMU_MAX_POLY; m++) {
+		for (int i = 0; i < 4; i++) {
+			Partial *partial = polyTable[m].partials[i];
+			if (partial != NULL && partial->patchCache == &cache[i]) {
+				partial->cachebackup = cache[i];
+				partial->patchCache = &partial->cachebackup;
 			}
 		}
-#endif
 	}
+}
 
-	memcpy(currentInstr, timbre->common.name, 10);
-
+void Part::cacheTimbre(PatchCache cache[4], const TimbreParam *timbre) {
+	backupCacheToPartials(cache);
 	int partialCount = 0;
 	for (int t = 0; t < 4; t++) {
 		if (((timbre->common.pmute >> t) & 0x1) == 1) {
-			patchCache[t].playPartial = true;
+			cache[t].playPartial = true;
 			partialCount++;
 		} else {
-			patchCache[t].playPartial = false;
+			cache[t].playPartial = false;
 			continue;
 		}
 
 		// Calculate and cache common parameters
 
-		patchCache[t].pcm = timbre->partial[t].wg.pcmwave;
-		patchCache[t].useBender = (timbre->partial[t].wg.bender == 1);
+		cache[t].pcm = timbre->partial[t].wg.pcmwave;
+		cache[t].useBender = (timbre->partial[t].wg.bender == 1);
 
 		switch (t) {
 		case 0:
-			patchCache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct12] & 0x2) ? true : false;
-			patchCache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct12];
-			patchCache[t].structurePosition = 0;
-			patchCache[t].structurePair = 1;
+			cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct12] & 0x2) ? true : false;
+			cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct12];
+			cache[t].structurePosition = 0;
+			cache[t].structurePair = 1;
 			break;
 		case 1:
-			patchCache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct12] & 0x1) ? true : false;
-			patchCache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct12];
-			patchCache[t].structurePosition = 1;
-			patchCache[t].structurePair = 0;
+			cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct12] & 0x1) ? true : false;
+			cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct12];
+			cache[t].structurePosition = 1;
+			cache[t].structurePair = 0;
 			break;
 		case 2:
-			patchCache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct34] & 0x2) ? true : false;
-			patchCache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct34];
-			patchCache[t].structurePosition = 0;
-			patchCache[t].structurePair = 3;
+			cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct34] & 0x2) ? true : false;
+			cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct34];
+			cache[t].structurePosition = 0;
+			cache[t].structurePair = 3;
 			break;
 		case 3:
-			patchCache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct34] & 0x1) ? true : false;
-			patchCache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct34];
-			patchCache[t].structurePosition = 1;
-			patchCache[t].structurePair = 2;
+			cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct34] & 0x1) ? true : false;
+			cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct34];
+			cache[t].structurePosition = 1;
+			cache[t].structurePair = 2;
 			break;
 		default:
 			break;
 		}
 
-		patchCache[t].waveform = timbre->partial[t].wg.waveform;
-		patchCache[t].pulsewidth = timbre->partial[t].wg.pulsewid;
-		patchCache[t].pwsens = timbre->partial[t].wg.pwvelo;
-		patchCache[t].pitchkeyfollow = fixKeyfollow(timbre->partial[t].wg.keyfollow, &patchCache[t].pitchkeydir);
-
-		// Calculate and cache pitch stuff
-		patchCache[t].pitchshift = timbre->partial[t].wg.coarse;
-		Bit32s pFine, fShift;
-		pFine = (Bit32s)timbre->partial[t].wg.fine;
-		if (isRhythm) {
-			patchCache[t].pitchshift += 24;
-			fShift = pFine + 50;
+		cache[t].waveform = timbre->partial[t].wg.waveform;
+		cache[t].pulsewidth = timbre->partial[t].wg.pulsewid;
+		cache[t].pwsens = timbre->partial[t].wg.pwvelo;
+		if (timbre->partial[t].wg.keyfollow > 16) {
+			synth->printDebug("Bad keyfollow value in timbre!");
+			cache[t].pitchKeyfollow = 1.0f;
 		} else {
-			patchCache[t].pitchshift += patchTemp->patch.keyShift;
-			fShift = pFine + (Bit32s)patchTemp->patch.fineTune;
+			cache[t].pitchKeyfollow = floatKeyfollow[timbre->partial[t].wg.keyfollow];
 		}
-		patchCache[t].fineshift = finetable[fShift];
 
-		patchCache[t].pitchEnv = timbre->partial[t].env;
-		patchCache[t].pitchEnv.sensitivity = (char)((float)patchCache[t].pitchEnv.sensitivity*1.27);
-		patchCache[t].pitchsustain = patchCache[t].pitchEnv.level[3];
+		cache[t].pitch = timbre->partial[t].wg.coarse + (timbre->partial[t].wg.fine - 50) / 100.0f + 24.0f;
+		cache[t].pitchEnv = timbre->partial[t].env;
+		cache[t].pitchEnv.sensitivity = (char)((float)cache[t].pitchEnv.sensitivity * 1.27f);
+		cache[t].pitchsustain = cache[t].pitchEnv.level[3];
 
 		// Calculate and cache TVA envelope stuff
-		patchCache[t].ampEnv = timbre->partial[t].tva;
+		cache[t].ampEnv = timbre->partial[t].tva;
 		for (int i = 0; i < 4; i++)
-			patchCache[t].ampEnv.envlevel[i] = (char)((float)patchCache[t].ampEnv.envlevel[i] * 1.27f);
-		patchCache[t].ampEnv.level = (char)((float)patchCache[t].ampEnv.level * 1.27f);
+			cache[t].ampEnv.envlevel[i] = (char)((float)cache[t].ampEnv.envlevel[i] * 1.27f);
+		cache[t].ampEnv.level = (char)((float)cache[t].ampEnv.level * 1.27f);
 		float tvelo = ((float)timbre->partial[t].tva.velosens / 100.0f);
 		float velo = fabs(tvelo-0.5f) * 2.0f;
 		velo *= 63.0f;
-		patchCache[t].ampEnv.velosens = (char)velo;
+		cache[t].ampEnv.velosens = (char)velo;
 		if (tvelo<0.5f)
-			patchCache[t].ampenvdir = 1;
+			cache[t].ampenvdir = 1;
 		else
-			patchCache[t].ampenvdir = 0;
+			cache[t].ampenvdir = 0;
 
-		patchCache[t].ampbias[0] = fixBiaslevel(patchCache[t].ampEnv.biaspoint1, &patchCache[t].ampdir[0]);
-		patchCache[t].ampblevel[0] = 12 - patchCache[t].ampEnv.biaslevel1;
-		patchCache[t].ampbias[1] = fixBiaslevel(patchCache[t].ampEnv.biaspoint2, &patchCache[t].ampdir[1]);
-		patchCache[t].ampblevel[1] = 12 - patchCache[t].ampEnv.biaslevel2;
-		patchCache[t].ampdepth = patchCache[t].ampEnv.envvkf * patchCache[t].ampEnv.envvkf;
-		patchCache[t].ampsustain = patchCache[t].ampEnv.envlevel[3];
-		patchCache[t].amplevel = patchCache[t].ampEnv.level;
+		cache[t].ampbias[0] = fixBiaslevel(cache[t].ampEnv.biaspoint1, &cache[t].ampdir[0]);
+		cache[t].ampblevel[0] = 12 - cache[t].ampEnv.biaslevel1;
+		cache[t].ampbias[1] = fixBiaslevel(cache[t].ampEnv.biaspoint2, &cache[t].ampdir[1]);
+		cache[t].ampblevel[1] = 12 - cache[t].ampEnv.biaslevel2;
+		cache[t].ampdepth = cache[t].ampEnv.envvkf * cache[t].ampEnv.envvkf;
+		cache[t].ampsustain = cache[t].ampEnv.envlevel[3];
+		cache[t].amplevel = cache[t].ampEnv.level;
 
 		// Calculate and cache filter stuff
-		patchCache[t].filtEnv = timbre->partial[t].tvf;
-		patchCache[t].tvfdepth = patchCache[t].filtEnv.envdkf;
-		patchCache[t].filtkeyfollow  = fixKeyfollow(patchCache[t].filtEnv.keyfollow, &patchCache[t].keydir);
-		patchCache[t].filtEnv.envdepth = (char)((float)patchCache[t].filtEnv.envdepth * 1.27);
-		patchCache[t].tvfbias = fixBiaslevel(patchCache[t].filtEnv.biaspoint, &patchCache[t].tvfdir);
-		patchCache[t].tvfblevel = patchCache[t].filtEnv.biaslevel;
-		patchCache[t].filtsustain  = patchCache[t].filtEnv.envlevel[3];
+		cache[t].filtEnv = timbre->partial[t].tvf;
+		cache[t].tvfdepth = cache[t].filtEnv.envdkf;
+		cache[t].filtkeyfollow  = fixKeyfollow(cache[t].filtEnv.keyfollow);
+		cache[t].filtEnv.envdepth = (char)((float)cache[t].filtEnv.envdepth * 1.27);
+		cache[t].tvfbias = fixBiaslevel(cache[t].filtEnv.biaspoint, &cache[t].tvfdir);
+		cache[t].tvfblevel = cache[t].filtEnv.biaslevel;
+		cache[t].filtsustain  = cache[t].filtEnv.envlevel[3];
 
 		// Calculate and cache LFO stuff
-		patchCache[t].lfodepth = timbre->partial[t].lfo.depth;
-		patchCache[t].lfoperiod = lfotable[(int)timbre->partial[t].lfo.rate];
-		patchCache[t].lforate = timbre->partial[t].lfo.rate;
-		patchCache[t].modsense = timbre->partial[t].lfo.modsense;
+		cache[t].lfodepth = timbre->partial[t].lfo.depth;
+		cache[t].lfoperiod = lfotable[(int)timbre->partial[t].lfo.rate];
+		cache[t].lforate = timbre->partial[t].lfo.rate;
+		cache[t].modsense = timbre->partial[t].lfo.modsense;
 	}
 	for (int t = 0; t < 4; t++) {
 		// Common parameters, stored redundantly
-		patchCache[t].partialCount = partialCount;
-		patchCache[t].sustain = (timbre->common.nosustain == 0);
-		if (isRhythm) {
-			patchCache[t].benderRange = 0;
-		} else {
-			patchCache[t].benderRange = patchTemp->patch.benderRange;
-		}
+		cache[t].dirty = false;
+		cache[t].partialCount = partialCount;
+		cache[t].sustain = (timbre->common.nosustain == 0);
 	}
-	//synth->printDebug("Res 1: %d 2: %d 3: %d 4: %d", patchCache[0].waveform, patchCache[1].waveform, patchCache[2].waveform, patchCache[3].waveform);
+	//synth->printDebug("Res 1: %d 2: %d 3: %d 4: %d", cache[0].waveform, cache[1].waveform, cache[2].waveform, cache[3].waveform);
 
-	if (isRhythm)
-		memcpy(drumCache[absTimbreNum - 128], patchCache, sizeof(patchCache));
-	else
-		allStop();
 #if MT32EMU_MONITOR_INSTRUMENTS == 1
-	synth->printDebug("%s: Recache, param %d (timbre: %s)", name, patchNum, currentInstr);
+	synth->printDebug("%s (%s): Recached timbre", name, currentInstr);
 	for (int i = 0; i < 4; i++) {
-		synth->printDebug(" %d: play=%s, pcm=%s (%d), wave=%d", i, patchCache[i].playPartial ? "YES" : "NO", patchCache[i].PCMPartial ? "YES" : "NO", timbre->partial[i].wg.pcmwave, timbre->partial[i].wg.waveform);
+		synth->printDebug(" %d: play=%s, pcm=%s (%d), wave=%d", i, cache[i].playPartial ? "YES" : "NO", cache[i].PCMPartial ? "YES" : "NO", timbre->partial[i].wg.pcmwave, timbre->partial[i].wg.waveform);
 	}
 #endif
 }
 
-char *Part::getName() {
+const char *Part::getName() const {
 	return name;
 }
 
@@ -393,72 +395,88 @@
 	volume = voltable[vol];
 }
 
-void Part::setPan(int pan) {
+void RhythmPart::setPan(unsigned int midiPan)
+{
 	// FIXME:KG: This is unchangeable for drums (they always use drumPan), is that correct?
+	synth->printDebug("%s: Setting pan (%d) not supported on rhythm", name, midiPan);
+}
+
+void Part::setPan(unsigned int midiPan) {
 	// FIXME:KG: Tweaked this a bit so that we have a left 100%, centre and right 100%
 	// (But this makes the range somewhat skewed)
-	if (pan < 64) {
+	if (midiPan < 64) {
 		volumesetting.leftvol = 32767;
-		volumesetting.rightvol = (Bit16s)(pan * 512);
-	} else if (pan == 64) {
+		volumesetting.rightvol = (Bit16s)(midiPan * 512);
+	} else if (midiPan == 64) {
 		volumesetting.leftvol = 32767;
 		volumesetting.rightvol = 32767;
 	} else {
 		volumesetting.rightvol = 32767;
-		volumesetting.leftvol = (Bit16s)((127 - pan) * 520);
+		volumesetting.leftvol = (Bit16s)((127 - midiPan) * 520);
 	}
 	//synth->printDebug("%s (%s): Set pan to %d", name, currentInstr, panpot);
 }
 
-void Part::playNote(PartialManager *partialManager, unsigned int key, int vel) {
-	int drumNum = -1; // Initialised to please compiler
-	int drumTimbre = -1; // As above
-	int freqNum;
+void RhythmPart::playNote(unsigned int key, int vel) {
+	if (key < 24 || key > 87) {
+		synth->printDebug("%s: Attempted to play invalid key %d", name, key);
+		return;
+	}
+	int drumNum = key - 24;
+	int drumTimbreNum = rhythmTemp[drumNum].timbre;
+	if (drumTimbreNum >= 94) {
+		synth->printDebug("%s: Attempted to play unmapped key %d", name, key);
+		return;
+	}
+	int absTimbreNum = drumTimbreNum + 128;
+	TimbreParam *timbre = &synth->mt32ram.timbres[absTimbreNum].timbre;
+	memcpy(currentInstr, timbre->common.name, 10);
+#if MT32EMU_MONITOR_INSTRUMENTS == 1
+	synth->printDebug("%s (%s): starting poly (drum %d, timbre %d) - Vel %d Key %d Vol %d", name, currentInstr, drumNum, absTimbreNum, vel, key, volume);
+#endif
+	if (drumCache[drumNum][0].dirty) {
+		cacheTimbre(drumCache[drumNum], timbre);
+	}
+	playPoly(drumCache[drumNum], key, MIDDLEC, vel);
+}
 
-	if (isRhythm) {
-		if (key < 24 || key > 87) {
-			synth->printDebug("%s: Attempted to play invalid key %d", name, key);
-			return;
-		}
-		drumNum = key - 24;
-		drumTimbre = rhythmTemp[drumNum].timbre;
-		if (drumTimbre >= 94) {
-			synth->printDebug("%s: Attempted to play unmapped key %d", name, key);
-			return;
-		}
-		memcpy(patchCache, drumCache[drumTimbre], sizeof(patchCache));
-		memcpy(&currentInstr, synth->mt32ram.params.timbres[128 + drumTimbre].timbre.common.name, 10);
-		freqNum = MIDDLEC;
-	} else {
-		if (key < 12) {
-			synth->printDebug("%s (%s): Attempted to play invalid key %d < 12; moving up by octave", name, currentInstr, key);
-			key += 12;
-		} else if (key > 108) {
-			synth->printDebug("%s (%s): Attempted to play invalid key %d > 108; moving down by octave", name, currentInstr, key);
-			while (key > 108) {
-				key -= 12;
-			}
+void Part::playNote(unsigned int key, int vel) {
+	int freqNum = key;
+	if (freqNum < 12) {
+		synth->printDebug("%s (%s): Attempted to play invalid key %d < 12; moving up by octave", name, currentInstr, key);
+		freqNum += 12;
+	} else if (freqNum > 108) {
+		synth->printDebug("%s (%s): Attempted to play invalid key %d > 108; moving down by octave", name, currentInstr, key);
+		while (freqNum > 108) {
+			freqNum -= 12;
 		}
-		freqNum = key;
 	}
 	// POLY1 mode, Single Assign
 	// Haven't found any software that uses any of the other poly modes
 	// FIXME:KG: Should this also apply to rhythm?
-	if (!isRhythm) {
-		for (unsigned int i = 0; i < MT32EMU_MAX_POLY; i++) {
-			if (polyTable[i].isActive() && (polyTable[i].key == key)) {
-				//AbortPoly(&polyTable[i]);
-				stopNote(key);
-				break;
-			}
+	for (unsigned int i = 0; i < MT32EMU_MAX_POLY; i++) {
+		if (polyTable[i].isActive() && (polyTable[i].key == key)) {
+			//AbortPoly(&polyTable[i]);
+			stopNote(key);
+			break;
 		}
 	}
+#if MT32EMU_MONITOR_INSTRUMENTS == 1
+	synth->printDebug("%s (%s): starting poly - Vel %d Key %d Vol %d", name, currentInstr, vel, key, volume);
+#endif
+	if (patchCache[0].dirty) {
+		cacheTimbre(patchCache, timbreTemp);
+	}
+	playPoly(patchCache, key, freqNum, vel);
+}
 
-	unsigned int needPartials = patchCache[0].partialCount;
+void Part::playPoly(const PatchCache cache[4], unsigned int key, int freqNum, int vel) {
+	unsigned int needPartials = cache[0].partialCount;
+	unsigned int freePartials = synth->partialManager->getFreePartialCount();
 
-	if (needPartials > partialManager->GetFreePartialCount()) {
-		if (!partialManager->FreePartials(needPartials, partNum)) {
-			synth->printDebug("%s (%s): Insufficient free partials to play key %d (vel=%d)", name, currentInstr, key, vel);
+	if (freePartials < needPartials) {
+		if (!synth->partialManager->freePartials(needPartials - freePartials, partNum)) {
+			synth->printDebug("%s (%s): Insufficient free partials to play key %d (vel=%d); needed=%d, free=%d", name, currentInstr, key, vel, needPartials, synth->partialManager->getFreePartialCount());
 			return;
 		}
 	}
@@ -485,8 +503,8 @@
 
 	bool allnull = true;
 	for (int x = 0; x < 4; x++) {
-		if (patchCache[x].playPartial) {
-			tpoly->partials[x] = partialManager->AllocPartial(partNum);
+		if (cache[x].playPartial) {
+			tpoly->partials[x] = synth->partialManager->allocPartial(partNum);
 			allnull = false;
 		} else {
 			tpoly->partials[x] = NULL;
@@ -496,27 +514,12 @@
 	if (allnull)
 		synth->printDebug("%s (%s): No partials to play for this instrument", name, this->currentInstr);
 
-	if (isRhythm) {
-		tpoly->pansetptr = &drumPan[drumNum];
-		tpoly->reverb = rhythmTemp[drumNum].reverbSwitch > 0;
-	} else {
-		tpoly->pansetptr = &volumesetting;
-		tpoly->reverb = patchTemp->patch.reverbSwitch > 0;
-	}
-	tpoly->sustain = patchCache[0].sustain;
+	tpoly->sustain = cache[0].sustain;
 	tpoly->volumeptr = &volume;
 
-#if MT32EMU_MONITOR_INSTRUMENTS == 1
-	if (isRhythm) {
-		synth->printDebug("%s (%s): starting poly %d (drum %d, timbre %d) - Vel %d Key %d Vol %d", name, currentInstr, m, drumNum, drumTimbre, vel, key, volume);
-	} else {
-		synth->printDebug("%s (%s): starting poly %d - Vel %d Key %d Vol %d", name, currentInstr, m, vel, key, volume);
-	}
-#endif
-
 	for (int x = 0; x < 4; x++) {
 		if (tpoly->partials[x] != NULL) {
-			tpoly->partials[x]->startPartial(tpoly, &patchCache[x], tpoly->partials[patchCache[x].structurePair]);
+			tpoly->partials[x]->startPartial(tpoly, &cache[x], tpoly->partials[cache[x].structurePair]);
 			tpoly->partials[x]->setBend(bend);
 		}
 	}

Index: part.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/part.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- part.h	14 Nov 2004 04:40:12 -0000	1.3
+++ part.h	28 Nov 2004 05:35:07 -0000	1.4
@@ -29,20 +29,12 @@
 
 class Part {
 private:
-	Synth *synth; // Only used for sending debug output
-
 	// Pointers to the areas of the MT-32's memory dedicated to this part (for parts 1-8)
 	MemParams::PatchTemp *patchTemp;
 	TimbreParam *timbreTemp;
-	//... and for rhythm
-	MemParams::RhythmTemp *rhythmTemp;
 
-	bool isRhythm;
-	bool init;
-	int partNum;
-
-	char name[8]; // "Part 1".."Part 8", "Rhythm"
-	char currentInstr[11];
+	// 0=Part 1, .. 7=Part 8, 8=Rhythm
+	unsigned int partNum;
 
 	bool holdpedal;
 
@@ -51,33 +43,61 @@
 	PatchCache patchCache[4];
 
 	float bend; // -1.0 .. +1.0 
-	Bit32s volume;
 
 	dpoly polyTable[MT32EMU_MAX_POLY];
 
 	void abortPoly(dpoly *poly);
 
-	static int fixKeyfollow(int srckey, int *dir);
+	static int fixKeyfollow(int srckey);
 	static int fixBiaslevel(int srcpnt, int *dir);
 
+	void setPatch(const PatchParam *patch);
+
+protected:
+	Synth *synth;
+	char name[8]; // "Part 1".."Part 8", "Rhythm"
+	char currentInstr[11];
+	Bit32u volume;
+	void backupCacheToPartials(PatchCache cache[4]);
+	void cacheTimbre(PatchCache cache[4], const TimbreParam *timbre);
+	void playPoly(const PatchCache cache[4], unsigned int key, int freqNum, int vel);
+	const char *getName() const;
+
 public:
-	Part(Synth *synth, int usePartNum);
-	char *getName();
-	void playNote(PartialManager *partialManager, unsigned int key, int vel);
+	Part(Synth *synth, unsigned int usePartNum);
+	virtual void playNote(unsigned int key, int vel);
 	void stopNote(unsigned int key);
 	void allStop();
 	void setVolume(int vol);
-	void setPan(int vol);
-	void setBend(int vol);
-	void setModulation(int vol);
-	void setPatch(int patchnum);
+	virtual void setPan(unsigned int midiPan);
+	virtual void setBend(unsigned int midiBend);
+	virtual void setModulation(unsigned int midiModulation);
+	virtual void setProgram(unsigned int patchNum);
 	void setHoldPedal(bool pedalval);
 	void stopPedalHold();
-	void refreshPatch();
-	void refreshDrumCache();
-	void setPatch(PatchParam *patch);
+	virtual void refresh();
+	virtual void refreshTimbre(unsigned int absTimbreNum);
 	void setTimbre(TimbreParam *timbre);
-	unsigned int getAbsTimbreNum();
+	virtual unsigned int getAbsTimbreNum() const;
+};
+
+class RhythmPart: public Part {
+	// Pointer to the area of the MT-32's memory dedicated to rhythm
+	const MemParams::RhythmTemp *rhythmTemp;
+
+	// This caches the timbres/settings in use by the rhythm part
+	PatchCache drumCache[64][4];
+	StereoVolume drumPan[64];
+public:
+	RhythmPart(Synth *synth, unsigned int usePartNum);
+	void refreshTimbre(unsigned int timbreNum);
+	void refresh();
+	void playNote(unsigned int key, int vel);
+	unsigned int getAbsTimbreNum() const;
+	void setPan(unsigned int midiPan);
+	void setBend(unsigned int midiBend);
+	void setModulation(unsigned int midiModulation);
+	void setProgram(unsigned int patchNum);
 };
 
 }

Index: partial.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/partial.cpp,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- partial.cpp	14 Nov 2004 08:04:55 -0000	1.10
+++ partial.cpp	28 Nov 2004 05:35:07 -0000	1.11
@@ -25,6 +25,11 @@
 
 #include "mt32emu.h"
 
+#define FIXEDPOINT_UDIV(x, y, point) (((x) << (point)) / ((y)))
+#define FIXEDPOINT_SDIV(x, y, point) (((x) * (1 << point)) / ((y)))
+#define FIXEDPOINT_UMULT(x, y, point) (((x) * (y)) >> point)
+#define FIXEDPOINT_SMULT(x, y, point) (((x) * (y)) / (1 << point))
+
 using namespace MT32Emu;
 
 Partial::Partial(Synth *useSynth) {
@@ -32,9 +37,20 @@
 	ownerPart = -1;
 	poly = NULL;
 	pair = NULL;
+#if MT32EMU_ACCURATENOTES == 1
+	for (int i = 0; i < 3; i++) {
+		noteLookupStorage.waveforms[i] = new Bit16s[65536];
+	}
+	noteLookup = ¬eLookupStorage;
+#endif
 }
 
 Partial::~Partial() {
+#if MT32EMU_ACCURATENOTES == 1
+	for (int i = 0; i < 3; i++) {
+		delete[] noteLookupStorage.waveforms[i];
+	}
+#endif
 }
 
 int Partial::getOwnerPart() {
@@ -68,55 +84,49 @@
 void Partial::initKeyFollow(int key) {
 	// Setup partial keyfollow
 	// Note follow relative to middle C
-	int keyfollow;
-	int realfol = (key * 2 - MIDDLEC * 2) / 2;
-	int antirealfol = (MIDDLEC * 2 - key * 2) / 2;
+
 	// Calculate keyfollow for pitch
-	switch(patchCache->pitchkeydir) {
-	case -1:
-		keyfollow = (antirealfol * patchCache->pitchkeyfollow) >> 12;
-		break;
-	case 0:
-		keyfollow =  0;
-		break;
-	case 1:
-		keyfollow = (realfol * patchCache->pitchkeyfollow) >> 12;
-		break;
-	default:
-		keyfollow = 0; // Please the compiler
-	}
-	if ((patchCache->pitchkeyfollow>4096) && (patchCache->pitchkeyfollow<4200)) {
-		// Be sure to round up on keys below MIDDLEC
-		if (realfol < 0)
-			keyfollow++;
+#if 1
+	float rel = key == -1 ? 0.0f : (key - MIDDLEC);
+	float newPitch = rel * patchCache->pitchKeyfollow + patchCache->pitch + patchCache->pitchShift;
+	//FIXME:KG: Does it truncate the keyfollowed pitch to a semitone (towards MIDDLEC)?
+	//int newKey = (int)(rel * patchCache->pitchKeyfollow);
+	//float newPitch = newKey + patchCache->pitch + patchCache->pitchShift;
+#else
+	float rel = key == -1 ? 0.0f : (key + patchCache->pitchShift - MIDDLEC);
+	float newPitch = rel * patchCache->pitchKeyfollow + patchCache->pitch;
+#endif
+#if MT32EMU_ACCURATENOTES == 1
+	noteVal = newPitch;
+	synth->printDebug("key=%d, pitch=%f, pitchKeyfollow=%f, pitchShift=%f, newPitch=%f", key, patchCache->pitch, patchCache->pitchKeyfollow, patchCache->pitchShift, newPitch);
+#else
+	float newPitchInt;
+	float newPitchFract = modff(newPitch, &newPitchInt);
+	synth->printDebug("Really: newPitch=%f, newPitchInt=%f, newPitchFract=%f", newPitch, newPitchInt, newPitchFract);
+	if (newPitchFract > 0.5f) {
+		newPitchInt += 1.0f;
+		newPitchFract -= 1.0f;
 	}
-	noteVal = (keyfollow + patchCache->pitchshift);
-	if (noteVal > 108)
-		noteVal = 108;
-	if (noteVal < 12)
-		noteVal = 12;
-
+	noteVal = (int)newPitchInt;
+	fineShift = (int)(powf(2.0f, newPitchFract / 12.0f) * 4096.0f);
+	synth->printDebug("key=%d, pitch=%f, pitchKeyfollow=%f, pitchShift=%f, newPitch=%f, noteVal=%d, fineShift=%d", key, patchCache->pitch, patchCache->pitchKeyfollow, patchCache->pitchShift, newPitch, noteVal, fineShift);
+#endif
+	// FIXME:KG: Raise/lower by octaves until in the supported range.
+	while (noteVal > HIGHEST_NOTE) // FIXME:KG: see tables.cpp: >108?
+		noteVal -= 12;
+	while (noteVal < LOWEST_NOTE) // FIXME:KG: see tables.cpp: <12?
+		noteVal += 12;
 	// Calculate keyfollow for filter
-	switch(patchCache->keydir) {
-	case -1:
-		keyfollow = (antirealfol * patchCache->filtkeyfollow) >> 12;
-		break;
-	case 0:
-		keyfollow = key;
-		break;
-	case 1:
-		keyfollow = (realfol * patchCache->filtkeyfollow) >> 12;
-		break;
-	}
+	int keyfollow = ((key - MIDDLEC) * patchCache->filtkeyfollow) / 4096;
 	if (keyfollow > 108)
 		keyfollow = 108;
 	if (keyfollow < -108)
 		keyfollow = -108;
 	filtVal = keytable[keyfollow + 108];
-	realVal = keytable[realfol + 108];
+	realVal = keytable[(key - MIDDLEC) + 108];
 }
 
-void Partial::startPartial(dpoly *usePoly, PatchCache *useCache, Partial *pairPartial) {
+void Partial::startPartial(dpoly *usePoly, const PatchCache *useCache, Partial *pairPartial) {
 	if (usePoly == NULL || useCache == NULL) {
 		synth->printDebug("*** Error: Starting partial for owner %d, usePoly=%s, useCache=%s", ownerPart, usePoly == NULL ? "*** NULL ***" : "OK", useCache == NULL ? "*** NULL ***" : "OK");
 		return;
@@ -128,11 +138,11 @@
 
 	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];
+#if MT32EMU_ACCURATENOTES == 0
+	noteLookup = &noteLookups[noteVal - LOWEST_NOTE];
+#else
+	TableInitialiser::initNote(synth, &noteLookupStorage, noteVal, (float)synth->myProp.sampleRate, synth->masterTune, synth->PCMList, NULL);
+#endif
 
 	lfoPos = 0;
 	pulsewidth = patchCache->pulsewidth + pwveltable[patchCache->pwsens][poly->vel];
@@ -154,8 +164,8 @@
 		envs[e].counter = 0;
 		envs[e].count = 0;
 	}
-	ampEnvCache = 0;
-	pitchEnvCache = 0;
+	ampEnvVal = 0;
+	pitchEnvVal = 0;
 	pitchSustain = false;
 	loopPos = 0;
 	partialOff.pcmoffset = partialOff.pcmplace = 0;
@@ -181,22 +191,16 @@
 
 	Bit16s *partialBuf = &myBuffer[0];
 	while (length--) {
-		Bit32s envval, ampval;
-		Bit32s ptemp = 0;
-		if (envs[EnvelopeType_amp].sustaining)
-			ampval = ampEnvCache;
-		else {
+		Bit32s envval;
+		Bit32s sample = 0;
+		if (!envs[EnvelopeType_amp].sustaining) {
 			if (envs[EnvelopeType_amp].count <= 0) {
-				ampval = getAmpEnvelope();
+				Bit32u ampval = getAmpEnvelope();
 				if (!play) {
 					deactivate();
 					break;
 				}
-				if (ampval < 0) {
-					//TODO: check what is going on here
-					synth->printDebug("ampval<0! ampval=%ld, active=%d", ampval, isActive());
-					ampval = 0;
-				} else if (ampval > 127) {
+				if (ampval > 127) {
 					ampval = 127;
 				}
 
@@ -208,15 +212,12 @@
 					tmpvel = poly->vel;
 				ampval = (ampval * ampveltable[tmpvel][(int)patchCache->ampEnv.velosens]) >> 8;
 				//if (envs[EnvelopeType_amp].sustaining)
-				ampEnvCache = ampval;
-			} else
-				ampval = ampEnvCache;
+				ampEnvVal = ampval;
+			}
 			--envs[EnvelopeType_amp].count;
 		}
 
-		// Calculate Pitch envelope
 		int lfoat = 0x1000;
-		int pdep;
 		if (pitchSustain) {
 			// Calculate LFO position
 			// LFO does not kick in completely until pitch envelope sustains
@@ -224,17 +225,15 @@
 				lfoPos++;
 				if (lfoPos >= patchCache->lfoperiod)
 					lfoPos = 0;
-				int lfoatm = (lfoPos << 16) / patchCache->lfoperiod;
+				int lfoatm = FIXEDPOINT_UDIV(lfoPos, patchCache->lfoperiod, 16);
 				int lfoatr = sintable[lfoatm];
 				lfoat = lfoptable[patchCache->lfodepth][lfoatr];
 			}
-			pdep = pitchEnvCache;
 		} else {
+			// Calculate Pitch envelope
 			envval = getPitchEnvelope();
 			int pd = patchCache->pitchEnv.depth;
-			pdep = penvtable[pd][envval];
-			if (pitchSustain)
-				pitchEnvCache = pdep;
+			pitchEnvVal = penvtable[pd][envval];
 		}
 
 		int delta;
@@ -242,36 +241,23 @@
 		PCMWaveEntry *pcmWave = NULL; // Initialise to please compiler
 		int pcmAddr = 0; // Initialise to please compiler
 
-		// Get waveform - either PCM or synthesized sawtooth or square
+		// Wrap positions or end if necessary
 		if (patchCache->PCMPartial) {
 			// PCM partial
 			int len;
 			pcmWave = &synth->PCMList[patchCache->pcm];
 
-			if (pcmWave->aggSound == -1) {
-				delta = noteLookup->wavTable[pcmWave->pcmnum];
-				pcmAddr = pcmWave->addr;
-				len = pcmWave->len;
-				if (partialOff.pcmplace >= len) {
-					if (pcmWave->loop) {
-						partialOff.pcmplace = partialOff.pcmoffset = 0;
-						// FIXME:KG: Use this?: partialOff.pcmplace %= len;
-					} else {
-						play = false;
-						deactivate();
-						break;
-					}
-				}
-			} else {
-				int tmppcm = LoopPatterns[pcmWave->aggSound][loopPos];
-				delta = noteLookup->loopTable[pcmWave->aggSound][loopPos];
-				pcmAddr = synth->PCM[tmppcm].addr;
-				len = synth->PCM[tmppcm].len;
-				if (partialOff.pcmplace >= len) {
-					loopPos++;
-					if (LoopPatterns[pcmWave->aggSound][loopPos] == -1)
-						loopPos = 0;
-					partialOff.pcmplace = partialOff.pcmoffset = 0;
+			delta = noteLookup->wavTable[patchCache->pcm];
+			pcmAddr = pcmWave->addr;
+			len = pcmWave->len;
+			if (partialOff.pcmplace >= len) {
+				if (pcmWave->loop) {
+					//partialOff.pcmplace = partialOff.pcmoffset = 0;
+					partialOff.pcmplace %= len;
+				} else {
+					play = false;
+					deactivate();
+					break;
 				}
 			}
 		} else {
@@ -282,14 +268,18 @@
 
 		// Build delta for position of next sample
 		// Fix delta code
-		Bit64s tdelta = (Bit64s)delta;
-		tdelta = (tdelta * patchCache->fineshift) >> 12;
-		tdelta = (tdelta * pdep) >> 12;
+		Bit64u tdelta = (Bit64u)delta;
+#if MT32EMU_ACCURATENOTES == 0
+		tdelta = (tdelta * fineShift) >> 12;
+#endif
+		tdelta = (tdelta * pitchEnvVal) >> 12;
 		tdelta = (tdelta * lfoat) >> 12;
 		tdelta = (tdelta * bendShift) >> 12;
 		delta = (int)tdelta;
+		Bit32u volume = *poly->volumeptr;
 
-		if (ampval > 0) {
+		// Get waveform - either PCM or synthesized sawtooth or square
+		if (ampEnvVal > 0) {
 			if (patchCache->PCMPartial) {
 				// Render PCM sample
 				int ra, rb, dist;
@@ -301,7 +291,7 @@
 					//FIXME:KG: Deal with condition that taddr + 1 is past PCM length
 					rb = synth->romfile[taddr + 1];
 					dist = rb - ra;
-					ptemp = (ra + ((dist * (Bit32s)(partialOff.pcmoffset >> 8)) >> 8));
+					sample = (ra + ((dist * (Bit32s)(partialOff.pcmoffset >> 8)) >> 8));
 				} else {
 					// Sound decimation
 					// The right way to do it is to use a lowpass filter on the waveform before selecting
@@ -311,11 +301,11 @@
 					ra = 0;
 					for (int ix = 0; ix < idelta; ix++)
 						ra += synth->romfile[taddr++];
-					ptemp = ra / idelta;
+					sample = ra / idelta;
 				}
 			} else {
 				// Render synthesised sample
-				int div = noteLookup->div;
+				Bit32u div = noteLookup->div;
 				int wf = patchCache->waveform;
 				int toff = partialOff.pcmplace;
 				int minorplace = partialOff.pcmoffset >> 14;
@@ -328,26 +318,23 @@
 					// Square waveform.  Made by combining two pregenerated bandlimited
 					// sawtooth waveforms
 					// Pulse width is not yet correct
-					int pa, pb;
-					int divmark = div << 8;
-
 					if (div == 0) {
 						synth->printDebug("ERROR: div=0 generating square wave, this should never happen!");
 						div = 1;
 					}
-					int ofsA = toff % div;
-					int ofsB = toff + ((divmark * pulsetable[pulsewidth]) >> 16);
+					Bit32u ofsA = toff % div;
+					Bit32u ofsB = toff + FIXEDPOINT_UMULT(div, pulsetable[pulsewidth], 8);
 					ofsB = ofsB % div;
-					pa = noteLookup->waveforms[0][(ofsA << 2) + minorplace];
-					pb = noteLookup->waveforms[0][(ofsB << 2) + minorplace];
-					ptemp = (pa - pb) * 4;
+					Bit16s pa = noteLookup->waveforms[0][(ofsA << 2) + minorplace];
+					Bit16s pb = noteLookup->waveforms[0][(ofsB << 2) + minorplace];
+					sample = (pa - pb) * 4;
 					// Non-bandlimited squarewave
 					/*
 					ofs = ((div << 1) * pulsetable[patchCache->pulsewidth]) >> 8;
 					if (toff < ofs)
-						ptemp = 1 * WGAMP;
+						sample = 1 * WGAMP;
 					else
-						ptemp = -1 * WGAMP;
+						sample = -1 * WGAMP;
 					*/
 				} else {
 					// Sawtooth.  Made by combining the full cosine and half cosine according
@@ -355,33 +342,32 @@
 					// square wave and multiplies it by a full cosine
 					int waveoff = (toff << 2) + minorplace;
 					if (toff < noteLookup->sawTable[pulsewidth])
-						ptemp = noteLookup->waveforms[1][waveoff % noteLookup->waveformSize[1]];
+						sample = noteLookup->waveforms[1][waveoff % noteLookup->waveformSize[1]];
 					else
-						ptemp = noteLookup->waveforms[2][waveoff % noteLookup->waveformSize[2]];
-					ptemp = ptemp * 4;
+						sample = noteLookup->waveforms[2][waveoff % noteLookup->waveformSize[2]];
+					sample = sample * 4;
 					// This is the correct way
 					// Seems slow to me (though bandlimited) -- doesn't seem to
 					// sound any better though
 					/*
-					int divmark = noteLookup->div << 8;
 					//int pw = (patchCache->pulsewidth * pulsemod[filtval]) >> 8;
 
-					int ofs = toff % div;
+					Bit32u ofs = toff % div;
 
-					int ofs3 = toff + ((divmark * pulsetable[patchCache->pulsewidth]) >> 16);
+					Bit32u ofs3 = toff + FIXEDPOINT_UMULT(div, pulsetable[patchCache->pulsewidth], 8);
 					ofs3 = ofs3 % div;
 
 					pa = noteLookup->waveforms[0][ofs];
 					pb = noteLookup->waveforms[0][ofs3];
-					ptemp = ((pa - pb) * noteLookup->waveforms[2][toff]) / WGAMP;
-					ptemp = ptemp *4;
+					sample = ((pa - pb) * noteLookup->waveforms[2][toff]) / WGAMP;
+					sample = sample *4;
 					*/
 				}
 
 				//Very exact filter
 				if (filtval > ((FILTERGRAN * 15) / 16))
 					filtval = ((FILTERGRAN * 15) / 16);
-				ptemp = (Bit32s)floor((usefilter)((float)ptemp, &history[0], filtcoeff[filtval][(int)patchCache->filtEnv.resonance], patchCache->filtEnv.resonance));
+				sample = (Bit32s)floor((synth->iirFilter)((float)sample, &history[0], filtcoeff[filtval][(int)patchCache->filtEnv.resonance], patchCache->filtEnv.resonance));
 			}
 		}
 
@@ -392,14 +378,13 @@
 		partialOff.pcmoffset = (Bit16u)(absOff & 0xFFFF);
 
 		// Put volume envelope over generated sample
-		ptemp = (ptemp * ampval) >> 9;
-		ptemp = (ptemp * *poly->volumeptr) >> 7;
-
+		sample = FIXEDPOINT_SMULT(sample, ampEnvVal, 9);
+		sample = FIXEDPOINT_SMULT(sample, volume, 7);
 		envs[EnvelopeType_amp].envpos++;
 		envs[EnvelopeType_pitch].envpos++;
 		envs[EnvelopeType_filt].envpos++;
 
-		*partialBuf++ = (Bit16s)ptemp;
+		*partialBuf++ = (Bit16s)sample;
 	}
 	// We may have deactivated and broken out of the loop before the end of the buffer,
 	// if so then fill the remainder with 0s.
@@ -414,9 +399,10 @@
 		return;
 	}
 	// NOTE:KG: We can't do this smoothly with lookup tables, unless we use several MB.
+	// FIXME:KG: Bend should be influenced by pitch key-follow too, according to docs.
 	float bendSemitones = factor * patchCache->benderRange; // -24 .. 24
 	float mult = powf(2.0f, bendSemitones / 12.0f);
-	synth->printDebug("setBend(): semitones=%f, mult=%f, factor=%f, benderRange=%d\n", bendSemitones, mult, factor, patchCache->benderRange);
+	synth->printDebug("setBend(): factor=%f, benderRange=%f, semitones=%f, mult=%f\n", factor, patchCache->benderRange, bendSemitones, mult);
 	bendShift = (int)(mult * 4096.0f);
 }
 
@@ -601,8 +587,8 @@
 		return false;
 
 	Bit16s leftvol, rightvol;
-	leftvol = poly->pansetptr->leftvol;
-	rightvol = poly->pansetptr->rightvol;
+	leftvol = patchCache->pansetptr->leftvol;
+	rightvol = patchCache->pansetptr->rightvol;
 
 #if MT32EMU_USE_MMX >= 2
 	// FIXME:KG: This appears to introduce crackle
@@ -624,7 +610,7 @@
 
 	int cutoff,depth,keyfollow, realfollow;
 
-	envstatus *tStat  = &envs[EnvelopeType_filt];
+	EnvelopeStatus *tStat  = &envs[EnvelopeType_filt];
 
 	keyfollow = filtVal;
 	realfollow = realVal;
@@ -651,7 +637,7 @@
 				if (tStat->envstat == 3) {
 					tStat->envsize = lasttimetable[(int)patchCache->filtEnv.envtime[tStat->envstat]];
 				} else {
-					tStat->envsize = (envtimetable[(int)patchCache->filtEnv.envtime[tStat->envstat]] * keyLookup->timekeyTable[(int)patchCache->filtEnv.envtkf]) >> 8;
+					tStat->envsize = (envtimetable[(int)patchCache->filtEnv.envtime[tStat->envstat]] * noteLookup->timekeyTable[(int)patchCache->filtEnv.envtkf]) >> 8;
 				}
 
 				tStat->envsize++;
@@ -678,16 +664,17 @@
 	int dist;
 
 	if (bias!=0) {
+		//FIXME:KG: Is this really based on pitch (as now), or key pressed?
 		//synth->printDebug("Cutoff before %d", cutoff);
 		if (patchCache->tvfdir == 0) {
-			if (keyVal < bias) {
-				dist = bias - keyVal;
+			if (noteVal < bias) {
+				dist = bias - noteVal;
 				cutoff = (cutoff * fbiastable[patchCache->tvfblevel][dist]) >> 8;
 			}
 		} else {
 			// > Bias
-			if (keyVal > bias) {
-				dist = keyVal - bias;
+			if (noteVal > bias) {
+				dist = noteVal - bias;
 				cutoff = (cutoff * fbiastable[patchCache->tvfblevel][dist]) >> 8;
 			}
 
@@ -695,7 +682,7 @@
 		//synth->printDebug("Cutoff after %d", cutoff);
 	}
 
-	depth = (depth * keyLookup->fildepTable[patchCache->tvfdepth]) >> 8;
+	depth = (depth * noteLookup->fildepTable[patchCache->tvfdepth]) >> 8;
 	reshigh = (reshigh * depth) >> 7;
 
 	Bit32s tmp;
@@ -714,7 +701,7 @@
 		reshigh = 100;
 	else if (reshigh<0)
 		reshigh = 0;
-	tmp = keyLookup->nfiltTable[cutoff][reshigh];
+	tmp = noteLookup->nfiltTable[cutoff][reshigh];
 	//tmp *= keyfollow;
 	//tmp /= realfollow;
 
@@ -725,13 +712,13 @@
 bool Partial::shouldReverb() {
 	if (!isActive())
 		return false;
-	return poly->reverb;
+	return patchCache->reverb;
 }
 
-Bit32s Partial::getAmpEnvelope() {
-	Bit32s tc;
+Bit32u Partial::getAmpEnvelope() {
+	Bit32u tc;
 
-	envstatus *tStat = &envs[EnvelopeType_amp];
+	EnvelopeStatus *tStat = &envs[EnvelopeType_amp];
 
 	if (!play)
 		return 0;
@@ -780,7 +767,7 @@
 			default:
 				//Spot for timekey follow
 				//Only used in subsquent envelope parameters, including the decay
-				tStat->envsize = (envtimetable[(int)patchCache->ampEnv.envtime[tStat->envstat]] * keyLookup->timekeyTable[(int)patchCache->ampEnv.envtkf]) >> 8;
+				tStat->envsize = (envtimetable[(int)patchCache->ampEnv.envtime[tStat->envstat]] * noteLookup->timekeyTable[(int)patchCache->ampEnv.envtkf]) >> 8;
 
 				//synth->printDebug("Envstat %d, size %d", tStat->envstat, tStat->envsize);
 				break;
@@ -809,21 +796,19 @@
 
 	//Bias level crap stuff now
 
-	int dist, bias;
-
 	for (int i = 0; i < 2; i++) {
 		if (patchCache->ampblevel[i]!=0) {
-			bias = patchCache->ampbias[i];
+			int bias = patchCache->ampbias[i];
 			if (patchCache->ampdir[i]==0) {
 				// < Bias
-				if (keyVal < bias) {
-					dist = bias - keyVal;
+				if (noteVal < bias) {
+					int dist = bias - noteVal;
 					tc = (tc * ampbiastable[patchCache->ampblevel[i]][dist]) >> 8;
 				}
 			} else {
 				// > Bias
-				if (keyVal > bias) {
-					dist = keyVal - bias;
+				if (noteVal > bias) {
+					int dist = noteVal - bias;
 					tc = (tc * ampbiastable[patchCache->ampblevel[i]][dist]) >> 8;
 				}
 			}
@@ -833,7 +818,7 @@
 }
 
 Bit32s Partial::getPitchEnvelope() {
-	envstatus *tStat = &envs[EnvelopeType_pitch];
+	EnvelopeStatus *tStat = &envs[EnvelopeType_pitch];
 
 	Bit32s tc;
 	pitchSustain = false;
@@ -856,7 +841,7 @@
 				tStat->envstat++;
 
 				tStat->envbase = patchCache->pitchEnv.level[tStat->envstat];
-				tStat->envsize = (envtimetable[(int)patchCache->pitchEnv.time[tStat->envstat]] * keyLookup->timekeyTable[(int)patchCache->pitchEnv.timekeyfollow]) >> 8;
+				tStat->envsize = (envtimetable[(int)patchCache->pitchEnv.time[tStat->envstat]] * noteLookup->timekeyTable[(int)patchCache->pitchEnv.timekeyfollow]) >> 8;
 
 				tStat->envpos = 0;
 				tStat->envsize++;
@@ -878,7 +863,7 @@
 }
 
 void Partial::startDecay(EnvelopeType envnum, Bit32s startval) {
-	envstatus *tStat  = &envs[envnum];
+	EnvelopeStatus *tStat  = &envs[envnum];
 
 	tStat->sustaining = false;
 	tStat->decaying = true;
@@ -887,15 +872,15 @@
 
 	switch(envnum) {
 	case EnvelopeType_amp:
-		tStat->envsize = (decaytimetable[(int)patchCache->ampEnv.envtime[4]] * keyLookup->timekeyTable[(int)patchCache->ampEnv.envtkf]) >> 8;
+		tStat->envsize = (decaytimetable[(int)patchCache->ampEnv.envtime[4]] * noteLookup->timekeyTable[(int)patchCache->ampEnv.envtkf]) >> 8;
 		tStat->envdist = -startval;
 		break;
 	case EnvelopeType_filt:
-		tStat->envsize = (decaytimetable[(int)patchCache->filtEnv.envtime[4]] * keyLookup->timekeyTable[(int)patchCache->filtEnv.envtkf]) >> 8;
+		tStat->envsize = (decaytimetable[(int)patchCache->filtEnv.envtime[4]] * noteLookup->timekeyTable[(int)patchCache->filtEnv.envtkf]) >> 8;
 		tStat->envdist = -startval;
 		break;
 	case EnvelopeType_pitch:
-		tStat->envsize = (decaytimetable[(int)patchCache->pitchEnv.time[3]] * keyLookup->timekeyTable[(int)patchCache->pitchEnv.timekeyfollow]) >> 8 ;
+		tStat->envsize = (decaytimetable[(int)patchCache->pitchEnv.time[3]] * noteLookup->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.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- partial.h	14 Nov 2004 08:04:55 -0000	1.6
+++ partial.h	28 Nov 2004 05:35:07 -0000	1.7
@@ -33,7 +33,7 @@
 	EnvelopeType_pitch = 2
 };
 
-struct envstatus {
+struct EnvelopeStatus {
 	Bit32s envpos;
 	Bit32s envstat;
 	Bit32s envbase;
@@ -51,7 +51,7 @@
 // Class definition of MT-32 partials.  32 in all.
 class Partial {
 private:
-	Synth *synth; // Only used for sending debug output
+	Synth *synth;
 
 	int ownerPart; // -1 if unassigned
 	int mixType;
@@ -63,25 +63,28 @@
 	bool play;
 
 	// Keyfollowed note value
+#if MT32EMU_ACCURATENOTES == 1
+	NoteLookup noteLookupStorage;
+	float noteVal;
+#else
 	int noteVal;
-	NoteLookup *noteLookup; // Lookup stuff for this noteVal
-
-	int keyVal;
-	NoteLookup *keyLookup;
+	int fineShift;
+#endif
+	const NoteLookup *noteLookup; // LUTs for this noteVal
 
 	// Keyfollowed filter values
 	int realVal;
 	int filtVal;
 
-	envstatus envs[3];
+	EnvelopeStatus envs[3];
 
 	int pulsewidth;
 
 	Bit32u lfoPos;
 	soundaddr partialOff;
 
-	Bit32u ampEnvCache;
-	Bit32u pitchEnvCache;
+	Bit32u ampEnvVal;
+	Bit32u pitchEnvVal;
 
 	float history[32];
 
@@ -93,19 +96,19 @@
 
 	int bendShift;
 
-	Bit16s *mixBuffers(Bit16s * buf1, Bit16s * buf2, int len);
-	Bit16s *mixBuffersRingMix(Bit16s * buf1, Bit16s * buf2, int len);
-	Bit16s *mixBuffersRing(Bit16s * buf1, Bit16s * buf2, int len);
-	void mixBuffersStereo(Bit16s * buf1, Bit16s * buf2, Bit16s * outBuf, int len);
+	Bit16s *mixBuffers(Bit16s *buf1, Bit16s *buf2, int len);
+	Bit16s *mixBuffersRingMix(Bit16s *buf1, Bit16s *buf2, int len);
+	Bit16s *mixBuffersRing(Bit16s *buf1, Bit16s *buf2, int len);
+	void mixBuffersStereo(Bit16s *buf1, Bit16s *buf2, Bit16s *outBuf, int len);
 
 	Bit32s getFiltEnvelope();
-	Bit32s getAmpEnvelope();
+	Bit32u getAmpEnvelope();
 	Bit32s getPitchEnvelope();
 
 	void initKeyFollow(int freqNum);
 
 public:
-	PatchCache *patchCache;
+	const PatchCache *patchCache;
 	PatchCache cachebackup;
 
 	Partial *pair;
@@ -119,7 +122,7 @@
 	bool isActive();
 	void activate(int part);
 	void deactivate(void);
-	void startPartial(dpoly *usePoly, PatchCache *useCache, Partial *pairPartial);
+	void startPartial(dpoly *usePoly, const PatchCache *useCache, Partial *pairPartial);
 	void startDecay(EnvelopeType envnum, Bit32s startval);
 	void startDecayAll();
 	void setBend(float factor);

Index: partialManager.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/partialManager.cpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- partialManager.cpp	14 Nov 2004 04:40:12 -0000	1.2
+++ partialManager.cpp	28 Nov 2004 05:35:07 -0000	1.3
@@ -36,7 +36,7 @@
 		delete partialTable[i];
 }
 
-void PartialManager::GetPerPartPartialUsage(int usage[9]) {
+void PartialManager::getPerPartPartialUsage(int usage[9]) {
 	memset(usage, 0, 9 * sizeof (int));
 	for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
 		if (partialTable[i]->isActive())
@@ -44,12 +44,12 @@
 	}
 }
 
-void PartialManager::ClearAlreadyOutputed() {
+void PartialManager::clearAlreadyOutputed() {
 	for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++)
 		partialTable[i]->alreadyOutputed = false;
 }
 
-void PartialManager::AgeAll() {
+void PartialManager::ageAll() {
 	for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++)
 		partialTable[i]->age++;
 }
@@ -58,28 +58,28 @@
 	return partialTable[i]->shouldReverb();
 }
 
-bool PartialManager::ProduceOutput(int i, Bit16s *buffer, Bit32u bufferLength) {
+bool PartialManager::produceOutput(int i, Bit16s *buffer, Bit32u bufferLength) {
 	return partialTable[i]->produceOutput(buffer, bufferLength);
 }
 
-void PartialManager::DeactivateAll() {
+void PartialManager::deactivateAll() {
 	for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
 		partialTable[i]->deactivate();
 	}
 }
 
-unsigned int PartialManager::SetReserve(char *rset) {
+unsigned int PartialManager::setReserve(Bit8u *rset) {
 	unsigned int pr = 0;
 	for (int x = 0; x < 9; x++) {
 		for (int y = 0; y < rset[x]; y++) {
-			PartialReserveTable[pr] = x;
+			partialReserveTable[pr] = x;
 			pr++;
 		}
 	}
 	return pr;
 }
 
-Partial * PartialManager::AllocPartial(int partNum) {
+Partial *PartialManager::allocPartial(int partNum) {
 	Partial *outPartial = NULL;
 
 	// Use the first inactive partial reserved for the specified part (if there are any)
@@ -87,7 +87,7 @@
 	for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
 		if (!partialTable[i]->isActive()) {
 			outPartial = partialTable[i];
-			if (PartialReserveTable[i] == partNum)
+			if (partialReserveTable[i] == partNum)
 				break;
 		}
 	}
@@ -98,7 +98,7 @@
 	return outPartial;
 }
 
-unsigned int PartialManager::GetFreePartialCount(void) {
+unsigned int PartialManager::getFreePartialCount(void) {
 	int count = 0;
 	memset(partialPart, 0, sizeof(partialPart));
 	for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
@@ -111,9 +111,9 @@
 }
 
 /*
-bool PartialManager::FreePartials(unsigned int needed, int partNum) {
+bool PartialManager::freePartials(unsigned int needed, int partNum) {
 	int i;
-	int myPartPrior = (int)mt32ram.params.system.reserveSettings[partNum];
+	int myPartPrior = (int)mt32ram.system.reserveSettings[partNum];
 	if (myPartPrior<partialPart[partNum]) {
 		//This can have more parts, must kill off those with less priority
 		int most, mostPart;
@@ -125,7 +125,7 @@
 			int diff;
 
 			for (i=0;i<9;i++) {
-				diff = partialPart[i] - (int)mt32ram.params.system.reserveSettings[i];
+				diff = partialPart[i] - (int)mt32ram.system.reserveSettings[i];
 
 				if (diff>0) {
 					if (diff>most) {
@@ -143,7 +143,7 @@
 			bool found;
 			int oldest;
 			int oldnum;
-			while (partialPart[selectPart] > (int)mt32ram.params.system.reserveSettings[selectPart]) {
+			while (partialPart[selectPart] > (int)mt32ram.system.reserveSettings[selectPart]) {
 				oldest = -1;
 				oldnum = -1;
 				found = false;
@@ -198,7 +198,7 @@
 
 }
 */
-bool PartialManager::FreePartials(unsigned int needed, int partNum) {
+bool PartialManager::freePartials(unsigned int needed, int partNum) {
 	if (needed == 0) {
 		return true;
 	}
@@ -206,7 +206,7 @@
 	// Kill those that are already decaying first
 	/*
 	for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
-		if (PartialReserveTable[i] == partNum) {
+		if (partialReserveTable[i] == partNum) {
 			if (partialTable[i]->ownerPart != partNum) {
 				if (partialTable[i]->partCache->envs[AMPENV].decaying) {
 					partialTable[i]->isActive = false;
@@ -223,10 +223,10 @@
 		int priornum = -1;
 
 		for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
-			if (PartialReserveTable[i] == partNum && partialTable[i]->isActive() && partialTable[i]->getOwnerPart() != partNum) {
+			if (partialReserveTable[i] == partNum && partialTable[i]->isActive() && partialTable[i]->getOwnerPart() != partNum) {
 				/*
-				if (mt32ram.params.system.reserveSettings[partialTable[i]->ownerPart] < prior) {
-					prior = mt32ram.params.system.reserveSettings[partialTable[i]->ownerPart];
+				if (mt32ram.system.reserveSettings[partialTable[i]->ownerPart] < prior) {
+					prior = mt32ram.system.reserveSettings[partialTable[i]->ownerPart];
 					priornum = i;
 				}*/
 				if (partialTable[i]->age > prior) {
@@ -244,17 +244,14 @@
 	}
 
 	// Kill off the oldest partials within this part
-
 	while (needed > 0) {
 		Bit64s oldest = -1;
 		Bit64s oldlist = -1;
 		for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
-			if (partialTable[i]->isActive()) {
-				if (partialTable[i]->getOwnerPart() == partNum) {
-					if (partialTable[i]->age > oldest) {
-						oldest = partialTable[i]->age;
-						oldlist = i;
-					}
+			if (partialTable[i]->getOwnerPart() == partNum && partialTable[i]->isActive()) {
+				if (partialTable[i]->age > oldest) {
+					oldest = partialTable[i]->age;
+					oldlist = i;
 				}
 			}
 		}

Index: partialManager.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/partialManager.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- partialManager.h	14 Nov 2004 04:40:12 -0000	1.2
+++ partialManager.h	28 Nov 2004 05:35:07 -0000	1.3
@@ -31,22 +31,22 @@
 	Synth *synth; // Only used for sending debug output
 
 	Partial *partialTable[MT32EMU_MAX_PARTIALS];
-	Bit32s PartialReserveTable[MT32EMU_MAX_PARTIALS];
+	Bit32s partialReserveTable[MT32EMU_MAX_PARTIALS];
 	Bit32s partialPart[9]; // The count of partials played per part
 
 public:
 	PartialManager(Synth *synth);
 	~PartialManager();
-	Partial *AllocPartial(int partNum);
-	unsigned int GetFreePartialCount(void);
-	bool FreePartials(unsigned int needed, int partNum);
-	unsigned int SetReserve(char *rset);
-	void DeactivateAll();
-	void AgeAll();
-	bool ProduceOutput(int i, Bit16s *buffer, Bit32u bufferLength);
+	Partial *allocPartial(int partNum);
+	unsigned int getFreePartialCount(void);
+	bool freePartials(unsigned int needed, int partNum);
+	unsigned int setReserve(Bit8u *rset);
+	void deactivateAll();
+	void ageAll();
+	bool produceOutput(int i, Bit16s *buffer, Bit32u bufferLength);
 	bool shouldReverb(int i);
-	void ClearAlreadyOutputed();
-	void GetPerPartPartialUsage(int usage[9]);
+	void clearAlreadyOutputed();
+	void getPerPartPartialUsage(int usage[9]);
 };
 
 }

Index: structures.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/structures.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- structures.h	14 Nov 2004 11:46:29 -0000	1.10
+++ structures.h	28 Nov 2004 05:35:07 -0000	1.11
@@ -56,92 +56,92 @@
 struct TimbreParam {
 	struct commonParam {
 		char name[10];
-		char pstruct12;  // 1&2  0-12 (1-13)
-		char pstruct34;  // #3&4  0-12 (1-13)
-		char pmute;  // 0-15 (0000-1111)
-		char nosustain; // 0-1(Normal, No sustain)
+		Bit8u pstruct12;  // 1&2  0-12 (1-13)
+		Bit8u pstruct34;  // #3&4  0-12 (1-13)
+		Bit8u pmute;  // 0-15 (0000-1111)
+		Bit8u nosustain; // 0-1(Normal, No sustain)
 	} MT32EMU_ALIGN_PACKED common;
 
 	struct partialParam {
 		struct wgParam {
-			char coarse;  // 0-96 (C1,C#1-C9)
-			char fine;  // 0-100 (-50 to +50 (cents?))
-			char keyfollow;  // 0-16 (-1,-1/2,0,1,1/8,1/4,3/8,1/2,5/8,3/4,7/8,1,5/4,3/2,2.s1,s2)
-			char bender;  // 0,1 (ON/OFF)
-			char waveform; //  0-1 (SQU/SAW)
-			char pcmwave; // 0-127 (1-128)
-			char pulsewid; // 0-100
-			char pwvelo; // 0-14 (-7 - +7)
+			Bit8u coarse;  // 0-96 (C1,C#1-C9)
+			Bit8u fine;  // 0-100 (-50 to +50 (cents?))
+			Bit8u keyfollow;  // 0-16 (-1,-1/2,0,1,1/8,1/4,3/8,1/2,5/8,3/4,7/8,1,5/4,3/2,2.s1,s2)
+			Bit8u bender;  // 0,1 (ON/OFF)
+			Bit8u waveform; //  0-1 (SQU/SAW)
+			Bit8u pcmwave; // 0-127 (1-128)
+			Bit8u pulsewid; // 0-100
+			Bit8u pwvelo; // 0-14 (-7 - +7)
 		} MT32EMU_ALIGN_PACKED wg;
 
 		struct envParam {
-			char depth; // 0-10
-			char sensitivity; // 1-100
-			char timekeyfollow; // 0-4
-			char time[4]; // 1-100
-			char level[5]; // 1-100 (-50 - +50)
+			Bit8u depth; // 0-10
+			Bit8u sensitivity; // 1-100
+			Bit8u timekeyfollow; // 0-4
+			Bit8u time[4]; // 1-100
+			Bit8u level[5]; // 1-100 (-50 - +50)
 		} MT32EMU_ALIGN_PACKED env;
 
 		struct lfoParam {
-			char rate; // 0-100
-			char depth; // 0-100
-			char modsense; // 0-100
+			Bit8u rate; // 0-100
+			Bit8u depth; // 0-100
+			Bit8u modsense; // 0-100
 		} MT32EMU_ALIGN_PACKED lfo;
 
 		struct tvfParam {
-			char cutoff; // 0-100
-			char resonance; // 0-30
-			char keyfollow; // 0-16 (-1,-1/2,1/4,0,1,1/8,1/4,3/8,1/2,5/8,3/2,7/8,1,5/4,3/2,2,s1,s2)
-			char biaspoint; // 0-127 (<1A-<7C >1A-7C)
-			char biaslevel; // 0-14 (-7 - +7)
-			char envdepth; // 0-100
-			char envsense; // 0-100
-			char envdkf; // DEPTH KEY FOLL0W 0-4
-			char envtkf; // TIME KEY FOLLOW 0-4
-			char envtime[5]; // 1-100
-			char envlevel[4]; // 1-100
+			Bit8u cutoff; // 0-100
+			Bit8u resonance; // 0-30
+			Bit8u keyfollow; // 0-16 (-1,-1/2,1/4,0,1,1/8,1/4,3/8,1/2,5/8,3/2,7/8,1,5/4,3/2,2,s1,s2)
+			Bit8u biaspoint; // 0-127 (<1A-<7C >1A-7C)
+			Bit8u biaslevel; // 0-14 (-7 - +7)
+			Bit8u envdepth; // 0-100
+			Bit8u envsense; // 0-100
+			Bit8u envdkf; // DEPTH KEY FOLL0W 0-4
+			Bit8u envtkf; // TIME KEY FOLLOW 0-4
+			Bit8u envtime[5]; // 1-100
+			Bit8u envlevel[4]; // 1-100
 		} MT32EMU_ALIGN_PACKED tvf;
 
 		struct tvaParam {
-			char level; // 0-100
-			char velosens; // 0-100
-			char biaspoint1; // 0-127 (<1A-<7C >1A-7C)
-			char biaslevel1; // 0-12 (-12 - 0)
-			char biaspoint2; // 0-127 (<1A-<7C >1A-7C)
-			char biaslevel2; // 0-12 (-12 - 0)
-			char envtkf; // TIME KEY FOLLOW 0-4
-			char envvkf; // VELOS KEY FOLL0W 0-4
-			char envtime[5]; // 1-100
-			char envlevel[4]; // 1-100
+			Bit8u level; // 0-100
+			Bit8u velosens; // 0-100
+			Bit8u biaspoint1; // 0-127 (<1A-<7C >1A-7C)
+			Bit8u biaslevel1; // 0-12 (-12 - 0)
+			Bit8u biaspoint2; // 0-127 (<1A-<7C >1A-7C)
+			Bit8u biaslevel2; // 0-12 (-12 - 0)
+			Bit8u envtkf; // TIME KEY FOLLOW 0-4
+			Bit8u envvkf; // VELOS KEY FOLL0W 0-4
+			Bit8u envtime[5]; // 1-100
+			Bit8u envlevel[4]; // 1-100
 		} MT32EMU_ALIGN_PACKED tva;
 	} MT32EMU_ALIGN_PACKED partial[4];
 } MT32EMU_ALIGN_PACKED;
 
 struct PatchParam {
-	char timbreGroup; // TIMBRE GROUP  0-3 (group A, group B, Memory, Rhythm)
-	char timbreNum; // TIMBRE NUMBER 0-63
-	char keyShift; // KEY SHIFT 0-48 (-24 - +24 semitones)
-	char fineTune; // FINE TUNE 0-100 (-50 - +50 cents)
-	char benderRange; // BENDER RANGE 0-24
-	char assignMode;  // ASSIGN MODE 0-3 (POLY1, POLY2, POLY3, POLY4)
-	char reverbSwitch;  // REVERB SWITCH 0-1 (OFF,ON)
-	char dummy; // (DUMMY)
+	Bit8u timbreGroup; // TIMBRE GROUP  0-3 (group A, group B, Memory, Rhythm)
+	Bit8u timbreNum; // TIMBRE NUMBER 0-63
+	Bit8u keyShift; // KEY SHIFT 0-48 (-24 - +24 semitones)
+	Bit8u fineTune; // FINE TUNE 0-100 (-50 - +50 cents)
+	Bit8u benderRange; // BENDER RANGE 0-24
+	Bit8u assignMode;  // ASSIGN MODE 0-3 (POLY1, POLY2, POLY3, POLY4)
+	Bit8u reverbSwitch;  // REVERB SWITCH 0-1 (OFF,ON)
+	Bit8u dummy; // (DUMMY)
 } MT32EMU_ALIGN_PACKED;
 
 struct MemParams {
 	struct PatchTemp {
 		PatchParam patch;
-		char outlevel; // OUTPUT LEVEL 0-100
-		char panpot; // PANPOT 0-14 (R-L)
-		char dummyv[6];
+		Bit8u outlevel; // OUTPUT LEVEL 0-100
+		Bit8u panpot; // PANPOT 0-14 (R-L)
+		Bit8u dummyv[6];
 	} MT32EMU_ALIGN_PACKED patchSettings[8];
 
 	struct RhythmTemp {
-		char timbre; // TIMBRE  0-94 (M1-M64,R1-30,OFF)
-		char outlevel; // OUTPUT LEVEL 0-100
-		char panpot; // PANPOT 0-14 (R-L)
-		char reverbSwitch;  // REVERB SWITCH 0-1 (OFF,ON)
-	} MT32EMU_ALIGN_PACKED rhythmSettings[64];
+		Bit8u timbre; // TIMBRE  0-94 (M1-M64,R1-30,OFF)
+		Bit8u outlevel; // OUTPUT LEVEL 0-100
+		Bit8u panpot; // PANPOT 0-14 (R-L)
+		Bit8u reverbSwitch;  // REVERB SWITCH 0-1 (OFF,ON)
+	} MT32EMU_ALIGN_PACKED rhythmSettings[86]; // FIXME: Was 64, but let's support the next model...
 
 	TimbreParam MT32EMU_ALIGN_PACKED timbreSettings[8];
 
@@ -149,58 +149,43 @@
 
 	struct PaddedTimbre {
 		TimbreParam timbre;
-		char padding[10];
+		Bit8u padding[10];
 	} MT32EMU_ALIGN_PACKED timbres[64 + 64 + 64 + 30]; // Group A, Group B, Memory, Rhythm
 
 	struct SystemArea {
-		char masterTune; // MASTER TUNE 0-127 432.1-457.6Hz
-		char reverbMode; // REVERB MODE 0-3 (room, hall, plate, tap delay)
-		char reverbTime; // REVERB TIME 0-7 (1-8)
-		char reverbLevel; // REVERB LEVEL 0-7 (1-8)
-		char reserveSettings[9]; // PARTIAL RESERVE (PART 1) 0-32
-		char chanAssign[9]; // MIDI CHANNEL (PART1) 0-16 (1-16,OFF)
-		char masterVol; // MASTER VOLUME 0-100
+		Bit8u masterTune; // MASTER TUNE 0-127 432.1-457.6Hz
+		Bit8u reverbMode; // REVERB MODE 0-3 (room, hall, plate, tap delay)
+		Bit8u reverbTime; // REVERB TIME 0-7 (1-8)
+		Bit8u reverbLevel; // REVERB LEVEL 0-7 (1-8)
+		Bit8u reserveSettings[9]; // PARTIAL RESERVE (PART 1) 0-32
+		Bit8u chanAssign[9]; // MIDI CHANNEL (PART1) 0-16 (1-16,OFF)
+		Bit8u masterVol; // MASTER VOLUME 0-100
 	} MT32EMU_ALIGN_PACKED system;
 };
 
 struct MemBanks {
-	char pTemp[8][sizeof(MemParams::PatchTemp)];
-	char rTemp[64][sizeof(MemParams::RhythmTemp)];
-	char tTemp[8][sizeof(TimbreParam)];
-	char patchBank[128][sizeof(PatchParam)];
-	char timbreBank[64 + 64 + 64 + 30][sizeof(MemParams::PaddedTimbre)];
-	char systemBank[sizeof(MemParams::SystemArea)];
+	Bit8u pTemp[8][sizeof(MemParams::PatchTemp)];
+	Bit8u rTemp[86][sizeof(MemParams::RhythmTemp)];
+	Bit8u tTemp[8][sizeof(TimbreParam)];
+	Bit8u patchBank[128][sizeof(PatchParam)];
+	Bit8u timbreBank[64 + 64 + 64 + 30][sizeof(MemParams::PaddedTimbre)];
+	Bit8u systemBank[sizeof(MemParams::SystemArea)];
 	// System memory 0x100000
 	// Display 0x200000
 	// Reset 0x7F0000
 };
 
-union MT32RAMFormat {
-	MemParams params;
-	MemBanks banks;
-} MT32EMU_ALIGN_PACKED;
-
 #if defined(_MSC_VER) || defined (__MINGW32__)
 #pragma pack(pop)
 #else
 #pragma pack()
 #endif
 
-struct PCMWave {
-	char name[16];
-	Bit32u addr;
-	Bit32u len;
-	bool loop;
-	float tune;
-	Bit32s ampval;
-};
-
 struct PCMWaveEntry {
 	Bit32u addr;
 	Bit32u len;
-	Bit32u pcmnum;
+	double tune;
 	bool loop;
-	Bit32s aggSound; // This variable is for the last 9 PCM samples, which are actually loop combinations
 };
 
 struct soundaddr {
@@ -221,17 +206,15 @@
 	char waveform;
 	int pulsewidth;
 	int pwsens;
-	int pitchshift;
-	int fineshift;
+
+	float pitch;
 
 	int lfodepth;
 	int lforate;
 	Bit32u lfoperiod;
 	int modsense;
 
-	int keydir;
-	int pitchkeyfollow;
-	int pitchkeydir;
+	float pitchKeyfollow;
 
 	int filtkeyfollow;
 
@@ -264,8 +247,12 @@
 	int structurePair;
 
 	// The following fields are actually common to all partials in the timbre
+	bool dirty;
 	Bit32u partialCount;
 	bool sustain;
+	float pitchShift;
+	bool reverb;
+	const StereoVolume *pansetptr;
 };
 
 class Partial; // Forward reference for class defined in partial.h
@@ -277,19 +264,17 @@
 	int freqnum;
 	int vel;
 
-	bool reverb;
 	bool isDecay;
 
-	const Bit32s *volumeptr;
-	const StereoVolume *pansetptr;
+	const Bit32u *volumeptr;
 
 	Partial *partials[4];
 
 	bool pedalhold; // This marks keys that have been released on the keyboard, but are being held by the pedal
 	bool sustain;
 
-	bool isActive();
-	Bit64s getAge();
+	bool isActive() const;
+	Bit64s getAge() const;
 };
 
 }

Index: synth.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/synth.cpp,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- synth.cpp	15 Nov 2004 23:33:06 -0000	1.23
+++ synth.cpp	28 Nov 2004 05:35:07 -0000	1.24
@@ -26,20 +26,10 @@
 
 #include "mt32emu.h"
 
-#if MT32EMU_BENCHMARK_FILTERS > 0
-#include <time.h>
-#endif
-
 namespace MT32Emu {
 
 const int MAX_SYSEX_SIZE = 512;
 
[...1128 lines suppressed...]
-					ProduceOutput1(&tmpBuffer[0], stream, len, mastervolume);
+				if (partialManager->produceOutput(i, &tmpBuffer[0], len)) {
+					ProduceOutput1(&tmpBuffer[0], stream, len, masterVolume);
 				}
 			}
 		}
 	} else {
 		for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
-			if (partialManager->ProduceOutput(i, &tmpBuffer[0], len))
-				ProduceOutput1(&tmpBuffer[0], stream, len, mastervolume);
+			if (partialManager->produceOutput(i, &tmpBuffer[0], len))
+				ProduceOutput1(&tmpBuffer[0], stream, len, masterVolume);
 		}
 	}
 
-	partialManager->ClearAlreadyOutputed();
+	partialManager->clearAlreadyOutputed();
 
 #if MT32EMU_MONITOR_PARTIALS == 1
 	samplepos += len;

Index: synth.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/synth.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- synth.h	15 Nov 2004 23:33:06 -0000	1.9
+++ synth.h	28 Nov 2004 05:35:07 -0000	1.10
@@ -39,27 +39,27 @@
 class Part;
 
 enum ReportType {
-	// Files missing
-	ReportType_errorPreset1    = 1,
-	ReportType_errorPreset2    = 2,
-	ReportType_errorDrumpat    = 3,
-	ReportType_errorPatchlog   = 4,
-	ReportType_errorMT32ROM    = 5,
-	ReportType_errorSampleRate = 6,
+	// Errors
+	ReportType_errorControlROM = 1,
+	ReportType_errorPCMROM,
+	ReportType_errorSampleRate,
+
+	// Progress
+	ReportType_progressInit,
 
 	// HW spec
-	ReportType_availableSSE    = 7,
-	ReportType_available3DNow  = 8,
-	ReportType_usingSSE        = 9,
-	ReportType_using3DNow      = 10,
+	ReportType_availableSSE,
+	ReportType_available3DNow,
+	ReportType_usingSSE,
+	ReportType_using3DNow,
 
 	// General info
-	ReportType_lcdMessage      = 11,
-	ReportType_devReset        = 12,
-	ReportType_devReconfig     = 13,
-	ReportType_newReverbMode   = 14,
-	ReportType_newReverbTime   = 15,
-	ReportType_newReverbLevel  = 16
+	ReportType_lcdMessage,
+	ReportType_devReset,
+	ReportType_devReconfig,
+	ReportType_newReverbMode,
+	ReportType_newReverbTime,
+	ReportType_newReverbLevel
 };
 
 struct SynthProperties {
@@ -84,7 +84,7 @@
 	// This is used as the first argument to all callbacks
 	void *userData;
 	// Callback for reporting various errors and information. May be NULL
-	void (*report)(void *userData, ReportType type, const void *reportData);
+	int (*report)(void *userData, ReportType type, const void *reportData);
 	// Callback for debug messages, in vprintf() format
 	void (*printDebug)(void *userData, const char *fmt, va_list list);
 	// Callback for providing an implementation of File, opened and ready for use
@@ -105,19 +105,20 @@
 bool RecalcWaveforms(char * baseDir, int sampRate, recalcStatusCallback callBack);
 
 typedef float (*iir_filter_type)(float input,float *hist1_ptr, float *coef_ptr, int revLevel);
-extern iir_filter_type usefilter;
 
 class Synth {
 friend class Part;
+friend class RhythmPart;
 friend class Partial;
 friend class TableInitialiser;
 private:
 	bool isEnabled;
 
-	PCMWave PCM[54];
+	iir_filter_type iirFilter;
+
 	PCMWaveEntry PCMList[128];
-	Bit32s PCMLoopTable[54];
 
+	Bit8u controlROMData[64 * 1024];
 	Bit16s romfile[PCMSIZE + GRAN];
 	Bit8s chantable[32];
 
@@ -125,15 +126,12 @@
 	static Bit32s samplepos = 0;
 	#endif
 
-	MT32RAMFormat mt32ram, mt32default;
+	MemParams mt32ram, mt32default;
 
 	revmodel *reverbModel;
 
-	Bit16s mastervolume;
-
-	char curRevMode;
-	char curRevTime;
-	Bit32u curRevLevel;
+	float masterTune;
+	Bit16u masterVolume;
 
 	unsigned char initmode;
 	bool isOpen;
@@ -150,25 +148,30 @@
 	SynthProperties myProp;
 
 	bool loadPreset(const char *filename);
-	void initReverb(char newRevMode, char newRevTime);
+	void initReverb(Bit8u newRevMode, Bit8u newRevTime, Bit8u newRevLevel);
 	void doRender(Bit16s * stream, Bit32u len);
 	void playMsgOnPart(unsigned char part, unsigned char code, unsigned char note, unsigned char velocity);
-	void playSysexWithoutHeader(unsigned char channel, Bit8u *sysex, Bit32u len);
+	void playSysexWithoutHeader(unsigned char channel, const Bit8u *sysex, Bit32u len);
 
-	bool loadDrums(const char *filename);
-	bool loadPCMToROMMap(const char *filename);
-	bool loadROM(const char *filename);
-	void dumpDrums(const char *filename);
-	// Save the system state to a sysex file specified by filename
-	int dumpSysex(char *filename);
+	bool loadControlROM(const char *filename);
+	bool loadPCMROM(const char *filename);
+	bool dumpTimbre(File *file, const TimbreParam *timbre, Bit32u addr);
+	int dumpTimbres(const char *filename, int start, int len);
 
+	void initPCMList();
+	void initRhythmTimbres();
+	void initTimbres(Bit16u mapAddress, int startTimbre);
+	void initRhythmTimbre(int drumNum, const Bit8u *mem);
+	bool refreshSystem();
 protected:
-	void report(ReportType type, const void *reportData);
+	int report(ReportType type, const void *reportData);
 	File *openFile(const char *filename, File::OpenMode mode);
 	void closeFile(File *file);
 	void printDebug(const char *fmt, ...);
 
 public:
+	static Bit8u calcSysexChecksum(const Bit8u *data, Bit32u len, Bit8u checksum);
+
 	Synth();
 	~Synth();
 
@@ -182,11 +185,10 @@
 	// Sends a 4-byte MIDI message to the MT-32 for immediate playback
 	void playMsg(Bit32u msg);
 
-	static Bit8u calcSysexChecksum(Bit8u *data, Bit32u len, Bit8u checksum);
 	// Sends a string of Sysex commands to the MT-32 for immediate interpretation
 	// The length is in bytes
-	void playSysex(Bit8u *sysex, Bit32u len);
-	void playSysexWithoutFraming(Bit8u *sysex, Bit32u len);
+	void playSysex(const Bit8u *sysex, Bit32u len);
+	void playSysexWithoutFraming(const Bit8u *sysex, Bit32u len);
 
 	// This callback routine is used to have the MT-32 generate samples to the specified
 	// output stream.  The length is in whole samples, not bytes. (I.E. in 16-bit stereo,

Index: tables.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/tables.cpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- tables.cpp	14 Nov 2004 08:04:56 -0000	1.3
+++ tables.cpp	28 Nov 2004 05:35:07 -0000	1.4
@@ -25,36 +25,14 @@
 
 #include "mt32emu.h"
 
+#define FIXEDPOINT_MAKE(x, point) ((Bit32u)((1 << point) * x))
+
 namespace MT32Emu {
 
 //Amplitude time velocity follow exponential coefficients
 const double tvcatconst[5] = {0.0, 0.002791309, 0.005942882, 0.012652792, 0.026938637};
 const double tvcatmult[5] = {1.0, 1.072662811, 1.169129367, 1.288579123, 1.229630539};
 
-const Bit8s LoopPatterns[9][10] = {
-	{ 2,  3, 4,   5,  6,  7, -1, -1, -1, -1},
-	{ 8,  9, 10, 11, 12, 13, 14, 15, 16, -1},
-	{17, 18, 19, 20, 21, -1, -1, -1, -1, -1},
-	{22, 23, 24, 25, 26, 27, 28, 29, -1, -1},
-	{30, 31, 32, 33, 34, 35, 36, 37, -1, -1},
-	{45, 46, 47, 48, 49, 50, 51, 52, 53, -1},
-	{15, 11, 12, 13, 14, 15, 16, -1, -1, -1},
-	{30, 35, 32, 33, 34, -1, -1, -1, -1, -1},
-	{ 2,  3, -1, -1, -1, -1, -1, -1, -1, -1},
-};
-
-static const Bit32s LoopPatternTuning[9][10] = {
-	{0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A,      -1,      -1,      -1,      -1},
-	{0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A,      -1},
-	{0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A,      -1,      -1,      -1,      -1,      -1},
-	{0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A,      -1,      -1},
-	{0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A,      -1,      -1},
-	{0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A,      -1},
-	{0x2590B, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A,      -1,      -1,      -1},
-	{0x1294A, 0x1294A, 0x1294A, 0x1294A, 0x1294A,      -1,      -1,      -1,      -1,      -1},
-	{0x1294A, 0x1294A,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1},
-};
-
 // These are division constants for the TVF depth key follow
 static const Bit32u depexp[5] = {3000, 950, 485, 255, 138};
 
@@ -63,6 +41,7 @@
 static const double tkcatmult[5] = {1.0, 1.058245688, 1.048488989, 1.016049301, 1.097538067};
 
 static float initialisedSampleRate = 0.0f;
+static float initialisedMasterTune = 0.0f;
 
 Bit16s smallnoise[MAX_SAMPLE_OUTPUT];
 
@@ -215,7 +194,7 @@
 		//lasttimetable[lf] = (int)((exp(logtime)/(312.12*6)) * (float)samplerate);
 
 		float mv = (float)lf / 100.0f;
-		float pt = mv-0.5f;
+		float pt = mv - 0.5f;
 		if (pt < 0)
 			pt = 0;
 
@@ -319,7 +298,7 @@
 
 	for (lf = 0; lf < 128; lf++) {
 		// Converts MIDI velocity to volume.
-		voltable[lf] = (int)(127.0f * powf((float)lf / 127.0f, FLOAT_LN));
+		voltable[lf] = FIXEDPOINT_MAKE(powf((float)lf / 127.0f, FLOAT_LN), 7);
 	}
 	for (unsigned int i = 0; i < MAX_SAMPLE_OUTPUT; i++) {
 		int myRand;
@@ -523,7 +502,7 @@
 
 #if 0
 			//FIXME:KG: Credit Timo Strunk (bastardo on #scummvm) for help with this!
-			float saw = 0.5f * FLOAT_PI - sa / 2;
+			double saw = 0.5 * DOUBLE_PI - sa / 2;
 #else
 			double saw = 0.0;
 			for (int sinus = 1; sinus < div; sinus++) {
@@ -581,12 +560,15 @@
 	}
 }
 
-File *TableInitialiser::initNote(Synth *synth, NoteLookup *noteLookup, float note, float rate, float tuning, PCMWave pcmWaves[54], File *file) {
+File *TableInitialiser::initNote(Synth *synth, NoteLookup *noteLookup, float note, float rate, float masterTune, PCMWaveEntry pcmWaves[128], File *file) {
 	float ampsize = WGAMP;
-	float freq = (float)(tuning * pow(2.0, ((double)note - MIDDLEA) / 12.0));
+	float freq = (float)(masterTune * pow(2.0, ((double)note - MIDDLEA) / 12.0));
 	float div = rate / freq;
 	noteLookup->div = (int)div;
 
+	if (noteLookup->div == 0)
+		noteLookup->div = 1;
+
 	initSaw(noteLookup, noteLookup->div);
 	initDep(noteLookup, note);
 
@@ -595,18 +577,10 @@
 
 	// 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));
-		}
+	double rateMult = 32000.0 / rate;
+	double tuner = freq * 65536.0f;
+	for (int pc = 0; pc < 128; pc++) {
+		noteLookup->wavTable[pc] = (int)(tuner / pcmWaves[pc].tune * rateMult);
 	}
 
 	initFiltTable(noteLookup, freq, rate);
@@ -614,11 +588,14 @@
 	return file;
 }
 
-void TableInitialiser::initNotes(Synth *synth, PCMWave pcmWaves[54], float rate, float tuning) {
+bool TableInitialiser::initNotes(Synth *synth, PCMWaveEntry pcmWaves[128], float rate, float masterTune) {
+	const char *NoteNames[12] = {
+		"C ", "C#", "D ", "D#", "E ", "F ", "F#", "G ", "G#", "A ", "A#", "B "
+	};
 	char filename[64];
 	int intRate = (int)rate;
-	char version[4] = {0, 0, 0, 1};
-	sprintf(filename, "waveformcache-%d-%.1f.raw", intRate, tuning);
+	char version[4] = {0, 0, 0, 2};
+	sprintf(filename, "waveformcache-%d-%.2f.raw", intRate, masterTune);
 
 	File *file = NULL;
 	char header[20];
@@ -631,11 +608,11 @@
 	header[pos++] = (char)((intRate >> 16) & 0xFF);
 	header[pos++] = (char)((intRate >> 8) & 0xFF);
 	header[pos++] = (char)(intRate & 0xFF);
-	int intTuning = (int)tuning;
+	int intTuning = (int)masterTune;
 	header[pos++] = (char)((intTuning >> 8) & 0xFF);
 	header[pos++] = (char)(intTuning & 0xFF);
 	header[pos++] = 0;
-	header[pos] = (char)((tuning - intTuning) * 10);
+	header[pos] = (char)((masterTune - intTuning) * 10);
 #if MT32EMU_WAVECACHEMODE < 2
 	bool reading = false;
 	file = synth->openFile(filename, File::OpenMode_read);
@@ -648,33 +625,37 @@
 					if (endianCheck == 1) {
 						reading = true;
 					} else {
-						synth->printDebug("Endian check in %s does not match expected - will generate", filename);
+						synth->printDebug("Endian check in %s does not match expected", filename);
 					}
 				} else {
-					synth->printDebug("Unable to read endian check in %s - will generate", filename);
+					synth->printDebug("Unable to read endian check in %s", filename);
 				}
 			} else {
-				synth->printDebug("Header of %s does not match expected - will generate", filename);
+				synth->printDebug("Header of %s does not match expected", filename);
 			}
 		} else {
-			synth->printDebug("Error reading 16 bytes of %s - will generate", filename);
+			synth->printDebug("Error reading 16 bytes of %s", filename);
 		}
 		if (!reading) {
 			file->close();
 			file = NULL;
 		}
 	} else {
-		synth->printDebug("Unable to open %s for reading - will generate", filename);
+		synth->printDebug("Unable to open %s for reading", 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);
+	float progress = 0.0f;
+	bool abort = false;
+	synth->report(ReportType_progressInit, &progress);
+	for (int f = LOWEST_NOTE; f <= HIGHEST_NOTE; f++) {
+		synth->printDebug("Initialising note %s%d", NoteNames[f % 12], (f / 12) - 1);
+		NoteLookup *noteLookup = &noteLookups[f - LOWEST_NOTE];
+		file = initNote(synth, noteLookup, (float)f, rate, masterTune, pcmWaves, file);
+		progress = (f - LOWEST_NOTE + 1) / (float)NUM_NOTES;
+		abort = synth->report(ReportType_progressInit, &progress) != 0;
+		if (abort)
+			break;
 	}
 
 #if MT32EMU_WAVECACHEMODE == 0 || MT32EMU_WAVECACHEMODE == 2
@@ -682,7 +663,7 @@
 		file = synth->openFile(filename, File::OpenMode_write);
 		if (file != NULL) {
 			if (file->write(header, 16) == 16 && file->writeBit16u(1)) {
-				for (int f = 12; f < 109 && file != NULL; f++) {
+				for (int f = 0; f < NUM_NOTES; f++) {
 					for (int i = 0; i < 3 && file != NULL; i++) {
 						int len = noteLookups[f].waveformSize[i];
 						for (int j = 0; j < len; j++) {
@@ -706,21 +687,42 @@
 
 	if (file != NULL)
 		synth->closeFile(file);
+	return !abort;
 }
 
-bool TableInitialiser::initMT32Tables(Synth *synth, PCMWave pcms[54], float sampleRate) {
+void TableInitialiser::freeNotes() {
+	for (int t = 0; t < 3; t++) {
+		for (int m = 0; m < NUM_NOTES; m++) {
+			if (noteLookups[m].waveforms[t] != NULL) {
+				delete[] noteLookups[m].waveforms[t];
+				noteLookups[m].waveforms[t] = NULL;
+				noteLookups[m].waveformSize[t] = 0;
+			}
+		}
+	}
+	initialisedMasterTune = 0.0f;
+}
+
+bool TableInitialiser::initMT32Tables(Synth *synth, PCMWaveEntry pcmWaves[128], float sampleRate, float masterTune) {
 	if (sampleRate <= 0.0f) {
 		synth->printDebug("Bad sampleRate (%d <= 0.0f)", sampleRate);
 		return false;
 	}
 	if (initialisedSampleRate == 0.0f) {
 		initMT32ConstantTables(synth);
+	}
+	if (initialisedSampleRate != sampleRate) {
 		initFiltCoeff(sampleRate);
 		initEnvelopes(sampleRate);
+	}
+	if (initialisedSampleRate != sampleRate || initialisedMasterTune != masterTune) {
+		freeNotes();
+		if (!initNotes(synth, pcmWaves, sampleRate, masterTune)) {
+			return false;
+		}
 		initialisedSampleRate = sampleRate;
+		initialisedMasterTune = masterTune;
 	}
-	// This always needs to be done, to allocate the waveforms
-	initNotes(synth, pcms, sampleRate, TUNING);
 	return true;
 }
 

Index: tables.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/midi/mt32/tables.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- tables.h	14 Nov 2004 08:04:56 -0000	1.3
+++ tables.h	28 Nov 2004 05:35:07 -0000	1.4
@@ -36,21 +36,19 @@
 const int MIDDLEC = 60;
 const int MIDDLEA = 69; // By this I mean "A above middle C"
 
-// Constant tuning for now. The manual claims "Standard pitch" is 442.0.
-// I assume they mean this is the MT-32 default pitch, and not concert pitch,
-// since the latter has been internationally defined as 440Hz for decades.
-// 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; // Number of slots for note LUT (we actually only use 12..108)
+//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?
+const int LOWEST_NOTE = 12;
+const int HIGHEST_NOTE = 127;
+const int NUM_NOTES = HIGHEST_NOTE - LOWEST_NOTE + 1; // Number of slots for note LUT
 
 // Amplitude of waveform generator
 const int WGAMP = 7168; // 8192?
 
 class Synth;
 
-extern const Bit8s LoopPatterns[9][10];
-
 extern Bit16s smallnoise[MAX_SAMPLE_OUTPUT];
 
 // Some optimization stuff
@@ -75,9 +73,8 @@
 extern float ResonInv[31];
 
 struct NoteLookup {
-	Bit32s div;
-	Bit32u wavTable[54];
-	Bit32u loopTable[9][10];
+	Bit32u div;
+	Bit32u wavTable[128];
 	Bit32s sawTable[101];
 	Bit32s fildepTable[5];
 	Bit32s timekeyTable[5];
@@ -92,10 +89,11 @@
 class TableInitialiser {
 	static void initMT32ConstantTables(Synth *synth);
 	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);
+	static bool initNotes(Synth *synth, PCMWaveEntry pcmWaves[128], 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);
+	static bool initMT32Tables(Synth *synth, PCMWaveEntry pcmWaves[128], float sampleRate, float masterTune);
+	static File *initNote(Synth *synth, NoteLookup *noteLookup, float note, float rate, float tuning, PCMWaveEntry pcmWaves[128], File *file);
+	static void freeNotes();
 };
 
 }





More information about the Scummvm-git-logs mailing list