diff --git a/audio/adlib.cpp b/audio/adlib.cpp
index b4099128a8f..196e7feed89 100644
--- a/audio/adlib.cpp
+++ b/audio/adlib.cpp
@@ -942,7 +942,6 @@ public:
uint32 getBaseTempo() override { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
void setPitchBendRange(byte channel, uint range) override;
- void sysEx_customInstrument(byte channel, uint32 type, const byte *instr) override;
MidiChannel *allocateChannel() override;
MidiChannel *getPercussionChannel() override { return &_percussion; } // Percussion partially supported
@@ -1585,10 +1584,6 @@ void MidiDriver_ADLIB::setPitchBendRange(byte channel, uint range) {
}
}
-void MidiDriver_ADLIB::sysEx_customInstrument(byte channel, uint32 type, const byte *instr) {
- _parts[channel].sysEx_customInstrument(type, instr);
-}
-
MidiChannel *MidiDriver_ADLIB::allocateChannel() {
AdLibPart *part;
uint i;
diff --git a/audio/mididrv.h b/audio/mididrv.h
index adc85b6e905..49a279f6246 100644
--- a/audio/mididrv.h
+++ b/audio/mididrv.h
@@ -499,8 +499,6 @@ public:
*/
void sendGMReset();
- virtual void sysEx_customInstrument(byte channel, uint32 type, const byte *instr) { }
-
// Timing functions - MidiDriver now operates timers
virtual void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) = 0;
diff --git a/audio/mpu401.cpp b/audio/mpu401.cpp
index 76ae76fd8f0..06ab6ebd355 100644
--- a/audio/mpu401.cpp
+++ b/audio/mpu401.cpp
@@ -71,9 +71,6 @@ void MidiChannel_MPU401::pitchBendFactor(byte value) {
_owner->setPitchBendRange(_channel, value);
}
-void MidiChannel_MPU401::sysEx_customInstrument(uint32 type, const byte *instr) {
- _owner->sysEx_customInstrument(_channel, type, instr);
-}
const char *MidiDriver::getErrorName(int error_code) {
static const char *const midi_errors[] = {
diff --git a/audio/mpu401.h b/audio/mpu401.h
index 9d91a144bd4..13857d852ab 100644
--- a/audio/mpu401.h
+++ b/audio/mpu401.h
@@ -55,7 +55,7 @@ public:
virtual void pitchBendFactor(byte value);
// SysEx messages
- virtual void sysEx_customInstrument(uint32 type, const byte *instr);
+ virtual void sysEx_customInstrument(uint32 type, const byte *instr) {}
// Only to be called by the owner
void init(MidiDriver *owner, byte channel);
diff --git a/engines/scumm/imuse/drivers/fmtowns.cpp b/engines/scumm/imuse/drivers/fmtowns.cpp
index 787e787a5cf..6161bc8c82a 100644
--- a/engines/scumm/imuse/drivers/fmtowns.cpp
+++ b/engines/scumm/imuse/drivers/fmtowns.cpp
@@ -19,15 +19,17 @@
*
*/
-#include "engines/scumm/imuse/drivers/fmtowns.h"
+#include "scumm/imuse/drivers/fmtowns.h"
#include "audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h"
#include "common/textconsole.h"
#include "common/system.h"
+namespace Scumm {
+
class TownsMidiOutputChannel {
friend class TownsMidiInputChannel;
public:
- TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanId);
+ TownsMidiOutputChannel(IMuseDriver_FMTowns *driver, int chanId);
~TownsMidiOutputChannel();
void noteOn(uint8 msb, uint16 lsb);
@@ -103,7 +105,7 @@ private:
uint16 _freq;
int16 _freqAdjust;
- MidiDriver_TOWNS *_driver;
+ IMuseDriver_FMTowns *_driver;
static const uint8 _chanMap[];
static const uint8 _chanMap2[];
@@ -116,11 +118,12 @@ private:
class TownsMidiInputChannel : public MidiChannel {
friend class TownsMidiOutputChannel;
public:
- TownsMidiInputChannel(MidiDriver_TOWNS *driver, int chanIndex);
+ TownsMidiInputChannel(IMuseDriver_FMTowns *driver, int16 number);
~TownsMidiInputChannel() override;
MidiDriver *device() override { return _driver; }
- byte getNumber() override { return _chanIndex; }
+ byte getNumber() override { return _number; }
+
bool allocate();
void release() override;
@@ -147,8 +150,8 @@ private:
TownsMidiOutputChannel *_out;
+ const byte _number;
uint8 *_instrument;
- uint8 _chanIndex;
uint8 _priority;
uint8 _tl;
int8 _transpose;
@@ -161,7 +164,7 @@ private:
bool _allocated;
- MidiDriver_TOWNS *_driver;
+ IMuseDriver_FMTowns *_driver;
static const uint8 _programAdjustLevel[];
};
@@ -207,7 +210,7 @@ uint8 TownsMidiChanState::get(uint8 type) {
return 0;
}
-TownsMidiOutputChannel::TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanIndex) : _driver(driver), _chan(chanIndex),
+TownsMidiOutputChannel::TownsMidiOutputChannel(IMuseDriver_FMTowns *driver, int number) : _driver(driver), _chan(number),
_in(nullptr), _prev(nullptr), _next(nullptr), _adjustModTl(0), _operator2Tl(0), _note(0), _operator1Tl(0), _sustainNoteOff(0), _duration(0), _freq(0), _freqAdjust(0) {
_effectEnvelopes = new EffectEnvelope[2]();
_effectDefs = new EffectDef[2]();
@@ -651,7 +654,7 @@ const uint16 TownsMidiOutputChannel::_freqLSB[] = {
0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B
};
-TownsMidiInputChannel::TownsMidiInputChannel(MidiDriver_TOWNS *driver, int chanIndex) : MidiChannel(), _driver(driver), _out(nullptr), _chanIndex(chanIndex),
+TownsMidiInputChannel::TownsMidiInputChannel(IMuseDriver_FMTowns *driver, int16 number) : MidiChannel(), _driver(driver), _number(number), _out(nullptr),
_priority(0), _tl(0), _transpose(0), _pitchBendFactor(0), _pitchBend(0), _sustain(0), _freqLSB(0), _detune(0), _modWheel(0), _allocated(false) {
_instrument = new uint8[30]();
}
@@ -672,7 +675,7 @@ void TownsMidiInputChannel::release() {
}
void TownsMidiInputChannel::send(uint32 b) {
- _driver->send(b | _chanIndex);
+ device()->send(b | _number);
}
void TownsMidiInputChannel::noteOff(byte note) {
@@ -836,7 +839,7 @@ const uint8 TownsMidiInputChannel::_programAdjustLevel[] = {
0x3D, 0x3D, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F
};
-MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerProc(nullptr), _timerProcPara(nullptr), _channels(nullptr), _out(nullptr),
+IMuseDriver_FMTowns::IMuseDriver_FMTowns(Audio::Mixer *mixer) : _timerProc(nullptr), _timerProcPara(nullptr), _channels(nullptr), _out(nullptr),
_baseTempo(10080), _chanState(nullptr), _operatorLevelTable(nullptr), _tickCounter(0), _rand(1), _allocCurPos(0), _isOpen(false) {
_intf = new TownsAudioInterface(mixer, this, true);
@@ -859,7 +862,7 @@ MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerProc(nullptr), _
_operatorLevelTable[i << 5] = 0;
}
-MidiDriver_TOWNS::~MidiDriver_TOWNS() {
+IMuseDriver_FMTowns::~IMuseDriver_FMTowns() {
close();
delete _intf;
@@ -883,7 +886,7 @@ MidiDriver_TOWNS::~MidiDriver_TOWNS() {
_operatorLevelTable = nullptr;
}
-int MidiDriver_TOWNS::open() {
+int IMuseDriver_FMTowns::open() {
if (_isOpen)
return MERR_ALREADY_OPEN;
@@ -906,7 +909,7 @@ int MidiDriver_TOWNS::open() {
return 0;
}
-void MidiDriver_TOWNS::close() {
+void IMuseDriver_FMTowns::close() {
if (!_isOpen)
return;
@@ -916,7 +919,7 @@ void MidiDriver_TOWNS::close() {
g_system->delayMillis(20);
}
-void MidiDriver_TOWNS::send(uint32 b) {
+void IMuseDriver_FMTowns::send(uint32 b) {
if (!_isOpen)
return;
@@ -954,16 +957,16 @@ void MidiDriver_TOWNS::send(uint32 b) {
}
}
-void MidiDriver_TOWNS::setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
+void IMuseDriver_FMTowns::setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
_timerProc = timer_proc;
_timerProcPara = timer_param;
}
-uint32 MidiDriver_TOWNS::getBaseTempo() {
+uint32 IMuseDriver_FMTowns::getBaseTempo() {
return _baseTempo;
}
-MidiChannel *MidiDriver_TOWNS::allocateChannel() {
+MidiChannel *IMuseDriver_FMTowns::allocateChannel() {
if (!_isOpen)
return nullptr;
@@ -976,11 +979,11 @@ MidiChannel *MidiDriver_TOWNS::allocateChannel() {
return nullptr;
}
-MidiChannel *MidiDriver_TOWNS::getPercussionChannel() {
+MidiChannel *IMuseDriver_FMTowns::getPercussionChannel() {
return nullptr;
}
-void MidiDriver_TOWNS::timerCallback(int timerId) {
+void IMuseDriver_FMTowns::timerCallback(int timerId) {
if (!_isOpen)
return;
@@ -994,12 +997,12 @@ void MidiDriver_TOWNS::timerCallback(int timerId) {
}
}
-void MidiDriver_TOWNS::updateParser() {
+void IMuseDriver_FMTowns::updateParser() {
if (_timerProc)
_timerProc(_timerProcPara);
}
-void MidiDriver_TOWNS::updateOutputChannels() {
+void IMuseDriver_FMTowns::updateOutputChannels() {
_tickCounter += _baseTempo;
while (_tickCounter >= 16667) {
_tickCounter -= 16667;
@@ -1010,7 +1013,7 @@ void MidiDriver_TOWNS::updateOutputChannels() {
}
}
-TownsMidiOutputChannel *MidiDriver_TOWNS::allocateOutputChannel(uint8 pri) {
+TownsMidiOutputChannel *IMuseDriver_FMTowns::allocateOutputChannel(uint8 pri) {
TownsMidiOutputChannel *res = nullptr;
for (int i = 0; i < 6; i++) {
@@ -1033,7 +1036,9 @@ TownsMidiOutputChannel *MidiDriver_TOWNS::allocateOutputChannel(uint8 pri) {
return res;
}
-int MidiDriver_TOWNS::randomValue(int para) {
+int IMuseDriver_FMTowns::randomValue(int para) {
_rand = (_rand & 1) ? (_rand >> 1) ^ 0xb8 : (_rand >> 1);
return (_rand * para) >> 8;
}
+
+} // end of namespace Scumm
diff --git a/engines/scumm/imuse/drivers/fmtowns.h b/engines/scumm/imuse/drivers/fmtowns.h
index 5ece0182c91..aa8a8cedd02 100644
--- a/engines/scumm/imuse/drivers/fmtowns.h
+++ b/engines/scumm/imuse/drivers/fmtowns.h
@@ -25,17 +25,18 @@
#include "audio/softsynth/fmtowns_pc98/towns_audio.h"
#include "audio/mididrv.h"
+namespace Scumm {
class TownsMidiOutputChannel;
class TownsMidiInputChannel;
class TownsMidiChanState;
-class MidiDriver_TOWNS : public MidiDriver, public TownsAudioInterfacePluginDriver {
+class IMuseDriver_FMTowns : public MidiDriver, public TownsAudioInterfacePluginDriver {
friend class TownsMidiInputChannel;
friend class TownsMidiOutputChannel;
public:
- MidiDriver_TOWNS(Audio::Mixer *mixer);
- ~MidiDriver_TOWNS() override;
+ IMuseDriver_FMTowns(Audio::Mixer *mixer);
+ ~IMuseDriver_FMTowns() override;
int open() override;
bool isOpen() const override { return _isOpen; }
@@ -79,4 +80,6 @@ private:
const uint16 _baseTempo;
};
+} // end of namespace Scumm
+
#endif
diff --git a/engines/scumm/imuse/drivers/gmidi.cpp b/engines/scumm/imuse/drivers/gmidi.cpp
new file mode 100644
index 00000000000..eaa322cb981
--- /dev/null
+++ b/engines/scumm/imuse/drivers/gmidi.cpp
@@ -0,0 +1,195 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include "common/debug.h"
+#include "common/system.h"
+#include "scumm/imuse/drivers/gmidi.h"
+
+namespace Scumm {
+
+IMuseDriver_GMidi::IMuseDriver_GMidi(MidiDriver::DeviceHandle dev, bool rolandGSMode, bool newSystem) : MidiDriver(), _drv(nullptr), _gsMode(rolandGSMode), _newSystem(newSystem) {
+ _drv = MidiDriver::createMidi(dev);
+ assert(_drv);
+}
+
+IMuseDriver_GMidi::~IMuseDriver_GMidi() {
+ delete _drv;
+}
+
+int IMuseDriver_GMidi::open() {
+ if (!_drv)
+ return MERR_CANNOT_CONNECT;
+
+ int res = _drv->open();
+
+ if (_gsMode)
+ initDeviceAsRolandGS();
+ else
+ initDevice();
+
+ return res;
+}
+
+MidiChannel *IMuseDriver_GMidi::allocateChannel() {
+ if (!_newSystem)
+ return _drv->allocateChannel();
+
+ return nullptr;
+}
+
+MidiChannel *IMuseDriver_GMidi::getPercussionChannel() {
+ if (!_newSystem)
+ return _drv->getPercussionChannel();
+
+ return nullptr;
+}
+
+void IMuseDriver_GMidi::initDevice() {
+ // These are the init messages from the DOTT General Midi
+ // driver. This is the major part of the bug fix for bug
+ // no. 13460 ("DOTT: Incorrect MIDI pitch bending").
+ // SAMNMAX has some less of the default settings (since
+ // the driver works a bit different), but it uses the same
+ // values for the pitch bend range.
+ for (int i = 0; i < 16; ++i) {
+ send(0x0064B0 | i);
+ send(0x0065B0 | i);
+ send(0x1006B0 | i);
+ send(0x7F07B0 | i);
+ send(0x3F0AB0 | i);
+ send(0x0000C0 | i);
+ send(0x4000E0 | i);
+ send(0x0001B0 | i);
+ send(0x0040B0 | i);
+ send(0x405BB0 | i);
+ send(0x005DB0 | i);
+ send(0x0000B0 | i);
+ send(0x007BB0 | i);
+ }
+}
+
+void IMuseDriver_GMidi::initDeviceAsRolandGS() {
+ byte buffer[12];
+ int i;
+
+ // General MIDI System On message
+ // Resets all GM devices to default settings
+ memcpy(&buffer[0], "\x7E\x7F\x09\x01", 4);
+ _drv->sysEx(buffer, 4);
+ debug(2, "GM SysEx: GM System On");
+ g_system->delayMillis(200);
+
+ // All GS devices recognize the GS Reset command,
+ // even using Roland's ID. It is impractical to
+ // support other manufacturers' devices for
+ // further GS settings, as there are limitless
+ // numbers of them out there that would each
+ // require individual SysEx commands with unique IDs.
+
+ // Roland GS SysEx ID
+ memcpy(&buffer[0], "\x41\x10\x42\x12", 4);
+
+ // GS Reset
+ memcpy(&buffer[4], "\x40\x00\x7F\x00\x41", 5);
+ _drv->sysEx(buffer, 9);
+ debug(2, "GS SysEx: GS Reset");
+ g_system->delayMillis(200);
+
+ // Set global Master Tune to 442.0kHz, as on the MT-32
+ memcpy(&buffer[4], "\x40\x00\x00\x00\x04\x04\x0F\x29", 8);
+ _drv->sysEx(buffer, 12);
+ debug(2, "GS SysEx: Master Tune set to 442.0kHz");
+
+ // Note: All Roland GS devices support CM-64/32L maps
+
+ // Set Channels 1-16 to SC-55 Map, then CM-64/32L Variation
+ for (i = 0; i < 16; ++i) {
+ _drv->send((127 << 16) | (0 << 8) | (0xB0 | i));
+ _drv->send((1 << 16) | (32 << 8) | (0xB0 | i));
+ _drv->send((0 << 16) | (0 << 8) | (0xC0 | i));
+ }
+ debug(2, "GS Program Change: CM-64/32L Map Selected");
+
+ // Set Percussion Channel to SC-55 Map (CC#32, 01H), then
+ // Switch Drum Map to CM-64/32L (MT-32 Compatible Drums)
+ getPercussionChannel()->controlChange(0, 0);
+ getPercussionChannel()->controlChange(32, 1);
+ _drv->send(127 << 8 | 0xC0 | 9);
+ debug(2, "GS Program Change: Drum Map is CM-64/32L");
+
+ // Set Master Chorus to 0. The MT-32 has no chorus capability.
+ memcpy(&buffer[4], "\x40\x01\x3A\x00\x05", 5);
+ _drv->sysEx(buffer, 9);
+ debug(2, "GS SysEx: Master Chorus Level is 0");
+
+ // Set Channels 1-16 Reverb to 64, which is the
+ // equivalent of MT-32 default Reverb Level 5
+ for (i = 0; i < 16; ++i)
+ _drv->send((64 << 16) | (91 << 8) | (0xB0 | i));
+ debug(2, "GM Controller 91 Change: Channels 1-16 Reverb Level is 64");
+
+ // Set Channels 1-16 Pitch Bend Sensitivity to
+ // 12 semitones; then lock the RPN by setting null.
+ for (i = 0; i < 16; ++i)
+ _drv->setPitchBendRange(i, 12);
+ debug(2, "GM Controller 6 Change: Channels 1-16 Pitch Bend Sensitivity is 12 semitones");
+
+ // Set channels 1-16 Mod. LFO1 Pitch Depth to 4
+ memcpy(&buffer[4], "\x40\x20\x04\x04\x18", 5);
+ for (i = 0; i < 16; ++i) {
+ buffer[5] = 0x20 + i;
+ buffer[8] = 0x18 - i;
+ _drv->sysEx(buffer, 9);
+ }
+
+ debug(2, "GS SysEx: Channels 1-16 Mod. LFO1 Pitch Depth Level is 4");
+
+ // Set Percussion Channel Expression to 80
+ getPercussionChannel()->controlChange(11, 80);
+ debug(2, "GM Controller 11 Change: Percussion Channel Expression Level is 80");
+
+ // Turn off Percussion Channel Rx. Expression so that
+ // Expression cannot be modified. I don't know why, but
+ // Roland does it this way.
+ memcpy(&buffer[4], "\x40\x10\x0E\x00\x22", 5);
+ _drv->sysEx(buffer, 9);
+ debug(2, "GS SysEx: Percussion Channel Rx. Expression is OFF");
+
+ // Change Reverb Character to 0. I don't think this
+ // sounds most like MT-32, but apparently Roland does.
+ memcpy(&buffer[4], "\x40\x01\x31\x00\x0E", 5);
+ _drv->sysEx(buffer, 9);
+ debug(2, "GS SysEx: Reverb Character is 0");
+
+ // Change Reverb Pre-LF to 4, which is similar to
+ // what MT-32 reverb does.
+ memcpy(&buffer[4], "\x40\x01\x32\x04\x09", 5);
+ _drv->sysEx(buffer, 9);
+ debug(2, "GS SysEx: Reverb Pre-LF is 4");
+
+ // Change Reverb Time to 106; the decay on Hall 2
+ // Reverb is too fast compared to the MT-32's
+ memcpy(&buffer[4], "\x40\x01\x34\x6A\x21", 5);
+ _drv->sysEx(buffer, 9);
+ debug(2, "GS SysEx: Reverb Time is 106");
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/imuse/drivers/gmidi.h b/engines/scumm/imuse/drivers/gmidi.h
new file mode 100644
index 00000000000..311c8d9a45e
--- /dev/null
+++ b/engines/scumm/imuse/drivers/gmidi.h
@@ -0,0 +1,60 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef SCUMM_IMUSE_DRV_GMIDI_H
+#define SCUMM_IMUSE_DRV_GMIDI_H
+
+#include "audio/mididrv.h"
+
+namespace Scumm {
+
+class IMuseDriver_GMidi : public MidiDriver {
+public:
+ IMuseDriver_GMidi(MidiDriver::DeviceHandle dev, bool rolandGSMode, bool newSystem);
+ ~IMuseDriver_GMidi() override;
+
+ int open() override;
+
+ // Just pass these through...
+ bool isOpen() const override { return _drv ? _drv->isOpen() : false; }
+ void close() override { if (_drv) _drv->close(); }
+ uint32 property(int prop, uint32 param) override { return _drv ? _drv->property(prop, param) : 0; }
+ void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) override { if (_drv) _drv->setTimerCallback(timerParam, timerProc); }
+ uint32 getBaseTempo() override { return _drv ? _drv->getBaseTempo() : 0; }
+ void send(uint32 b) override { if (_drv) _drv->send(b); };
+ void sysEx(const byte *msg, uint16 length) override { if (_drv) _drv->sysEx(msg, length); }
+
+ // Channel allocation functions
+ MidiChannel *allocateChannel() override;
+ MidiChannel *getPercussionChannel() override;
+
+private:
+ void initDevice();
+ void initDeviceAsRolandGS();
+
+ MidiDriver *_drv;
+ const bool _gsMode;
+ const bool _newSystem;
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/imuse/drivers/mac_m68k.cpp b/engines/scumm/imuse/drivers/mac_m68k.cpp
index 33e5993ff56..600c07032ce 100644
--- a/engines/scumm/imuse/drivers/mac_m68k.cpp
+++ b/engines/scumm/imuse/drivers/mac_m68k.cpp
@@ -27,14 +27,19 @@
namespace Scumm {
-MacM68kDriver::MacM68kDriver(Audio::Mixer *mixer)
- : MidiDriver_Emulated(mixer) {
+IMuseDriver_MacM68k::IMuseDriver_MacM68k(Audio::Mixer *mixer)
+ : MidiDriver_Emulated(mixer), _mixBuffer(nullptr), _mixBufferLength(0), _volumeTable(nullptr), _lastUsedVoiceChannel(0) {
+ memset(_channels, 0, sizeof(_channels));
+ memset(_pitchTable, 0, sizeof(_pitchTable));
+ memset(_voiceChannels, 0, sizeof(_voiceChannels));
}
-MacM68kDriver::~MacM68kDriver() {
+IMuseDriver_MacM68k::~IMuseDriver_MacM68k() {
+ for (uint i = 0; i < ARRAYSIZE(_channels); ++i)
+ delete _channels[i];
}
-int MacM68kDriver::open() {
+int IMuseDriver_MacM68k::open() {
if (_isOpen) {
return MERR_ALREADY_OPEN;
}
@@ -45,7 +50,8 @@ int MacM68kDriver::open() {
}
for (uint i = 0; i < ARRAYSIZE(_channels); ++i) {
- _channels[i].init(this, i);
+ delete _channels[i];
+ _channels[i] = new MidiChannel_MacM68k(this, i);
}
memset(_voiceChannels, 0, sizeof(_voiceChannels));
@@ -88,7 +94,7 @@ int MacM68kDriver::open() {
return 0;
}
-void MacM68kDriver::close() {
+void IMuseDriver_MacM68k::close() {
if (!_isOpen) {
return;
}
@@ -106,25 +112,21 @@ void MacM68kDriver::close() {
_mixBufferLength = 0;
}
-void MacM68kDriver::send(uint32 d) {
+void IMuseDriver_MacM68k::send(uint32 d) {
assert(false);
}
-void MacM68kDriver::sysEx_customInstrument(byte channel, uint32 type, const byte *instr) {
- assert(false);
-}
-
-MidiChannel *MacM68kDriver::allocateChannel() {
+MidiChannel *IMuseDriver_MacM68k::allocateChannel() {
for (uint i = 0; i < ARRAYSIZE(_channels); ++i) {
- if (_channels[i].allocate()) {
- return &_channels[i];
+ if (_channels[i]->allocate()) {
+ return _channels[i];
}
}
return nullptr;
}
-MacM68kDriver::Instrument MacM68kDriver::getInstrument(int idx) const {
+IMuseDriver_MacM68k::Instrument IMuseDriver_MacM68k::getInstrument(int idx) const {
InstrumentMap::const_iterator i = _instruments.find(idx);
if (i != _instruments.end()) {
return i->_value;
@@ -133,7 +135,7 @@ MacM68kDriver::Instrument MacM68kDriver::getInstrument(int idx) const {
}
}
-void MacM68kDriver::generateSamples(int16 *buf, int len) {
+void IMuseDriver_MacM68k::generateSamples(int16 *buf, int len) {
int silentChannels = 0;
if (_mixBufferLength < len) {
@@ -191,7 +193,7 @@ void MacM68kDriver::generateSamples(int16 *buf, int len) {
}
}
-void MacM68kDriver::loadAllInstruments() {
+void IMuseDriver_MacM68k::loadAllInstruments() {
Common::MacResManager resource;
if (resource.open("iMUSE Setups")) {
if (!resource.hasResFork()) {
@@ -225,7 +227,7 @@ void MacM68kDriver::loadAllInstruments() {
}
}
-void MacM68kDriver::addInstrument(int idx, Common::SeekableReadStream *data) {
+void IMuseDriver_MacM68k::addInstrument(int idx, Common::SeekableReadStream *data) {
// We parse the "SND" files manually here, since we need special data
// from their header and need to work on them raw while mixing.
data->skip(2);
@@ -251,7 +253,7 @@ void MacM68kDriver::addInstrument(int idx, Common::SeekableReadStream *data) {
_instruments[idx] = inst;
}
-void MacM68kDriver::setPitch(OutputChannel *out, int frequency) {
+void IMuseDriver_MacM68k::setPitch(OutputChannel *out, int frequency) {
out->frequency = frequency;
out->isFinished = false;
@@ -266,7 +268,7 @@ void MacM68kDriver::setPitch(OutputChannel *out, int frequency) {
}
}
-void MacM68kDriver::VoiceChannel::off() {
+void IMuseDriver_MacM68k::VoiceChannel::off() {
if (out.start) {
out.isFinished = true;
}
@@ -275,14 +277,14 @@ void MacM68kDriver::VoiceChannel::off() {
part = nullptr;
}
-void MacM68kDriver::MidiChannel_MacM68k::release() {
+void IMuseDriver_MacM68k::MidiChannel_MacM68k::release() {
_allocated = false;
while (_voice) {
_voice->off();
}
}
-void MacM68kDriver::MidiChannel_MacM68k::send(uint32 b) {
+void IMuseDriver_MacM68k::MidiChannel_MacM68k::send(uint32 b) {
uint8 type = b & 0xF0;
uint8 p1 = (b >> 8) & 0xFF;
uint8 p2 = (b >> 16) & 0xFF;
@@ -313,7 +315,7 @@ void MacM68kDriver::MidiChannel_MacM68k::send(uint32 b) {
}
}
-void MacM68kDriver::MidiChannel_MacM68k::noteOff(byte note) {
+void IMuseDriver_MacM68k::MidiChannel_MacM68k::noteOff(byte note) {
for (VoiceChannel *i = _voice; i; i = i->next) {
if (i->note == note) {
if (_sustain) {
@@ -325,7 +327,7 @@ void MacM68kDriver::MidiChannel_MacM68k::noteOff(byte note) {
}
}
-void MacM68kDriver::MidiChannel_MacM68k::noteOn(byte note, byte velocity) {
+void IMuseDriver_MacM68k::MidiChannel_MacM68k::noteOn(byte note, byte velocity) {
// Do not start a not unless there is an instrument set up
if (!_instrument.data) {
return;
@@ -366,18 +368,18 @@ void MacM68kDriver::MidiChannel_MacM68k::noteOn(byte note, byte velocity) {
voice->out.subPos = 0;
}
-void MacM68kDriver::MidiChannel_MacM68k::programChange(byte program) {
+void IMuseDriver_MacM68k::MidiChannel_MacM68k::programChange(byte program) {
_instrument = _owner->getInstrument(program + kProgramChangeBase);
}
-void MacM68kDriver::MidiChannel_MacM68k::pitchBend(int16 bend) {
+void IMuseDriver_MacM68k::MidiChannel_MacM68k::pitchBend(int16 bend) {
_pitchBend = (bend * _pitchBendFactor) >> 6;
for (VoiceChannel *i = _voice; i; i = i->next) {
_owner->setPitch(&i->out, (i->note << 7) + _pitchBend);
}
}
-void MacM68kDriver::MidiChannel_MacM68k::controlChange(byte control, byte value) {
+void IMuseDriver_MacM68k::MidiChannel_MacM68k::controlChange(byte control, byte value) {
switch (control) {
// volume change
case 7:
@@ -412,28 +414,22 @@ void MacM68kDriver::MidiChannel_MacM68k::controlChange(byte control, byte value)
}
}
-void MacM68kDriver::MidiChannel_MacM68k::pitchBendFactor(byte value) {
+void IMuseDriver_MacM68k::MidiChannel_MacM68k::pitchBendFactor(byte value) {
_pitchBendFactor = value;
}
-void MacM68kDriver::MidiChannel_MacM68k::priority(byte value) {
+void IMuseDriver_MacM68k::MidiChannel_MacM68k::priority(byte value) {
_priority = value;
}
-void MacM68kDriver::MidiChannel_MacM68k::sysEx_customInstrument(uint32 type, const byte *instr) {
+void IMuseDriver_MacM68k::MidiChannel_MacM68k::sysEx_customInstrument(uint32 type, const byte *instr) {
assert(instr);
if (type == 'MAC ') {
_instrument = _owner->getInstrument(*instr + kSysExBase);
}
}
-void MacM68kDriver::MidiChannel_MacM68k::init(MacM68kDriver *owner, byte channel) {
- _owner = owner;
- _number = channel;
- _allocated = false;
-}
-
-bool MacM68kDriver::MidiChannel_MacM68k::allocate() {
+bool IMuseDriver_MacM68k::MidiChannel_MacM68k::allocate() {
if (_allocated) {
return false;
}
@@ -448,7 +444,7 @@ bool MacM68kDriver::MidiChannel_MacM68k::allocate() {
return true;
}
-void MacM68kDriver::MidiChannel_MacM68k::addVoice(VoiceChannel *voice) {
+void IMuseDriver_MacM68k::MidiChannel_MacM68k::addVoice(VoiceChannel *voice) {
voice->next = _voice;
voice->prev = nullptr;
voice->part = this;
@@ -458,7 +454,7 @@ void MacM68kDriver::MidiChannel_MacM68k::addVoice(VoiceChannel *voice) {
_voice = voice;
}
-void MacM68kDriver::MidiChannel_MacM68k::removeVoice(VoiceChannel *voice) {
+void IMuseDriver_MacM68k::MidiChannel_MacM68k::removeVoice(VoiceChannel *voice) {
VoiceChannel *i = _voice;
while (i && i != voice) {
i = i->next;
@@ -477,7 +473,7 @@ void MacM68kDriver::MidiChannel_MacM68k::removeVoice(VoiceChannel *voice) {
}
}
-MacM68kDriver::VoiceChannel *MacM68kDriver::allocateVoice(int priority) {
+IMuseDriver_MacM68k::VoiceChannel *IMuseDriver_MacM68k::allocateVoice(int priority) {
VoiceChannel *channel = nullptr;
for (int i = 0; i < kChannelCount; ++i) {
if (++_lastUsedVoiceChannel == kChannelCount) {
@@ -504,7 +500,7 @@ MacM68kDriver::VoiceChannel *MacM68kDriver::allocateVoice(int priority) {
return channel;
}
-const int MacM68kDriver::_volumeBaseTable[32] = {
+const int IMuseDriver_MacM68k::_volumeBaseTable[32] = {
0, 0, 1, 1, 2, 3, 5, 6,
8, 11, 13, 16, 19, 22, 26, 30,
34, 38, 43, 48, 53, 58, 64, 70,
diff --git a/engines/scumm/imuse/drivers/mac_m68k.h b/engines/scumm/imuse/drivers/mac_m68k.h
index d04e769da5f..cf51c5d90d6 100644
--- a/engines/scumm/imuse/drivers/mac_m68k.h
+++ b/engines/scumm/imuse/drivers/mac_m68k.h
@@ -32,20 +32,19 @@ class SeekableReadStream;
namespace Scumm {
-class MacM68kDriver : public MidiDriver_Emulated {
+class IMuseDriver_MacM68k : public MidiDriver_Emulated {
friend class MidiChannel_MacM68k;
public:
- MacM68kDriver(Audio::Mixer *mixer);
- ~MacM68kDriver() override;
+ IMuseDriver_MacM68k(Audio::Mixer *mixer);
+ ~IMuseDriver_MacM68k() override;
int open() override;
void close() override;
void send(uint32 d) override;
- void sysEx_customInstrument(byte channel, uint32 type, const byte *instr) override;
MidiChannel *allocateChannel() override;
- MidiChannel *getPercussionChannel() override { return 0; }
+ MidiChannel *getPercussionChannel() override { return nullptr; }
bool isStereo() const override { return false; }
int getRate() const override {
@@ -127,8 +126,9 @@ private:
};
class MidiChannel_MacM68k : public MidiChannel {
- friend class MacM68kDriver;
+ friend class IMuseDriver_MacM68k;
public:
+ MidiChannel_MacM68k(IMuseDriver_MacM68k *driver, byte number) : MidiChannel(), _owner(driver), _number(number), _allocated(false) {}
MidiDriver *device() override { return _owner; }
byte getNumber() override { return _number; }
void release() override;
@@ -143,15 +143,14 @@ private:
void priority(byte value) override;
void sysEx_customInstrument(uint32 type, const byte *instr) override;
- void init(MacM68kDriver *owner, byte channel);
bool allocate();
void addVoice(VoiceChannel *voice);
void removeVoice(VoiceChannel *voice);
private:
- MacM68kDriver *_owner;
+ IMuseDriver_MacM68k *_owner;
+ const byte _number;
bool _allocated;
- int _number;
VoiceChannel *_voice;
int _priority;
@@ -162,7 +161,7 @@ private:
int _volume;
};
- MidiChannel_MacM68k _channels[32];
+ MidiChannel_MacM68k *_channels[32];
enum {
kChannelCount = 8
diff --git a/engines/scumm/imuse/drivers/mt32.cpp b/engines/scumm/imuse/drivers/mt32.cpp
new file mode 100644
index 00000000000..e65001834ac
--- /dev/null
+++ b/engines/scumm/imuse/drivers/mt32.cpp
@@ -0,0 +1,103 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include "common/str.h"
+#include "common/system.h"
+#include "base/version.h"
+#include "scumm/imuse/drivers/mt32.h"
+
+namespace Scumm {
+
+IMuseDriver_MT32::IMuseDriver_MT32(MidiDriver::DeviceHandle dev, bool newSystem) : MidiDriver(), _newSystem(newSystem), _drv(nullptr) {
+ _drv = MidiDriver::createMidi(dev);
+ assert(_drv);
+
+ if (!_newSystem)
+ _drv->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+}
+
+IMuseDriver_MT32::~IMuseDriver_MT32() {
+ delete _drv;
+}
+
+int IMuseDriver_MT32::open() {
+ if (!_drv)
+ return MERR_CANNOT_CONNECT;
+
+ int res = _drv->open();
+
+ initDevice();
+
+ return res;
+}
+
+MidiChannel *IMuseDriver_MT32::allocateChannel() {
+ if (!_newSystem)
+ return _drv->allocateChannel();
+
+ return nullptr;
+}
+
+MidiChannel *IMuseDriver_MT32::getPercussionChannel() {
+ if (!_newSystem)
+ return _drv->getPercussionChannel();
+
+ return nullptr;
+}
+
+void IMuseDriver_MT32::initDevice() {
+ byte buffer[52];
+
+ // Reset the MT-32
+ _drv->sysEx((const byte *) "\x41\x10\x16\x12\x7f\x00\x00\x01\x00", 9);
+ g_system->delayMillis(250);
+
+ // Setup master tune, reverb mode, reverb time, reverb level,
+ // channel mapping, partial reserve and master volume
+ _drv->sysEx((const byte *) "\x41\x10\x16\x12\x10\x00\x00\x40\x00\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x64\x77", 31);
+ g_system->delayMillis(250);
+
+ // Map percussion to notes 24 - 34 without reverb
+ if (!_newSystem) {
+ _drv->sysEx((const byte *) "\x41\x10\x16\x12\x03\x01\x10\x40\x64\x07\x00\x4a\x64\x06\x00\x41\x64\x07\x00\x4b\x64\x08\x00\x45\x64\x06\x00\x44\x64\x0b\x00\x51\x64\x05\x00\x43\x64\x08\x00\x50\x64\x07\x00\x42\x64\x03\x00\x4c\x64\x07\x00\x44", 52);
+ g_system->delayMillis(250);
+ }
+
+ // Compute version string (truncated to 20 chars max.)
+ Common::String infoStr = "ScummVM ";
+ infoStr += gScummVMVersion;
+ int len = infoStr.size();
+ if (len > 20)
+ len = 20;
+
+ // Display a welcome message on MT-32 displays.
+ memcpy(&buffer[0], "\x41\x10\x16\x12\x20\x00\x00", 7);
+ memcpy(&buffer[7], " ", 20);
+ memcpy(buffer + 7 + (20 - len) / 2, infoStr.c_str(), len);
+ byte checksum = 0;
+ for (int i = 4; i < 27; ++i)
+ checksum -= buffer[i];
+ buffer[27] = checksum & 0x7F;
+ _drv->sysEx(buffer, 28);
+ g_system->delayMillis(1000);
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/imuse/drivers/mt32.h b/engines/scumm/imuse/drivers/mt32.h
new file mode 100644
index 00000000000..9f6cf7b2687
--- /dev/null
+++ b/engines/scumm/imuse/drivers/mt32.h
@@ -0,0 +1,59 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef SCUMM_IMUSE_DRV_MT32_H
+#define SCUMM_IMUSE_DRV_MT32_H
+
+#include "audio/mididrv.h"
+
+namespace Scumm {
+
+class IMuseDriver_MT32 : public MidiDriver {
+public:
+ IMuseDriver_MT32(MidiDriver::DeviceHandle dev, bool newSystem);
+ ~IMuseDriver_MT32() override;
+
+ int open() override;
+
+ // Just pass these through...
+ bool isOpen() const override { return _drv ? _drv->isOpen() : false; }
+ void close() override { if (_drv) _drv->close(); }
+ uint32 property(int prop, uint32 param) override { return _drv ? _drv->property(prop, param) : 0; }
+ void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) override { if (_drv) _drv->setTimerCallback(timerParam, timerProc); }
+ uint32 getBaseTempo() override { return _drv ? _drv->getBaseTempo() : 0; }
+ void send(uint32 b) override { if (_drv) _drv->send(b); };
+ void sysEx(const byte *msg, uint16 length) override { if (_drv) _drv->sysEx(msg, length); }
+ void setPitchBendRange(byte channel, uint range) override { if (_drv) _drv->setPitchBendRange(channel, range); }
+
+ // Channel allocation functions
+ MidiChannel *allocateChannel() override;
+ MidiChannel *getPercussionChannel() override;
+
+private:
+ void initDevice();
+
+ MidiDriver *_drv;
+ const bool _newSystem;
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/imuse/drivers/pcspk.cpp b/engines/scumm/imuse/drivers/pcspk.cpp
index 4ccfa8e0c3f..546d674321a 100644
--- a/engines/scumm/imuse/drivers/pcspk.cpp
+++ b/engines/scumm/imuse/drivers/pcspk.cpp
@@ -25,22 +25,26 @@
namespace Scumm {
-PcSpkDriver::PcSpkDriver(Audio::Mixer *mixer)
- : MidiDriver_Emulated(mixer), _pcSpk(mixer->getOutputRate()) {
+IMuseDriver_PCSpk::IMuseDriver_PCSpk(Audio::Mixer *mixer)
+ : MidiDriver_Emulated(mixer), _pcSpk(mixer->getOutputRate()) , _activeChannel(nullptr), _lastActiveChannel(nullptr), _lastActiveOut(0), _effectTimer(0), _randBase(1) {
+ memset(_channels, 0, sizeof(_channels));
}
-PcSpkDriver::~PcSpkDriver() {
+IMuseDriver_PCSpk::~IMuseDriver_PCSpk() {
close();
}
-int PcSpkDriver::open() {
+int IMuseDriver_PCSpk::open() {
if (_isOpen)
return MERR_ALREADY_OPEN;
MidiDriver_Emulated::open();
- for (uint i = 0; i < 6; ++i)
- _channels[i].init(this, i);
+ for (uint i = 0; i < 6; ++i) {
+ delete _channels[i];
+ _channels[i] = new MidiChannel_PcSpk(this, i);
+ }
+
_activeChannel = nullptr;
_effectTimer = 0;
_randBase = 1;
@@ -59,44 +63,41 @@ int PcSpkDriver::open() {
return 0;
}
-void PcSpkDriver::close() {
+void IMuseDriver_PCSpk::close() {
if (!_isOpen)
return;
_isOpen = false;
_mixer->stopHandle(_mixerSoundHandle);
+
+ for (uint i = 0; i < 6; ++i)
+ delete _channels[i];
}
-void PcSpkDriver::send(uint32 d) {
+void IMuseDriver_PCSpk::send(uint32 d) {
assert((d & 0x0F) < 6);
- _channels[(d & 0x0F)].send(d);
+ _channels[(d & 0x0F)]->send(d);
}
-void PcSpkDriver::sysEx_customInstrument(byte channel, uint32 type, const byte *instr) {
- assert(channel < 6);
- if (type == 'SPK ')
- _channels[channel].sysEx_customInstrument(type, instr);
-}
-
-MidiChannel *PcSpkDriver::allocateChannel() {
+MidiChannel *IMuseDriver_PCSpk::allocateChannel() {
for (uint i = 0; i < 6; ++i) {
- if (_channels[i].allocate())
- return &_channels[i];
+ if (_channels[i]->allocate())
+ return _channels[i];
}
return nullptr;
}
-void PcSpkDriver::generateSamples(int16 *buf, int len) {
+void IMuseDriver_PCSpk::generateSamples(int16 *buf, int len) {
_pcSpk.readBuffer(buf, len);
}
-void PcSpkDriver::onTimer() {
+void IMuseDriver_PCSpk::onTimer() {
if (!_activeChannel)
return;
for (uint i = 0; i < 6; ++i) {
- OutputChannel &out = _channels[i]._out;
+ OutputChannel &out = _channels[i]->_out;
if (!out.active)
continue;
@@ -113,9 +114,9 @@ void PcSpkDriver::onTimer() {
_effectTimer = 0;
if (out.effectEnvelopeA.state)
- updateEffectGenerator(_channels[i], out.effectEnvelopeA, out.effectDefA);
+ updateEffectGenerator(*_channels[i], out.effectEnvelopeA, out.effectDefA);
if (out.effectEnvelopeB.state)
- updateEffectGenerator(_channels[i], out.effectEnvelopeB, out.effectDefB);
+ updateEffectGenerator(*_channels[i], out.effectEnvelopeB, out.effectDefB);
}
} else {
out.active = 0;
@@ -133,13 +134,13 @@ void PcSpkDriver::onTimer() {
}
}
-void PcSpkDriver::updateNote() {
+void IMuseDriver_PCSpk::updateNote() {
uint8 priority = 0;
_activeChannel = nullptr;
for (uint i = 0; i < 6; ++i) {
- if (_channels[i]._allocated && _channels[i]._out.active && _channels[i]._priority >= priority) {
- priority = _channels[i]._priority;
- _activeChannel = &_channels[i];
+ if (_channels[i]->_allocated && _channels[i]->_out.active && _channels[i]->_priority >= priority) {
+ priority = _channels[i]->_priority;
+ _activeChannel = _channels[i];
}
}
@@ -152,7 +153,7 @@ void PcSpkDriver::updateNote() {
}
}
-void PcSpkDriver::output(uint16 out) {
+void IMuseDriver_PCSpk::output(uint16 out) {
byte v1 = (out >> 7) & 0xFF;
byte v2 = (out >> 2) & 0x1E;
@@ -170,14 +171,11 @@ void PcSpkDriver::output(uint16 out) {
}
}
-void PcSpkDriver::MidiChannel_PcSpk::init(PcSpkDriver *owner, byte channel) {
- _owner = owner;
- _channel = channel;
- _allocated = false;
+IMuseDriver_PCSpk::MidiChannel_PcSpk::MidiChannel_PcSpk(IMuseDriver_PCSpk *owner, byte number) : MidiChannel(), _owner(owner), _number(number), _allocated(false) {
memset(&_out, 0, sizeof(_out));
}
-bool PcSpkDriver::MidiChannel_PcSpk::allocate() {
+bool IMuseDriver_PCSpk::MidiChannel_PcSpk::allocate() {
if (_allocated)
return false;
@@ -190,21 +188,13 @@ bool PcSpkDriver::MidiChannel_PcSpk::allocate() {
return true;
}
-MidiDriver *PcSpkDriver::MidiChannel_PcSpk::device() {
- return _owner;
-}
-
-byte PcSpkDriver::MidiChannel_PcSpk::getNumber() {
- return _channel;
-}
-
-void PcSpkDriver::MidiChannel_PcSpk::release() {
+void IMuseDriver_PCSpk::MidiChannel_PcSpk::release() {
_out.active = 0;
_allocated = false;
_owner->updateNote();
}
-void PcSpkDriver::MidiChannel_PcSpk::send(uint32 b) {
+void IMuseDriver_PCSpk::MidiChannel_PcSpk::send(uint32 b) {
uint8 type = b & 0xF0;
uint8 p1 = (b >> 8) & 0xFF;
uint8 p2 = (b >> 16) & 0xFF;
@@ -234,7 +224,7 @@ void PcSpkDriver::MidiChannel_PcSpk::send(uint32 b) {
}
}
-void PcSpkDriver::MidiChannel_PcSpk::noteOff(byte note) {
+void IMuseDriver_PCSpk::MidiChannel_PcSpk::noteOff(byte note) {
if (!_allocated)
return;
@@ -249,7 +239,7 @@ void PcSpkDriver::MidiChannel_PcSpk::noteOff(byte note) {
}
}
-void PcSpkDriver::MidiChannel_PcSpk::noteOn(byte note, byte velocity) {
+void IMuseDriver_PCSpk::MidiChannel_PcSpk::noteOn(byte note, byte velocity) {
if (!_allocated)
return;
@@ -257,7 +247,7 @@ void PcSpkDriver::MidiChannel_PcSpk::noteOn(byte note, byte velocity) {
_out.sustainNoteOff = 0;
_out.length = _instrument[0];
- if (_instrument[4] * 256 < ARRAYSIZE(PcSpkDriver::_outInstrumentData))
+ if (_instrument[4] * 256 < ARRAYSIZE(IMuseDriver_PCSpk::_outInstrumentData))
_out.instrument = _owner->_outInstrumentData + _instrument[4] * 256;
else
_out.instrument = nullptr;
@@ -278,7 +268,7 @@ void PcSpkDriver::MidiChannel_PcSpk::noteOn(byte note, byte velocity) {
}
_owner->updateNote();
- _out.unkC += PcSpkDriver::getEffectModifier(_instrument[3] + ((velocity & 0xFE) << 4));
+ _out.unkC += IMuseDriver_PCSpk::getEffectModifier(_instrument[3] + ((velocity & 0xFE) << 4));
if (_out.unkC > 63)
_out.unkC = 63;
@@ -289,16 +279,16 @@ void PcSpkDriver::MidiChannel_PcSpk::noteOn(byte note, byte velocity) {
_owner->setupEffects(*this, _out.effectEnvelopeB, _out.effectDefB, _instrument[14], _instrument + 15);
}
-void PcSpkDriver::MidiChannel_PcSpk::programChange(byte program) {
+void IMuseDriver_PCSpk::MidiChannel_PcSpk::programChange(byte program) {
// Nothing to implement here, the iMuse code takes care of passing us the
// instrument data.
}
-void PcSpkDriver::MidiChannel_PcSpk::pitchBend(int16 bend) {
+void IMuseDriver_PCSpk::MidiChannel_PcSpk::pitchBend(int16 bend) {
_pitchBend = (bend * _pitchBendFactor) >> 6;
}
-void PcSpkDriver::MidiChannel_PcSpk::controlChange(byte control, byte value) {
+void IMuseDriver_PCSpk::MidiChannel_PcSpk::controlChange(byte control, byte value) {
switch (control) {
case 1:
if (_out.effectEnvelopeA.state && _out.effectDefA.useModWheel)
@@ -338,19 +328,19 @@ void PcSpkDriver::MidiChannel_PcSpk::controlChange(byte control, byte value) {
}
}
-void PcSpkDriver::MidiChannel_PcSpk::pitchBendFactor(byte value) {
+void IMuseDriver_PCSpk::MidiChannel_PcSpk::pitchBendFactor(byte value) {
_pitchBendFactor = value;
}
-void PcSpkDriver::MidiChannel_PcSpk::priority(byte value) {
+void IMuseDriver_PCSpk::MidiChannel_PcSpk::priority(byte value) {
_priority = value;
}
-void PcSpkDriver::MidiChannel_PcSpk::sysEx_customInstrument(uint32 type, const byte *instr) {
+void IMuseDriver_PCSpk::MidiChannel_PcSpk::sysEx_customInstrument(uint32 type, const byte *instr) {
memcpy(_instrument, instr, sizeof(_instrument));
}
-uint8 PcSpkDriver::getEffectModifier(uint16 level) {
+uint8 IMuseDriver_PCSpk::getEffectModifier(uint16 level) {
uint8 base = level / 32;
uint8 index = level % 32;
@@ -360,7 +350,7 @@ uint8 PcSpkDriver::getEffectModifier(uint16 level) {
return (base * (index + 1)) >> 5;
}
-int16 PcSpkDriver::getEffectModLevel(int16 level, int8 mod) {
+int16 IMuseDriver_PCSpk::getEffectModLevel(int16 level, int8 mod) {
if (!mod) {
return 0;
} else if (mod == 31) {
@@ -380,7 +370,7 @@ int16 PcSpkDriver::getEffectModLevel(int16 level, int8 mod) {
}
}
-int16 PcSpkDriver::getRandScale(int16 input) {
+int16 IMuseDriver_PCSpk::getRandScale(int16 input) {
if (_randBase & 1)
_randBase = (_randBase >> 1) ^ 0xB8;
else
@@ -389,7 +379,7 @@ int16 PcSpkDriver::getRandScale(int16 input) {
return (_randBase * input) >> 8;
}
-void PcSpkDriver::setupEffects(MidiChannel_PcSpk &chan, EffectEnvelope &env, EffectDefinition &def, byte flags, const byte *data) {
+void IMuseDriver_PCSpk::setupEffects(MidiChannel_PcSpk &chan, EffectEnvelope &env, EffectDefinition &def, byte flags, const byte *data) {
def.phase = 0;
def.useModWheel = flags & 0x40;
env.loop = flags & 0x20;
@@ -446,7 +436,7 @@ void PcSpkDriver::setupEffects(MidiChannel_PcSpk &chan, EffectEnvelope &env, Eff
startEffect(env, data);
}
-void PcSpkDriver::startEffect(EffectEnvelope &env, const byte *data) {
+void IMuseDriver_PCSpk::startEffect(EffectEnvelope &env, const byte *data) {
env.state = 1;
env.currentLevel = 0;
env.modWheelLast = 31;
@@ -465,7 +455,7 @@ void PcSpkDriver::startEffect(EffectEnvelope &env, const byte *data) {
initNextEnvelopeState(env);
}
-void PcSpkDriver::initNextEnvelopeState(EffectEnvelope &env) {
+void IMuseDriver_PCSpk::initNextEnvelopeState(EffectEnvelope &env) {
uint8 lastState = env.state - 1;
uint16 stepCount = _effectEnvStepTable[getEffectModifier(((env.stateTargetLevels[lastState] & 0x7F) << 5) + env.modWheelSensitivity)];
@@ -501,7 +491,7 @@ void PcSpkDriver::initNextEnvelopeState(EffectEnvelope &env) {
env.changeCountRem = 0;
}
-void PcSpkDriver::updateEffectGenerator(MidiChannel_PcSpk &chan, EffectEnvelope &env, EffectDefinition &def) {
+void IMuseDriver_PCSpk::updateEffectGenerator(MidiChannel_PcSpk &chan, EffectEnvelope &env, EffectDefinition &def) {
if (advanceEffectEnvelope(env, def) & 1) {
switch (def.type) {
case 0: case 1:
@@ -537,7 +527,7 @@ void PcSpkDriver::updateEffectGenerator(MidiChannel_PcSpk &chan, EffectEnvelope
}
}
-uint8 PcSpkDriver::advanceEffectEnvelope(EffectEnvelope &env, EffectDefinition &def) {
+uint8 IMuseDriver_PCSpk::advanceEffectEnvelope(EffectEnvelope &env, EffectDefinition &def) {
if (env.duration != 0) {
env.duration -= 17;
if (env.duration <= 0) {
@@ -584,7 +574,7 @@ uint8 PcSpkDriver::advanceEffectEnvelope(EffectEnvelope &env, EffectDefinition &
return changedFlags;
}
-const byte PcSpkDriver::_outInstrumentData[1024] = {
+const byte IMuseDriver_PCSpk::_outInstrumentData[1024] = {
0x00, 0x03, 0x06, 0x09, 0x0C, 0x0F, 0x12, 0x15,
0x18, 0x1B, 0x1E, 0x21, 0x24, 0x27, 0x2A, 0x2D,
0x30, 0x33, 0x36, 0x39, 0x3B, 0x3E, 0x41, 0x43,
@@ -715,7 +705,7 @@ const byte PcSpkDriver::_outInstrumentData[1024] = {
0xD4, 0xF7, 0x4A, 0x4A, 0xD0, 0x57, 0x68, 0x76
};
-const byte PcSpkDriver::_outputTable1[] = {
+const byte IMuseDriver_PCSpk::_outputTable1[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -734,7 +724,7 @@ const byte PcSpkDriver::_outputTable1[] = {
7, 7, 7, 7, 7, 7, 7, 7
};
-const byte PcSpkDriver::_outputTable2[] = {
+const byte IMuseDriver_PCSpk::_outputTable2[] = {
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
@@ -769,7 +759,7 @@ const byte PcSpkDriver::_outputTable2[] = {
4, 5, 6, 7
};
-const uint16 PcSpkDriver::_effectEnvStepTable[] = {
+const uint16 IMuseDriver_PCSpk::_effectEnvStepTable[] = {
1, 2, 4, 5,
6, 7, 8, 9,
10, 12, 14, 16,
@@ -780,7 +770,7 @@ const uint16 PcSpkDriver::_effectEnvStepTable[] = {
600, 860, 1200, 1600
};
-const uint16 PcSpkDriver::_frequencyTable[] = {
+const uint16 IMuseDriver_PCSpk::_frequencyTable[] = {
0x8E84, 0x8E00, 0x8D7D, 0x8CFA,
0x8C78, 0x8BF7, 0x8B76, 0x8AF5,
0x8A75, 0x89F5, 0x8976, 0x88F7,
diff --git a/engines/scumm/imuse/drivers/pcspk.h b/engines/scumm/imuse/drivers/pcspk.h
index 8d4c23521d6..bad9f1269ff 100644
--- a/engines/scumm/imuse/drivers/pcspk.h
+++ b/engines/scumm/imuse/drivers/pcspk.h
@@ -27,19 +27,18 @@
namespace Scumm {
-class PcSpkDriver : public MidiDriver_Emulated {
+class IMuseDriver_PCSpk : public MidiDriver_Emulated {
public:
- PcSpkDriver(Audio::Mixer *mixer);
- ~PcSpkDriver() override;
+ IMuseDriver_PCSpk(Audio::Mixer *mixer);
+ ~IMuseDriver_PCSpk() override;
int open() override;
void close() override;
void send(uint32 d) override;
- void sysEx_customInstrument(byte channel, uint32 type, const byte *instr) override;
MidiChannel *allocateChannel() override;
- MidiChannel *getPercussionChannel() override { return 0; }
+ MidiChannel *getPercussionChannel() override { return nullptr; }
bool isStereo() const override { return _pcSpk.isStereo(); }
int getRate() const override { return _pcSpk.getRate(); }
@@ -103,9 +102,11 @@ private:
int16 unk60;
};
- struct MidiChannel_PcSpk : public MidiChannel {
- MidiDriver *device() override;
- byte getNumber() override;
+ class MidiChannel_PcSpk: public MidiChannel {
+ public:
+ MidiChannel_PcSpk(IMuseDriver_PCSpk *owner, byte number);
+ MidiDriver *device() override { return _owner; }
+ byte getNumber() override { return _number; }
void release() override;
void send(uint32 b) override;
@@ -118,22 +119,23 @@ private:
void priority(byte value) override;
void sysEx_customInstrument(uint32 type, const byte *instr) override;
- void init(PcSpkDriver *owner, byte channel);
bool allocate();
- PcSpkDriver *_owner;
bool _allocated;
- byte _channel;
-
OutputChannel _out;
uint8 _instrument[23];
- uint8 _programNr;
uint8 _priority;
uint8 _tl;
uint8 _modWheel;
+ int16 _pitchBend;
+
+ private:
+ IMuseDriver_PCSpk *_owner;
+ const byte _number;
+ uint8 _programNr;
uint8 _sustain;
uint8 _pitchBendFactor;
- int16 _pitchBend;
+
};
void setupEffects(MidiChannel_PcSpk &chan, EffectEnvelope &env, EffectDefinition &def, byte flags, const byte *data);
@@ -142,7 +144,7 @@ private:
void updateEffectGenerator(MidiChannel_PcSpk &chan, EffectEnvelope &env, EffectDefinition &def);
uint8 advanceEffectEnvelope(EffectEnvelope &env, EffectDefinition &def);
- MidiChannel_PcSpk _channels[6];
+ MidiChannel_PcSpk *_channels[6];
MidiChannel_PcSpk *_activeChannel;
MidiChannel_PcSpk *_lastActiveChannel;
diff --git a/engines/scumm/imuse/imuse.cpp b/engines/scumm/imuse/imuse.cpp
index 93699c49311..8b071e2f838 100644
--- a/engines/scumm/imuse/imuse.cpp
+++ b/engines/scumm/imuse/imuse.cpp
@@ -1437,17 +1437,6 @@ int IMuseInternal::initialize(OSystem *syst, MidiDriver *native_midi, MidiDriver
init_queue();
init_parts();
- if (_midi_native && _soundType != MDT_MACINTOSH && _soundType != MDT_AMIGA) {
- if (_native_mt32 && !_enable_gs) {
- initMT32(_midi_native);
- } else if (_enable_gs) {
- initGS(_midi_native);
- } else if (!_native_mt32) {
- // If GS is disabled we do the "normal" init from the original GM drivers.
- initGM();
- }
- }
-
_initialized = true;
return 0;
@@ -1463,174 +1452,6 @@ void IMuseInternal::initMidiDriver(TimerCallbackInfo *info) {
info->driver->setTimerCallback(info, &IMuseInternal::midiTimerCallback);
}
-void IMuseInternal::initMT32(MidiDriver *midi) {
- byte buffer[52];
-
- // Reset the MT-32
- midi->sysEx((const byte *) "\x41\x10\x16\x12\x7f\x00\x00\x01\x00", 9);
- _system->delayMillis(250);
-
- // Setup master tune, reverb mode, reverb time, reverb level,
- // channel mapping, partial reserve and master volume
- midi->sysEx((const byte *) "\x41\x10\x16\x12\x10\x00\x00\x40\x00\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x64\x77", 31);
- _system->delayMillis(250);
-
- // Map percussion to notes 24 - 34 without reverb
- midi->sysEx((const byte *) "\x41\x10\x16\x12\x03\x01\x10\x40\x64\x07\x00\x4a\x64\x06\x00\x41\x64\x07\x00\x4b\x64\x08\x00\x45\x64\x06\x00\x44\x64\x0b\x00\x51\x64\x05\x00\x43\x64\x08\x00\x50\x64\x07\x00\x42\x64\x03\x00\x4c\x64\x07\x00\x44", 52);
- _system->delayMillis(250);
-
- // Compute version string (truncated to 20 chars max.)
- Common::String infoStr = "ScummVM ";
- infoStr += gScummVMVersion;
- int len = infoStr.size();
- if (len > 20)
- len = 20;
-
- // Display a welcome message on MT-32 displays.
- memcpy(&buffer[0], "\x41\x10\x16\x12\x20\x00\x00", 7);
- memcpy(&buffer[7], " ", 20);
- memcpy(buffer + 7 + (20 - len) / 2, infoStr.c_str(), len);
- byte checksum = 0;
- for (int i = 4; i < 27; ++i)
- checksum -= buffer[i];
- buffer[27] = checksum & 0x7F;
- midi->sysEx(buffer, 28);
- _system->delayMillis(1000);
-}
-
-void IMuseInternal::initGS(MidiDriver *midi) {
- byte buffer[12];
- int i;
-
- // General MIDI System On message
- // Resets all GM devices to default settings
- memcpy(&buffer[0], "\x7E\x7F\x09\x01", 4);
- midi->sysEx(buffer, 4);
- debug(2, "GM SysEx: GM System On");
- _system->delayMillis(200);
-
- if (_enable_gs) {
- // All GS devices recognize the GS Reset command,
- // even using Roland's ID. It is impractical to
- // support other manufacturers' devices for
- // further GS settings, as there are limitless
- // numbers of them out there that would each
- // require individual SysEx commands with unique IDs.
-
- // Roland GS SysEx ID
- memcpy(&buffer[0], "\x41\x10\x42\x12", 4);
-
- // GS Reset
- memcpy(&buffer[4], "\x40\x00\x7F\x00\x41", 5);
- midi->sysEx(buffer, 9);
- debug(2, "GS SysEx: GS Reset");
- _system->delayMillis(200);
-
- // Set global Master Tune to 442.0kHz, as on the MT-32
- memcpy(&buffer[4], "\x40\x00\x00\x00\x04\x04\x0F\x29", 8);
- midi->sysEx(buffer, 12);
- debug(2, "GS SysEx: Master Tune set to 442.0kHz");
-
- // Note: All Roland GS devices support CM-64/32L maps
-
- // Set Channels 1-16 to SC-55 Map, then CM-64/32L Variation
- for (i = 0; i < 16; ++i) {
- midi->send((127 << 16) | (0 << 8) | (0xB0 | i));
- midi->send((1 << 16) | (32 << 8) | (0xB0 | i));
- midi->send((0 << 16) | (0 << 8) | (0xC0 | i));
- }
- debug(2, "GS Program Change: CM-64/32L Map Selected");
-
- // Set Percussion Channel to SC-55 Map (CC#32, 01H), then
- // Switch Drum Map to CM-64/32L (MT-32 Compatible Drums)
- midi->getPercussionChannel()->controlChange(0, 0);
- midi->getPercussionChannel()->controlChange(32, 1);
- midi->send(127 << 8 | 0xC0 | 9);
- debug(2, "GS Program Change: Drum Map is CM-64/32L");
-
- // Set Master Chorus to 0. The MT-32 has no chorus capability.
- memcpy(&buffer[4], "\x40\x01\x3A\x00\x05", 5);
- midi->sysEx(buffer, 9);
- debug(2, "GS SysEx: Master Chorus Level is 0");
-
- // Set Channels 1-16 Reverb to 64, which is the
- // equivalent of MT-32 default Reverb Level 5
- for (i = 0; i < 16; ++i)
- midi->send((64 << 16) | (91 << 8) | (0xB0 | i));
- debug(2, "GM Controller 91 Change: Channels 1-16 Reverb Level is 64");
-
- // Set Channels 1-16 Pitch Bend Sensitivity to
- // 12 semitones; then lock the RPN by setting null.
- for (i = 0; i < 16; ++i) {
- midi->setPitchBendRange(i, 12);
- }
- debug(2, "GM Controller 6 Change: Channels 1-16 Pitch Bend Sensitivity is 12 semitones");
-
- // Set channels 1-16 Mod. LFO1 Pitch Depth to 4
- memcpy(&buffer[4], "\x40\x20\x04\x04\x18", 5);
- for (i = 0; i < 16; ++i) {
- buffer[5] = 0x20 + i;
- buffer[8] = 0x18 - i;
- midi->sysEx(buffer, 9);
- }
- debug(2, "GS SysEx: Channels 1-16 Mod. LFO1 Pitch Depth Level is 4");
-
- // Set Percussion Channel Expression to 80
- midi->getPercussionChannel()->controlChange(11, 80);
- debug(2, "GM Controller 11 Change: Percussion Channel Expression Level is 80");
-
- // Turn off Percussion Channel Rx. Expression so that
- // Expression cannot be modified. I don't know why, but
- // Roland does it this way.
- memcpy(&buffer[4], "\x40\x10\x0E\x00\x22", 5);
- midi->sysEx(buffer, 9);
- debug(2, "GS SysEx: Percussion Channel Rx. Expression is OFF");
-
- // Change Reverb Character to 0. I don't think this
- // sounds most like MT-32, but apparently Roland does.
- memcpy(&buffer[4], "\x40\x01\x31\x00\x0E", 5);
- midi->sysEx(buffer, 9);
- debug(2, "GS SysEx: Reverb Character is 0");
-
- // Change Reverb Pre-LF to 4, which is similar to
- // what MT-32 reverb does.
- memcpy(&buffer[4], "\x40\x01\x32\x04\x09", 5);
- midi->sysEx(buffer, 9);
- debug(2, "GS SysEx: Reverb Pre-LF is 4");
-
- // Change Reverb Time to 106; the decay on Hall 2
- // Reverb is too fast compared to the MT-32's
- memcpy(&buffer[4], "\x40\x01\x34\x6A\x21", 5);
- midi->sysEx(buffer, 9);
- debug(2, "GS SysEx: Reverb Time is 106");
- }
-}
-
-void IMuseInternal::initGM() {
- // These are the init messages from the DOTT General Midi
- // driver. This is the major part of the bug fix for bug
- // no. 13460 ("DOTT: Incorrect MIDI pitch bending").
- // SAMNMAX has some less of the default settings (since
- // the driver works a bit different), but it uses the same
- // value for the pitch bend range.
- MidiDriver *m = _midi_native;
- for (int i = 0; i < 16; ++i) {
- m->send(0x0064B0 | i);
- m->send(0x0065B0 | i);
- m->send(0x1006B0 | i);
- m->send(0x7F07B0 | i);
- m->send(0x3F0AB0 | i);
- m->send(0x0000C0 | i);
- m->send(0x4000E0 | i);
- m->send(0x0001B0 | i);
- m->send(0x0040B0 | i);
- m->send(0x405BB0 | i);
- m->send(0x005DB0 | i);
- m->send(0x0000B0 | i);
- m->send(0x007BB0 | i);
- }
-}
-
void IMuseInternal::init_queue() {
_queue_adding = false;
_queue_pos = 0;
diff --git a/engines/scumm/imuse/imuse_internal.h b/engines/scumm/imuse/imuse_internal.h
index c7d883b83c3..7539eb55423 100644
--- a/engines/scumm/imuse/imuse_internal.h
+++ b/engines/scumm/imuse/imuse_internal.h
@@ -367,6 +367,7 @@ struct Part : public Common::Serializable {
void set_pri(int8 pri);
void set_pan(int8 pan);
+ void set_sm17(int8 val);
void set_onoff(bool on);
void fix_after_load();
@@ -481,9 +482,6 @@ protected:
void handle_marker(uint id, byte data);
int get_channel_volume(uint a);
void initMidiDriver(TimerCallbackInfo *info);
- void initGS(MidiDriver *midi);
- void initMT32(MidiDriver *midi);
- void initGM();
void init_players();
void init_parts();
void init_queue();
diff --git a/engines/scumm/imuse/imuse_part.cpp b/engines/scumm/imuse/imuse_part.cpp
index 46e69f1c492..28f3e345e80 100644
--- a/engines/scumm/imuse/imuse_part.cpp
+++ b/engines/scumm/imuse/imuse_part.cpp
@@ -24,8 +24,8 @@
#include "common/debug.h"
#include "common/textconsole.h"
#include "common/util.h"
-#include "scumm/imuse/imuse_internal.h"
#include "scumm/scumm.h"
+#include "scumm/imuse/imuse_internal.h"
namespace Scumm {
@@ -146,6 +146,10 @@ void Part::set_pan(int8 pan) {
sendPanPosition(_pan_eff + 0x40);
}
+void Part::set_sm17(int8 val) {
+
+}
+
void Part::set_transpose(int8 transpose, int8 clipRangeLow, int8 clipRangeHi) {
if (_se->_game_id == GID_TENTACLE && (transpose > 24 || transpose < -24))
return;
diff --git a/engines/scumm/imuse/imuse_player.cpp b/engines/scumm/imuse/imuse_player.cpp
index 73a4c75dbbf..4837f960c76 100644
--- a/engines/scumm/imuse/imuse_player.cpp
+++ b/engines/scumm/imuse/imuse_player.cpp
@@ -223,7 +223,7 @@ int Player::start_seq_sound(int sound, bool reset_vars) {
}
void Player::loadStartParameters(int sound) {
- _priority = 0x80;
+ _priority = (_se->_game_id != GID_SAMNMAX) ? 0x80 : 0;
_volume = 0x7F;
_vol_chan = 0xFFFF;
_vol_eff = (_se->get_channel_volume(0xFFFF) << 7) >> 7;
@@ -319,10 +319,15 @@ void Player::send(uint32 b) {
part->pitchBendFactor(param2);
break;
case 17: // GP Slider 2
- part->set_detune(param2 - 0x40);
+ if (_se->_game_id == GID_SAMNMAX)
+ part->set_sm17(param2);
+ else
+ part->set_detune(param2 - 0x40);
break;
case 18: // GP Slider 3
- part->set_pri(param2 - 0x40);
+ if (_se->_game_id != GID_SAMNMAX)
+ param2 -= 0x40;
+ part->set_pri(param2);
_se->reallocateMidiChannels(_midi);
break;
case 64: // Sustain Pedal
@@ -401,9 +406,6 @@ void Player::sysEx(const byte *p, uint16 len) {
part->_instrument.send(part->_mc);
}
}
- } else if (a == YM2612_SYSEX_ID) {
- // FM-TOWNS custom instrument definition
- _midi->sysEx_customInstrument(p[0], 'EUP ', p + 1);
} else {
// SysEx manufacturer 0x97 has been spotted in the
// Monkey Island 2 AdLib music, so don't make this a
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index d8686d2c672..49f12e3e241 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -33,7 +33,9 @@ MODULE_OBJS := \
imuse/sysex_scumm.o \
imuse/drivers/amiga.o \
imuse/drivers/fmtowns.o \
+ imuse/drivers/gmidi.o \
imuse/drivers/mac_m68k.o \
+ imuse/drivers/mt32.o \
imuse/drivers/pcspk.o \
input.o \
ks_check.o \
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 2da35837065..3ddf5b5a295 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -81,6 +81,8 @@
#include "scumm/imuse/drivers/mac_m68k.h"
#include "scumm/imuse/drivers/amiga.h"
#include "scumm/imuse/drivers/fmtowns.h"
+#include "scumm/imuse/drivers/gmidi.h"
+#include "scumm/imuse/drivers/mt32.h"
#include "scumm/detection_steam.h"
#include "backends/audiocd/audiocd.h"
@@ -2044,10 +2046,16 @@ void ScummEngine::setupMusic(int midi, const Common::String &macInstrumentFile)
bool multi_midi = ConfMan.getBool("multi_midi") && _sound->_musicType != MDT_NONE && _sound->_musicType != MDT_PCSPK && (midi & MDT_ADLIB);
bool useOnlyNative = false;
+ uint32 imsFlags = 0;
+ if (_native_mt32)
+ imsFlags |= IMuse::kFlagNativeMT32;
+ if (enable_gs && MidiDriver::getMusicType(dev) != MT_MT32)
+ imsFlags |= IMuse::kFlagRolandGS;
+
if (isMacM68kIMuse()) {
// We setup this driver as native MIDI driver to avoid playback
// of the Mac music via a selected MIDI device.
- nativeMidiDriver = new MacM68kDriver(_mixer);
+ nativeMidiDriver = new IMuseDriver_MacM68k(_mixer);
// The Mac driver is never MT-32.
_native_mt32 = false;
// Ignore non-native drivers. This also ignores the multi MIDI setting.
@@ -2057,31 +2065,25 @@ void ScummEngine::setupMusic(int midi, const Common::String &macInstrumentFile)
_native_mt32 = enable_gs = false;
useOnlyNative = true;
} else if (_sound->_musicType != MDT_ADLIB && _sound->_musicType != MDT_TOWNS && _sound->_musicType != MDT_PCSPK) {
- nativeMidiDriver = MidiDriver::createMidi(dev);
+ if (_native_mt32)
+ nativeMidiDriver = new IMuseDriver_MT32(dev, _game.id == GID_SAMNMAX);
+ else
+ nativeMidiDriver = new IMuseDriver_GMidi(dev, imsFlags & IMuse::kFlagRolandGS, _game.id == GID_SAMNMAX);
}
- if (nativeMidiDriver != nullptr && _native_mt32)
- nativeMidiDriver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
-
if (!useOnlyNative) {
- if (_sound->_musicType == MDT_TOWNS) {
- adlibMidiDriver = new MidiDriver_TOWNS(_mixer);
- } else if (_sound->_musicType == MDT_ADLIB || multi_midi) {
- adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(_sound->_musicType == MDT_TOWNS ? MDT_TOWNS : MDT_ADLIB));
+ if (_sound->_musicType == MDT_ADLIB || multi_midi) {
+ adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(MDT_ADLIB));
adlibMidiDriver->property(MidiDriver::PROP_OLD_ADLIB, (_game.features & GF_SMALL_HEADER) ? 1 : 0);
// Try to use OPL3 mode for Sam&Max when possible.
adlibMidiDriver->property(MidiDriver::PROP_SCUMM_OPL3, (_game.id == GID_SAMNMAX) ? 1 : 0);
+ } else if (_sound->_musicType == MDT_TOWNS) {
+ adlibMidiDriver = new IMuseDriver_FMTowns(_mixer);
} else if (_sound->_musicType == MDT_PCSPK) {
- adlibMidiDriver = new PcSpkDriver(_mixer);
+ adlibMidiDriver = new IMuseDriver_PCSpk(_mixer);
}
}
- uint32 imsFlags = 0;
- if (_native_mt32)
- imsFlags |= IMuse::kFlagNativeMT32;
- if (enable_gs && MidiDriver::getMusicType(dev) != MT_MT32)
- imsFlags |= IMuse::kFlagRolandGS;
-
_imuse = IMuse::create(this, nativeMidiDriver, adlibMidiDriver, isMacM68kIMuse() ? MDT_MACINTOSH : _sound->_musicType, imsFlags);
if (_game.platform == Common::kPlatformFMTowns) {