[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(¤tInstr, 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 = ¬eLookups[noteVal];
-
- // FIXME:KG: I think most places should refer to noteVal/noteLookup instead of these.
- keyVal = poly->freqnum;
- keyLookup = ¬eLookups[poly->freqnum];
+#if MT32EMU_ACCURATENOTES == 0
+ noteLookup = ¬eLookups[noteVal - LOWEST_NOTE];
+#else
+ TableInitialiser::initNote(synth, ¬eLookupStorage, 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 = ¬eLookups[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 = ¬eLookups[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