diff options
Diffstat (limited to 'audio/softsynth/mt32.cpp')
-rw-r--r-- | audio/softsynth/mt32.cpp | 201 |
1 files changed, 106 insertions, 95 deletions
diff --git a/audio/softsynth/mt32.cpp b/audio/softsynth/mt32.cpp index 4420657854..38978b8edf 100644 --- a/audio/softsynth/mt32.cpp +++ b/audio/softsynth/mt32.cpp @@ -25,9 +25,6 @@ #ifdef USE_MT32EMU -#include "audio/softsynth/mt32/mt32emu.h" -#include "audio/softsynth/mt32/ROMInfo.h" - #include "audio/softsynth/emumidi.h" #include "audio/musicplugin.h" #include "audio/mpu401.h" @@ -42,6 +39,7 @@ #include "common/archive.h" #include "common/textconsole.h" #include "common/translation.h" +#include "common/osd_message_queue.h" #include "graphics/fontman.h" #include "graphics/surface.h" @@ -51,16 +49,16 @@ #include "gui/message.h" -namespace MT32Emu { - -class ReportHandlerScummVM : public ReportHandler { -friend class Synth; +// prevents load of unused FileStream API because it includes a standard library +// include, per _sev +#define MT32EMU_FILE_STREAM_H -public: - virtual ~ReportHandlerScummVM() {} +#include "audio/softsynth/mt32/c_interface/cpp_interface.h" -protected: +namespace MT32Emu { +class ScummVMReportHandler : public MT32Emu::IReportHandler { +public: // Callback for debug messages, in vprintf() format void printDebug(const char *fmt, va_list list) { Common::String out = Common::String::vformat(fmt, list); @@ -69,18 +67,32 @@ protected: // Callbacks for reporting various errors and information void onErrorControlROM() { - GUI::MessageDialog dialog("MT32emu: Init Error - Missing or invalid Control ROM image", "OK"); + GUI::MessageDialog dialog("MT32Emu: Init Error - Missing or invalid Control ROM image", "OK"); dialog.runModal(); error("MT32emu: Init Error - Missing or invalid Control ROM image"); } void onErrorPCMROM() { - GUI::MessageDialog dialog("MT32emu: Init Error - Missing PCM ROM image", "OK"); + GUI::MessageDialog dialog("MT32Emu: Init Error - Missing PCM ROM image", "OK"); dialog.runModal(); error("MT32emu: Init Error - Missing PCM ROM image"); } void showLCDMessage(const char *message) { - g_system->displayMessageOnOSD(message); + Common::OSDMessageQueue::instance().addMessage(message); } + + // Unused callbacks + virtual void onMIDIMessagePlayed() {} + virtual bool onMIDIQueueOverflow() { return false; } + virtual void onMIDISystemRealtime(Bit8u /* system_realtime */) {} + virtual void onDeviceReset() {} + virtual void onDeviceReconfig() {} + virtual void onNewReverbMode(Bit8u /* mode */) {} + virtual void onNewReverbTime(Bit8u /* time */) {} + virtual void onNewReverbLevel(Bit8u /* level */) {} + virtual void onPolyStateChanged(Bit8u /* part_num */) {} + virtual void onProgramChanged(Bit8u /* part_num */, const char * /* sound_group_name */, const char * /* patch_name */) {} + + virtual ~ScummVMReportHandler() {} }; } // end of namespace MT32Emu @@ -94,11 +106,10 @@ class MidiDriver_MT32 : public MidiDriver_Emulated { private: MidiChannel_MT32 _midiChannels[16]; uint16 _channelMask; - MT32Emu::Synth *_synth; - MT32Emu::ReportHandlerScummVM *_reportHandler; - const MT32Emu::ROMImage *_controlROM, *_pcmROM; - Common::File *_controlFile, *_pcmFile; - void deleteMuntStructures(); + MT32Emu::Service _service; + MT32Emu::ScummVMReportHandler _reportHandler; + byte *_controlData, *_pcmData; + Common::Mutex _mutex; int _outputRate; @@ -106,15 +117,13 @@ protected: void generateSamples(int16 *buf, int len); public: - bool _initializing; - MidiDriver_MT32(Audio::Mixer *mixer); virtual ~MidiDriver_MT32(); int open(); void close(); void send(uint32 b); - void setPitchBendRange (byte channel, uint range); + void setPitchBendRange(byte channel, uint range); void sysEx(const byte *msg, uint16 length); uint32 property(int prop, uint32 param); @@ -138,52 +147,19 @@ MidiDriver_MT32::MidiDriver_MT32(Audio::Mixer *mixer) : MidiDriver_Emulated(mixe for (i = 0; i < ARRAYSIZE(_midiChannels); ++i) { _midiChannels[i].init(this, i); } - _reportHandler = NULL; - _synth = NULL; - // Unfortunately bugs in the emulator cause inaccurate tuning - // at rates other than 32KHz, thus we produce data at 32KHz and - // rely on Mixer to convert. - _outputRate = 32000; //_mixer->getOutputRate(); - _initializing = false; - - // Initialized in open() - _controlROM = NULL; - _pcmROM = NULL; - _controlFile = NULL; - _pcmFile = NULL; + _outputRate = 0; + _controlData = nullptr; + _pcmData = nullptr; } MidiDriver_MT32::~MidiDriver_MT32() { - deleteMuntStructures(); -} - -void MidiDriver_MT32::deleteMuntStructures() { - delete _synth; - _synth = NULL; - delete _reportHandler; - _reportHandler = NULL; - - if (_controlROM) - MT32Emu::ROMImage::freeROMImage(_controlROM); - _controlROM = NULL; - if (_pcmROM) - MT32Emu::ROMImage::freeROMImage(_pcmROM); - _pcmROM = NULL; - - delete _controlFile; - _controlFile = NULL; - delete _pcmFile; - _pcmFile = NULL; + close(); } int MidiDriver_MT32::open() { if (_isOpen) return MERR_ALREADY_OPEN; - MidiDriver_Emulated::open(); - _reportHandler = new MT32Emu::ReportHandlerScummVM(); - _synth = new MT32Emu::Synth(_reportHandler); - Graphics::PixelFormat screenFormat = g_system->getScreenFormat(); if (screenFormat.bytesPerPixel == 1) { @@ -196,31 +172,54 @@ int MidiDriver_MT32::open() { g_system->getPaletteManager()->setPalette(dummy_palette, 0, 3); } - _initializing = true; debug(4, _s("Initializing MT-32 Emulator")); - _controlFile = new Common::File(); - if (!_controlFile->open("CM32L_CONTROL.ROM") && !_controlFile->open("MT32_CONTROL.ROM")) - error("Error opening MT32_CONTROL.ROM / CM32L_CONTROL.ROM"); - _pcmFile = new Common::File(); - if (!_pcmFile->open("CM32L_PCM.ROM") && !_pcmFile->open("MT32_PCM.ROM")) - error("Error opening MT32_PCM.ROM / CM32L_PCM.ROM"); - _controlROM = MT32Emu::ROMImage::makeROMImage(_controlFile); - _pcmROM = MT32Emu::ROMImage::makeROMImage(_pcmFile); - if (!_synth->open(*_controlROM, *_pcmROM)) - return MERR_DEVICE_NOT_AVAILABLE; - double gain = (double)ConfMan.getInt("midi_gain") / 100.0; - _synth->setOutputGain(1.0f * gain); - _synth->setReverbOutputGain(0.68f * gain); + Common::File controlFile; + if (!controlFile.open("CM32L_CONTROL.ROM") && !controlFile.open("MT32_CONTROL.ROM")) + error("Error opening MT32_CONTROL.ROM / CM32L_CONTROL.ROM. Check that your Extra Path in Paths settings is set to the correct directory"); - _initializing = false; + Common::File pcmFile; + if (!pcmFile.open("CM32L_PCM.ROM") && !pcmFile.open("MT32_PCM.ROM")) + error("Error opening MT32_PCM.ROM / CM32L_PCM.ROM. Check that your Extra Path in Paths settings is set to the correct directory"); - if (screenFormat.bytesPerPixel > 1) - g_system->fillScreen(screenFormat.RGBToColor(0, 0, 0)); - else - g_system->fillScreen(0); + _controlData = new byte[controlFile.size()]; + controlFile.read(_controlData, controlFile.size()); + _pcmData = new byte[pcmFile.size()]; + pcmFile.read(_pcmData, pcmFile.size()); - g_system->updateScreen(); + _service.createContext(_reportHandler); + + if (_service.addROMData(_controlData, controlFile.size()) != MT32EMU_RC_ADDED_CONTROL_ROM) { + error("Adding control ROM failed. Check that your control ROM is valid"); + } + + controlFile.close(); + + if (_service.addROMData(_pcmData, pcmFile.size()) != MT32EMU_RC_ADDED_PCM_ROM) { + error("Adding PCM ROM failed. Check that your PCM ROM is valid"); + } + + pcmFile.close(); + + if (_service.openSynth() != MT32EMU_RC_OK) + return MERR_DEVICE_NOT_AVAILABLE; + + double gain = (double)ConfMan.getInt("midi_gain") / 100.0; + _service.setOutputGain(1.0f * gain); + _service.setReverbOutputGain(1.0f * gain); + // We let the synthesizer play MIDI messages immediately. Our MIDI + // handling is synchronous to sample generation. This makes delaying MIDI + // events result in odd sound output in some cases. For example, the + // shattering window in the Indiana Jones and the Fate of Atlantis intro + // will sound like a bell if we use any delay here. + // Bug #6242 "AUDIO: Built-In MT-32 MUNT Produces Wrong Sounds". + _service.setMIDIDelayMode(MT32Emu::MIDIDelayMode_IMMEDIATE); + + // We need to report the sample rate MUNT renders at as sample rate of our + // AudioStream. + _outputRate = _service.getActualStereoOutputSamplerate(); + + MidiDriver_Emulated::open(); _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); @@ -228,31 +227,37 @@ int MidiDriver_MT32::open() { } void MidiDriver_MT32::send(uint32 b) { - _synth->playMsg(b); + Common::StackLock lock(_mutex); + _service.playMsg(b); } +// Indiana Jones and the Fate of Atlantis (including the demo) uses +// setPitchBendRange, if you need a game for testing purposes void MidiDriver_MT32::setPitchBendRange(byte channel, uint range) { if (range > 24) { warning("setPitchBendRange() called with range > 24: %d", range); } - byte benderRangeSysex[9]; - benderRangeSysex[0] = 0x41; // Roland - benderRangeSysex[1] = channel; - benderRangeSysex[2] = 0x16; // MT-32 - benderRangeSysex[3] = 0x12; // Write - benderRangeSysex[4] = 0x00; - benderRangeSysex[5] = 0x00; - benderRangeSysex[6] = 0x04; - benderRangeSysex[7] = (byte)range; - benderRangeSysex[8] = MT32Emu::Synth::calcSysexChecksum(&benderRangeSysex[4], 4, 0); - sysEx(benderRangeSysex, 9); + byte benderRangeSysex[4] = { 0, 0, 4, (uint8)range }; + Common::StackLock lock(_mutex); + _service.writeSysex(channel, benderRangeSysex, 4); } void MidiDriver_MT32::sysEx(const byte *msg, uint16 length) { if (msg[0] == 0xf0) { - _synth->playSysex(msg, length); + Common::StackLock lock(_mutex); + _service.playSysex(msg, length); } else { - _synth->playSysexWithoutFraming(msg, length); + enum { + SYSEX_CMD_DT1 = 0x12, + SYSEX_CMD_DAT = 0x42 + }; + + if (msg[3] == SYSEX_CMD_DT1 || msg[3] == SYSEX_CMD_DAT) { + Common::StackLock lock(_mutex); + _service.writeSysex(msg[1], msg + 4, length - 5); + } else { + warning("Unused sysEx command %d", msg[3]); + } } } @@ -266,12 +271,18 @@ void MidiDriver_MT32::close() { // Detach the mixer callback handler _mixer->stopHandle(_mixerSoundHandle); - _synth->close(); - deleteMuntStructures(); + Common::StackLock lock(_mutex); + _service.closeSynth(); + _service.freeContext(); + delete[] _controlData; + _controlData = nullptr; + delete[] _pcmData; + _pcmData = nullptr; } void MidiDriver_MT32::generateSamples(int16 *data, int len) { - _synth->render(data, len); + Common::StackLock lock(_mutex); + _service.renderBit16s(data, len); } uint32 MidiDriver_MT32::property(int prop, uint32 param) { |