aboutsummaryrefslogtreecommitdiff
path: root/backends/midi/mt32
diff options
context:
space:
mode:
authorJerome Fisher2004-11-14 04:13:15 +0000
committerJerome Fisher2004-11-14 04:13:15 +0000
commit1aeca6838b1ba5405674d0f5e38174fe6dedd138 (patch)
tree29452d977920959157474f6902c12d456b96c83a /backends/midi/mt32
parent5e442766e533339c1e2f3389a2859601c6ab1127 (diff)
downloadscummvm-rg350-1aeca6838b1ba5405674d0f5e38174fe6dedd138.tar.gz
scummvm-rg350-1aeca6838b1ba5405674d0f5e38174fe6dedd138.tar.bz2
scummvm-rg350-1aeca6838b1ba5405674d0f5e38174fe6dedd138.zip
MT32 MidiDriver:
- Cleanup MT32Emu: - Lots more cleanup. - Properly implemented pitch bending (not fast, but theoretically perfect). - Full position delta is now calculated before PCM interpolation/decimation is performed, so that pitch modifiers will be considered. - Now reports when using SSE or 3DNow, and when the samplerate is invalid. svn-id: r15801
Diffstat (limited to 'backends/midi/mt32')
-rw-r--r--backends/midi/mt32/i386.cpp4
-rw-r--r--backends/midi/mt32/i386.h4
-rw-r--r--backends/midi/mt32/mt32emu.h36
-rw-r--r--backends/midi/mt32/part.cpp159
-rw-r--r--backends/midi/mt32/part.h44
-rw-r--r--backends/midi/mt32/partial.cpp175
-rw-r--r--backends/midi/mt32/partial.h16
-rw-r--r--backends/midi/mt32/structures.h28
-rw-r--r--backends/midi/mt32/synth.cpp118
-rw-r--r--backends/midi/mt32/synth.h53
-rw-r--r--backends/midi/mt32/tables.cpp70
-rw-r--r--backends/midi/mt32/tables.h64
12 files changed, 413 insertions, 358 deletions
diff --git a/backends/midi/mt32/i386.cpp b/backends/midi/mt32/i386.cpp
index 9bc5bcb4c5..e2e4b0f790 100644
--- a/backends/midi/mt32/i386.cpp
+++ b/backends/midi/mt32/i386.cpp
@@ -21,7 +21,7 @@
#include "mt32emu.h"
-#ifdef HAVE_X86
+#ifdef MT32EMU_HAVE_X86
namespace MT32Emu {
@@ -628,7 +628,7 @@ float iir_filter_3dnow(float input,float *hist1_ptr, float *coef_ptr, int revLev
return output;
}
-#if USE_MMX > 0
+#if MT32EMU_USE_MMX > 0
int i386_partialProductOutput(int len, Bit16s leftvol, Bit16s rightvol, Bit16s *partialBuf, Bit16s *mixedBuf) {
int tmplen = len >> 1;
diff --git a/backends/midi/mt32/i386.h b/backends/midi/mt32/i386.h
index 544a7bf6da..c26fcb4110 100644
--- a/backends/midi/mt32/i386.h
+++ b/backends/midi/mt32/i386.h
@@ -23,7 +23,7 @@
#define MT32EMU_I386_H
namespace MT32Emu {
-#ifdef HAVE_X86
+#ifdef MT32EMU_HAVE_X86
// Function that detects the availablity of SSE SIMD instructions
bool DetectSIMD();
@@ -34,7 +34,7 @@ float iir_filter_sse(float input,float *hist1_ptr, float *coef_ptr, int revLevel
float iir_filter_3dnow(float input,float *hist1_ptr, float *coef_ptr, int revLevel);
float iir_filter_normal(float input,float *hist1_ptr, float *coef_ptr, int revLevel);
-#if USE_MMX > 0
+#if MT32EMU_USE_MMX > 0
int i386_partialProductOutput(int len, Bit16s leftvol, Bit16s rightvol, Bit16s *partialBuf, Bit16s *mixedBuf);
int i386_mixBuffers(Bit16s * buf1, Bit16s *buf2, int len);
int i386_mixBuffersRingMix(Bit16s * buf1, Bit16s *buf2, int len);
diff --git a/backends/midi/mt32/mt32emu.h b/backends/midi/mt32/mt32emu.h
index c31afee389..bf4648c905 100644
--- a/backends/midi/mt32/mt32emu.h
+++ b/backends/midi/mt32/mt32emu.h
@@ -22,15 +22,49 @@
#ifndef MT32EMU_MT32EMU_H
#define MT32EMU_MT32EMU_H
+// Debugging
+// Show the instruments played
+#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_DRUMP_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
+//#define MT32EMU_WAVECACHEMODE 2 // Ignore existing cache, generate and save cache
+//#define MT32EMU_WAVECACHEMODE 3 // Ignore existing cache, generate but don't save cache
+
+// Configuration
+// The maximum number of partials playing simultaneously
+#define MT32EMU_MAX_PARTIALS 32
+// The maximum number of notes playing simultaneously per part.
+// No point making it more than MT32EMU_MAX_PARTIALS, since each note needs at least one partial.
+#define MT32EMU_MAX_POLY 32
+// This calculates the exact frequencies of notes as they are played, instead of offsetting from pre-cached semitones. Potentially very slow.
+#define MT32EMU_ACCURATENOTES 0
+
+#if (defined (_MSC_VER) && defined(_M_IX86)) || (defined(__GNUC__) && defined(__i386__))
+#define MT32EMU_HAVE_X86
+#endif
+
+#ifdef MT32EMU_HAVE_X86
+#define MT32EMU_USE_MMX 1
+#else
+#define MT32EMU_USE_MMX 0
+#endif
+
#include "freeverb.h"
#include "structures.h"
#include "i386.h"
#include "mt32_file.h"
+#include "tables.h"
#include "partial.h"
#include "partialManager.h"
#include "part.h"
-#include "tables.h"
#include "synth.h"
#endif
diff --git a/backends/midi/mt32/part.cpp b/backends/midi/mt32/part.cpp
index cfb40f3d50..bc5f7d8939 100644
--- a/backends/midi/mt32/part.cpp
+++ b/backends/midi/mt32/part.cpp
@@ -24,10 +24,6 @@
#include "mt32emu.h"
-// Debugging stuff
-// Shows the instruments played
-#define DISPLAYINSTR 1
-
namespace MT32Emu {
static const Bit8u PartialStruct[13] = {
@@ -38,12 +34,9 @@ static const Bit8u PartialMixStruct[13] = {
0, 1, 0, 1, 1, 0,
1, 3, 3, 2, 2, 2, 2 };
-static const Bit32u drumBend = 0x1000;
-
// This caches the timbres/settings in use by the rhythm part
static PatchCache drumCache[94][4];
-
-static volset drumPan[64];
+static StereoVolume drumPan[64];
//FIXME:KG: Put this dpoly stuff somewhere better
bool dpoly::isActive() {
@@ -76,39 +69,49 @@ Part::Part(Synth *useSynth, int usePartNum) {
rhythmTemp = NULL;
}
currentInstr[0] = 0;
+ currentInstr[10] = 0;
volume = 102;
volumesetting.leftvol = 32767;
volumesetting.rightvol = 32767;
- bend = 0x1000;
+ bend = 0.0f;
memset(polyTable,0,sizeof(polyTable));
memset(patchCache, 0, sizeof(patchCache));
if (isRhythm) {
init = true;
- RefreshDrumCache();
+ refreshDrumCache();
}
init = false;
}
-void Part::SetHoldPedal(bool pedalval) {
+void Part::setHoldPedal(bool pedalval) {
if (holdpedal && !pedalval)
- StopPedalHold();
+ stopPedalHold();
holdpedal = pedalval;
}
-void Part::SetBend(int vol) {
+void Part::setBend(int midiBend) {
if (isRhythm) {
- synth->printDebug("%s: Setting bend (%d) not supported on rhythm", name, vol);
+ synth->printDebug("%s: Setting bend (%d) not supported on rhythm", name, midiBend);
return;
}
- //int tmpbend = ((vol - 0x2000) * (int)patchTemp->patch.benderRange) >> 13;
- //bend = bendtable[tmpbend+24];
-
- float bend_range = (float)patchTemp->patch.benderRange / 24;
- bend = (Bit32u)(4096 + (vol - 8192) * bend_range);
+ // FIXME:KG: Slightly uneven increments, but I wanted min -1.0, centre 0.0 and max 1.0
+ if (midiBend <= 0x2000) {
+ bend = (midiBend - 0x2000) / (float)0x2000;
+ } else {
+ bend = (midiBend - 0x2000) / (float)0x1FFF;
+ }
+ // Loop through all partials to update their bend
+ for (int i = 0; i < MT32EMU_MAX_POLY; i++) {
+ for (int j = 0; j < 4; j++) {
+ if (polyTable[i].partials[j] != NULL) {
+ polyTable[i].partials[j]->setBend(bend);
+ }
+ }
+ }
}
-void Part::SetModulation(int vol) {
+void Part::setModulation(int vol) {
if (isRhythm) {
synth->printDebug("%s: Setting modulation (%d) not supported on rhythm", name, vol);
return;
@@ -124,7 +127,7 @@ void Part::SetModulation(int vol) {
}
}
-void Part::RefreshDrumCache() {
+void Part::refreshDrumCache() {
if (!isRhythm) {
synth->printDebug("ERROR: RefreshDrumCache() called on non-rhythm part");
}
@@ -133,7 +136,7 @@ void Part::RefreshDrumCache() {
int drumTimbre = rhythmTemp[m].timbre;
if (drumTimbre >= 94)
continue;
- SetPatch(drumTimbre + 128); // This is to cache all the mapped drum timbres ahead of time
+ 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...
// FIXME:KG: If I don't have left/right mixed up here, it's pure luck
if (pan < 7) {
@@ -146,7 +149,7 @@ void Part::RefreshDrumCache() {
}
}
-int Part::FixBiaslevel(int srcpnt, int *dir) {
+int Part::fixBiaslevel(int srcpnt, int *dir) {
int noteat = srcpnt & 63;
int outnote;
*dir = 1;
@@ -158,7 +161,7 @@ int Part::FixBiaslevel(int srcpnt, int *dir) {
return outnote;
}
-int Part::FixKeyfollow(int srckey, int *dir) {
+int Part::fixKeyfollow(int srckey, int *dir) {
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};
@@ -177,11 +180,11 @@ int Part::FixKeyfollow(int srckey, int *dir) {
}
}
-void Part::RefreshPatch() {
- SetPatch(-1);
+void Part::refreshPatch() {
+ setPatch(-1);
}
-void Part::AbortPoly(dpoly *poly) {
+void Part::abortPoly(dpoly *poly) {
if (!poly->isPlaying) {
return;
}
@@ -210,8 +213,7 @@ unsigned int Part::getAbsTimbreNum() {
return (patchTemp->patch.timbreGroup * 64) + patchTemp->patch.timbreNum;
}
-void Part::SetPatch(int patchNum) {
- int pcm;
+void Part::setPatch(int patchNum) {
int absTimbreNum = -1; // Initialised to please compiler
TimbreParam timSrc;
if (isRhythm) {
@@ -232,7 +234,7 @@ void Part::SetPatch(int patchNum) {
timSrc = *timbreTemp;
#if 0
// Immediately stop all partials on this part (this is apparently *not* the correct behaviour)
- for (int m = 0; m < MAXPOLY; m++) {
+ for (int m = 0; m < MT32EMU_MAX_POLY; m++) {
AbortPoly(poly);
}
#else
@@ -240,7 +242,7 @@ void Part::SetPatch(int patchNum) {
// 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.
// Hopefully this is fairly rare.
- for (int m = 0; m < MAXPOLY; m++) {
+ 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) {
@@ -255,7 +257,6 @@ void Part::SetPatch(int patchNum) {
}
memcpy(currentInstr, timSrc.common.name, 10);
- currentInstr[10] = 0;
int partialCount = 0;
for (int t=0;t<4;t++) {
@@ -269,33 +270,31 @@ void Part::SetPatch(int patchNum) {
// Calculate and cache common parameters
- pcm = timSrc.partial[t].wg.pcmwave;
-
patchCache[t].pcm = timSrc.partial[t].wg.pcmwave;
patchCache[t].useBender = (timSrc.partial[t].wg.bender == 1);
switch (t) {
case 0:
patchCache[t].PCMPartial = (PartialStruct[(int)timSrc.common.pstruct12] & 0x2) ? true : false;
- patchCache[t].mix = PartialMixStruct[(int)timSrc.common.pstruct12];
+ patchCache[t].structureMix = PartialMixStruct[(int)timSrc.common.pstruct12];
patchCache[t].structurePosition = 0;
patchCache[t].structurePair = 1;
break;
case 1:
patchCache[t].PCMPartial = (PartialStruct[(int)timSrc.common.pstruct12] & 0x1) ? true : false;
- patchCache[t].mix = PartialMixStruct[(int)timSrc.common.pstruct12];
+ patchCache[t].structureMix = PartialMixStruct[(int)timSrc.common.pstruct12];
patchCache[t].structurePosition = 1;
patchCache[t].structurePair = 0;
break;
case 2:
patchCache[t].PCMPartial = (PartialStruct[(int)timSrc.common.pstruct34] & 0x2) ? true : false;
- patchCache[t].mix = PartialMixStruct[(int)timSrc.common.pstruct34];
+ patchCache[t].structureMix = PartialMixStruct[(int)timSrc.common.pstruct34];
patchCache[t].structurePosition = 0;
patchCache[t].structurePair = 3;
break;
case 3:
patchCache[t].PCMPartial = (PartialStruct[(int)timSrc.common.pstruct34] & 0x1) ? true : false;
- patchCache[t].mix = PartialMixStruct[(int)timSrc.common.pstruct34];
+ patchCache[t].structureMix = PartialMixStruct[(int)timSrc.common.pstruct34];
patchCache[t].structurePosition = 1;
patchCache[t].structurePair = 2;
break;
@@ -306,7 +305,7 @@ void Part::SetPatch(int patchNum) {
patchCache[t].waveform = timSrc.partial[t].wg.waveform;
patchCache[t].pulsewidth = timSrc.partial[t].wg.pulsewid;
patchCache[t].pwsens = timSrc.partial[t].wg.pwvelo;
- patchCache[t].pitchkeyfollow = FixKeyfollow(timSrc.partial[t].wg.keyfollow, &patchCache[t].pitchkeydir);
+ patchCache[t].pitchkeyfollow = fixKeyfollow(timSrc.partial[t].wg.keyfollow, &patchCache[t].pitchkeydir);
// Calculate and cache pitch stuff
patchCache[t].pitchshift = timSrc.partial[t].wg.coarse;
@@ -339,9 +338,9 @@ void Part::SetPatch(int patchNum) {
else
patchCache[t].ampenvdir = 0;
- patchCache[t].ampbias[0] = FixBiaslevel(patchCache[t].ampEnv.biaspoint1, &patchCache[t].ampdir[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].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];
@@ -350,9 +349,9 @@ void Part::SetPatch(int patchNum) {
// Calculate and cache filter stuff
patchCache[t].filtEnv = timSrc.partial[t].tvf;
patchCache[t].tvfdepth = patchCache[t].filtEnv.envdkf;
- patchCache[t].filtkeyfollow = FixKeyfollow(patchCache[t].filtEnv.keyfollow, &patchCache[t].keydir);
+ 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].tvfbias = fixBiaslevel(patchCache[t].filtEnv.biaspoint, &patchCache[t].tvfdir);
patchCache[t].tvfblevel = patchCache[t].filtEnv.biaslevel;
patchCache[t].filtsustain = patchCache[t].filtEnv.envlevel[3];
@@ -366,17 +365,22 @@ void Part::SetPatch(int patchNum) {
// Common parameters, stored redundantly
patchCache[t].partialCount = partialCount;
patchCache[t].sustain = (timSrc.common.nosustain == 0);
+ if (isRhythm) {
+ patchCache[t].benderRange = 0;
+ } else {
+ patchCache[t].benderRange = patchTemp->patch.benderRange;
+ }
}
//synth->printDebug("Res 1: %d 2: %d 3: %d 4: %d", patchCache[0].waveform, patchCache[1].waveform, patchCache[2].waveform, patchCache[3].waveform);
if (isRhythm)
memcpy(drumCache[absTimbreNum - 128], patchCache, sizeof(patchCache));
else
- AllStop();
-#if DISPLAYINSTR == 1
- synth->printDebug("%s: Recache, param %d (timbre: %s), %d partials", name, patchNum, currentInstr, partialCount);
+ allStop();
+#if MT32EMU_MONITOR_INSTRUMENTS == 1
+ synth->printDebug("%s: Recache, param %d (timbre: %s)", name, patchNum, currentInstr);
for (int i = 0; i < 4; i++) {
- synth->printDebug(" %d: play=%s, pcm=%d, wave=%d", i, patchCache[i].playPartial ? "YES" : "NO", timSrc.partial[i].wg.pcmwave, timSrc.partial[i].wg.waveform);
+ synth->printDebug(" %d: play=%s, pcm=%s (%d), wave=%d", i, patchCache[i].playPartial ? "YES" : "NO", patchCache[i].PCMPartial ? "YES" : "NO", timSrc.partial[i].wg.pcmwave, timSrc.partial[i].wg.waveform);
}
#endif
}
@@ -385,11 +389,11 @@ char *Part::getName() {
return name;
}
-void Part::SetVolume(int vol) {
+void Part::setVolume(int vol) {
volume = voltable[vol];
}
-void Part::SetPan(int pan) {
+void Part::setPan(int pan) {
// FIXME:KG: This is unchangeable for drums (they always use drumPan), is that correct?
// FIXME:KG: There is no way to get a centred balance here... And the middle two
// pan settings have a distance of 1024, double the usual.
@@ -405,7 +409,7 @@ void Part::SetPan(int pan) {
//synth->printDebug("%s (%s): Set pan to %d", name, currentInstr, panpot);
}
-void Part::PlayNote(PartialManager *partialManager, int f, int vel) {
+void Part::playNote(PartialManager *partialManager, int f, int vel) {
int drumNum = -1; // Initialised to please compiler
int drumTimbre = -1; // As above
int freqNum;
@@ -436,10 +440,10 @@ void Part::PlayNote(PartialManager *partialManager, int f, int vel) {
// Haven't found any software that uses any of the other poly modes
// FIXME:KG: Should this also apply to rhythm?
if (!isRhythm) {
- for (int i = 0; i < MAXPOLY; i++) {
+ for (int i = 0; i < MT32EMU_MAX_POLY; i++) {
if (polyTable[i].isActive() && (polyTable[i].note == f)) {
//AbortPoly(&polyTable[i]);
- StopNote(f);
+ stopNote(f);
break;
}
}
@@ -455,12 +459,12 @@ void Part::PlayNote(PartialManager *partialManager, int f, int vel) {
}
// Find free note
int m;
- for (m = 0; m < MAXPOLY; m++) {
+ for (m = 0; m < MT32EMU_MAX_POLY; m++) {
if (!polyTable[m].isActive()) {
break;
}
}
- if (m == MAXPOLY) {
+ if (m == MT32EMU_MAX_POLY) {
synth->printDebug("%s (%s): No free poly to play note %d (vel %d)", name, currentInstr, f, vel);
return;
}
@@ -490,33 +494,32 @@ void Part::PlayNote(PartialManager *partialManager, int f, int vel) {
synth->printDebug("%s (%s): No partials to play for this instrument", name, this->currentInstr);
if (isRhythm) {
- tpoly->bendptr = &drumBend;
tpoly->pansetptr = &drumPan[drumNum];
tpoly->reverb = rhythmTemp[drumNum].reverbSwitch > 0;
} else {
- tpoly->bendptr = &bend;
tpoly->pansetptr = &volumesetting;
tpoly->reverb = patchTemp->patch.reverbSwitch > 0;
}
tpoly->sustain = patchCache[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, f, volume);
+ } else {
+ synth->printDebug("%s (%s): starting poly %d - Vel %d Key %d Vol %d", name, currentInstr, m, vel, f, 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]->setBend(bend);
}
}
-
-#if DISPLAYINSTR == 1
- if (isRhythm) {
- synth->printDebug("%s (%s): starting note poly %d (drum %d, timbre %d) - Vel %d Vol %d", name, currentInstr, m, drumNum, drumTimbre, vel, volume);
- } else {
- synth->printDebug("%s (%s): starting note poly %d - Vel %d Freq %d Vol %d", name, currentInstr, m, vel, f, volume);
- }
-#endif
}
-static void StartDecayPoly(dpoly *tpoly) {
+static void startDecayPoly(dpoly *tpoly) {
if (tpoly->isDecay) {
return;
}
@@ -531,41 +534,41 @@ static void StartDecayPoly(dpoly *tpoly) {
tpoly->isPlaying = false;
}
-void Part::AllStop() {
- for (int q = 0; q < MAXPOLY; q++) {
+void Part::allStop() {
+ for (int q = 0; q < MT32EMU_MAX_POLY; q++) {
dpoly *tpoly = &polyTable[q];
if (tpoly->isPlaying) {
- StartDecayPoly(tpoly);
+ startDecayPoly(tpoly);
}
}
}
-void Part::StopPedalHold() {
- for (int q = 0; q < MAXPOLY; q++) {
+void Part::stopPedalHold() {
+ for (int q = 0; q < MT32EMU_MAX_POLY; q++) {
dpoly *tpoly;
tpoly = &polyTable[q];
if (tpoly->isActive() && tpoly->pedalhold)
- StopNote(tpoly->note);
+ stopNote(tpoly->note);
}
}
-void Part::StopNote(int f) {
+void Part::stopNote(int f) {
// Non-sustaining instruments ignore stop note commands.
// They die away eventually anyway
//if (!tpoly->sustain) return;
-#if DISPLAYINSTR == 1
- synth->printDebug("%s (%s): stopping note %d", name, currentInstr, f);
+#if MT32EMU_MONITOR_INSTRUMENTS == 1
+ synth->printDebug("%s (%s): stopping key %d", name, currentInstr, f);
#endif
if (f != -1) {
- for (int q = 0; q < MAXPOLY; q++) {
+ for (int q = 0; q < MT32EMU_MAX_POLY; q++) {
dpoly *tpoly = &polyTable[q];
if (tpoly->isPlaying && tpoly->note == f) {
if (holdpedal)
tpoly->pedalhold = true;
else if (tpoly->sustain)
- StartDecayPoly(tpoly);
+ startDecayPoly(tpoly);
}
}
return;
@@ -576,7 +579,7 @@ void Part::StopNote(int f) {
int oldest = -1;
Bit64s oldage = -1;
- for (int q = 0; q < MAXPOLY; q++) {
+ for (int q = 0; q < MT32EMU_MAX_POLY; q++) {
dpoly *tpoly = &polyTable[q];
if (tpoly->isPlaying && !tpoly->isDecay) {
@@ -588,7 +591,7 @@ void Part::StopNote(int f) {
}
if (oldest!=-1) {
- StartDecayPoly(&polyTable[oldest]);
+ startDecayPoly(&polyTable[oldest]);
}
}
diff --git a/backends/midi/mt32/part.h b/backends/midi/mt32/part.h
index 302ca4d2fb..da73334af1 100644
--- a/backends/midi/mt32/part.h
+++ b/backends/midi/mt32/part.h
@@ -22,12 +22,6 @@
#ifndef MT32EMU_PART_H
#define MT32EMU_PART_H
-#define AMPENV 0
-#define FILTENV 1
-#define PITCHENV 2
-
-#define MAXPOLY 64
-
namespace MT32Emu {
class PartialManager;
@@ -52,38 +46,38 @@ private:
bool holdpedal;
- volset volumesetting;
+ StereoVolume volumesetting;
PatchCache patchCache[4];
- Bit32u bend;
+ float bend; // -1.0 .. +1.0
Bit32s volume;
- dpoly polyTable[MAXPOLY];
+ dpoly polyTable[MT32EMU_MAX_POLY];
- void AbortPoly(dpoly *poly);
+ void abortPoly(dpoly *poly);
+
+ static int fixKeyfollow(int srckey, int *dir);
+ static int fixBiaslevel(int srcpnt, int *dir);
public:
Part(Synth *synth, int usePartNum);
char *getName();
- void PlayNote(PartialManager *partialManager, int f, int vel);
- void StopNote(int f);
- void AllStop();
- void SetVolume(int vol);
- void SetPan(int vol);
- void SetBend(int vol);
- void SetModulation(int vol);
- void SetPatch(int patchnum);
- void SetHoldPedal(bool pedalval);
- void StopPedalHold();
- void RefreshPatch();
- void RefreshDrumCache();
+ void playNote(PartialManager *partialManager, int f, int vel);
+ void stopNote(int f);
+ void allStop();
+ void setVolume(int vol);
+ void setPan(int vol);
+ void setBend(int vol);
+ void setModulation(int vol);
+ void setPatch(int patchnum);
+ void setHoldPedal(bool pedalval);
+ void stopPedalHold();
+ void refreshPatch();
+ void refreshDrumCache();
void setPatch(PatchParam *patch);
void setTimbre(TimbreParam *timbre);
unsigned int getAbsTimbreNum();
-
- int FixKeyfollow(int srckey, int *dir);
- int FixBiaslevel(int srcpnt, int *dir);
};
}
diff --git a/backends/midi/mt32/partial.cpp b/backends/midi/mt32/partial.cpp
index bc5151e565..b3e2f661ba 100644
--- a/backends/midi/mt32/partial.cpp
+++ b/backends/midi/mt32/partial.cpp
@@ -34,6 +34,9 @@ Partial::Partial(Synth *useSynth) {
pair = NULL;
}
+Partial::~Partial() {
+}
+
int Partial::getOwnerPart() {
return ownerPart;
}
@@ -62,12 +65,12 @@ void Partial::deactivate() {
}
}
-void Partial::initKeyFollow(int freqNum) {
+void Partial::initKeyFollow(int key) {
// Setup partial keyfollow
// Note follow relative to middle C
int keyfollow;
- int realfol = (freqNum * 2 - MIDDLEC * 2) / 2;
- int antirealfol = (MIDDLEC * 2 - freqNum * 2) / 2;
+ int realfol = (key * 2 - MIDDLEC * 2) / 2;
+ int antirealfol = (MIDDLEC * 2 - key * 2) / 2;
// Calculate keyfollow for pitch
switch(patchCache->pitchkeydir) {
case -1:
@@ -99,7 +102,7 @@ void Partial::initKeyFollow(int freqNum) {
keyfollow = (antirealfol * patchCache->filtkeyfollow) >> 12;
break;
case 0:
- keyfollow = freqNum;
+ keyfollow = key;
break;
case 1:
keyfollow = (realfol * patchCache->filtkeyfollow) >> 12;
@@ -120,11 +123,11 @@ void Partial::startPartial(dpoly *usePoly, PatchCache *useCache, Partial *pairPa
}
patchCache = useCache;
poly = usePoly;
- mixType = patchCache->mix;
+ mixType = patchCache->structureMix;
structurePosition = patchCache->structurePosition;
play = true;
- initKeyFollow(poly->freqnum);
+ initKeyFollow(poly->freqnum); // Initialises noteVal, filtVal and realVal
lfoPos = 0;
pulsewidth = patchCache->pulsewidth + pwveltable[patchCache->pwsens][poly->vel];
if (pulsewidth > 100) {
@@ -174,10 +177,10 @@ Bit16s *Partial::generateSamples(long length) {
while (length--) {
Bit32s envval, ampval;
Bit32s ptemp = 0;
- if (envs[AMPENV].sustaining)
+ if (envs[EnvelopeType_amp].sustaining)
ampval = ampEnvCache;
else {
- if (envs[AMPENV].count<=0) {
+ if (envs[EnvelopeType_amp].count <= 0) {
ampval = getAmpEnvelope();
if (!play) {
deactivate();
@@ -192,26 +195,26 @@ Bit16s *Partial::generateSamples(long length) {
}
ampval = voltable[ampval];
- int tmpvel = poly->vel;
+ int tmpvel;
if (patchCache->ampenvdir == 1)
- tmpvel = 127 - tmpvel;
+ tmpvel = 127 - poly->vel;
+ else
+ tmpvel = poly->vel;
ampval = (ampval * ampveltable[tmpvel][(int)patchCache->ampEnv.velosens]) >> 8;
- //if (envs[AMPENV].sustaining)
+ //if (envs[EnvelopeType_amp].sustaining)
ampEnvCache = ampval;
} else
ampval = ampEnvCache;
- --envs[AMPENV].count;
+ --envs[EnvelopeType_amp].count;
}
- int delta = 0x10707;
-
// Calculate Pitch envelope
int lfoat = 0x1000;
int pdep;
if (pitchSustain) {
// Calculate LFO position
// LFO does not kick in completely until pitch envelope sustains
- if (patchCache->lfodepth>0) {
+ if (patchCache->lfodepth > 0) {
lfoPos++;
if (lfoPos >= patchCache->lfoperiod)
lfoPos = 0;
@@ -228,18 +231,23 @@ Bit16s *Partial::generateSamples(long length) {
pitchEnvCache = pdep;
}
+ int delta;
+ // These two are only for PCM partials, obviously
+ PCMWaveEntry *pcmWave = NULL; // Initialise to please compiler
+ int pcmAddr = 0; // Initialise to please compiler
+
// Get waveform - either PCM or synthesized sawtooth or square
if (patchCache->PCMPartial) {
// PCM partial
- int addr,len;
- sampleTable *tPCM = &synth->PCMList[patchCache->pcm];
+ int len;
+ pcmWave = &synth->PCMList[patchCache->pcm];
- if (tPCM->aggSound == -1) {
- delta = wavtabler[tPCM->pcmnum][noteVal];
- addr = tPCM->addr;
- len = tPCM->len;
+ if (pcmWave->aggSound == -1) {
+ delta = wavtabler[pcmWave->pcmnum][noteVal];
+ pcmAddr = pcmWave->addr;
+ len = pcmWave->len;
if (partialOff.pcmplace >= len) {
- if (tPCM->loop) {
+ if (pcmWave->loop) {
partialOff.pcmplace = partialOff.pcmoffset = 0;
// FIXME:KG: Use this?: partialOff.pcmplace %= len;
} else {
@@ -249,57 +257,67 @@ Bit16s *Partial::generateSamples(long length) {
}
}
} else {
- int tmppcm = LoopPatterns[tPCM->aggSound][loopPos];
- delta = looptabler[tPCM->aggSound][loopPos][noteVal];
- addr = synth->PCM[tmppcm].addr;
+ int tmppcm = LoopPatterns[pcmWave->aggSound][loopPos];
+ delta = looptabler[pcmWave->aggSound][loopPos][noteVal];
+ pcmAddr = synth->PCM[tmppcm].addr;
len = synth->PCM[tmppcm].len;
if (partialOff.pcmplace >= len) {
loopPos++;
- if (LoopPatterns[tPCM->aggSound][loopPos]==-1)
- loopPos=0;
+ if (LoopPatterns[pcmWave->aggSound][loopPos] == -1)
+ loopPos = 0;
partialOff.pcmplace = partialOff.pcmoffset = 0;
}
}
+ } else {
+ // Synthesis partial
+ delta = 0x10707;
+ partialOff.pcmplace %= (Bit16u)(divtable[noteVal] >> 15);
+ }
- if (ampval>0) {
- int ra,rb,dist;
+ // Build delta for position of next sample
+ // Fix delta code
+ Bit64s tdelta = (Bit64s)delta;
+ tdelta = (tdelta * patchCache->fineshift) >> 12;
+ tdelta = (tdelta * pdep) >> 12;
+ tdelta = (tdelta * lfoat) >> 12;
+ tdelta = (tdelta * bendShift) >> 12;
+ delta = (int)tdelta;
+
+ if (ampval > 0) {
+ if (patchCache->PCMPartial) {
+ // Render PCM sample
+ int ra, rb, dist;
int taddr;
- if (delta<0x10000) {
+ if (delta < 0x10000) {
// Linear sound interpolation
- taddr = addr + partialOff.pcmplace;
+ taddr = pcmAddr + partialOff.pcmplace;
if (taddr >= ROMSIZE) {
synth->printDebug("Overflow ROMSIZE!");
taddr = ROMSIZE - 1;
}
ra = synth->romfile[taddr];
- rb = synth->romfile[taddr+1];
- dist = rb-ra;
+ //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));
} else {
// Sound decimation
// The right way to do it is to use a lowpass filter on the waveform before selecting
// a point. This is too slow. The following approximates this as fast as possible
int idelta = delta >> 16;
- taddr = addr + partialOff.pcmplace;
+ taddr = pcmAddr + partialOff.pcmplace;
ra = 0;
for (int ix = 0; ix < idelta; ix++)
ra += synth->romfile[taddr++];
ptemp = ra / idelta;
}
- }
- } else {
- // Synthesis partial
- int divis = divtable[noteVal] >> 15;
-
- partialOff.pcmplace %= (Bit16u)divis;
-
- if (ampval > 0) {
- int wf = patchCache->waveform ;
+ } else {
+ // Render synthesised sample
+ int divis = divtable[noteVal] >> 15;
+ int wf = patchCache->waveform;
int toff = partialOff.pcmplace;
int minorplace = partialOff.pcmoffset >> 14;
- int pa, pb;
-
Bit32s filtval = getFiltEnvelope();
//synth->printDebug("Filtval: %d", filtval);
@@ -308,7 +326,7 @@ Bit16s *Partial::generateSamples(long length) {
// Square waveform. Made by combining two pregenerated bandlimited
// sawtooth waveforms
// Pulse width is not yet correct
-
+ int pa, pb;
int hdivis = divis >> 1;
int divmark = smalldivtable[noteVal];
@@ -371,18 +389,9 @@ Bit16s *Partial::generateSamples(long length) {
}
}
- // Build delta for position of next sample
- // Fix delta code
- Bit64s tdelta = (Bit64s)delta;
- tdelta = (tdelta * patchCache->fineshift)>>12;
- tdelta = (tdelta * pdep)>>12;
- tdelta = (tdelta * lfoat)>>12;
- if (patchCache->useBender)
- tdelta = (tdelta * *poly->bendptr)>>12;
-
// Add calculated delta to our waveform offset
Bit32u absOff = ((partialOff.pcmplace << 16) | partialOff.pcmoffset);
- absOff += (int)tdelta;
+ absOff += delta;
partialOff.pcmplace = (Bit16u)((absOff & 0xFFFF0000) >> 16);
partialOff.pcmoffset = (Bit16u)(absOff & 0xFFFF);
@@ -390,17 +399,31 @@ Bit16s *Partial::generateSamples(long length) {
ptemp = (ptemp * ampval) >> 9;
ptemp = (ptemp * *poly->volumeptr) >> 7;
- envs[AMPENV].envpos++;
- envs[PITCHENV].envpos++;
- envs[FILTENV].envpos++;
+ envs[EnvelopeType_amp].envpos++;
+ envs[EnvelopeType_pitch].envpos++;
+ envs[EnvelopeType_filt].envpos++;
*partialBuf++ = (Bit16s)ptemp;
}
+ // We may have deactivated and broken out of the loop before the end of the buffer,
+ // if so then fill the remainder with 0s.
if (++length > 0)
memset(partialBuf, 0, length * 2);
return &myBuffer[0];
}
+void Partial::setBend(float factor) {
+ if (!patchCache->useBender || factor == 0.0f) {
+ bendShift = 4096;
+ return;
+ }
+ // NOTE:KG: We can't do this smoothly with lookup tables, unless we use several MB.
+ 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);
+ bendShift = (int)(mult * 4096.0f);
+}
+
Bit16s *Partial::mixBuffers(Bit16s * buf1, Bit16s *buf2, int len) {
if (buf1 == NULL)
return buf2;
@@ -408,7 +431,7 @@ Bit16s *Partial::mixBuffers(Bit16s * buf1, Bit16s *buf2, int len) {
return buf1;
Bit16s *outBuf = buf1;
-#if USE_MMX >= 1
+#if MT32EMU_USE_MMX >= 1
// KG: This seems to be fine
int donelen = i386_mixBuffers(buf1, buf2, len);
len -= donelen;
@@ -438,7 +461,7 @@ Bit16s *Partial::mixBuffersRingMix(Bit16s * buf1, Bit16s *buf2, int len) {
}
Bit16s *outBuf = buf1;
-#if USE_MMX >= 1
+#if MT32EMU_USE_MMX >= 1
// KG: This seems to be fine
int donelen = i386_mixBuffersRingMix(buf1, buf2, len);
len -= donelen;
@@ -471,7 +494,7 @@ Bit16s *Partial::mixBuffersRing(Bit16s * buf1, Bit16s *buf2, int len) {
}
Bit16s *outBuf = buf1;
-#if USE_MMX >= 1
+#if MT32EMU_USE_MMX >= 1
// FIXME:KG: Not really checked as working
int donelen = i386_mixBuffersRing(buf1, buf2, len);
len -= donelen;
@@ -585,7 +608,7 @@ bool Partial::produceOutput(Bit16s *partialBuf, long length) {
leftvol = poly->pansetptr->leftvol;
rightvol = poly->pansetptr->rightvol;
-#if USE_MMX >= 2
+#if MT32EMU_USE_MMX >= 2
// FIXME:KG: This appears to introduce crackle
int donelen = i386_partialProductOutput(length, leftvol, rightvol, partialBuf, mixedBuf);
length -= donelen;
@@ -605,7 +628,7 @@ Bit32s Partial::getFiltEnvelope() {
int cutoff,depth,keyfollow, realfollow;
- envstatus *tStat = &envs[FILTENV];
+ envstatus *tStat = &envs[EnvelopeType_filt];
keyfollow = filtVal;
realfollow = realVal;
@@ -621,7 +644,7 @@ Bit32s Partial::getFiltEnvelope() {
if (tStat->envstat==4) {
reshigh = patchCache->filtsustain;
if (!poly->sustain) {
- startDecay(FILTENV, reshigh);
+ startDecay(EnvelopeType_filt, reshigh);
}
} else {
if ((tStat->envstat==-1) || (tStat->envpos >= tStat->envsize)) {
@@ -713,7 +736,7 @@ bool Partial::shouldReverb() {
Bit32s Partial::getAmpEnvelope() {
Bit32s tc;
- envstatus *tStat = &envs[AMPENV];
+ envstatus *tStat = &envs[EnvelopeType_amp];
if (!play)
return 0;
@@ -754,7 +777,7 @@ Bit32s Partial::getAmpEnvelope() {
//synth->printDebug("Envstat %d, size %d", tStat->envstat, tStat->envsize);
tc = patchCache->ampsustain;
if (!poly->sustain)
- startDecay(AMPENV, tc);
+ startDecay(EnvelopeType_amp, tc);
else
tStat->sustaining = true;
@@ -815,7 +838,7 @@ PastCalc:
}
Bit32s Partial::getPitchEnvelope() {
- envstatus *tStat = &envs[PITCHENV];
+ envstatus *tStat = &envs[EnvelopeType_pitch];
Bit32s tc;
pitchSustain = false;
@@ -832,7 +855,7 @@ Bit32s Partial::getPitchEnvelope() {
if (poly->sustain)
pitchSustain = true;
else
- startDecay(PITCHENV, tc);
+ startDecay(EnvelopeType_pitch, tc);
} else {
if ((tStat->envstat==-1) || (tStat->envpos >= tStat->envsize)) {
tStat->envstat++;
@@ -853,13 +876,13 @@ Bit32s Partial::getPitchEnvelope() {
}
void Partial::startDecayAll() {
- startDecay(AMPENV, envs[AMPENV].prevlevel);
- startDecay(FILTENV, envs[FILTENV].prevlevel);
- startDecay(PITCHENV, envs[PITCHENV].prevlevel);
+ startDecay(EnvelopeType_amp, envs[EnvelopeType_amp].prevlevel);
+ startDecay(EnvelopeType_filt, envs[EnvelopeType_filt].prevlevel);
+ startDecay(EnvelopeType_pitch, envs[EnvelopeType_pitch].prevlevel);
pitchSustain = false;
}
-void Partial::startDecay(int envnum, Bit32s startval) {
+void Partial::startDecay(EnvelopeType envnum, Bit32s startval) {
envstatus *tStat = &envs[envnum];
tStat->sustaining = false;
@@ -868,15 +891,15 @@ void Partial::startDecay(int envnum, Bit32s startval) {
tStat->envbase = startval;
switch(envnum) {
- case AMPENV:
+ case EnvelopeType_amp:
tStat->envsize = (decaytimetable[(int)patchCache->ampEnv.envtime[4]] * timekeytable[(int)patchCache->ampEnv.envtkf][poly->freqnum]) >> 8;
tStat->envdist = -startval;
break;
- case FILTENV:
+ case EnvelopeType_filt:
tStat->envsize = (decaytimetable[(int)patchCache->filtEnv.envtime[4]] * timekeytable[(int)patchCache->filtEnv.envtkf][poly->freqnum]) >> 8;
tStat->envdist = -startval;
break;
- case PITCHENV:
+ case EnvelopeType_pitch:
tStat->envsize = (decaytimetable[(int)patchCache->pitchEnv.time[3]] * timekeytable[(int)patchCache->pitchEnv.timekeyfollow][poly->freqnum]) >> 8 ;
tStat->envdist = patchCache->pitchEnv.level[4] - startval;
break;
diff --git a/backends/midi/mt32/partial.h b/backends/midi/mt32/partial.h
index 20160dca5f..ad7cd65b0b 100644
--- a/backends/midi/mt32/partial.h
+++ b/backends/midi/mt32/partial.h
@@ -24,6 +24,14 @@
namespace MT32Emu {
+class Synth;
+
+enum EnvelopeType {
+ EnvelopeType_amp = 0,
+ EnvelopeType_filt = 1,
+ EnvelopeType_pitch = 2
+};
+
struct envstatus {
Bit32s envpos;
Bit32s envstat;
@@ -39,8 +47,6 @@ struct envstatus {
Bit32s count;
};
-class Synth;
-
// Class definition of MT-32 partials. 32 in all.
class Partial {
private:
@@ -80,6 +86,8 @@ private:
dpoly *poly;
+ 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);
@@ -100,14 +108,16 @@ public:
Bit64s age;
Partial(Synth *synth);
+ ~Partial();
int getOwnerPart();
bool isActive();
void activate(int part);
void deactivate(void);
void startPartial(dpoly *usePoly, PatchCache *useCache, Partial *pairPartial);
- void startDecay(int envnum, Bit32s startval);
+ void startDecay(EnvelopeType envnum, Bit32s startval);
void startDecayAll();
+ void setBend(float factor);
bool shouldReverb();
// Returns true only if data written to buffer
diff --git a/backends/midi/mt32/structures.h b/backends/midi/mt32/structures.h
index 5b1db5921b..4c1e237f3e 100644
--- a/backends/midi/mt32/structures.h
+++ b/backends/midi/mt32/structures.h
@@ -22,19 +22,10 @@
#ifndef MT32EMU_STRUCTURES_H
#define MT32EMU_STRUCTURES_H
-#if (defined (_MSC_VER) && defined(_M_IX86)) || (defined(__GNUC__) && defined(__i386__))
-#define HAVE_X86
-#endif
-
-#define MAX_SAMPLE_OUTPUT 4096
-#ifdef HAVE_X86
-#define USE_MMX 1
-#else
-#define USE_MMX 0
-#endif
-
namespace MT32Emu {
+const unsigned int MAX_SAMPLE_OUTPUT = 4096;
+
#ifdef _MSC_VER
#define MT32EMU_ALIGN_PACKED __declspec(align(1))
typedef unsigned __int64 Bit64u;
@@ -195,7 +186,8 @@ union MT32RAMFormat {
#pragma pack()
#endif
-struct sampleFormat {
+struct PCMWave {
+ char name[16];
Bit32u addr;
Bit32u len;
bool loop;
@@ -203,7 +195,7 @@ struct sampleFormat {
Bit32s ampval;
};
-struct sampleTable {
+struct PCMWaveEntry {
Bit32u addr;
Bit32u len;
Bit32u pcmnum;
@@ -216,7 +208,7 @@ struct soundaddr {
Bit16u pcmoffset;
};
-struct volset {
+struct StereoVolume {
Bit16s leftvol;
Bit16s rightvol;
};
@@ -257,6 +249,7 @@ struct PatchCache {
int tvfdepth;
bool useBender;
+ float benderRange; // 0.0, 1.0, .., 24.0 (semitones)
TimbreParam::partialParam::envParam pitchEnv;
TimbreParam::partialParam::tvaParam ampEnv;
@@ -266,7 +259,7 @@ struct PatchCache {
Bit32s pitchsustain;
Bit32s filtsustain;
- Bit32u mix;
+ Bit32u structureMix;
int structurePosition;
int structurePair;
@@ -288,9 +281,8 @@ struct dpoly {
bool reverb;
bool isDecay;
- const Bit32u *bendptr;
- Bit32s *volumeptr;
- volset *pansetptr;
+ const Bit32s *volumeptr;
+ const StereoVolume *pansetptr;
Partial *partials[4];
diff --git a/backends/midi/mt32/synth.cpp b/backends/midi/mt32/synth.cpp
index 2647fdae85..4c697b893f 100644
--- a/backends/midi/mt32/synth.cpp
+++ b/backends/midi/mt32/synth.cpp
@@ -19,21 +19,16 @@
* IN THE SOFTWARE.
*/
-#define BENCHMARK 0
-
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
-#if BENCHMARK > 0
-#include <time.h>
-#endif
#include "mt32emu.h"
-// Debugging stuff
-// Used to dump drum patches to syx file for viewing
-#define DUMPDRUMS 0
+#if MT32EMU_BENCHMARK_FILTERS > 0
+#include <time.h>
+#endif
namespace MT32Emu {
@@ -347,7 +342,8 @@ bool Synth::loadPCMToROMMap(const char *filename) {
return false;
}
- for (int i=0;i<54;i++) {
+ Bit32u PCMReassign[54];
+ for (int i = 0; i < 54; i++) {
PCMReassign[i] = i;
PCM[i].tune = 220.0f;
PCM[i].ampval = 256;
@@ -378,6 +374,8 @@ bool Synth::loadPCMToROMMap(const char *filename) {
if (cp != NULL) {
cp = strtok(NULL," \n\r");
if (cp != NULL) {
+ strncpy(PCM[patchcount].name, cp, 15);
+ PCM[patchcount].name[15] = 0;
cp = strtok(NULL," \n\r");
if (cp !=NULL) {
int newpcm = atoi(cp);
@@ -581,7 +579,7 @@ bool Synth::open(SynthProperties &useProp) {
return false;
}
-#if DUMPDRUMS == 1
+#if MT32EMU_DUMP_DRUMS == 1
strcpy(&pathBuf[0], baseDir);
dumpDrums(strcat(&pathBuf[0],"drumsys.syx"));
#endif
@@ -605,12 +603,14 @@ bool Synth::open(SynthProperties &useProp) {
mt32ram.params.patches[i].timbreNum = i & 63;
}
- TableInitialiser tableInitialiser;
- tableInitialiser.initMT32Tables(this, PCM, (float)myProp.SampleRate);
- if (myProp.UseDefault)
- initReverb(0,5);
+ if (!TableInitialiser::initMT32Tables(this, PCM, (float)myProp.sampleRate)) {
+ report(ReportType_errorSampleRate, NULL);
+ return false;
+ }
+ if (myProp.useDefaultReverb)
+ initReverb(0, 5);
else
- initReverb(myProp.RevType, myProp.RevTime);
+ initReverb(myProp.reverbType, myProp.reverbTime);
for (int i = 0; i < 9; i++) {
parts[i] = new Part(this, i);
@@ -619,14 +619,14 @@ bool Synth::open(SynthProperties &useProp) {
// The patch is already set by the presets, now set the timbre it wants
parts[i]->setTimbre(&mt32ram.params.timbres[parts[i]->getAbsTimbreNum()].timbre);
// And refresh the part's cache
- parts[i]->RefreshPatch();
+ parts[i]->refreshPatch();
}
}
// For resetting mt32 mid-execution
mt32default = mt32ram;
-#ifdef HAVE_X86
+#ifdef MT32EMU_HAVE_X86
bool availableSSE = DetectSIMD();
bool available3DNow = Detect3DNow();
@@ -646,7 +646,7 @@ bool Synth::open(SynthProperties &useProp) {
}
#endif
-#if BENCHMARK > 1
+#if MT32EMU_BENCHMARK_FILTERS > 1
// Benchmark 3DNow, Floating point, and SSE filters
clock_t start, end;
float histval[50];
@@ -691,7 +691,7 @@ void Synth::close(void) {
return;
for (int t = 0; t < 4; t++) {
- for (int m = 0; m < 128; m++) {
+ for (int m = 0; m < NUM_NOTES; m++) {
if (waveforms[t][m]!=NULL) {
delete[] waveforms[t][m];
waveforms[t][m] = NULL;
@@ -743,51 +743,52 @@ void Synth::playMsgOnPart(unsigned char part, unsigned char code, unsigned char
case 0x8:
//printDebug("Note OFF - Part %d", part);
// The MT-32 ignores velocity for note off
- parts[part]->StopNote(note);
+ parts[part]->stopNote(note);
break;
case 0x9:
//printDebug("Note ON - Part %d, Note %d Vel %d", part, note, velocity);
if (velocity == 0) {
// MIDI defines note-on with velocity 0 as being the same as note-off with velocity 40
- parts[part]->StopNote(note);
+ parts[part]->stopNote(note);
} else {
- parts[part]->PlayNote(partialManager, note, velocity);
+ parts[part]->playNote(partialManager, note, velocity);
}
break;
case 0xB: // Control change
switch (note) {
case 0x01: // Modulation
//printDebug("Modulation: %d", velocity);
- parts[part]->SetModulation(velocity);
- break;
- case 0x0B:
- //printDebug("Expression set: %d", velocity);
- parts[part]->SetVolume(velocity);
+ parts[part]->setModulation(velocity);
break;
case 0x07: // Set volume
//if (part!=3) return;
//printDebug("Volume set: %d", velocity);
- parts[part]->SetVolume(velocity);
+ parts[part]->setVolume(velocity);
break;
case 0x0A: // Pan
//printDebug("Pan set: %d", velocity);
- parts[part]->SetPan(velocity);
+ parts[part]->setPan(velocity);
+ break;
+ case 0x0B:
+ //printDebug("Expression set: %d", velocity);
+ parts[part]->setVolume(velocity);
break;
case 0x40: // Hold pedal
//printDebug("Hold pedal set: %d", velocity);
- parts[part]->SetHoldPedal(velocity>=64);
+ parts[part]->setHoldPedal(velocity>=64);
break;
- case 0x7B: // All notes off
- //printDebug("All notes off");
- parts[part]->AllStop();
- break;
case 0x79: // Reset all controllers
printDebug("Reset all controllers (NYI)");
break;
+ case 0x7B: // All notes off
+ //printDebug("All notes off");
+ parts[part]->allStop();
+ break;
+
default:
- printDebug("Unknown MIDI Control code: 0x%02x - vel %02x",note, velocity);
+ printDebug("Unknown MIDI Control code: 0x%02x - vel 0x%02x", note, velocity);
break;
}
@@ -795,7 +796,7 @@ void Synth::playMsgOnPart(unsigned char part, unsigned char code, unsigned char
case 0xC: // Program change
//printDebug("Program change %01x", note);
if (part < 8) {
- parts[part]->SetPatch(note);
+ parts[part]->setPatch(note);
} else {
printDebug("Program change attempted on rhythm part");
}
@@ -803,7 +804,7 @@ void Synth::playMsgOnPart(unsigned char part, unsigned char code, unsigned char
case 0xE: // Pitch bender
bend = (velocity << 7) | (note);
//printDebug("Pitch bender %02x", bend);
- parts[part]->SetBend(bend);
+ parts[part]->setBend(bend);
break;
default:
printDebug("Unknown Midi code: 0x%01x - %02x - %02x", code, note, velocity);
@@ -936,8 +937,13 @@ void Synth::playSysexWithoutHeader(unsigned char device, Bit8u *sysex, Bit32u le
timbreName[10] = 0;
printDebug("WRITE-PARTPATCH (%d-%d@%d..%d): %d; timbre=%d (%s)", firstPart, lastPart, off, off + len, i, absTimbreNum, timbreName);
if (parts[i] != NULL) {
- parts[i]->setTimbre(&mt32ram.params.timbres[parts[i]->getAbsTimbreNum()].timbre);
- parts[i]->RefreshPatch();
+ if (i == firstPart && off > 2) {
+ printDebug(" (Not updating timbre, since those values weren't touched)");
+ } else {
+ // Not sure whether we should do this at all, really.
+ parts[i]->setTimbre(&mt32ram.params.timbres[parts[i]->getAbsTimbreNum()].timbre);
+ }
+ parts[i]->refreshPatch();
}
}
} else if (addr >= MEMADDR(0x030110) && addr < MEMADDR(0x040000)) {
@@ -963,7 +969,7 @@ void Synth::playSysexWithoutHeader(unsigned char device, Bit8u *sysex, Bit32u le
printDebug("WRITE-RHYTHM (%d-%d@%d..%d): %d; level=%02x, panpot=%02x, reverb=%02x, timbre=%d (%s)", firstDrum, lastDrum, off, off + len, i, mt32ram.params.rhythmSettings[i].outlevel, mt32ram.params.rhythmSettings[i].panpot, mt32ram.params.rhythmSettings[i].reverbSwitch, mt32ram.params.rhythmSettings[i].timbre, timbreName);
}
if (parts[8] != NULL) {
- parts[8]->RefreshDrumCache();
+ parts[8]->refreshDrumCache();
}
} else if (addr >= MEMADDR(0x040000) && addr < MEMADDR(0x050000)) {
int off = addr - MEMADDR(0x040000);
@@ -982,7 +988,7 @@ void Synth::playSysexWithoutHeader(unsigned char device, Bit8u *sysex, Bit32u le
instrumentName[10] = 0;
printDebug("WRITE-PARTTIMBRE (%d-%d@%d..%d): timbre=%d (%s)", firstPart, lastPart, off, off + len, i, instrumentName);
if (parts[i] != NULL) {
- parts[i]->RefreshPatch();
+ parts[i]->refreshPatch();
}
}
}
@@ -1053,12 +1059,12 @@ void Synth::playSysexWithoutHeader(unsigned char device, Bit8u *sysex, Bit32u le
// Does the real MT-32 automatically do this?
if (i >= 128 && parts[8] != NULL) {
// FIXME:KG: Only bother to re-cache when this timbre's actually in the rhythm map
- parts[8]->SetPatch(i); // Re-cache this timbre
+ parts[8]->setPatch(i); // Re-cache this timbre
}
for (unsigned int part = 0; part < 8; part++) {
if (parts[part] != NULL) {
if (parts[part]->getAbsTimbreNum() == i) {
- parts[part]->RefreshPatch();
+ parts[part]->refreshPatch();
}
}
}
@@ -1080,7 +1086,7 @@ void Synth::playSysexWithoutHeader(unsigned char device, Bit8u *sysex, Bit32u le
for (unsigned int i = 0; i < 9; i++) {
//LOG(LOG_MISC|LOG_ERROR,"Part %d set to MIDI channel %d",i,mt32ram.params.system.chanAssign[i]);
if (mt32ram.params.system.chanAssign[i] == 16) {
- parts[i]->AllStop();
+ parts[i]->allStop();
} else {
chantable[(int)mt32ram.params.system.chanAssign[i]] = (char)i;
}
@@ -1093,12 +1099,12 @@ void Synth::playSysexWithoutHeader(unsigned char device, Bit8u *sysex, Bit32u le
report(ReportType_newReverbLevel, &mt32ram.params.system.reverbLevel);
if ((mt32ram.params.system.reverbMode != curRevMode) || (mt32ram.params.system.reverbTime != curRevTime)) {
- if (myProp.UseDefault) {
+ if (myProp.useDefaultReverb) {
initReverb(mt32ram.params.system.reverbMode, mt32ram.params.system.reverbTime);
curRevLevel = mt32ram.params.system.reverbLevel;
} else {
- initReverb(myProp.RevType, myProp.RevTime);
- curRevLevel = myProp.RevLevel;
+ initReverb(myProp.reverbType, myProp.reverbTime);
+ curRevLevel = myProp.reverbLevel;
}
}
@@ -1127,9 +1133,9 @@ void Synth::playSysexWithoutHeader(unsigned char device, Bit8u *sysex, Bit32u le
partialManager->DeactivateAll();
mt32ram = mt32default;
for (int i = 0; i < 8; i++) {
- parts[i]->RefreshPatch();
+ parts[i]->refreshPatch();
}
- parts[8]->RefreshDrumCache();
+ parts[8]->refreshDrumCache();
isEnabled = false;
} else {
printDebug("Sysex write to unrecognised address %06x", SYSEXMEMADDR(addr));
@@ -1195,7 +1201,7 @@ int Synth::dumpSysex(char *filename) {
}
void ProduceOutput1(Bit16s *useBuf, Bit16s *stream, Bit32u len, Bit16s volume) {
-#if USE_MMX > 2
+#if MT32EMU_USE_MMX > 2
//FIXME:KG: This appears to introduce crackle
int donelen = i386_produceOutput1(useBuf, stream, len, volume);
len -= donelen;
@@ -1226,9 +1232,9 @@ void Synth::doRender(Bit16s * stream,Bit32u len) {
partialManager->AgeAll();
- if (myProp.UseReverb) {
+ if (myProp.useReverb) {
bool hasOutput = false;
- for (unsigned int i = 0; i < MAXPARTIALS; i++) {
+ for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
if (partialManager->shouldReverb(i)) {
if (partialManager->ProduceOutput(i, &tmpBuffer[0], len)) {
ProduceOutput1(&tmpBuffer[0], stream, len, mastervolume);
@@ -1254,7 +1260,7 @@ void Synth::doRender(Bit16s * stream,Bit32u len) {
m++;
}
}
- for (unsigned int i = 0; i < MAXPARTIALS; i++) {
+ for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
if (!partialManager->shouldReverb(i)) {
if (partialManager->ProduceOutput(i, &tmpBuffer[0], len)) {
ProduceOutput1(&tmpBuffer[0], stream, len, mastervolume);
@@ -1262,7 +1268,7 @@ void Synth::doRender(Bit16s * stream,Bit32u len) {
}
}
} else {
- for (unsigned int i = 0; i < MAXPARTIALS; i++) {
+ for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
if (partialManager->ProduceOutput(i, &tmpBuffer[0], len))
ProduceOutput1(&tmpBuffer[0], stream, len, mastervolume);
}
@@ -1270,14 +1276,14 @@ void Synth::doRender(Bit16s * stream,Bit32u len) {
partialManager->ClearAlreadyOutputed();
-#if MONITORPARTIALS == 1
+#if MT32EMU_MONITOR_PARTIALS == 1
samplepos += len;
if (samplepos > myProp.SampleRate * 5) {
samplepos = 0;
int partialUsage[9];
partialManager->GetPerPartPartialUsage(partialUsage);
printDebug("1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d", partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7]);
- printDebug("Rhythm: %02d TOTAL: %02d", partialUsage[8], MAXPARTIALS - partialManager->GetFreePartialCount());
+ printDebug("Rhythm: %02d TOTAL: %02d", partialUsage[8], MT32EMU_MAX_PARTIALS - partialManager->GetFreePartialCount());
}
#endif
}
diff --git a/backends/midi/mt32/synth.h b/backends/midi/mt32/synth.h
index f2fc3ffae6..3609592a2f 100644
--- a/backends/midi/mt32/synth.h
+++ b/backends/midi/mt32/synth.h
@@ -24,17 +24,14 @@
#include <stdarg.h>
-// Shows number of partials MT-32 is playing
-#define MONITORPARTIALS 0
-
-#define ROMSIZE (512 * 1024)
-#define PCMSIZE (ROMSIZE / 2)
-#define GRAN 512
-
class revmodel;
namespace MT32Emu {
+const int ROMSIZE = 512 * 1024;
+const int PCMSIZE = ROMSIZE / 2;
+const int GRAN = 512;
+
class File;
class TableInitialiser;
class Partial;
@@ -48,38 +45,39 @@ enum ReportType {
ReportType_errorDrumpat = 3,
ReportType_errorPatchlog = 4,
ReportType_errorMT32ROM = 5,
+ ReportType_errorSampleRate = 6,
// HW spec
- ReportType_availableSSE = 6,
- ReportType_available3DNow = 7,
- ReportType_usingSSE = 8,
- ReportType_using3DNow = 9,
+ ReportType_availableSSE = 7,
+ ReportType_available3DNow = 8,
+ ReportType_usingSSE = 9,
+ ReportType_using3DNow = 10,
// General info
- ReportType_lcdMessage = 10,
- ReportType_devReset = 11,
- ReportType_devReconfig = 12,
- ReportType_newReverbMode = 13,
- ReportType_newReverbTime = 14,
- ReportType_newReverbLevel = 15
+ ReportType_lcdMessage = 11,
+ ReportType_devReset = 12,
+ ReportType_devReconfig = 13,
+ ReportType_newReverbMode = 14,
+ ReportType_newReverbTime = 15,
+ ReportType_newReverbLevel = 16
};
struct SynthProperties {
// Sample rate to use in mixing
- int SampleRate;
+ int sampleRate;
// Flag to activate reverb. True = use reverb, False = no reverb
- bool UseReverb;
- // Flag True to use software set reverb settings, Flag False to set reverb settings in
+ bool useReverb;
+ // True to use software set reverb settings, False to set reverb settings in
// following parameters
- bool UseDefault;
+ bool useDefaultReverb;
// When not using the default settings, this specifies one of the 4 reverb types
// 1 = Room 2 = Hall 3 = Plate 4 = Tap
- unsigned char RevType;
+ unsigned char reverbType;
// This specifies the delay time, from 0-7 (not sure of the actual MT-32's measurement)
- unsigned char RevTime;
+ unsigned char reverbTime;
// This specifies the reverb level, from 0-7 (not sure of the actual MT-32's measurement)
- unsigned char RevLevel;
+ unsigned char reverbLevel;
// The name of the directory in which the ROM and data files are stored (with trailing slash/backslash)
// Not used if "openFile" is set. May be NULL in any case.
char *baseDir;
@@ -116,15 +114,14 @@ friend class TableInitialiser;
private:
bool isEnabled;
- sampleFormat PCM[54];
- sampleTable PCMList[128];
- Bit32u PCMReassign[54];
+ PCMWave PCM[54];
+ PCMWaveEntry PCMList[128];
Bit32s PCMLoopTable[54];
Bit16s romfile[PCMSIZE + GRAN];
Bit8s chantable[32];
- #if MONITORPARTIALS == 1
+ #if MT32EMU_MONITOR_PARTIALS == 1
static Bit32s samplepos = 0;
#endif
diff --git a/backends/midi/mt32/tables.cpp b/backends/midi/mt32/tables.cpp
index b09b3c58bc..3afd03e226 100644
--- a/backends/midi/mt32/tables.cpp
+++ b/backends/midi/mt32/tables.cpp
@@ -25,15 +25,6 @@
#include "mt32emu.h"
-// Determines how the waveform cache file is handled (must be regenerated after sampling rate change)
-#define WAVECACHEMODE 0 // Load existing cache if possible, otherwise generate and save cache
-//#define WAVECACHEMODE 1 // Load existing cache if possible, otherwise generage but don't save cache
-//#define WAVECACHEMODE 2 // Ignore existing cache, generate and save cache
-//#define WAVECACHEMODE 3 // Ignore existing cache, generate but don't save cache
-
-// Constant tuning for now
-#define TUNING 440.0f
-
namespace MT32Emu {
//Amplitude time velocity follow exponential coefficients
@@ -95,26 +86,25 @@ Bit32s envtimetable[101];
Bit32s decaytimetable[101];
Bit32s lasttimetable[101];
Bit32s voltable[128];
-Bit32s bendtable[49];
float ResonFactor[31];
float ResonInv[31];
// Per-note initialisation tables follow
-Bit16s freqtable[NUMNOTES];
-Bit32s fildeptable[5][NUMNOTES];
-Bit32s timekeytable[5][NUMNOTES];
-int filttable[2][NUMNOTES][201];
-int nfilttable[NUMNOTES][101][101];
+Bit16s freqtable[NUM_NOTES];
+Bit32s fildeptable[5][NUM_NOTES];
+Bit32s timekeytable[5][NUM_NOTES];
+int filttable[2][NUM_NOTES][201];
+int nfilttable[NUM_NOTES][101][101];
-Bit32s divtable[NUMNOTES];
-Bit32s smalldivtable[NUMNOTES];
-Bit32u wavtabler[54][NUMNOTES];
-Bit32u looptabler[9][10][NUMNOTES];
-Bit32s sawtable[NUMNOTES][101];
+Bit32s divtable[NUM_NOTES];
+Bit32s smalldivtable[NUM_NOTES];
+Bit32u wavtabler[54][NUM_NOTES];
+Bit32u looptabler[9][10][NUM_NOTES];
+Bit32s sawtable[NUM_NOTES][101];
-Bit16s *waveforms[4][NUMNOTES];
-Bit32u waveformsize[4][NUMNOTES];
+Bit16s *waveforms[4][NUM_NOTES];
+Bit32u waveformsize[4][NUM_NOTES];
static Bit16s tmpforms[4][65536];
@@ -126,7 +116,7 @@ static Bit16s tmpforms[4][65536];
static void prewarp(double *a1, double *a2, double fc, double fs) {
double wp;
- wp = 2.0 * fs * tan(PI * fc / fs);
+ wp = 2.0 * fs * tan(DOUBLE_PI * fc / fs);
*a2 = *a2 / (wp * wp);
*a1 = *a1 / wp;
@@ -331,8 +321,6 @@ void TableInitialiser::initMT32ConstantTables(Synth *synth) {
//FIXME:KG: I'm fairly sure this is wrong... lf=100 should yield no fine-tuning (4096)?
finetable[lf] = (int)((powf(2.0f, (((float)lf / 200.0f) - 1.0f) / 12.0f)) * 4096.0f);
}
- for (lf = 0; lf <= 48; lf++)
- bendtable[lf] = (int)((powf(2.0f, (((float)lf / 12.0f) - 2.0f))) * 4096.0f);
float lff;
for (lf = 0; lf < 128; lf++) {
@@ -345,7 +333,7 @@ void TableInitialiser::initMT32ConstantTables(Synth *synth) {
for (lf = 0; lf < 128; lf++) {
// Converts MIDI velocity to volume.
- voltable[lf] = (int)(127.0 * pow((float)lf / 127.0, LN));
+ voltable[lf] = (int)(127.0 * pow((float)lf / 127.0, DOUBLE_LN));
}
for (lf = 0; lf < MAX_SAMPLE_OUTPUT; lf++) {
int myRand;
@@ -440,7 +428,7 @@ void TableInitialiser::initMT32ConstantTables(Synth *synth) {
dval = 1;
ampbiastable[lf][distval] = 256;
} else {
- amplog = powf(1.431817011f, (float)lf) / (float)PI;
+ amplog = powf(1.431817011f, (float)lf) / FLOAT_PI;
dval = ((128.0f - (float)distval) / 128.0f);
amplog = expf(amplog);
dval = powf(amplog, dval) / amplog;
@@ -459,8 +447,8 @@ void TableInitialiser::initMT32ConstantTables(Synth *synth) {
dval = 1;
fbiastable[lf][distval] = 256;
} else {
- //amplog = pow(1.431817011, filval) / (float)PI;
- amplog = powf(1.531817011f, filval) / (float)PI;
+ //amplog = pow(1.431817011, filval) / FLOAT_PI;
+ amplog = powf(1.531817011f, filval) / FLOAT_PI;
dval = (128.0f - (float)distval) / 128.0f;
amplog = expf(amplog);
dval = powf(amplog,dval)/amplog;
@@ -519,7 +507,7 @@ static void initDep(int f) {
}
void TableInitialiser::initWave(Synth *synth, File *file, bool reading, bool writing, int f, float freq, float rate, double ampsize, Bit32s div) {
- double sd = (2.0*PI)/((((float)div/65536.0)) * 4.0);
+ double sd = (2.0 * DOUBLE_PI) / ((((float)div / 65536.0)) * 4.0);
waveformsize[0][f] = div >> 14;
waveformsize[1][f] = div >> 14;
waveformsize[2][f] = div >> 14;
@@ -541,15 +529,15 @@ void TableInitialiser::initWave(Synth *synth, File *file, bool reading, bool wri
int fa = 0;
memset(tmpforms, 0,sizeof(tmpforms));
- while (sa <= (2.0 * PI)) {
+ while (sa <= (2.0 * DOUBLE_PI)) {
float sqp;
- if (sa < PI) {
+ if (sa < DOUBLE_PI) {
sqp = -1;
- sqp = (float)(sqp + (0.25 * (sa/PI)));
+ sqp = (float)(sqp + (0.25 * (sa/DOUBLE_PI)));
} else {
sqp=1;
- sqp = (float)(sqp - (0.25 * ((sa-PI)/PI)));
+ sqp = (float)(sqp - (0.25 * ((sa - DOUBLE_PI)/DOUBLE_PI)));
}
saw = 0;
@@ -565,8 +553,8 @@ void TableInitialiser::initWave(Synth *synth, File *file, bool reading, bool wri
tmpforms[1][fa] = (Bit16s)(saw * ampsize / 2);
tmpforms[2][fa] = (Bit16s)(cos(dumbfire) * -ampsize);
- tmpforms[3][fa * 2] = (Bit16s)(cos(sa - PI) * -ampsize);
- tmpforms[3][fa * 2 + 1] = (Bit16s)(cos((sa + (sd / 2)) - PI) * -ampsize);
+ tmpforms[3][fa * 2] = (Bit16s)(cos(sa - DOUBLE_PI) * -ampsize);
+ tmpforms[3][fa * 2 + 1] = (Bit16s)(cos((sa + (sd / 2)) - DOUBLE_PI) * -ampsize);
fa++;
sa += sd;
@@ -628,7 +616,7 @@ static void initNFiltTable(int f, float freq, float rate) {
}
}
-void TableInitialiser::initNotes(Synth *synth, sampleFormat pcms[54], float rate) {
+void TableInitialiser::initNotes(Synth *synth, PCMWave pcms[54], float rate) {
char filename[32];
int intRate = (int)rate;
sprintf(filename, "waveformcache-%d.raw", intRate);
@@ -645,7 +633,7 @@ void TableInitialiser::initNotes(Synth *synth, sampleFormat pcms[54], float rate
header[pos++] = (char)((intRate >> 8) & 0xFF);
header[pos++] = (char)((intRate >> 16) & 0xFF);
header[pos] = (char)((intRate >> 24) & 0xFF);
-#if WAVECACHEMODE < 2
+#if MT32EMU_WAVECACHEMODE < 2
file = synth->openFile(filename, File::OpenMode_read);
if (file != NULL) {
char fileHeader[16];
@@ -662,7 +650,7 @@ void TableInitialiser::initNotes(Synth *synth, sampleFormat pcms[54], float rate
synth->printDebug("Unable to open %s for reading - will generate", filename);
}
#endif
-#if WAVECACHEMODE == 0 || WAVECACHEMODE == 2
+#if MT32EMU_WAVECACHEMODE == 0 || MT32EMU_WAVECACHEMODE == 2
if (!reading) {
file = synth->openFile(filename, File::OpenMode_write);
if (file != NULL) {
@@ -710,9 +698,10 @@ void TableInitialiser::initNotes(Synth *synth, sampleFormat pcms[54], float rate
synth->closeFile(file);
}
-void TableInitialiser::initMT32Tables(Synth *synth, sampleFormat pcms[54], float sampleRate) {
+bool TableInitialiser::initMT32Tables(Synth *synth, PCMWave pcms[54], float sampleRate) {
if (sampleRate <= 0.0f) {
synth->printDebug("Bad sampleRate (%d <= 0.0f)", sampleRate);
+ return false;
}
if (initialisedSampleRate == 0.0f) {
initMT32ConstantTables(synth);
@@ -722,6 +711,7 @@ void TableInitialiser::initMT32Tables(Synth *synth, sampleFormat pcms[54], float
}
// This always needs to be done, to allocate the waveforms
initNotes(synth, pcms, sampleRate);
+ return true;
}
}
diff --git a/backends/midi/mt32/tables.h b/backends/midi/mt32/tables.h
index 1f4fdab8b2..3e73400edf 100644
--- a/backends/midi/mt32/tables.h
+++ b/backends/midi/mt32/tables.h
@@ -22,44 +22,50 @@
#ifndef MT32EMU_TABLES_H
#define MT32EMU_TABLES_H
+namespace MT32Emu {
+
// Mathematical constants
-#ifndef PI
-#define PI 3.1415926535897932384626433832795
-#endif
-#ifndef LN
-#define LN 2.30258509
-#endif
+const double DOUBLE_PI = 3.1415926535897932384626433832795;
+const double DOUBLE_LN = 2.3025850929940456840179914546844;
+const float FLOAT_PI = 3.1415926535897932384626433832795f;
+const float FLOAT_LN = 2.3025850929940456840179914546844f;
// Filter settings
-#define FILTERGRAN 512
+const int FILTERGRAN = 512;
-#define MIDDLEC 60
+const int MIDDLEC = 60;
+const int MIDDLEA = 69; // By this I mean "A above middle C"
-#define NUMNOTES 128 // MIDI supports 128 notes/keys
+// 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;
-// Amplitude of waveform generator
-#define WGAMP (7168)
-//#define WGAMP (8192)
+const int NUM_NOTES = 128; // MIDI supports 128 notes/keys
-namespace MT32Emu {
+// 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
extern Bit32s keytable[217];
-extern Bit32s divtable[NUMNOTES];
-extern Bit32s smalldivtable[NUMNOTES];
-extern Bit32u wavtabler[54][NUMNOTES];
-extern Bit32u looptabler[9][10][NUMNOTES];
+extern Bit32s divtable[NUM_NOTES];
+extern Bit32s smalldivtable[NUM_NOTES];
+extern Bit32u wavtabler[54][NUM_NOTES];
+extern Bit32u looptabler[9][10][NUM_NOTES];
extern Bit16s sintable[65536];
extern Bit32u lfotable[101];
extern Bit32s penvtable[16][101];
extern Bit32s filveltable[128][101];
extern Bit32s veltkeytable[5][128];
extern Bit32s pulsetable[101];
-extern Bit32s sawtable[NUMNOTES][101];
+extern Bit32s sawtable[NUM_NOTES][101];
extern Bit32s ampbiastable[13][128];
extern Bit32s fbiastable[15][128];
extern float filtcoeff[FILTERGRAN][31][8];
@@ -73,23 +79,23 @@ extern Bit32s lasttimetable[101];
extern Bit32s voltable[128];
extern float ResonInv[31];
-extern Bit16s freqtable[NUMNOTES];
-extern Bit32s fildeptable[5][NUMNOTES];
-extern Bit32s timekeytable[5][NUMNOTES];
-extern int filttable[2][NUMNOTES][201];
-extern int nfilttable[NUMNOTES][101][101];
+extern Bit16s freqtable[NUM_NOTES];
+extern Bit32s fildeptable[5][NUM_NOTES];
+extern Bit32s timekeytable[5][NUM_NOTES];
+extern int filttable[2][NUM_NOTES][201];
+extern int nfilttable[NUM_NOTES][101][101];
extern const Bit8s LoopPatterns[9][10];
-extern Bit16s *waveforms[4][NUMNOTES];
-extern Bit32u waveformsize[4][NUMNOTES];
+extern Bit16s *waveforms[4][NUM_NOTES];
+extern Bit32u waveformsize[4][NUM_NOTES];
class TableInitialiser {
- void initMT32ConstantTables(Synth *synth);
- void initWave(Synth *synth, File *file, bool reading, bool writing, int f, float freq, float rate, double ampsize, Bit32s div);
- void initNotes(Synth *synth, sampleFormat pcms[54], float rate);
+ static void initMT32ConstantTables(Synth *synth);
+ static void initWave(Synth *synth, File *file, bool reading, bool writing, int f, float freq, float rate, double ampsize, Bit32s div);
+ static void initNotes(Synth *synth, PCMWave pcms[54], float rate);
public:
- void initMT32Tables(Synth *synth, sampleFormat pcms[54], float sampleRate);
+ static bool initMT32Tables(Synth *synth, PCMWave pcms[54], float sampleRate);
};
}