aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--audio/module.mk3
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_midi.cpp239
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_midi.h70
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp87
-rw-r--r--audio/softsynth/ym2612.cpp790
-rw-r--r--audio/softsynth/ym2612.h176
-rw-r--r--base/plugins.cpp1
-rw-r--r--engines/scumm/player_towns.cpp13
-rw-r--r--engines/scumm/player_towns.h6
-rw-r--r--engines/scumm/scumm.cpp6
10 files changed, 414 insertions, 977 deletions
diff --git a/audio/module.mk b/audio/module.mk
index a9d9bfc869..840b6d6692 100644
--- a/audio/module.mk
+++ b/audio/module.mk
@@ -39,10 +39,11 @@ MODULE_OBJS := \
softsynth/opl/mame.o \
softsynth/fmtowns_pc98/towns_audio.o \
softsynth/fmtowns_pc98/towns_euphony.o \
+ softsynth/fmtowns_pc98/towns_midi.o \
softsynth/fmtowns_pc98/towns_pc98_driver.o \
softsynth/fmtowns_pc98/towns_pc98_fmsynth.o \
+ softsynth/fmtowns_pc98/towns_pc98_plugins.o \
softsynth/appleiigs.o \
- softsynth/ym2612.o \
softsynth/fluidsynth.o \
softsynth/mt32.o \
softsynth/eas.o \
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
new file mode 100644
index 0000000000..c223d44c11
--- /dev/null
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -0,0 +1,239 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL: $
+ * $Id: $
+ */
+
+#include "audio/softsynth/fmtowns_pc98/towns_midi.h"
+#include "common/textconsole.h"
+
+class MidiChannel_TOWNS : public MidiChannel {
+public:
+ MidiChannel_TOWNS(MidiDriver_TOWNS *driver);
+ ~MidiChannel_TOWNS();
+
+ MidiDriver *device() { return _driver; }
+ byte getNumber() { return 0; }
+ void release();
+
+ void send(uint32 b);
+
+ void noteOff(byte note);
+ void noteOn(byte note, byte velocity);
+ void programChange(byte program);
+ void pitchBend(int16 bend);
+ void controlChange(byte control, byte value);
+ void pitchBendFactor(byte value);
+ void priority(byte value);
+
+ void sysEx_customInstrument(uint32 type, const byte *instr);
+
+private:
+ MidiDriver_TOWNS *_driver;
+};
+
+MidiChannel_TOWNS::MidiChannel_TOWNS(MidiDriver_TOWNS *driver) : MidiChannel(), _driver(driver) {
+
+}
+
+MidiChannel_TOWNS::~MidiChannel_TOWNS() {
+
+}
+
+void MidiChannel_TOWNS::release() {
+
+}
+
+void MidiChannel_TOWNS::send(uint32 b) {
+
+}
+
+void MidiChannel_TOWNS::noteOff(byte note) {
+
+}
+
+void MidiChannel_TOWNS::noteOn(byte note, byte velocity) {
+
+}
+
+void MidiChannel_TOWNS::programChange(byte program) {
+
+}
+
+void MidiChannel_TOWNS::pitchBend(int16 bend) {
+
+}
+
+void MidiChannel_TOWNS::controlChange(byte control, byte value) {
+
+}
+
+void MidiChannel_TOWNS::pitchBendFactor(byte value) {
+
+}
+
+void MidiChannel_TOWNS::priority(byte value) {
+
+}
+
+void MidiChannel_TOWNS::sysEx_customInstrument(uint32 type, const byte *instr) {
+
+}
+
+MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerBproc(0), _timerBpara(0), _open(false) {
+ _intf = new TownsAudioInterface(mixer, this);
+ _channels = new MidiChannel_TOWNS*[16];
+ for (int i = 0; i < 16; i++)
+ _channels[i] = new MidiChannel_TOWNS(this);
+
+ _tickCounter = 0;
+ _curChan = 0;
+ //unbuffered write: _intf->callback(17, part, reg, val);
+ //buffered write: _intf->callback(19, part, reg, val);
+}
+
+MidiDriver_TOWNS::~MidiDriver_TOWNS() {
+ close();
+ delete _intf;
+ setTimerCallback(0, 0);
+
+ for (int i = 0; i < 16; i++)
+ delete _channels[i];
+ delete[] _channels;
+}
+
+int MidiDriver_TOWNS::open() {
+ if (_open)
+ return MERR_ALREADY_OPEN;
+
+ if (!_intf->init())
+ return MERR_CANNOT_CONNECT;
+
+ _intf->callback(0);
+
+ _intf->callback(21, 255, 1);
+ _intf->callback(21, 0, 1);
+ _intf->callback(22, 255, 221);
+
+ _intf->callback(33, 8);
+ _intf->setSoundEffectChanMask(~0x3f);
+
+ _open = true;
+
+ return 0;
+}
+
+void MidiDriver_TOWNS::close() {
+ _open = false;
+}
+
+void MidiDriver_TOWNS::send(uint32 b) {
+ byte param2 = (b >> 16) & 0xFF;
+ byte param1 = (b >> 8) & 0xFF;
+ byte cmd = b & 0xF0;
+
+ /*AdLibPart *part;
+ if (chan == 9)
+ part = &_percussion;
+ else**/
+ MidiChannel_TOWNS *c = _channels[b & 0x0F];
+
+ switch (cmd) {
+ case 0x80:
+ //part->noteOff(param1);
+ break;
+ case 0x90:
+ //part->noteOn(param1, param2);
+ if (param2)
+ c->noteOn(param1, param2);
+ else
+ c->noteOff(param1);
+ break;
+ case 0xB0:
+ // supported: 1, 7, 0x40
+ c->controlChange(param1, param2);
+ break;
+ case 0xC0:
+ c->programChange(param1);
+ break;
+ case 0xE0:
+ //part->pitchBend((param1 | (param2 << 7)) - 0x2000);
+ c->pitchBend((param1 | (param2 << 7)) - 0x2000);
+ break;
+ case 0xF0:
+ warning("MidiDriver_ADLIB: Receiving SysEx command on a send() call");
+ break;
+
+ default:
+ break;
+ }
+}
+
+void MidiDriver_TOWNS::setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
+ _timerBproc = timer_proc;
+ _timerBpara = timer_param;
+}
+
+uint32 MidiDriver_TOWNS::getBaseTempo() {
+ return 0;
+}
+
+MidiChannel *MidiDriver_TOWNS::allocateChannel() {
+ MidiChannel *res = 0;
+
+ for (int i = 0; i < 6; i++) {
+ if (++_curChan == 6)
+ _curChan = 0;
+
+ //if (_channels[i]-> //// )
+ // return _channels[i];
+
+ }
+
+ //if (res)
+ // res->noteOff();
+
+ return res;
+}
+
+MidiChannel *MidiDriver_TOWNS::getPercussionChannel() {
+ return 0;
+}
+
+void MidiDriver_TOWNS::timerCallback(int timerId) {
+ if (!_open)
+ return;
+
+ switch (timerId) {
+ case 1:
+ if (_timerBproc) {
+ _timerBproc(_timerBpara);
+ _tickCounter += 10000;
+ while (_tickCounter >= 4167) {
+ _tickCounter -= 4167;
+ //_timerBproc(_timerBpara);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h
new file mode 100644
index 0000000000..658c5a456b
--- /dev/null
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.h
@@ -0,0 +1,70 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL: $
+ * $Id: $
+ */
+
+#ifndef TOWNS_MIDI_H
+#define TOWNS_MIDI_H
+
+#include "audio/mididrv.h"
+#include "audio/softsynth/fmtowns_pc98/towns_audio.h"
+
+class MidiChannel_TOWNS;
+class MidiDriver_TOWNS : public MidiDriver, public TownsAudioInterfacePluginDriver {
+friend class MidiChannel_TOWNS;
+public:
+ MidiDriver_TOWNS(Audio::Mixer *mixer);
+ ~MidiDriver_TOWNS();
+
+ int open();
+ bool isOpen() const { return _open; }
+ void close();
+ void send(uint32 b);
+ //virtual uint32 property(int prop, uint32 param) { return 0; }
+ //virtual void sysEx(const byte *msg, uint16 length) { }
+ //virtual void sysEx_customInstrument(byte channel, uint32 type, const byte *instr) { }
+ //virtual void metaEvent(byte type, byte *data, uint16 length) { }
+ void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc);
+ uint32 getBaseTempo();
+ MidiChannel *allocateChannel();
+ MidiChannel *getPercussionChannel();
+
+ void timerCallback(int timerId);
+
+ TownsAudioInterface *intf() { return _intf; }
+
+private:
+ MidiChannel_TOWNS **_channels;
+
+ Common::TimerManager::TimerProc _timerBproc;
+ void *_timerBpara;
+
+ TownsAudioInterface *_intf;
+
+ uint32 _tickCounter;
+ uint8 _curChan;
+
+ bool _open;
+};
+
+#endif
+
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp
new file mode 100644
index 0000000000..bbde75eb66
--- /dev/null
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp
@@ -0,0 +1,87 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL: $
+ * $Id: $
+ */
+
+#include "audio/softsynth/fmtowns_pc98/towns_midi.h"
+#include "audio/musicplugin.h"
+#include "common/translation.h"
+#include "common/error.h"
+
+
+class TownsEmuMusicPlugin : public MusicPluginObject {
+public:
+ const char *getName() const {
+ return _s("FM-Towns Audio");
+ }
+
+ const char *getId() const {
+ return "towns";
+ }
+
+ MusicDevices getDevices() const;
+ Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
+};
+
+MusicDevices TownsEmuMusicPlugin::getDevices() const {
+ MusicDevices devices;
+ devices.push_back(MusicDevice(this, "", MT_TOWNS));
+ return devices;
+}
+
+Common::Error TownsEmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
+ *mididriver = new MidiDriver_TOWNS(g_system->getMixer());
+ return Common::kNoError;
+}
+
+class PC98EmuMusicPlugin : public MusicPluginObject {
+public:
+ const char *getName() const {
+ return _s("PC-98 Audio");
+ }
+
+ const char *getId() const {
+ return "pc98";
+ }
+
+ MusicDevices getDevices() const;
+ Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
+};
+
+MusicDevices PC98EmuMusicPlugin::getDevices() const {
+ MusicDevices devices;
+ devices.push_back(MusicDevice(this, "", MT_PC98));
+ return devices;
+}
+
+Common::Error PC98EmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
+ //*mididriver = /**/
+ return Common::kNoError;
+}
+
+//#if PLUGIN_ENABLED_DYNAMIC(TOWNS)
+ //REGISTER_PLUGIN_DYNAMIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin);
+ //REGISTER_PLUGIN_DYNAMIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin);
+//#else
+ REGISTER_PLUGIN_STATIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin);
+ REGISTER_PLUGIN_STATIC(PC98, PLUGIN_TYPE_MUSIC, PC98EmuMusicPlugin);
+//#endif
diff --git a/audio/softsynth/ym2612.cpp b/audio/softsynth/ym2612.cpp
deleted file mode 100644
index d966595ae4..0000000000
--- a/audio/softsynth/ym2612.cpp
+++ /dev/null
@@ -1,790 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <math.h>
-
-#include "audio/softsynth/ym2612.h"
-#include "common/util.h"
-#include "audio/musicplugin.h"
-#include "common/error.h"
-#include "common/system.h"
-#include "common/textconsole.h"
-#include "common/translation.h"
-#include "common/types.h"
-
-////////////////////////////////////////
-//
-// Miscellaneous
-//
-////////////////////////////////////////
-
-static int *sintbl = 0;
-static int *powtbl = 0;
-static int *frequencyTable = 0;
-static int *keycodeTable = 0;
-static int *keyscaleTable = 0;
-static int *attackOut = 0;
-
-
-////////////////////////////////////////
-//
-// Operator2612 implementation
-//
-////////////////////////////////////////
-
-Operator2612::Operator2612 (Voice2612 *owner) :
- _owner (owner),
- _state (_s_ready),
- _currentLevel ((int32)0x7f << 15),
- _phase (0),
- _lastOutput (0),
- _feedbackLevel (0),
- _detune (0),
- _multiple (1),
- _keyScale (0),
- _specifiedTotalLevel (127),
- _specifiedAttackRate (0),
- _specifiedDecayRate (0),
- _specifiedSustainRate (0),
- _specifiedReleaseRate (15) {
- velocity(0);
-}
-
-Operator2612::~Operator2612()
-{ }
-
-void Operator2612::velocity(int velo) {
- _velocity = velo;
- _totalLevel = ((int32)_specifiedTotalLevel << 15) +
- ((int32)(127-_velocity) << 13);
- _sustainLevel = ((int32)_specifiedSustainLevel << 17);
-}
-
-void Operator2612::feedbackLevel(int level) {
- _feedbackLevel = level;
-}
-
-void Operator2612::setInstrument(byte const *instrument) {
- _detune = (instrument[8] >> 4) & 7;
- _multiple = instrument[8] & 15;
- _specifiedTotalLevel = instrument[12] & 127;
- _keyScale = (instrument[16] >> 6) & 3;
- _specifiedAttackRate = instrument[16] & 31;
- _specifiedDecayRate = instrument[20] & 31;
- _specifiedSustainRate = instrument[24] & 31;
- _specifiedSustainLevel = (instrument[28] >> 4) & 15;
- _specifiedReleaseRate = instrument[28] & 15;
- _state = _s_ready;
- velocity(_velocity);
-}
-
-void Operator2612::keyOn() {
- _state = _s_attacking;
- _tickCount = 0;
- _phase = 0;
- _currentLevel = ((int32)0x7f << 15);
-}
-
-void Operator2612::keyOff() {
- if (_state != _s_ready)
- _state = _s_releasing;
-}
-
-void Operator2612::frequency(int freq) {
- double value; // Use for intermediate computations to avoid int64 arithmetic
- int r;
-
- _frequency = freq / _owner->_rate;
-
- r = _specifiedAttackRate;
- if (r != 0) {
- r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
- if (r >= 64)
- r = 63;
- }
-
- r = 63 - r;
- if (_specifiedTotalLevel >= 128)
- value = 0;
- else {
- value = powtbl[(r&3) << 7];
- value *= 1 << (r >> 2);
- value *= 41;
- value /= 1 << (15 + 5);
- value *= 127 - _specifiedTotalLevel;
- value /= 127;
- }
- _attackTime = (int32) value; // 1 ?? == (1 << 12)
- if (_attackTime > 0)
- _attackTime = (1 << (12+10)) / (_owner->_rate * _attackTime);
-
- r = _specifiedDecayRate;
- if (r != 0) {
- r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
- if (r >= 64)
- r = 63;
- }
- value = (double) powtbl[(r&3) << 7] * (0x10 << (r>>2)) / 31;
- _decayRate = (int32) value / _owner->_rate;
-
- r = _specifiedSustainRate;
- if (r != 0) {
- r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
- if (r >= 64)
- r = 63;
- }
- value = (double) powtbl[(r&3) << 7] * (0x10 << (r>>2)) / 31;
- _sustainRate = (int32) value / _owner->_rate;
-
- r = _specifiedReleaseRate;
- if (r != 0) {
- r = r * 2 + 1; // (Translated) I cannot know whether the timing is a good choice or not
- r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
- // KS
- if (r >= 64)
- r = 63;
- }
- value = (double) powtbl[(r&3) << 7] * (0x10 << (r>>2)) / 31;
- _releaseRate = (int32) value / _owner->_rate;
-}
-
-void Operator2612::nextTick(const int *phasebuf, int *outbuf, int buflen) {
- if (_state == _s_ready)
- return;
- if (_state == _s_attacking && _attackTime <= 0) {
- _currentLevel = 0;
- _state = _s_decaying;
- }
-
- int32 levelIncrement = 0;
- int32 target = 0;
- State next_state = _s_ready;
- const int32 zero_level = ((int32)0x7f << 15);
- const int phaseIncrement = (_multiple > 0) ? (_frequency * _multiple) : (_frequency / 2);
-
- int32 output = _lastOutput;
- int32 level = _currentLevel + _totalLevel;
-
- while (buflen) {
- switch (_state) {
- case _s_ready:
- return;
- case _s_attacking:
- next_state = _s_attacking;
- break;
- case _s_decaying:
- levelIncrement = _decayRate;
- target = _sustainLevel + _totalLevel;
- next_state = _s_sustaining;
- break;
- case _s_sustaining:
- levelIncrement = _sustainRate;
- target = zero_level + _totalLevel;
- next_state = _s_ready;
- break;
- case _s_releasing:
- levelIncrement = _releaseRate;
- target = zero_level + _totalLevel;
- next_state = _s_ready;
- break;
- }
-
- bool switching = false;
- do {
- if (next_state == _s_attacking) {
- // Attack phase
- ++_tickCount;
- int i = (int) (_tickCount * _attackTime);
- if (i >= 1024) {
- level = _totalLevel;
- _state = _s_decaying;
- switching = true;
- } else {
- level = (attackOut[i] << (31 - 8 - 16)) + _totalLevel;
- }
- } else {
- // Decay, Sustain and Release phases
- level += levelIncrement;
- if (level >= target) {
- level = target;
- _state = next_state;
- switching = true;
- }
- }
-
- if (level < zero_level) {
- int phaseShift = *phasebuf >> 2;
- if (_feedbackLevel)
- phaseShift += (output << (_feedbackLevel - 1)) / 1024;
- output = sintbl[((_phase >> 7) + phaseShift) & 0x7ff];
- output >>= (level >> 18);
- // Here is the original code, which requires 64-bit ints
-// output *= powtbl[511 - ((level>>25)&511)];
-// output >>= 16;
-// output >>= 1;
- // And here's our 32-bit trick for doing it. (Props to Fingolfin!)
- // Result varies from original code by max of 1.
-// int powVal = powtbl[511 - ((level>>9)&511)];
-// int outputHI = output / 256;
-// int powHI = powVal / 256;
-// output = (outputHI * powHI) / 2 + (outputHI * (powVal % 256) + powHI * (output % 256)) / 512;
- // And here's the even faster code.
- // Result varies from original code by max of 8.
- output = ((output >> 4) * (powtbl[511-((level>>9)&511)] >> 3)) / 1024;
-
- _phase += phaseIncrement;
- _phase &= 0x3ffff;
- } else
- output = 0;
-
- *outbuf += output;
- --buflen;
- ++phasebuf;
- ++outbuf;
- } while (buflen && !switching);
- }
- _lastOutput = output;
- _currentLevel = level - _totalLevel;
-}
-
-////////////////////////////////////////
-//
-// Voice2612 implementation
-//
-////////////////////////////////////////
-
-Voice2612::Voice2612() {
- next = 0;
- _control7 = 127;
- _note = 40;
- _frequency = 440;
- _frequencyOffs = 0x2000;
- _algorithm = 7;
-
- _buffer = 0;
- _buflen = 0;
-
- int i;
- for (i = 0; i < ARRAYSIZE(_opr); ++i)
- _opr[i] = new Operator2612 (this);
- velocity(0);
-}
-
-Voice2612::~Voice2612() {
- int i;
- for (i = 0; i < ARRAYSIZE(_opr); ++i)
- delete _opr[i];
- free(_buffer);
-}
-
-void Voice2612::velocity(int velo) {
- _velocity = velo;
-#if 0
- int v = (velo * _control7) >> 7;
-#else
- int v = velo + (_control7 - 127) * 4;
-#endif
- bool iscarrier[8][4] = {
- { false, false, false, true, }, //0
- { false, false, false, true, }, //1
- { false, false, false, true, }, //2
- { false, false, false, true, }, //3
- { false, true, false, true, }, //4
- { false, true, true, true, }, //5
- { false, true, true, true, }, //6
- { true, true, true, true, }, //7
- };
- int opr;
- for (opr = 0; opr < 4; opr++)
- if (iscarrier[_algorithm][opr])
- _opr[opr]->velocity(v);
- else
- _opr[opr]->velocity(127);
-}
-
-void Voice2612::setControlParameter(int control, int value) {
- switch (control) {
- case 7:
- _control7 = value;
- velocity(_velocity);
- break;
- case 123:
- // All notes off
- noteOff(_note);
- };
-}
-
-void Voice2612::setInstrument(byte const *instrument) {
- if (instrument == NULL)
- return;
-
- _algorithm = instrument[32] & 7;
- _opr[0]->feedbackLevel((instrument[32] >> 3) & 7);
- _opr[1]->feedbackLevel(0);
- _opr[2]->feedbackLevel(0);
- _opr[3]->feedbackLevel(0);
- _opr[0]->setInstrument(instrument + 0);
- _opr[1]->setInstrument(instrument + 2);
- _opr[2]->setInstrument(instrument + 1);
- _opr[3]->setInstrument(instrument + 3);
-}
-
-void Voice2612::nextTick(int *outbuf, int buflen) {
- if (_velocity == 0)
- return;
-
- if (_buflen < buflen) {
- free(_buffer);
- _buflen = buflen;
- _buffer = (int *) malloc(sizeof(int) * buflen * 2);
- }
-
- int *buf1 = _buffer;
- int *buf2 = _buffer + buflen;
- memset(_buffer, 0, sizeof(int) * buflen * 2);
-
- switch (_algorithm) {
- case 0:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf2, buf1, buflen);
- memset (buf2, 0, sizeof (int) * buflen);
- _opr[2]->nextTick(buf1, buf2, buflen);
- _opr[3]->nextTick(buf2, outbuf, buflen);
- break;
- case 1:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf1, buf2, buflen);
- _opr[2]->nextTick(buf2, buf1, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- case 2:
- _opr[1]->nextTick(buf1, buf2, buflen);
- _opr[2]->nextTick(buf2, buf1, buflen);
- memset(buf2, 0, sizeof(int) * buflen);
- _opr[0]->nextTick(buf2, buf1, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- case 3:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf2, buf1, buflen);
- memset(buf2, 0, sizeof(int) * buflen);
- _opr[2]->nextTick(buf2, buf1, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- case 4:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf2, outbuf, buflen);
- _opr[2]->nextTick(buf1, buf1, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- case 5:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf2, outbuf, buflen);
- _opr[2]->nextTick(buf2, outbuf, buflen);
- _opr[3]->nextTick(buf2, outbuf, buflen);
- break;
- case 6:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf2, outbuf, buflen);
- _opr[2]->nextTick(buf1, outbuf, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- case 7:
- _opr[0]->nextTick(buf1, outbuf, buflen);
- _opr[1]->nextTick(buf1, outbuf, buflen);
- _opr[2]->nextTick(buf1, outbuf, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- };
-}
-
-void Voice2612::noteOn(int n, int onVelo) {
- _note = n;
- velocity(onVelo);
- recalculateFrequency();
- int i;
- for (i = 0; i < ARRAYSIZE(_opr); i++)
- _opr[i]->keyOn();
-}
-
-bool Voice2612::noteOff(int note) {
- if (_note != note)
- return false;
- int i;
- for (i = 0; i < ARRAYSIZE(_opr); i++)
- _opr[i]->keyOff();
- return true;
-}
-
-void Voice2612::pitchBend(int value) {
- _frequencyOffs = value;
- recalculateFrequency();
-}
-
-void Voice2612::recalculateFrequency() {
- //
- //
- //
- int32 basefreq = frequencyTable[_note];
- int cfreq = frequencyTable[_note - (_note % 12)];
- int oct = _note / 12;
- int fnum = (int) (((double)basefreq * (1 << 13)) / cfreq);
- fnum += _frequencyOffs - 0x2000;
- if (fnum < 0x2000) {
- fnum += 0x2000;
- oct--;
- }
- if (fnum >= 0x4000) {
- fnum -= 0x2000;
- oct++;
- }
-
- //
- _frequency = (int) ((frequencyTable[oct*12] * (double)fnum) / 8);
-
- int i;
- for (i = 0; i < ARRAYSIZE(_opr); i++)
- _opr[i]->frequency(_frequency);
-}
-
-////////////////////////////////////////
-//
-// MidiChannel_YM2612
-//
-////////////////////////////////////////
-
-MidiChannel_YM2612::MidiChannel_YM2612() {
- _voices = 0;
- _next_voice = 0;
-}
-
-MidiChannel_YM2612::~MidiChannel_YM2612() {
- removeAllVoices();
-}
-
-void MidiChannel_YM2612::removeAllVoices() {
- if (!_voices)
- return;
- Voice2612 *last, *voice = _voices;
- for (; voice; voice = last) {
- last = voice->next;
- delete voice;
- }
- _voices = _next_voice = 0;
-}
-
-void MidiChannel_YM2612::noteOn(byte note, byte onVelo) {
- if (!_voices)
- return;
- _next_voice = _next_voice ? _next_voice : _voices;
- _next_voice->noteOn(note, onVelo);
- _next_voice = _next_voice->next;
-}
-
-void MidiChannel_YM2612::noteOff(byte note) {
- if (!_voices)
- return;
- if (_next_voice == _voices)
- _next_voice = 0;
- Voice2612 *voice = _next_voice;
- do {
- if (!voice)
- voice = _voices;
- if (voice->noteOff(note)) {
- _next_voice = voice;
- break;
- }
- voice = voice->next;
- } while (voice != _next_voice);
-}
-
-void MidiChannel_YM2612::controlChange(byte control, byte value) {
- //
- if (control == 121) {
- // Reset controller
- removeAllVoices();
- } else {
- Voice2612 *voice = _voices;
- for (; voice; voice = voice->next)
- voice->setControlParameter(control, value);
- }
-}
-
-void MidiChannel_YM2612::sysEx_customInstrument(uint32 type, const byte *fmInst) {
- if (type != 'EUP ')
- return;
- Voice2612 *voice = new Voice2612;
- voice->next = _voices;
- _voices = voice;
- voice->_rate = _rate;
- voice->setInstrument(fmInst);
-}
-
-void MidiChannel_YM2612::pitchBend(int16 value) {
- //
- Voice2612 *voice = _voices;
- for (; voice; voice = voice->next)
- voice->pitchBend(value);
-}
-
-void MidiChannel_YM2612::nextTick(int *outbuf, int buflen) {
- Voice2612 *voice = _voices;
- for (; voice; voice = voice->next)
- voice->nextTick(outbuf, buflen);
-}
-
-void MidiChannel_YM2612::rate(uint16 r) {
- _rate = r;
- Voice2612 *voice = _voices;
- for (; voice; voice = voice->next)
- voice->_rate = r;
-}
-
-////////////////////////////////////////
-//
-// MidiDriver_YM2612
-//
-////////////////////////////////////////
-
-MidiDriver_YM2612::MidiDriver_YM2612(Audio::Mixer *mixer)
- : MidiDriver_Emulated(mixer) {
- _next_voice = 0;
-
- createLookupTables();
- _volume = 256;
- int i;
- for (i = 0; i < ARRAYSIZE(_channel); i++)
- _channel[i] = new MidiChannel_YM2612;
- rate(getRate());
-}
-
-MidiDriver_YM2612::~MidiDriver_YM2612() {
- int i;
- for (i = 0; i < ARRAYSIZE(_channel); i++)
- delete _channel[i];
- removeLookupTables();
-}
-
-int MidiDriver_YM2612::open() {
- if (_isOpen)
- return MERR_ALREADY_OPEN;
-
- MidiDriver_Emulated::open();
-
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
- return 0;
-}
-
-void MidiDriver_YM2612::close() {
- if (!_isOpen)
- return;
- _isOpen = false;
-
- _mixer->stopHandle(_mixerSoundHandle);
-}
-
-void MidiDriver_YM2612::send(uint32 b) {
- send(b & 0xF, b & 0xFFFFFFF0);
-}
-
-void MidiDriver_YM2612::send(byte chan, uint32 b) {
- //byte param3 = (byte) ((b >> 24) & 0xFF);
- byte param2 = (byte) ((b >> 16) & 0xFF);
- byte param1 = (byte) ((b >> 8) & 0xFF);
- byte cmd = (byte) (b & 0xF0);
- if (chan > ARRAYSIZE(_channel))
- return;
-
- switch (cmd) {
- case 0x80:// Note Off
- _channel[chan]->noteOff(param1);
- break;
- case 0x90: // Note On
- _channel[chan]->noteOn(param1, param2);
- break;
- case 0xA0: // Aftertouch
- break; // Not supported.
- case 0xB0: // Control Change
- _channel[chan]->controlChange(param1, param2);
- break;
- case 0xC0: // Program Change
- _channel[chan]->programChange(param1);
- break;
- case 0xD0: // Channel Pressure
- break; // Not supported.
- case 0xE0: // Pitch Bend
- _channel[chan]->pitchBend((param1 | (param2 << 7)) - 0x2000);
- break;
- case 0xF0: // SysEx
- // We should never get here! SysEx information has to be
- // sent via high-level semantic methods.
- warning("MidiDriver_YM2612: Receiving SysEx command on a send() call");
- break;
-
- default:
- warning("MidiDriver_YM2612: Unknown send() command 0x%02X", cmd);
- }
-}
-
-void MidiDriver_YM2612::sysEx(const byte *msg, uint16 length) {
- if (msg[0] != 0x7C || msg[1] >= ARRAYSIZE(_channel))
- return;
- _channel[msg[1]]->sysEx_customInstrument('EUP ', &msg[2]);
-}
-
-void MidiDriver_YM2612::generateSamples(int16 *data, int len) {
- memset(data, 0, 2 * sizeof(int16) * len);
- nextTick(data, len);
-}
-
-void MidiDriver_YM2612::nextTick(int16 *buf1, int buflen) {
- int *buf0 = (int *)buf1;
-
- int i;
- for (i = 0; i < ARRAYSIZE(_channel); i++)
- _channel[i]->nextTick(buf0, buflen);
-
- for (i = 0; i < buflen; ++i)
- buf1[i*2+1] = buf1[i*2] = ((buf0[i] * volume()) >> 10) & 0xffff;
-}
-
-void MidiDriver_YM2612::rate(uint16 r)
-{
- int i;
- for (i = 0; i < ARRAYSIZE(_channel); i++)
- _channel[i]->rate(r);
-}
-
-void MidiDriver_YM2612::createLookupTables() {
- {
- int i;
- sintbl = new int [2048];
- for (i = 0; i < 2048; i++)
- sintbl[i] = (int)(0xffff * sin(i/2048.0 * 2.0 * M_PI));
- }
-
- {
- int i;
- powtbl = new int [1025];
- for (i = 0; i <= 1024; i++)
- powtbl[i] = (int)(0x10000 * pow(2.0, (i - 512) / 512.0));
- }
-
- {
- int i;
- int block;
-
- static int fnum[] = {
- 0x026a, 0x028f, 0x02b6, 0x02df,
- 0x030b, 0x0339, 0x036a, 0x039e,
- 0x03d5, 0x0410, 0x044e, 0x048f,
- };
-
- // (int)(880.0 * 256.0 * pow(2.0, (note-0x51)/12.0))
- //
- frequencyTable = new int [120];
- for (block = -1; block < 9; block++) {
- for (i = 0; i < 12; i++) {
- double freq = fnum[i] * (166400.0 / 3) * pow(2.0, block-21);
- frequencyTable[(block+1)*12+i] = (int)(256.0 * freq);
- }
- }
-
- keycodeTable = new int [120];
- // detune
- for (block = -1; block < 9; block++) {
- for (i = 0; i < 12; i++) {
- // see p.204
- int f8 = (fnum[i] >> 7) & 1;
- int f9 = (fnum[i] >> 8) & 1;
- int f10 = (fnum[i] >> 9) & 1;
- int f11 = (fnum[i] >> 10) & 1;
- int n4 = f11;
- int n3 = (f11&(f10|f9|f8)) | (~f11&f10&f9&f8);
- int note = n4*2 + n3;
- // see p.207
- keycodeTable[(block+1)*12+i] = block*4 + note;
- }
- }
- }
-
- {
- int freq;
- keyscaleTable = new int [8192];
- keyscaleTable[0] = 0;
- for (freq = 1; freq < 8192; freq++) {
- keyscaleTable[freq] = (int)(log((double)freq) / 9.03 * 32.0) - 1;
- // 8368[Hz] (o9c)
- }
- }
-
- {
- int i;
- attackOut = new int [1024];
- for (i = 0; i < 1024; i++)
- attackOut[i] = (int)(((0x7fff+0x03a5)*30.0) / (30.0+i)) - 0x03a5;
- }
-}
-
-void MidiDriver_YM2612::removeLookupTables() {
- delete[] sintbl;
- delete[] powtbl;
- delete[] frequencyTable;
- delete[] keycodeTable;
- delete[] keyscaleTable;
- delete[] attackOut;
- sintbl = powtbl = frequencyTable = keycodeTable = keyscaleTable = attackOut = 0;
-}
-
-
-// Plugin interface
-
-class TownsEmuMusicPlugin : public MusicPluginObject {
-public:
- const char *getName() const {
- return _s("FM Towns Emulator");
- }
-
- const char *getId() const {
- return "towns";
- }
-
- MusicDevices getDevices() const;
- Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
-};
-
-MusicDevices TownsEmuMusicPlugin::getDevices() const {
- MusicDevices devices;
- devices.push_back(MusicDevice(this, "", MT_TOWNS));
- return devices;
-}
-
-Common::Error TownsEmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
- *mididriver = new MidiDriver_YM2612(g_system->getMixer());
-
- return Common::kNoError;
-}
-
-//#if PLUGIN_ENABLED_DYNAMIC(TOWNS)
- //REGISTER_PLUGIN_DYNAMIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin);
-//#else
- REGISTER_PLUGIN_STATIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin);
-//#endif
diff --git a/audio/softsynth/ym2612.h b/audio/softsynth/ym2612.h
deleted file mode 100644
index de91fc98e9..0000000000
--- a/audio/softsynth/ym2612.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef SOUND_SOFTSYNTH_Y2612_H
-#define SOUND_SOFTSYNTH_Y2612_H
-
-#include "common/scummsys.h"
-
-#include "audio/softsynth/emumidi.h"
-
-////////////////////////////////////////
-//
-// Class declarations
-//
-////////////////////////////////////////
-
-class Voice2612;
-class Operator2612 {
-protected:
- Voice2612 *_owner;
- enum State { _s_ready, _s_attacking, _s_decaying, _s_sustaining, _s_releasing };
- State _state;
- int32 _currentLevel;
- int _frequency;
- uint32 _phase;
- int _lastOutput;
- int _feedbackLevel;
- int _detune;
- int _multiple;
- int32 _totalLevel;
- int _keyScale;
- int _velocity;
- int _specifiedTotalLevel;
- int _specifiedAttackRate;
- int _specifiedDecayRate;
- int _specifiedSustainLevel;
- int _specifiedSustainRate;
- int _specifiedReleaseRate;
- int _tickCount;
- int _attackTime;
- int32 _decayRate;
- int32 _sustainLevel;
- int32 _sustainRate;
- int32 _releaseRate;
-
-public:
- Operator2612 (Voice2612 *owner);
- ~Operator2612();
- void feedbackLevel(int level);
- void setInstrument(byte const *instrument);
- void velocity(int velo);
- void keyOn();
- void keyOff();
- void frequency(int freq);
- void nextTick(const int *phaseShift, int *outbuf, int buflen);
- bool inUse() { return (_state != _s_ready); }
-};
-
-class Voice2612 {
-public:
- Voice2612 *next;
- uint16 _rate;
-
-protected:
- Operator2612 *_opr[4];
- int _velocity;
- int _control7;
- int _note;
- int _frequencyOffs;
- int _frequency;
- int _algorithm;
-
- int *_buffer;
- int _buflen;
-
-public:
- Voice2612();
- ~Voice2612();
- void setControlParameter(int control, int value);
- void setInstrument(byte const *instrument);
- void velocity(int velo);
- void nextTick(int *outbuf, int buflen);
- void noteOn(int n, int onVelo);
- bool noteOff(int note);
- void pitchBend(int value);
- void recalculateFrequency();
-};
-
-class MidiChannel_YM2612 : public MidiChannel {
-protected:
- uint16 _rate;
- Voice2612 *_voices;
- Voice2612 *_next_voice;
-
-public:
- void removeAllVoices();
- void nextTick(int *outbuf, int buflen);
- void rate(uint16 r);
-
-public:
- MidiChannel_YM2612();
- virtual ~MidiChannel_YM2612();
-
- // MidiChannel interface
- MidiDriver *device() { return 0; }
- byte getNumber() { return 0; }
- void release() { }
- void send(uint32 b) { }
- void noteOff(byte note);
- void noteOn(byte note, byte onVelo);
- void programChange(byte program) { }
- void pitchBend(int16 value);
- void controlChange(byte control, byte value);
- void pitchBendFactor(byte value) { }
- void sysEx_customInstrument(uint32 type, const byte *instr);
-};
-
-class MidiDriver_YM2612 : public MidiDriver_Emulated {
-protected:
- MidiChannel_YM2612 *_channel[16];
-
- int _next_voice;
- int _volume;
-
-protected:
- void nextTick(int16 *buf1, int buflen);
- int volume(int val = -1) { if (val >= 0) _volume = val; return _volume; }
- void rate(uint16 r);
-
- void generateSamples(int16 *buf, int len);
-
-public:
- MidiDriver_YM2612(Audio::Mixer *mixer);
- virtual ~MidiDriver_YM2612();
-
- static void createLookupTables();
- static void removeLookupTables();
-
- int open();
- void close();
- void send(uint32 b);
- void send(byte channel, uint32 b); // Supports higher than channel 15
- uint32 property(int prop, uint32 param) { return 0; }
-
- void setPitchBendRange(byte channel, uint range) { }
- void sysEx(const byte *msg, uint16 length);
-
- MidiChannel *allocateChannel() { return 0; }
- MidiChannel *getPercussionChannel() { return 0; }
-
-
- // AudioStream API
- bool isStereo() const { return true; }
- int getRate() const { return _mixer->getOutputRate(); }
-};
-
-#endif
-
diff --git a/base/plugins.cpp b/base/plugins.cpp
index 56bb1e63e5..4a3b201714 100644
--- a/base/plugins.cpp
+++ b/base/plugins.cpp
@@ -225,6 +225,7 @@ public:
LINK_PLUGIN(AMIGA)
LINK_PLUGIN(APPLEIIGS)
LINK_PLUGIN(TOWNS)
+ LINK_PLUGIN(PC98)
#if defined(USE_TIMIDITY)
LINK_PLUGIN(TIMIDITY)
#endif
diff --git a/engines/scumm/player_towns.cpp b/engines/scumm/player_towns.cpp
index 8927e8dcf8..2301b2a9b0 100644
--- a/engines/scumm/player_towns.cpp
+++ b/engines/scumm/player_towns.cpp
@@ -26,10 +26,8 @@
namespace Scumm {
-Player_Towns::Player_Towns(ScummEngine *vm, bool isVersion2) : _vm(vm), _v2(isVersion2), _numSoundMax(isVersion2 ? 256 : 200) {
+Player_Towns::Player_Towns(ScummEngine *vm, bool isVersion2) : _vm(vm), _v2(isVersion2), _intf(0), _numSoundMax(isVersion2 ? 256 : 200), _unkFlags(0x33) {
memset(_pcmCurrentSound, 0, sizeof(_pcmCurrentSound));
- _unkFlags = 0x33;
- _intf = 0;
}
void Player_Towns::setSfxVolume(int vol) {
@@ -576,15 +574,16 @@ void Player_Towns_v1::playCdaTrack(int sound, const uint8 *data, bool skipTrackV
_cdaCurrentSound = sound;
}
-Player_Towns_v2::Player_Towns_v2(ScummEngine *vm, IMuse *imuse, Audio::Mixer *mixer, bool disposeIMuse) : Player_Towns(vm, true), _imuse(imuse), _imuseDispose(disposeIMuse) {
+Player_Towns_v2::Player_Towns_v2(ScummEngine *vm, IMuse *imuse, Audio::Mixer *mixer, MidiDriver_TOWNS *driver, bool disposeIMuse, bool disposeDriver) : Player_Towns(vm, true), _imuse(imuse), _driver(driver), _imuseDispose(disposeIMuse), _driverDispose(disposeDriver), _sblData(0) {
_soundOverride = new SoundOvrParameters[_numSoundMax];
memset(_soundOverride, 0, _numSoundMax * sizeof(SoundOvrParameters));
- _sblData = 0;
- _intf = new TownsAudioInterface(mixer, 0);
+ if (_driver)
+ _intf = _driver->intf();
}
Player_Towns_v2::~Player_Towns_v2() {
- delete _intf;
+ if (_driverDispose)
+ delete _driver;
if (_imuseDispose)
delete _imuse;
diff --git a/engines/scumm/player_towns.h b/engines/scumm/player_towns.h
index aa4a1bb87d..900ea593bb 100644
--- a/engines/scumm/player_towns.h
+++ b/engines/scumm/player_towns.h
@@ -26,6 +26,7 @@
#include "scumm/scumm.h"
#include "scumm/imuse/imuse.h"
#include "audio/softsynth/fmtowns_pc98/towns_euphony.h"
+#include "audio/softsynth/fmtowns_pc98/towns_midi.h"
namespace Scumm {
@@ -141,7 +142,7 @@ private:
class Player_Towns_v2 : public Player_Towns {
public:
- Player_Towns_v2(ScummEngine *vm, IMuse *imuse, Audio::Mixer *mixer, bool disposeIMuse);
+ Player_Towns_v2(ScummEngine *vm, IMuse *imuse, Audio::Mixer *mixer, MidiDriver_TOWNS *driver, bool disposeIMuse, bool disposeDriver);
~Player_Towns_v2();
bool init();
@@ -170,7 +171,10 @@ private:
uint8 *_sblData;
IMuse *_imuse;
+ MidiDriver_TOWNS *_driver;
+
const bool _imuseDispose;
+ const bool _driverDispose;
};
} // End of namespace Scumm
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 1b7f16bdca..ff51158a4c 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1833,7 +1833,7 @@ void ScummEngine::setupMusic(int midi) {
if (nativeMidiDriver != NULL && _native_mt32)
nativeMidiDriver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
bool multi_midi = ConfMan.getBool("multi_midi") && _musicType != MDT_NONE && (midi & MDT_ADLIB);
- if (_musicType == MDT_ADLIB || multi_midi) {
+ if (_musicType == MDT_ADLIB || (multi_midi && _musicType != MDT_TOWNS)) {
adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(MDT_ADLIB));
adlibMidiDriver->property(MidiDriver::PROP_OLD_ADLIB, (_game.features & GF_SMALL_HEADER) ? 1 : 0);
}
@@ -1841,7 +1841,9 @@ void ScummEngine::setupMusic(int midi) {
_imuse = IMuse::create(_system, nativeMidiDriver, adlibMidiDriver);
if (_game.platform == Common::kPlatformFMTowns) {
- _musicEngine = _townsPlayer = new Player_Towns_v2(this, _imuse, _mixer, true);
+ MidiDriver *townsDriver = 0;
+ townsDriver = (_musicType == MDT_TOWNS) ? nativeMidiDriver : MidiDriver::createMidi(MidiDriver::detectDevice(MDT_TOWNS));
+ _musicEngine = _townsPlayer = new Player_Towns_v2(this, _imuse, _mixer, (MidiDriver_TOWNS*)townsDriver, true, (_musicType != MDT_TOWNS));
if (!_townsPlayer->init())
error("Failed to initialize FM-Towns audio driver");
} else {