aboutsummaryrefslogtreecommitdiff
path: root/audio/softsynth/mt32.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'audio/softsynth/mt32.cpp')
-rw-r--r--audio/softsynth/mt32.cpp201
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) {