diff options
author | Jerome Fisher | 2004-11-28 05:35:07 +0000 |
---|---|---|
committer | Jerome Fisher | 2004-11-28 05:35:07 +0000 |
commit | 077d19f5008e5cb911b1291f59b63fc46da18cc8 (patch) | |
tree | d3361671ac04d9d7f0e5e4354a78f4bd48a847d1 /backends/midi/mt32/tables.cpp | |
parent | 67b8abac08befed3e545dd500df4f28b7524348a (diff) | |
download | scummvm-rg350-077d19f5008e5cb911b1291f59b63fc46da18cc8.tar.gz scummvm-rg350-077d19f5008e5cb911b1291f59b63fc46da18cc8.tar.bz2 scummvm-rg350-077d19f5008e5cb911b1291f59b63fc46da18cc8.zip |
- 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.
svn-id: r15929
Diffstat (limited to 'backends/midi/mt32/tables.cpp')
-rw-r--r-- | backends/midi/mt32/tables.cpp | 126 |
1 files changed, 64 insertions, 62 deletions
diff --git a/backends/midi/mt32/tables.cpp b/backends/midi/mt32/tables.cpp index 2f710e8e0e..3d0ab5ea45 100644 --- a/backends/midi/mt32/tables.cpp +++ b/backends/midi/mt32/tables.cpp @@ -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 tkcatconst[5] = {0.0, 0.005853144, 0.011148054, 0.019086143, 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 @@ static void initEnvelopes(float samplerate) { //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 @@ void TableInitialiser::initMT32ConstantTables(Synth *synth) { 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 @@ File *TableInitialiser::initWave(Synth *synth, NoteLookup *noteLookup, float amp #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 @@ static void initNFiltTable(NoteLookup *noteLookup, float freq, float rate) { } } -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 @@ File *TableInitialiser::initNote(Synth *synth, NoteLookup *noteLookup, float not // 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 @@ File *TableInitialiser::initNote(Synth *synth, NoteLookup *noteLookup, float not 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 @@ void TableInitialiser::initNotes(Synth *synth, PCMWave pcmWaves[54], float rate, 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 @@ void TableInitialiser::initNotes(Synth *synth, PCMWave pcmWaves[54], float rate, 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 @@ void TableInitialiser::initNotes(Synth *synth, PCMWave pcmWaves[54], float rate, 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 @@ void TableInitialiser::initNotes(Synth *synth, PCMWave pcmWaves[54], float rate, if (file != NULL) synth->closeFile(file); + return !abort; +} + +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, PCMWave pcms[54], float sampleRate) { +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; } |