diff options
Diffstat (limited to 'audio/softsynth/mt32/Synth.cpp')
-rw-r--r-- | audio/softsynth/mt32/Synth.cpp | 702 |
1 files changed, 197 insertions, 505 deletions
diff --git a/audio/softsynth/mt32/Synth.cpp b/audio/softsynth/mt32/Synth.cpp index ca28898205..6df7eb9e31 100644 --- a/audio/softsynth/mt32/Synth.cpp +++ b/audio/softsynth/mt32/Synth.cpp @@ -1,5 +1,5 @@ /* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher - * Copyright (C) 2011-2016 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * Copyright (C) 2011, 2012, 2013, 2014 Dean Beeler, Jerome Fisher, Sergey V. Mikayev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,138 +15,42 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <cstdio> +//#include <cerrno> +//#include <cmath> +//#include <cstdlib> +//#include <cstring> +#include "mt32emu.h" +#include "mmath.h" #include "internals.h" -#include "Synth.h" #include "Analog.h" #include "BReverbModel.h" -#include "File.h" #include "MemoryRegion.h" #include "MidiEventQueue.h" -#include "Part.h" -#include "Partial.h" #include "PartialManager.h" -#include "Poly.h" -#include "ROMInfo.h" -#include "TVA.h" namespace MT32Emu { // MIDI interface data transfer rate in samples. Used to simulate the transfer delay. static const double MIDI_DATA_TRANSFER_RATE = (double)SAMPLE_RATE / 31250.0 * 8.0; -// FIXME: there should be more specific feature sets for various MT-32 control ROM versions -static const ControlROMFeatureSet OLD_MT32_COMPATIBLE = { true, true, true }; -static const ControlROMFeatureSet CM32L_COMPATIBLE = { false, false, false }; - static const ControlROMMap ControlROMMaps[7] = { - // ID Features PCMmap PCMc tmbrA tmbrAO, tmbrAC tmbrB tmbrBO tmbrBC tmbrR trC rhythm rhyC rsrv panpot prog rhyMax patMax sysMax timMax sndGrp sGC - { "ctrl_mt32_1_04", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x73A6, 85, 0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A, 0x7064, 19 }, - { "ctrl_mt32_1_05", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x7414, 85, 0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A, 0x70CA, 19 }, - { "ctrl_mt32_1_06", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x7414, 85, 0x57D9, 0x57F4, 0x57E2, 0x5264, 0x5270, 0x5280, 0x521C, 0x70CA, 19 }, - { "ctrl_mt32_1_07", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x73fe, 85, 0x57B1, 0x57CC, 0x57BA, 0x523C, 0x5248, 0x5258, 0x51F4, 0x70B0, 19 }, // MT-32 revision 1 - {"ctrl_mt32_bluer", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x741C, 85, 0x57E5, 0x5800, 0x57EE, 0x5270, 0x527C, 0x528C, 0x5228, 0x70CE, 19 }, // MT-32 Blue Ridge mod - {"ctrl_cm32l_1_00", CM32L_COMPATIBLE, 0x8100, 256, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4F65, 0x4F80, 0x4F6E, 0x48A1, 0x48A5, 0x48BE, 0x48D5, 0x5A6C, 19 }, - {"ctrl_cm32l_1_02", CM32L_COMPATIBLE, 0x8100, 256, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4F93, 0x4FAE, 0x4F9C, 0x48CB, 0x48CF, 0x48E8, 0x48FF, 0x5A96, 19 } // CM-32L + // ID IDc IDbytes PCMmap PCMc tmbrA tmbrAO, tmbrAC tmbrB tmbrBO, tmbrBC tmbrR trC rhythm rhyC rsrv panpot prog rhyMax patMax sysMax timMax + {0x4014, 22, "\000 ver1.04 14 July 87 ", 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x73A6, 85, 0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A}, + {0x4014, 22, "\000 ver1.05 06 Aug, 87 ", 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x7414, 85, 0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A}, + {0x4014, 22, "\000 ver1.06 31 Aug, 87 ", 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x7414, 85, 0x57D9, 0x57F4, 0x57E2, 0x5264, 0x5270, 0x5280, 0x521C}, + {0x4010, 22, "\000 ver1.07 10 Oct, 87 ", 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x73fe, 85, 0x57B1, 0x57CC, 0x57BA, 0x523C, 0x5248, 0x5258, 0x51F4}, // MT-32 revision 1 + {0x4010, 22, "\000verX.XX 30 Sep, 88 ", 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x741C, 85, 0x57E5, 0x5800, 0x57EE, 0x5270, 0x527C, 0x528C, 0x5228}, // MT-32 Blue Ridge mod + {0x2205, 22, "\000CM32/LAPC1.00 890404", 0x8100, 256, 0x8000, 0x8000, false, 0x8080, 0x8000, false, 0x8500, 64, 0x8580, 85, 0x4F65, 0x4F80, 0x4F6E, 0x48A1, 0x48A5, 0x48BE, 0x48D5}, + {0x2205, 22, "\000CM32/LAPC1.02 891205", 0x8100, 256, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4F93, 0x4FAE, 0x4F9C, 0x48CB, 0x48CF, 0x48E8, 0x48FF} // CM-32L // (Note that all but CM-32L ROM actually have 86 entries for rhythmTemp) }; -static const PartialState PARTIAL_PHASE_TO_STATE[8] = { - PartialState_ATTACK, PartialState_ATTACK, PartialState_ATTACK, PartialState_ATTACK, - PartialState_SUSTAIN, PartialState_SUSTAIN, PartialState_RELEASE, PartialState_INACTIVE -}; - -static inline PartialState getPartialState(PartialManager *partialManager, unsigned int partialNum) { - const Partial *partial = partialManager->getPartial(partialNum); - return partial->isActive() ? PARTIAL_PHASE_TO_STATE[partial->getTVA()->getPhase()] : PartialState_INACTIVE; -} - -static inline Bit16s convertSample(float sample) { - return Synth::clipSampleEx(Bit32s(sample * 16384.0f)); // This multiplier takes into account the DAC bit shift -} - -static inline float convertSample(Bit16s sample) { - return float(sample) / 16384.0f; // This multiplier takes into account the DAC bit shift -} - -class SampleFormatConverter { -protected: -#if MT32EMU_USE_FLOAT_SAMPLES - Bit16s *outBuffer; -#else - float *outBuffer; -#endif - -public: - Sample *sampleBuffer; - - SampleFormatConverter(Sample *buffer) : outBuffer(NULL), sampleBuffer(buffer) {} - - inline bool isConversionNeeded() { - return outBuffer != NULL; - } - - inline void convert(Bit32u len) { - if (sampleBuffer == NULL) return; - if (outBuffer == NULL) { - sampleBuffer += len; - return; - } - Sample *inBuffer = sampleBuffer; - while (len--) { - *(outBuffer++) = convertSample(*(inBuffer++)); - } - } - - inline void addSilence(Bit32u len) { - if (outBuffer != NULL) { - Synth::muteSampleBuffer(outBuffer, len); - outBuffer += len; - } else if (sampleBuffer != NULL) { - Synth::muteSampleBuffer(sampleBuffer, len); - sampleBuffer += len; - } - } -}; - -template <int BUFFER_SIZE_MULTIPLIER = 1> -class BufferedSampleFormatConverter : public SampleFormatConverter { - Sample renderingBuffer[BUFFER_SIZE_MULTIPLIER * MAX_SAMPLES_PER_RUN]; - -public: -#if MT32EMU_USE_FLOAT_SAMPLES - BufferedSampleFormatConverter(Bit16s *buffer) -#else - BufferedSampleFormatConverter(float *buffer) -#endif - : SampleFormatConverter(renderingBuffer) - { - outBuffer = buffer; - if (buffer == NULL) sampleBuffer = NULL; +static inline void advanceStreamPosition(Sample *&stream, Bit32u posDelta) { + if (stream != NULL) { + stream += posDelta; } -}; - -class Renderer { - Synth &synth; - -public: - Renderer(Synth &useSynth) : synth(useSynth) {} - - void render(SampleFormatConverter &converter, Bit32u len); - void renderStreams(SampleFormatConverter &nonReverbLeft, SampleFormatConverter &nonReverbRight, SampleFormatConverter &reverbDryLeft, SampleFormatConverter &reverbDryRight, SampleFormatConverter &reverbWetLeft, SampleFormatConverter &reverbWetRight, Bit32u len); - void produceLA32Output(Sample *buffer, Bit32u len); - void convertSamplesToOutput(Sample *buffer, Bit32u len); - void doRenderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sample *reverbDryLeft, Sample *reverbDryRight, Sample *reverbWetLeft, Sample *reverbWetRight, Bit32u len); -}; - -Bit32u Synth::getLibraryVersionInt() { - return (MT32EMU_VERSION_MAJOR << 16) | (MT32EMU_VERSION_MINOR << 8) | (MT32EMU_VERSION_PATCH); -} - -const char *Synth::getLibraryVersionString() { - return MT32EMU_VERSION; } Bit8u Synth::calcSysexChecksum(const Bit8u *data, const Bit32u len, const Bit8u initChecksum) { @@ -157,17 +61,10 @@ Bit8u Synth::calcSysexChecksum(const Bit8u *data, const Bit32u len, const Bit8u return Bit8u(checksum & 0x7f); } -Bit32u Synth::getStereoOutputSampleRate(AnalogOutputMode analogOutputMode) { - static const unsigned int SAMPLE_RATES[] = {SAMPLE_RATE, SAMPLE_RATE, SAMPLE_RATE * 3 / 2, SAMPLE_RATE * 3}; - - return SAMPLE_RATES[analogOutputMode]; -} - -Synth::Synth(ReportHandler *useReportHandler) : mt32ram(*new MemParams), mt32default(*new MemParams), renderer(*new Renderer(*this)) { - opened = false; +Synth::Synth(ReportHandler *useReportHandler) : mt32ram(*new MemParams()), mt32default(*new MemParams()) { + isOpen = false; reverbOverridden = false; partialCount = DEFAULT_MAX_PARTIALS; - controlROMMap = NULL; controlROMFeatures = NULL; if (useReportHandler == NULL) { @@ -188,27 +85,11 @@ Synth::Synth(ReportHandler *useReportHandler) : mt32ram(*new MemParams), mt32def setOutputGain(1.0f); setReverbOutputGain(1.0f); setReversedStereoEnabled(false); - - patchTempMemoryRegion = NULL; - rhythmTempMemoryRegion = NULL; - timbreTempMemoryRegion = NULL; - patchesMemoryRegion = NULL; - timbresMemoryRegion = NULL; - systemMemoryRegion = NULL; - displayMemoryRegion = NULL; - resetMemoryRegion = NULL; - paddedTimbreMaxTable = NULL; - partialManager = NULL; - pcmWaves = NULL; - pcmROMData = NULL; - soundGroupNames = NULL; midiQueue = NULL; lastReceivedMIDIEventTimestamp = 0; memset(parts, 0, sizeof(parts)); renderedSampleCount = 0; - - reserved = NULL; } Synth::~Synth() { @@ -218,52 +99,47 @@ Synth::~Synth() { } delete &mt32ram; delete &mt32default; - delete &renderer; } void ReportHandler::showLCDMessage(const char *data) { - printf("WRITE-LCD: %s\n", data); + // We cannot use printf here. Since we already implement our own + // ReportHandler we simply disable the default implementation since it is + // never called anyway. +#if 0 + printf("WRITE-LCD: %s", data); + printf("\n"); +#endif } void ReportHandler::printDebug(const char *fmt, va_list list) { + // We cannot use (v)printf here. Since we already implement our own + // ReportHandler we simply disable the default implementation since it is + // never called anyway. +#if 0 vprintf(fmt, list); printf("\n"); +#endif } -void Synth::newTimbreSet(Bit8u partNum, Bit8u timbreGroup, Bit8u timbreNumber, const char patchName[]) { - const char *soundGroupName; - switch (timbreGroup) { - case 1: - timbreNumber += 64; - // Fall-through - case 0: - soundGroupName = soundGroupNames[soundGroupIx[timbreNumber]]; - break; - case 2: - soundGroupName = soundGroupNames[controlROMMap->soundGroupsCount - 2]; - break; - case 3: - soundGroupName = soundGroupNames[controlROMMap->soundGroupsCount - 1]; - break; - default: - soundGroupName = NULL; - break; - } - reportHandler->onProgramChanged(partNum, soundGroupName, patchName); +void Synth::polyStateChanged(int partNum) { + reportHandler->onPolyStateChanged(partNum); +} + +void Synth::newTimbreSet(int partNum, Bit8u timbreGroup, const char patchName[]) { + reportHandler->onProgramChanged(partNum, timbreGroup, patchName); } void Synth::printDebug(const char *fmt, ...) { va_list ap; va_start(ap, fmt); #if MT32EMU_DEBUG_SAMPLESTAMPS > 0 - reportHandler->printDebug("[%u]", (va_list)&renderedSampleCount); + reportHandler->printDebug("[%u] ", (char *)&renderedSampleCount); #endif reportHandler->printDebug(fmt, ap); va_end(ap); } void Synth::setReverbEnabled(bool newReverbEnabled) { - if (!opened) return; if (isReverbEnabled() == newReverbEnabled) return; if (newReverbEnabled) { bool oldReverbOverridden = reverbOverridden; @@ -291,23 +167,30 @@ bool Synth::isReverbOverridden() const { } void Synth::setReverbCompatibilityMode(bool mt32CompatibleMode) { - if (!opened || (isMT32ReverbCompatibilityMode() == mt32CompatibleMode)) return; - bool oldReverbEnabled = isReverbEnabled(); - setReverbEnabled(false); - for (int i = 0; i < 4; i++) { - delete reverbModels[i]; + if (reverbModels[REVERB_MODE_ROOM] != NULL) { + if (isMT32ReverbCompatibilityMode() == mt32CompatibleMode) return; + setReverbEnabled(false); + for (int i = 0; i < 4; i++) { + delete reverbModels[i]; + } + } + reverbModels[REVERB_MODE_ROOM] = new BReverbModel(REVERB_MODE_ROOM, mt32CompatibleMode); + reverbModels[REVERB_MODE_HALL] = new BReverbModel(REVERB_MODE_HALL, mt32CompatibleMode); + reverbModels[REVERB_MODE_PLATE] = new BReverbModel(REVERB_MODE_PLATE, mt32CompatibleMode); + reverbModels[REVERB_MODE_TAP_DELAY] = new BReverbModel(REVERB_MODE_TAP_DELAY, mt32CompatibleMode); +#if !MT32EMU_REDUCE_REVERB_MEMORY + for (int i = REVERB_MODE_ROOM; i <= REVERB_MODE_TAP_DELAY; i++) { + reverbModels[i]->open(); + } +#endif + if (isOpen) { + setReverbOutputGain(reverbOutputGain); + setReverbEnabled(true); } - initReverbModels(mt32CompatibleMode); - setReverbEnabled(oldReverbEnabled); - setReverbOutputGain(reverbOutputGain); } bool Synth::isMT32ReverbCompatibilityMode() const { - return opened && (reverbModels[REVERB_MODE_ROOM]->isMT32Compatible(REVERB_MODE_ROOM)); -} - -bool Synth::isDefaultReverbMT32Compatible() const { - return opened && controlROMFeatures->defaultReverbMT32Compatible; + return isOpen && (reverbModels[REVERB_MODE_ROOM]->isMT32Compatible(REVERB_MODE_ROOM)); } void Synth::setDACInputMode(DACInputMode mode) { @@ -356,18 +239,22 @@ void Synth::setReversedStereoEnabled(bool enabled) { reversedStereoEnabled = enabled; } -bool Synth::isReversedStereoEnabled() const { +bool Synth::isReversedStereoEnabled() { return reversedStereoEnabled; } bool Synth::loadControlROM(const ROMImage &controlROMImage) { - File *file = controlROMImage.getFile(); + Common::File *file = controlROMImage.getFile(); const ROMInfo *controlROMInfo = controlROMImage.getROMInfo(); if ((controlROMInfo == NULL) || (controlROMInfo->type != ROMInfo::Control) || (controlROMInfo->pairType != ROMInfo::Full)) { + return false; + } + controlROMFeatures = controlROMImage.getROMInfo()->controlROMFeatures; + if (controlROMFeatures == NULL) { #if MT32EMU_MONITOR_INIT - printDebug("Invalid Control ROM Info provided"); + printDebug("Invalid Control ROM Info provided without feature set"); #endif return false; } @@ -375,16 +262,13 @@ bool Synth::loadControlROM(const ROMImage &controlROMImage) { #if MT32EMU_MONITOR_INIT printDebug("Found Control ROM: %s, %s", controlROMInfo->shortName, controlROMInfo->description); #endif - const Bit8u *fileData = file->getData(); - memcpy(controlROMData, fileData, CONTROL_ROM_SIZE); + file->read(controlROMData, CONTROL_ROM_SIZE); // Control ROM successfully loaded, now check whether it's a known type controlROMMap = NULL; - controlROMFeatures = NULL; for (unsigned int i = 0; i < sizeof(ControlROMMaps) / sizeof(ControlROMMaps[0]); i++) { - if (strcmp(controlROMInfo->shortName, ControlROMMaps[i].shortName) == 0) { + if (memcmp(&controlROMData[ControlROMMaps[i].idPos], ControlROMMaps[i].idBytes, ControlROMMaps[i].idLen) == 0) { controlROMMap = &ControlROMMaps[i]; - controlROMFeatures = &controlROMMap->featureSet; return true; } } @@ -395,7 +279,7 @@ bool Synth::loadControlROM(const ROMImage &controlROMImage) { } bool Synth::loadPCMROM(const ROMImage &pcmROMImage) { - File *file = pcmROMImage.getFile(); + Common::File *file = pcmROMImage.getFile(); const ROMInfo *pcmROMInfo = pcmROMImage.getROMInfo(); if ((pcmROMInfo == NULL) || (pcmROMInfo->type != ROMInfo::PCM) @@ -405,21 +289,24 @@ bool Synth::loadPCMROM(const ROMImage &pcmROMImage) { #if MT32EMU_MONITOR_INIT printDebug("Found PCM ROM: %s, %s", pcmROMInfo->shortName, pcmROMInfo->description); #endif - size_t fileSize = file->getSize(); + size_t fileSize = file->size(); if (fileSize != (2 * pcmROMSize)) { #if MT32EMU_MONITOR_INIT printDebug("PCM ROM file has wrong size (expected %d, got %d)", 2 * pcmROMSize, fileSize); #endif return false; } - const Bit8u *fileData = file->getData(); + + byte *buffer = new byte[file->size()]; + file->read(buffer, file->size()); + const byte *fileData = buffer; for (size_t i = 0; i < pcmROMSize; i++) { Bit8u s = *(fileData++); Bit8u c = *(fileData++); int order[16] = {0, 9, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 8}; - Bit16s log = 0; + signed short log = 0; for (int u = 0; u < 15; u++) { int bit; if (order[u] < 8) { @@ -427,10 +314,13 @@ bool Synth::loadPCMROM(const ROMImage &pcmROMImage) { } else { bit = (c >> (7 - (order[u] - 8))) & 0x1; } - log = log | (Bit16s)(bit << (15 - u)); + log = log | (short)(bit << (15 - u)); } pcmROMData[i] = log; } + + delete[] buffer; + return true; } @@ -455,7 +345,7 @@ bool Synth::initPCMList(Bit16u mapAddress, Bit16u count) { return false; } -bool Synth::initCompressedTimbre(Bit16u timbreNum, const Bit8u *src, Bit32u srcLen) { +bool Synth::initCompressedTimbre(int timbreNum, const Bit8u *src, unsigned int srcLen) { // "Compressed" here means that muted partials aren't present in ROM (except in the case of partial 0 being muted). // Instead the data from the previous unmuted partial is used. if (srcLen < sizeof(TimbreParam::CommonParam)) { @@ -479,7 +369,7 @@ bool Synth::initCompressedTimbre(Bit16u timbreNum, const Bit8u *src, Bit32u srcL return true; } -bool Synth::initTimbres(Bit16u mapAddress, Bit16u offset, Bit16u count, Bit16u startTimbre, bool compressed) { +bool Synth::initTimbres(Bit16u mapAddress, Bit16u offset, int count, int startTimbre, bool compressed) { const Bit8u *timbreMap = &controlROMData[mapAddress]; for (Bit16u i = 0; i < count * 2; i += 2) { Bit16u address = (timbreMap[i + 1] << 8) | timbreMap[i]; @@ -501,32 +391,12 @@ bool Synth::initTimbres(Bit16u mapAddress, Bit16u offset, Bit16u count, Bit16u s return true; } -void Synth::initReverbModels(bool mt32CompatibleMode) { - reverbModels[REVERB_MODE_ROOM] = new BReverbModel(REVERB_MODE_ROOM, mt32CompatibleMode); - reverbModels[REVERB_MODE_HALL] = new BReverbModel(REVERB_MODE_HALL, mt32CompatibleMode); - reverbModels[REVERB_MODE_PLATE] = new BReverbModel(REVERB_MODE_PLATE, mt32CompatibleMode); - reverbModels[REVERB_MODE_TAP_DELAY] = new BReverbModel(REVERB_MODE_TAP_DELAY, mt32CompatibleMode); -#if !MT32EMU_REDUCE_REVERB_MEMORY - for (int i = REVERB_MODE_ROOM; i <= REVERB_MODE_TAP_DELAY; i++) { - reverbModels[i]->open(); - } -#endif -} - -void Synth::initSoundGroups(char newSoundGroupNames[][9]) { - memcpy(soundGroupIx, &controlROMData[controlROMMap->soundGroupsTable - sizeof(soundGroupIx)], sizeof(soundGroupIx)); - const SoundGroup *table = (SoundGroup *)&controlROMData[controlROMMap->soundGroupsTable]; - for (unsigned int i = 0; i < controlROMMap->soundGroupsCount; i++) { - memcpy(&newSoundGroupNames[i][0], table[i].name, sizeof(table[i].name)); - } -} - bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, AnalogOutputMode analogOutputMode) { return open(controlROMImage, pcmROMImage, DEFAULT_MAX_PARTIALS, analogOutputMode); } bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, unsigned int usePartialCount, AnalogOutputMode analogOutputMode) { - if (opened) { + if (isOpen) { return false; } partialCount = usePartialCount; @@ -541,7 +411,6 @@ bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, u if (!loadControlROM(controlROMImage)) { printDebug("Init Error - Missing or invalid Control ROM image"); reportHandler->onErrorControlROM(); - dispose(); return false; } @@ -559,24 +428,22 @@ bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, u if (!loadPCMROM(pcmROMImage)) { printDebug("Init Error - Missing PCM ROM image"); reportHandler->onErrorPCMROM(); - dispose(); return false; } #if MT32EMU_MONITOR_INIT printDebug("Initialising Reverb Models"); #endif - bool mt32CompatibleReverb = controlROMFeatures->defaultReverbMT32Compatible; + bool mt32CompatibleReverb = controlROMFeatures->isDefaultReverbMT32Compatible(); #if MT32EMU_MONITOR_INIT printDebug("Using %s Compatible Reverb Models", mt32CompatibleReverb ? "MT-32" : "CM-32L"); #endif - initReverbModels(mt32CompatibleReverb); + setReverbCompatibilityMode(mt32CompatibleReverb); #if MT32EMU_MONITOR_INIT printDebug("Initialising Timbre Bank A"); #endif if (!initTimbres(controlROMMap->timbreAMap, controlROMMap->timbreAOffset, 0x40, 0, controlROMMap->timbreACompressed)) { - dispose(); return false; } @@ -584,7 +451,6 @@ bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, u printDebug("Initialising Timbre Bank B"); #endif if (!initTimbres(controlROMMap->timbreBMap, controlROMMap->timbreBOffset, 0x40, 64, controlROMMap->timbreBCompressed)) { - dispose(); return false; } @@ -592,7 +458,6 @@ bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, u printDebug("Initialising Timbre Bank R"); #endif if (!initTimbres(controlROMMap->timbreRMap, 0, controlROMMap->timbreRCount, 192, true)) { - dispose(); return false; } @@ -654,10 +519,6 @@ bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, u refreshSystem(); reverbOverridden = oldReverbOverridden; - char(*writableSoundGroupNames)[9] = new char[controlROMMap->soundGroupsCount][9]; - soundGroupNames = writableSoundGroupNames; - initSoundGroups(writableSoundGroupNames); - for (int i = 0; i < 9; i++) { MemParams::PatchTemp *patchTemp = &mt32ram.patchTemp[i]; @@ -689,12 +550,12 @@ bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, u midiQueue = new MidiEventQueue(); - analog = new Analog(analogOutputMode, controlROMFeatures->oldMT32AnalogLPF); + analog = new Analog(analogOutputMode, controlROMFeatures); setOutputGain(outputGain); setReverbOutputGain(reverbOutputGain); - opened = true; - activated = false; + isOpen = true; + isEnabled = false; #if MT32EMU_MONITOR_INIT printDebug("*** Initialisation complete ***"); @@ -702,8 +563,10 @@ bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, u return true; } -void Synth::dispose() { - opened = false; +void Synth::close(bool forced) { + if (!forced && !isOpen) { + return; + } delete midiQueue; midiQueue = NULL; @@ -719,14 +582,8 @@ void Synth::dispose() { parts[i] = NULL; } - delete[] soundGroupNames; - soundGroupNames = NULL; - delete[] pcmWaves; - pcmWaves = NULL; - delete[] pcmROMData; - pcmROMData = NULL; deleteMemoryRegions(); @@ -736,17 +593,7 @@ void Synth::dispose() { } reverbModel = NULL; controlROMFeatures = NULL; - controlROMMap = NULL; -} - -void Synth::close() { - if (opened) { - dispose(); - } -} - -bool Synth::isOpen() const { - return opened; + isOpen = false; } void Synth::flushMIDIQueue() { @@ -817,19 +664,12 @@ bool Synth::playMsg(Bit32u msg) { } bool Synth::playMsg(Bit32u msg, Bit32u timestamp) { - if ((msg & 0xF8) == 0xF8) { - reportHandler->onMIDISystemRealtime((Bit8u)msg); - return true; - } if (midiQueue == NULL) return false; if (midiDelayMode != MIDIDelayMode_IMMEDIATE) { timestamp = addMIDIInterfaceDelay(getShortMessageLength(msg), timestamp); } - if (!activated) activated = true; - do { - if (midiQueue->pushShortMessage(msg, timestamp)) return true; - } while (reportHandler->onMIDIQueueOverflow()); - return false; + if (!isEnabled) isEnabled = true; + return midiQueue->pushShortMessage(msg, timestamp); } bool Synth::playSysex(const Bit8u *sysex, Bit32u len) { @@ -841,28 +681,24 @@ bool Synth::playSysex(const Bit8u *sysex, Bit32u len, Bit32u timestamp) { if (midiDelayMode == MIDIDelayMode_DELAY_ALL) { timestamp = addMIDIInterfaceDelay(len, timestamp); } - if (!activated) activated = true; - do { - if (midiQueue->pushSysex(sysex, len, timestamp)) return true; - } while (reportHandler->onMIDIQueueOverflow()); - return false; + if (!isEnabled) isEnabled = true; + return midiQueue->pushSysex(sysex, len, timestamp); } void Synth::playMsgNow(Bit32u msg) { - if (!opened) return; - // NOTE: Active sense IS implemented in real hardware. However, realtime processing is clearly out of the library scope. // It is assumed that realtime consumers of the library respond to these MIDI events as appropriate. - Bit8u code = (Bit8u)((msg & 0x0000F0) >> 4); - Bit8u chan = (Bit8u)(msg & 0x00000F); - Bit8u note = (Bit8u)((msg & 0x007F00) >> 8); - Bit8u velocity = (Bit8u)((msg & 0x7F0000) >> 16); + unsigned char code = (unsigned char)((msg & 0x0000F0) >> 4); + unsigned char chan = (unsigned char)(msg & 0x00000F); + unsigned char note = (unsigned char)((msg & 0x007F00) >> 8); + unsigned char velocity = (unsigned char)((msg & 0x7F0000) >> 16); + if (!isEnabled) isEnabled = true; //printDebug("Playing chan %d, code 0x%01x note: 0x%02x", chan, code, note); - Bit8u part = chantable[chan]; - if (part > 8) { + char part = chantable[chan]; + if (part < 0 || part > 8) { #if MT32EMU_MONITOR_MIDI > 0 printDebug("Play msg on unreg chan %d (%d): code=0x%01x, vel=%d", chan, part, code, velocity); #endif @@ -871,12 +707,9 @@ void Synth::playMsgNow(Bit32u msg) { playMsgOnPart(part, code, note, velocity); } -void Synth::playMsgOnPart(Bit8u part, Bit8u code, Bit8u note, Bit8u velocity) { - if (!opened) return; - +void Synth::playMsgOnPart(unsigned char part, unsigned char code, unsigned char note, unsigned char velocity) { Bit32u bend; - if (!activated) activated = true; //printDebug("Synth::playMsgOnPart(%02x, %02x, %02x, %02x)", part, code, note, velocity); switch (code) { case 0x8: @@ -1016,7 +849,7 @@ void Synth::playSysexWithoutFraming(const Bit8u *sysex, Bit32u len) { playSysexWithoutHeader(sysex[1], sysex[3], sysex + 4, len - 4); } -void Synth::playSysexWithoutHeader(Bit8u device, Bit8u command, const Bit8u *sysex, Bit32u len) { +void Synth::playSysexWithoutHeader(unsigned char device, unsigned char command, const Bit8u *sysex, Bit32u len) { if (device > 0x10) { // We have device ID 0x10 (default, but changeable, on real MT-32), < 0x10 is for channels printDebug("playSysexWithoutHeader: Message is not intended for this device ID (provided: %02x, expected: 0x10 or channel)", (int)device); @@ -1028,13 +861,6 @@ void Synth::playSysexWithoutHeader(Bit8u device, Bit8u command, const Bit8u *sys reset(); return; } - - if (command == SYSEX_CMD_EOD) { -#if MT32EMU_MONITOR_SYSEX > 0 - printDebug("playSysexWithoutHeader: Ignored unsupported command %02x", command); -#endif - return; - } if (len < 4) { printDebug("playSysexWithoutHeader: Message is too short (%d bytes)!", len); return; @@ -1046,19 +872,12 @@ void Synth::playSysexWithoutHeader(Bit8u device, Bit8u command, const Bit8u *sys } len -= 1; // Exclude checksum switch (command) { - case SYSEX_CMD_WSD: -#if MT32EMU_MONITOR_SYSEX > 0 - printDebug("playSysexWithoutHeader: Ignored unsupported command %02x", command); -#endif - break; case SYSEX_CMD_DAT: - /* Outcommented until we (ever) actually implement handshake communication if (hasActivePartials()) { printDebug("playSysexWithoutHeader: Got SYSEX_CMD_DAT but partials are active - ignoring"); // FIXME: We should send SYSEX_CMD_RJC in this case break; } - */ // Deliberate fall-through case SYSEX_CMD_DT1: writeSysex(device, sysex, len); @@ -1079,12 +898,11 @@ void Synth::playSysexWithoutHeader(Bit8u device, Bit8u command, const Bit8u *sys } } -void Synth::readSysex(Bit8u /*device*/, const Bit8u * /*sysex*/, Bit32u /*len*/) const { +void Synth::readSysex(unsigned char /*device*/, const Bit8u * /*sysex*/, Bit32u /*len*/) const { // NYI } -void Synth::writeSysex(Bit8u device, const Bit8u *sysex, Bit32u len) { - if (!opened) return; +void Synth::writeSysex(unsigned char device, const Bit8u *sysex, Bit32u len) { reportHandler->onMIDIMessagePlayed(); Bit32u addr = (sysex[0] << 16) | (sysex[1] << 8) | (sysex[2]); addr = MT32EMU_MEMADDR(addr); @@ -1100,7 +918,7 @@ void Synth::writeSysex(Bit8u device, const Bit8u *sysex, Bit32u len) { #endif if (/*addr >= MT32EMU_MEMADDR(0x000000) && */addr < MT32EMU_MEMADDR(0x010000)) { int offset; - if (chantable[device] > 8) { + if (chantable[device] == -1) { #if MT32EMU_MONITOR_SYSEX > 0 printDebug(" (Channel not mapped to a part... 0 offset)"); #endif @@ -1121,7 +939,7 @@ void Synth::writeSysex(Bit8u device, const Bit8u *sysex, Bit32u len) { addr += MT32EMU_MEMADDR(0x030110) - MT32EMU_MEMADDR(0x010000); } else if (/*addr >= MT32EMU_MEMADDR(0x020000) && */ addr < MT32EMU_MEMADDR(0x030000)) { int offset; - if (chantable[device] > 8) { + if (chantable[device] == -1) { #if MT32EMU_MONITOR_SYSEX > 0 printDebug(" (Channel not mapped to a part... 0 offset)"); #endif @@ -1168,7 +986,6 @@ void Synth::writeSysex(Bit8u device, const Bit8u *sysex, Bit32u len) { } void Synth::readMemory(Bit32u addr, Bit32u len, Bit8u *data) { - if (!opened) return; const MemoryRegion *region = findMemoryRegion(addr); if (region != NULL) { readMemoryRegion(region, addr, len, data); @@ -1462,16 +1279,16 @@ void Synth::writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u le if(firstPart < 0) firstPart = 0; int lastPart = off + len - SYSTEM_CHAN_ASSIGN_START_OFF; - if(lastPart > 8) - lastPart = 8; - refreshSystemChanAssign((Bit8u)firstPart, (Bit8u)lastPart); + if(lastPart > 9) + lastPart = 9; + refreshSystemChanAssign(firstPart, lastPart); } if (off <= SYSTEM_MASTER_VOL_OFF && off + len > SYSTEM_MASTER_VOL_OFF) { refreshSystemMasterVol(); } break; case MR_Display: - char buf[SYSEX_BUFFER_SIZE]; + char buf[MAX_SYSEX_SIZE]; memcpy(&buf, &data[0], len); buf[len] = 0; #if MT32EMU_MONITOR_SYSEX > 0 @@ -1544,19 +1361,19 @@ void Synth::refreshSystemReserveSettings() { partialManager->setReserve(rset); } -void Synth::refreshSystemChanAssign(Bit8u firstPart, Bit8u lastPart) { - memset(chantable, 0xFF, sizeof(chantable)); +void Synth::refreshSystemChanAssign(unsigned int firstPart, unsigned int lastPart) { + memset(chantable, -1, sizeof(chantable)); // CONFIRMED: In the case of assigning a channel to multiple parts, the lower part wins. - for (Bit32u i = 0; i <= 8; i++) { + for (unsigned int i = 0; i <= 8; i++) { if (parts[i] != NULL && i >= firstPart && i <= lastPart) { // CONFIRMED: Decay is started for all polys, and all controllers are reset, for every part whose assignment was touched by the sysex write. parts[i]->allSoundOff(); parts[i]->resetAllControllers(); } - Bit8u chan = mt32ram.system.chanAssign[i]; - if (chan < 16 && chantable[chan] > 8) { - chantable[chan] = (Bit8u)i; + int chan = mt32ram.system.chanAssign[i]; + if (chan != 16 && chantable[chan] == -1) { + chantable[chan] = i; } } @@ -1581,7 +1398,6 @@ void Synth::refreshSystem() { } void Synth::reset() { - if (!opened) return; #if MT32EMU_MONITOR_SYSEX > 0 printDebug("RESET"); #endif @@ -1597,7 +1413,7 @@ void Synth::reset() { } } refreshSystem(); - isActive(); + isEnabled = false; } MidiEvent::~MidiEvent() { @@ -1661,7 +1477,7 @@ bool MidiEventQueue::pushSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32 } const MidiEvent *MidiEventQueue::peekMidiEvent() { - return isEmpty() ? NULL : &ringBuffer[startPosition]; + return (startPosition == endPosition) ? NULL : &ringBuffer[startPosition]; } void MidiEventQueue::dropMidiEvent() { @@ -1675,24 +1491,15 @@ bool MidiEventQueue::isFull() const { return startPosition == ((endPosition + 1) & ringBufferMask); } -bool MidiEventQueue::isEmpty() const { - return startPosition == endPosition; -} - -Bit32u Synth::getStereoOutputSampleRate() const { +unsigned int Synth::getStereoOutputSampleRate() const { return (analog == NULL) ? SAMPLE_RATE : analog->getOutputSampleRate(); } -void Renderer::render(SampleFormatConverter &converter, Bit32u len) { - if (!synth.opened) { - converter.addSilence(len << 1); - return; - } - - if (!synth.activated) { - synth.renderedSampleCount += synth.analog->getDACStreamsLength(len); - synth.analog->process(NULL, NULL, NULL, NULL, NULL, NULL, NULL, len); - converter.addSilence(len << 1); +void Synth::render(Sample *stream, Bit32u len) { + if (!isEnabled) { + renderedSampleCount += analog->getDACStreamsLength(len); + analog->process(NULL, NULL, NULL, NULL, NULL, NULL, NULL, len); + muteSampleBuffer(stream, len << 1); return; } @@ -1703,53 +1510,19 @@ void Renderer::render(SampleFormatConverter &converter, Bit32u len) { while (len > 0) { Bit32u thisPassLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len; - synth.renderStreams(tmpNonReverbLeft, tmpNonReverbRight, tmpReverbDryLeft, tmpReverbDryRight, tmpReverbWetLeft, tmpReverbWetRight, synth.analog->getDACStreamsLength(thisPassLen)); - synth.analog->process(converter.sampleBuffer, tmpNonReverbLeft, tmpNonReverbRight, tmpReverbDryLeft, tmpReverbDryRight, tmpReverbWetLeft, tmpReverbWetRight, thisPassLen); - converter.convert(thisPassLen << 1); + renderStreams(tmpNonReverbLeft, tmpNonReverbRight, tmpReverbDryLeft, tmpReverbDryRight, tmpReverbWetLeft, tmpReverbWetRight, analog->getDACStreamsLength(thisPassLen)); + analog->process(&stream, tmpNonReverbLeft, tmpNonReverbRight, tmpReverbDryLeft, tmpReverbDryRight, tmpReverbWetLeft, tmpReverbWetRight, thisPassLen); len -= thisPassLen; } } -void Synth::render(Bit16s *stream, Bit32u len) { -#if MT32EMU_USE_FLOAT_SAMPLES - BufferedSampleFormatConverter<2> converter(stream); -#else - SampleFormatConverter converter(stream); -#endif - renderer.render(converter, len); -} - -void Synth::render(float *stream, Bit32u len) { -#if MT32EMU_USE_FLOAT_SAMPLES - SampleFormatConverter converter(stream); -#else - BufferedSampleFormatConverter<2> converter(stream); -#endif - renderer.render(converter, len); -} - -void Renderer::renderStreams( - SampleFormatConverter &nonReverbLeft, SampleFormatConverter &nonReverbRight, - SampleFormatConverter &reverbDryLeft, SampleFormatConverter &reverbDryRight, - SampleFormatConverter &reverbWetLeft, SampleFormatConverter &reverbWetRight, - Bit32u len) -{ - if (!synth.opened) { - nonReverbLeft.addSilence(len); - nonReverbRight.addSilence(len); - reverbDryLeft.addSilence(len); - reverbDryRight.addSilence(len); - reverbWetLeft.addSilence(len); - reverbWetRight.addSilence(len); - return; - } - +void Synth::renderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sample *reverbDryLeft, Sample *reverbDryRight, Sample *reverbWetLeft, Sample *reverbWetRight, Bit32u len) { while (len > 0) { // We need to ensure zero-duration notes will play so add minimum 1-sample delay. Bit32u thisLen = 1; - if (!synth.isAbortingPoly()) { - const MidiEvent *nextEvent = synth.midiQueue->peekMidiEvent(); - Bit32s samplesToNextEvent = (nextEvent != NULL) ? Bit32s(nextEvent->timestamp - synth.renderedSampleCount) : MAX_SAMPLES_PER_RUN; + if (!isAbortingPoly()) { + const MidiEvent *nextEvent = midiQueue->peekMidiEvent(); + Bit32s samplesToNextEvent = (nextEvent != NULL) ? Bit32s(nextEvent->timestamp - renderedSampleCount) : MAX_SAMPLES_PER_RUN; if (samplesToNextEvent > 0) { thisLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len; if (thisLen > (Bit32u)samplesToNextEvent) { @@ -1757,85 +1530,37 @@ void Renderer::renderStreams( } } else { if (nextEvent->sysexData == NULL) { - synth.playMsgNow(nextEvent->shortMessageData); + playMsgNow(nextEvent->shortMessageData); // If a poly is aborting we don't drop the event from the queue. // Instead, we'll return to it again when the abortion is done. - if (!synth.isAbortingPoly()) { - synth.midiQueue->dropMidiEvent(); + if (!isAbortingPoly()) { + midiQueue->dropMidiEvent(); } } else { - synth.playSysexNow(nextEvent->sysexData, nextEvent->sysexLength); - synth.midiQueue->dropMidiEvent(); + playSysexNow(nextEvent->sysexData, nextEvent->sysexLength); + midiQueue->dropMidiEvent(); } } } - doRenderStreams( - nonReverbLeft.sampleBuffer, nonReverbRight.sampleBuffer, - reverbDryLeft.sampleBuffer, reverbDryRight.sampleBuffer, - reverbWetLeft.sampleBuffer, reverbWetRight.sampleBuffer, - thisLen); - nonReverbLeft.convert(thisLen); - nonReverbRight.convert(thisLen); - reverbDryLeft.convert(thisLen); - reverbDryRight.convert(thisLen); - reverbWetLeft.convert(thisLen); - reverbWetRight.convert(thisLen); + doRenderStreams(nonReverbLeft, nonReverbRight, reverbDryLeft, reverbDryRight, reverbWetLeft, reverbWetRight, thisLen); + advanceStreamPosition(nonReverbLeft, thisLen); + advanceStreamPosition(nonReverbRight, thisLen); + advanceStreamPosition(reverbDryLeft, thisLen); + advanceStreamPosition(reverbDryRight, thisLen); + advanceStreamPosition(reverbWetLeft, thisLen); + advanceStreamPosition(reverbWetRight, thisLen); len -= thisLen; } } -void Synth::renderStreams( - Bit16s *nonReverbLeft, Bit16s *nonReverbRight, - Bit16s *reverbDryLeft, Bit16s *reverbDryRight, - Bit16s *reverbWetLeft, Bit16s *reverbWetRight, - Bit32u len) -{ -#if MT32EMU_USE_FLOAT_SAMPLES - BufferedSampleFormatConverter<> convNonReverbLeft(nonReverbLeft), convNonReverbRight(nonReverbRight); - BufferedSampleFormatConverter<> convReverbDryLeft(reverbDryLeft), convReverbDryRight(reverbDryRight); - BufferedSampleFormatConverter<> convReverbWetLeft(reverbWetLeft), convReverbWetRight(reverbWetRight); -#else - SampleFormatConverter convNonReverbLeft(nonReverbLeft), convNonReverbRight(nonReverbRight); - SampleFormatConverter convReverbDryLeft(reverbDryLeft), convReverbDryRight(reverbDryRight); - SampleFormatConverter convReverbWetLeft(reverbWetLeft), convReverbWetRight(reverbWetRight); -#endif - renderer.renderStreams( - convNonReverbLeft, convNonReverbRight, - convReverbDryLeft, convReverbDryRight, - convReverbWetLeft, convReverbWetRight, - len); -} - -void Synth::renderStreams( - float *nonReverbLeft, float *nonReverbRight, - float *reverbDryLeft, float *reverbDryRight, - float *reverbWetLeft, float *reverbWetRight, - Bit32u len) -{ -#if MT32EMU_USE_FLOAT_SAMPLES - SampleFormatConverter convNonReverbLeft(nonReverbLeft), convNonReverbRight(nonReverbRight); - SampleFormatConverter convReverbDryLeft(reverbDryLeft), convReverbDryRight(reverbDryRight); - SampleFormatConverter convReverbWetLeft(reverbWetLeft), convReverbWetRight(reverbWetRight); -#else - BufferedSampleFormatConverter<> convNonReverbLeft(nonReverbLeft), convNonReverbRight(nonReverbRight); - BufferedSampleFormatConverter<> convReverbDryLeft(reverbDryLeft), convReverbDryRight(reverbDryRight); - BufferedSampleFormatConverter<> convReverbWetLeft(reverbWetLeft), convReverbWetRight(reverbWetRight); -#endif - renderer.renderStreams( - convNonReverbLeft, convNonReverbRight, - convReverbDryLeft, convReverbDryRight, - convReverbWetLeft, convReverbWetRight, - len); -} - // In GENERATION2 units, the output from LA32 goes to the Boss chip already bit-shifted. // In NICE mode, it's also better to increase volume before the reverb processing to preserve accuracy. -void Renderer::produceLA32Output(Sample *buffer, Bit32u len) { +void Synth::produceLA32Output(Sample *buffer, Bit32u len) { #if MT32EMU_USE_FLOAT_SAMPLES (void)buffer; (void)len; #else - switch (synth.dacInputMode) { + switch (dacInputMode) { case DACInputMode_GENERATION2: while (len--) { *buffer = (*buffer & 0x8000) | ((*buffer << 1) & 0x7FFE) | ((*buffer >> 14) & 0x0001); @@ -1844,7 +1569,7 @@ void Renderer::produceLA32Output(Sample *buffer, Bit32u len) { break; case DACInputMode_NICE: while (len--) { - *buffer = Synth::clipSampleEx(SampleEx(*buffer) << 1); + *buffer = clipSampleEx(SampleEx(*buffer) << 1); ++buffer; } break; @@ -1854,12 +1579,12 @@ void Renderer::produceLA32Output(Sample *buffer, Bit32u len) { #endif } -void Renderer::convertSamplesToOutput(Sample *buffer, Bit32u len) { +void Synth::convertSamplesToOutput(Sample *buffer, Bit32u len) { #if MT32EMU_USE_FLOAT_SAMPLES (void)buffer; (void)len; #else - if (synth.dacInputMode == DACInputMode_GENERATION1) { + if (dacInputMode == DACInputMode_GENERATION1) { while (len--) { *buffer = Sample((*buffer & 0x8000) | ((*buffer << 1) & 0x7FFE)); ++buffer; @@ -1868,7 +1593,7 @@ void Renderer::convertSamplesToOutput(Sample *buffer, Bit32u len) { #endif } -void Renderer::doRenderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sample *reverbDryLeft, Sample *reverbDryRight, Sample *reverbWetLeft, Sample *reverbWetRight, Bit32u len) { +void Synth::doRenderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sample *reverbDryLeft, Sample *reverbDryRight, Sample *reverbWetLeft, Sample *reverbWetRight, Bit32u len) { // Even if LA32 output isn't desired, we proceed anyway with temp buffers Sample tmpBufNonReverbLeft[MAX_SAMPLES_PER_RUN], tmpBufNonReverbRight[MAX_SAMPLES_PER_RUN]; if (nonReverbLeft == NULL) nonReverbLeft = tmpBufNonReverbLeft; @@ -1878,30 +1603,30 @@ void Renderer::doRenderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sa if (reverbDryLeft == NULL) reverbDryLeft = tmpBufReverbDryLeft; if (reverbDryRight == NULL) reverbDryRight = tmpBufReverbDryRight; - if (synth.activated) { - Synth::muteSampleBuffer(nonReverbLeft, len); - Synth::muteSampleBuffer(nonReverbRight, len); - Synth::muteSampleBuffer(reverbDryLeft, len); - Synth::muteSampleBuffer(reverbDryRight, len); + if (isEnabled) { + muteSampleBuffer(nonReverbLeft, len); + muteSampleBuffer(nonReverbRight, len); + muteSampleBuffer(reverbDryLeft, len); + muteSampleBuffer(reverbDryRight, len); - for (unsigned int i = 0; i < synth.getPartialCount(); i++) { - if (synth.partialManager->shouldReverb(i)) { - synth.partialManager->produceOutput(i, reverbDryLeft, reverbDryRight, len); + for (unsigned int i = 0; i < getPartialCount(); i++) { + if (partialManager->shouldReverb(i)) { + partialManager->produceOutput(i, reverbDryLeft, reverbDryRight, len); } else { - synth.partialManager->produceOutput(i, nonReverbLeft, nonReverbRight, len); + partialManager->produceOutput(i, nonReverbLeft, nonReverbRight, len); } } produceLA32Output(reverbDryLeft, len); produceLA32Output(reverbDryRight, len); - if (synth.isReverbEnabled()) { - synth.reverbModel->process(reverbDryLeft, reverbDryRight, reverbWetLeft, reverbWetRight, len); + if (isReverbEnabled()) { + reverbModel->process(reverbDryLeft, reverbDryRight, reverbWetLeft, reverbWetRight, len); if (reverbWetLeft != NULL) convertSamplesToOutput(reverbWetLeft, len); if (reverbWetRight != NULL) convertSamplesToOutput(reverbWetRight, len); } else { - Synth::muteSampleBuffer(reverbWetLeft, len); - Synth::muteSampleBuffer(reverbWetRight, len); + muteSampleBuffer(reverbWetLeft, len); + muteSampleBuffer(reverbWetRight, len); } // Don't bother with conversion if the output is going to be unused @@ -1917,32 +1642,29 @@ void Renderer::doRenderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sa if (reverbDryRight != tmpBufReverbDryRight) convertSamplesToOutput(reverbDryRight, len); } else { // Avoid muting buffers that wasn't requested - if (nonReverbLeft != tmpBufNonReverbLeft) Synth::muteSampleBuffer(nonReverbLeft, len); - if (nonReverbRight != tmpBufNonReverbRight) Synth::muteSampleBuffer(nonReverbRight, len); - if (reverbDryLeft != tmpBufReverbDryLeft) Synth::muteSampleBuffer(reverbDryLeft, len); - if (reverbDryRight != tmpBufReverbDryRight) Synth::muteSampleBuffer(reverbDryRight, len); - Synth::muteSampleBuffer(reverbWetLeft, len); - Synth::muteSampleBuffer(reverbWetRight, len); + if (nonReverbLeft != tmpBufNonReverbLeft) muteSampleBuffer(nonReverbLeft, len); + if (nonReverbRight != tmpBufNonReverbRight) muteSampleBuffer(nonReverbRight, len); + if (reverbDryLeft != tmpBufReverbDryLeft) muteSampleBuffer(reverbDryLeft, len); + if (reverbDryRight != tmpBufReverbDryRight) muteSampleBuffer(reverbDryRight, len); + muteSampleBuffer(reverbWetLeft, len); + muteSampleBuffer(reverbWetRight, len); } - synth.partialManager->clearAlreadyOutputed(); - synth.renderedSampleCount += len; + partialManager->clearAlreadyOutputed(); + renderedSampleCount += len; } -void Synth::printPartialUsage(Bit32u sampleOffset) { +void Synth::printPartialUsage(unsigned long sampleOffset) { unsigned int partialUsage[9]; partialManager->getPerPartPartialUsage(partialUsage); if (sampleOffset > 0) { - printDebug("[+%u] Partial Usage: 1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d R: %02d TOTAL: %02d", sampleOffset, partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7], partialUsage[8], getPartialCount() - partialManager->getFreePartialCount()); + printDebug("[+%lu] Partial Usage: 1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d R: %02d TOTAL: %02d", sampleOffset, partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7], partialUsage[8], getPartialCount() - partialManager->getFreePartialCount()); } else { printDebug("Partial Usage: 1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d R: %02d TOTAL: %02d", partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7], partialUsage[8], getPartialCount() - partialManager->getFreePartialCount()); } } bool Synth::hasActivePartials() const { - if (!opened) { - return false; - } for (unsigned int partialNum = 0; partialNum < getPartialCount(); partialNum++) { if (partialManager->getPartial(partialNum)->isActive()) { return true; @@ -1951,76 +1673,46 @@ bool Synth::hasActivePartials() const { return false; } -bool Synth::isActive() { - if (!opened) { - return false; - } - if (!midiQueue->isEmpty() || hasActivePartials()) { +bool Synth::isAbortingPoly() const { + return abortingPoly != NULL; +} + +bool Synth::isActive() const { + if (hasActivePartials()) { return true; } - if (isReverbEnabled() && reverbModel->isActive()) { - return true; + if (isReverbEnabled()) { + return reverbModel->isActive(); } - activated = false; return false; } -Bit32u Synth::getPartialCount() const { +unsigned int Synth::getPartialCount() const { return partialCount; } void Synth::getPartStates(bool *partStates) const { - if (!opened) { - memset(partStates, 0, 9 * sizeof(bool)); - return; - } for (int partNumber = 0; partNumber < 9; partNumber++) { const Part *part = parts[partNumber]; partStates[partNumber] = part->getActiveNonReleasingPartialCount() > 0; } } -Bit32u Synth::getPartStates() const { - if (!opened) return 0; - bool partStates[9]; - getPartStates(partStates); - Bit32u bitSet = 0; - for (int partNumber = 8; partNumber >= 0; partNumber--) { - bitSet = (bitSet << 1) | (partStates[partNumber] ? 1 : 0); - } - return bitSet; -} - void Synth::getPartialStates(PartialState *partialStates) const { - if (!opened) { - memset(partialStates, 0, partialCount * sizeof(PartialState)); - return; - } - for (unsigned int partialNum = 0; partialNum < partialCount; partialNum++) { - partialStates[partialNum] = getPartialState(partialManager, partialNum); - } -} + static const PartialState partialPhaseToState[8] = { + PartialState_ATTACK, PartialState_ATTACK, PartialState_ATTACK, PartialState_ATTACK, + PartialState_SUSTAIN, PartialState_SUSTAIN, PartialState_RELEASE, PartialState_INACTIVE + }; -void Synth::getPartialStates(Bit8u *partialStates) const { - if (!opened) { - memset(partialStates, 0, ((partialCount + 3) >> 2)); - return; - } - for (unsigned int quartNum = 0; (4 * quartNum) < partialCount; quartNum++) { - Bit8u packedStates = 0; - for (unsigned int i = 0; i < 4; i++) { - unsigned int partialNum = (4 * quartNum) + i; - if (partialCount <= partialNum) break; - PartialState partialState = getPartialState(partialManager, partialNum); - packedStates |= (partialState & 3) << (2 * i); - } - partialStates[quartNum] = packedStates; + for (unsigned int partialNum = 0; partialNum < getPartialCount(); partialNum++) { + const Partial *partial = partialManager->getPartial(partialNum); + partialStates[partialNum] = partial->isActive() ? partialPhaseToState[partial->getTVA()->getPhase()] : PartialState_INACTIVE; } } -Bit32u Synth::getPlayingNotes(Bit8u partNumber, Bit8u *keys, Bit8u *velocities) const { - Bit32u playingNotes = 0; - if (opened && (partNumber < 9)) { +unsigned int Synth::getPlayingNotes(unsigned int partNumber, Bit8u *keys, Bit8u *velocities) const { + unsigned int playingNotes = 0; + if (isOpen && (partNumber < 9)) { const Part *part = parts[partNumber]; const Poly *poly = part->getFirstActivePoly(); while (poly != NULL) { @@ -2033,11 +1725,11 @@ Bit32u Synth::getPlayingNotes(Bit8u partNumber, Bit8u *keys, Bit8u *velocities) return playingNotes; } -const char *Synth::getPatchName(Bit8u partNumber) const { - return (!opened || partNumber > 8) ? NULL : parts[partNumber]->getCurrentInstr(); +const char *Synth::getPatchName(unsigned int partNumber) const { + return (!isOpen || partNumber > 8) ? NULL : parts[partNumber]->getCurrentInstr(); } -const Part *Synth::getPart(Bit8u partNum) const { +const Part *Synth::getPart(unsigned int partNum) const { if (partNum > 8) { return NULL; } @@ -2115,4 +1807,4 @@ void MemoryRegion::write(unsigned int entry, unsigned int off, const Bit8u *src, } } -} // namespace MT32Emu +} |