From 100dd52a8efcb8e2871924c8837dd0747a440eb0 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Tue, 2 Jun 2015 17:36:22 +0200 Subject: SHERLOCK: rename MT32 driver, fix SysExPos --- engines/sherlock/scalpel/drivers/midi.cpp | 289 ------------------------- engines/sherlock/scalpel/drivers/mididriver.h | 6 +- engines/sherlock/scalpel/drivers/mt32.cpp | 290 ++++++++++++++++++++++++++ 3 files changed, 293 insertions(+), 292 deletions(-) delete mode 100644 engines/sherlock/scalpel/drivers/midi.cpp create mode 100644 engines/sherlock/scalpel/drivers/mt32.cpp (limited to 'engines/sherlock/scalpel/drivers') diff --git a/engines/sherlock/scalpel/drivers/midi.cpp b/engines/sherlock/scalpel/drivers/midi.cpp deleted file mode 100644 index fce30afb90..0000000000 --- a/engines/sherlock/scalpel/drivers/midi.cpp +++ /dev/null @@ -1,289 +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 "sherlock/sherlock.h" -#include "sherlock/scalpel/drivers/mididriver.h" - -#include "common/config-manager.h" -#include "common/file.h" -#include "common/system.h" -#include "common/textconsole.h" - -//#include "audio/mididrv.h" - -namespace Sherlock { - -#define SHERLOCK_MT32_CHANNEL_COUNT 16 - -const byte mt32_reverbDataSysEx[] = { - 0x10, 0x00, 0x01, 0x01, 0x05, 0x05, 0xFF -}; - -class MidiDriver_MIDI : public MidiDriver { -public: - MidiDriver_MIDI() { - _driver = NULL; - _isOpen = false; - _MT32 = false; - _nativeMT32 = false; - _baseFreq = 250; - - memset(_MIDIchannelActive, 1, sizeof(_MIDIchannelActive)); - } - virtual ~MidiDriver_MIDI(); - - // MidiDriver - int open(); - void close(); - bool isOpen() const { return _isOpen; } - - void send(uint32 b); - - void newMusicData(byte *musicData, int32 musicDataSize); - - MidiChannel *allocateChannel() { - if (_driver) - return _driver->allocateChannel(); - return NULL; - } - MidiChannel *getPercussionChannel() { - if (_driver) - return _driver->getPercussionChannel(); - return NULL; - } - - void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) { - if (_driver) - _driver->setTimerCallback(timer_param, timer_proc); - } - - uint32 getBaseTempo() { - if (_driver) { - return _driver->getBaseTempo(); - } - return 1000000 / _baseFreq; - } - -private: - Common::TimerManager::TimerProc _timerProc; - void *_timerParam; - -protected: - Common::Mutex _mutex; - MidiDriver *_driver; - bool _MT32; - bool _nativeMT32; - - bool _isOpen; - int _baseFreq; - -private: - // points to a MIDI channel for each of the new voice channels - byte _MIDIchannelActive[SHERLOCK_MT32_CHANNEL_COUNT]; - -public: - void uploadMT32Patches(byte *driverData, int32 driverSize); - - void MT32SysEx(const byte *&dataPtr, int32 &bytesLeft); -}; - -MidiDriver_MIDI::~MidiDriver_MIDI() { - Common::StackLock lock(_mutex); - if (_driver) { - _driver->setTimerCallback(0, 0); - _driver->close(); - delete _driver; - } - _driver = NULL; -} - -int MidiDriver_MIDI::open() { - assert(!_driver); - - debugC(kDebugLevelMT32Driver, "MT32: starting driver"); - - // Setup midi driver - MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_PREFER_MT32); - MusicType musicType = MidiDriver::getMusicType(dev); - - switch (musicType) { - case MT_MT32: - _MT32 = true; - _nativeMT32 = false; - break; - case MT_GM: - if (ConfMan.getBool("native_mt32")) { - _MT32 = true; - _nativeMT32 = true; - } - break; - default: - break; - } - - _driver = MidiDriver::createMidi(dev); - if (!_driver) - return 255; - - if (_nativeMT32) - _driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); - - int ret = _driver->open(); - if (ret) - return ret; - - if (_MT32) - _driver->sendMT32Reset(); - else - _driver->sendGMReset(); - - return 0; -} - -void MidiDriver_MIDI::close() { - if (_driver) { - _driver->close(); - } -} - -// Called when a music track got loaded into memory -void MidiDriver_MIDI::newMusicData(byte *musicData, int32 musicDataSize) { - assert(musicDataSize >= 0x7F); // Security check - - // MIDI Channel Enable/Disable bytes at offset 0x2 of music data - memcpy(&_MIDIchannelActive, musicData + 0x2, SHERLOCK_MT32_CHANNEL_COUNT); - - // Send 16 bytes from offset 0x12 to MT32 - // All the music tracks of Sherlock seem to contain dummy data - // probably a feature, that was used in the game "Ski or Die" - // that's why we don't implement this - - // Also send these bytes to MT32 (SysEx) - seems to be reverb configuration - if (_MT32) { - const byte *reverbData = mt32_reverbDataSysEx; - int32 reverbDataSize = sizeof(mt32_reverbDataSysEx); - MT32SysEx(reverbData, reverbDataSize); - } -} - -void MidiDriver_MIDI::uploadMT32Patches(byte *driverData, int32 driverSize) { - if (!_driver) - return; - - if (!_MT32) - return; - - // patch data starts at offset 0x863 - assert(driverSize == 0x13B9); // Security check - assert(driverData[0x863] == 0x7F); // another security check - - const byte *patchPtr = driverData + 0x863; - int32 bytesLeft = driverSize - 0x863; - - while(1) { - MT32SysEx(patchPtr, bytesLeft); - - assert(bytesLeft); - if (*patchPtr == 0x80) // List terminator - break; - } -} - -void MidiDriver_MIDI::MT32SysEx(const byte *&dataPtr, int32 &bytesLeft) { - byte sysExMessage[270]; - byte sysExPos = 0; - byte sysExByte = 0; - uint16 sysExChecksum = 0; - - memset(&sysExMessage, 0, sizeof(sysExMessage)); - - sysExMessage[0] = 0x41; // Roland - sysExMessage[1] = 0x10; - sysExMessage[2] = 0x16; // Model MT32 - sysExMessage[3] = 0x12; // Command DT1 - - sysExPos = 4; - sysExChecksum = 0; - while (1) { - assert(bytesLeft); - - sysExByte = *dataPtr++; - bytesLeft--; - if (sysExByte == 0xff) - break; // Message done - - assert(sysExPos < 260); - sysExMessage[sysExPos++] = sysExByte; - sysExChecksum -= sysExByte; - } - - // Calculate checksum - sysExMessage[sysExPos++] = sysExChecksum & 0x7f; - - debugC(kDebugLevelMT32Driver, "MT32: uploading patch data, size %d", sysExPos); - - // Send SysEx - _driver->sysEx(sysExMessage, sysExPos); - - // Wait the time it takes to send the SysEx data - uint32 delay = (sysExPos + 2) * 1000 / 3125; - - // Plus an additional delay for the MT-32 rev00 - if (_nativeMT32) - delay += 40; - - g_system->delayMillis(delay); -} - -// MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php -void MidiDriver_MIDI::send(uint32 b) { - byte command = b & 0xf0; - byte channel = b & 0xf; - - if (command == 0xF0) { - if (_driver) { - _driver->send(b); - } - return; - } - - if (_MIDIchannelActive[channel]) { - // Only forward MIDI-data in case the channel is currently enabled via music-data - if (_driver) { - _driver->send(b); - } - } -} - -MidiDriver *MidiDriver_MIDI_create() { - return new MidiDriver_MIDI(); -} - -void MidiDriver_MIDI_newMusicData(MidiDriver *driver, byte *musicData, int32 musicDataSize) { - static_cast(driver)->newMusicData(musicData, musicDataSize); -} - -void MidiDriver_MIDI_uploadMT32Patches(MidiDriver *driver, byte *driverData, int32 driverSize) { - static_cast(driver)->uploadMT32Patches(driverData, driverSize); -} - -} // End of namespace Sci diff --git a/engines/sherlock/scalpel/drivers/mididriver.h b/engines/sherlock/scalpel/drivers/mididriver.h index e38f27dc4e..2d989f298a 100644 --- a/engines/sherlock/scalpel/drivers/mididriver.h +++ b/engines/sherlock/scalpel/drivers/mididriver.h @@ -32,9 +32,9 @@ namespace Sherlock { extern MidiDriver *MidiDriver_AdLib_create(); extern void MidiDriver_AdLib_newMusicData(MidiDriver *driver, byte *musicData, int32 musicDataSize); -extern MidiDriver *MidiDriver_MIDI_create(); -extern void MidiDriver_MIDI_uploadMT32Patches(MidiDriver *driver, byte *driverData, int32 driverSize); -extern void MidiDriver_MIDI_newMusicData(MidiDriver *driver, byte *musicData, int32 musicDataSize); +extern MidiDriver *MidiDriver_MT32_create(); +extern void MidiDriver_MT32_uploadPatches(MidiDriver *driver, byte *driverData, int32 driverSize); +extern void MidiDriver_MT32_newMusicData(MidiDriver *driver, byte *musicData, int32 musicDataSize); } // End of namespace Sci diff --git a/engines/sherlock/scalpel/drivers/mt32.cpp b/engines/sherlock/scalpel/drivers/mt32.cpp new file mode 100644 index 0000000000..13e2845fa3 --- /dev/null +++ b/engines/sherlock/scalpel/drivers/mt32.cpp @@ -0,0 +1,290 @@ +/* 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 "sherlock/sherlock.h" +#include "sherlock/scalpel/drivers/mididriver.h" + +#include "common/config-manager.h" +#include "common/file.h" +#include "common/system.h" +#include "common/textconsole.h" + +//#include "audio/mididrv.h" + +namespace Sherlock { + +#define SHERLOCK_MT32_CHANNEL_COUNT 16 + +const byte mt32_reverbDataSysEx[] = { + 0x10, 0x00, 0x01, 0x01, 0x05, 0x05, 0xFF +}; + +class MidiDriver_MT32 : public MidiDriver { +public: + MidiDriver_MT32() { + _driver = NULL; + _isOpen = false; + _MT32 = false; + _nativeMT32 = false; + _baseFreq = 250; + + memset(_MIDIchannelActive, 1, sizeof(_MIDIchannelActive)); + } + virtual ~MidiDriver_MT32(); + + // MidiDriver + int open(); + void close(); + bool isOpen() const { return _isOpen; } + + void send(uint32 b); + + void newMusicData(byte *musicData, int32 musicDataSize); + + MidiChannel *allocateChannel() { + if (_driver) + return _driver->allocateChannel(); + return NULL; + } + MidiChannel *getPercussionChannel() { + if (_driver) + return _driver->getPercussionChannel(); + return NULL; + } + + void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) { + if (_driver) + _driver->setTimerCallback(timer_param, timer_proc); + } + + uint32 getBaseTempo() { + if (_driver) { + return _driver->getBaseTempo(); + } + return 1000000 / _baseFreq; + } + +private: + Common::TimerManager::TimerProc _timerProc; + void *_timerParam; + +protected: + Common::Mutex _mutex; + MidiDriver *_driver; + bool _MT32; + bool _nativeMT32; + + bool _isOpen; + int _baseFreq; + +private: + // points to a MIDI channel for each of the new voice channels + byte _MIDIchannelActive[SHERLOCK_MT32_CHANNEL_COUNT]; + +public: + void uploadMT32Patches(byte *driverData, int32 driverSize); + + void MT32SysEx(const byte *&dataPtr, int32 &bytesLeft); +}; + +MidiDriver_MT32::~MidiDriver_MT32() { + Common::StackLock lock(_mutex); + if (_driver) { + _driver->setTimerCallback(0, 0); + _driver->close(); + delete _driver; + } + _driver = NULL; +} + +int MidiDriver_MT32::open() { + assert(!_driver); + + debugC(kDebugLevelMT32Driver, "MT32: starting driver"); + + // Setup midi driver + MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_PREFER_MT32); + MusicType musicType = MidiDriver::getMusicType(dev); + + switch (musicType) { + case MT_MT32: + _MT32 = true; + _nativeMT32 = false; + break; + case MT_GM: + if (ConfMan.getBool("native_mt32")) { + _MT32 = true; + _nativeMT32 = true; + } + break; + default: + break; + } + + _driver = MidiDriver::createMidi(dev); + if (!_driver) + return 255; + + if (_nativeMT32) + _driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); + + int ret = _driver->open(); + if (ret) + return ret; + + if (_MT32) + _driver->sendMT32Reset(); + else + _driver->sendGMReset(); + + return 0; +} + +void MidiDriver_MT32::close() { + if (_driver) { + _driver->close(); + } +} + +// Called when a music track got loaded into memory +void MidiDriver_MT32::newMusicData(byte *musicData, int32 musicDataSize) { + assert(musicDataSize >= 0x7F); // Security check + + // MIDI Channel Enable/Disable bytes at offset 0x2 of music data + memcpy(&_MIDIchannelActive, musicData + 0x2, SHERLOCK_MT32_CHANNEL_COUNT); + + // Send 16 bytes from offset 0x12 to MT32 + // All the music tracks of Sherlock seem to contain dummy data + // probably a feature, that was used in the game "Ski or Die" + // that's why we don't implement this + + // Also send these bytes to MT32 (SysEx) - seems to be reverb configuration + if (_MT32) { + const byte *reverbData = mt32_reverbDataSysEx; + int32 reverbDataSize = sizeof(mt32_reverbDataSysEx); + MT32SysEx(reverbData, reverbDataSize); + } +} + +void MidiDriver_MT32::uploadMT32Patches(byte *driverData, int32 driverSize) { + if (!_driver) + return; + + if (!_MT32) + return; + + // patch data starts at offset 0x863 + assert(driverSize == 0x13B9); // Security check + assert(driverData[0x863] == 0x7F); // another security check + + const byte *patchPtr = driverData + 0x863; + int32 bytesLeft = driverSize - 0x863; + + while(1) { + MT32SysEx(patchPtr, bytesLeft); + + assert(bytesLeft); + if (*patchPtr == 0x80) // List terminator + break; + } +} + +void MidiDriver_MT32::MT32SysEx(const byte *&dataPtr, int32 &bytesLeft) { + byte sysExMessage[270]; + uint16 sysExPos = 0; + byte sysExByte = 0; + uint16 sysExChecksum = 0; + + memset(&sysExMessage, 0, sizeof(sysExMessage)); + + sysExMessage[0] = 0x41; // Roland + sysExMessage[1] = 0x10; + sysExMessage[2] = 0x16; // Model MT32 + sysExMessage[3] = 0x12; // Command DT1 + + sysExPos = 4; + sysExChecksum = 0; + while (1) { + assert(bytesLeft); + + sysExByte = *dataPtr++; + bytesLeft--; + if (sysExByte == 0xff) + break; // Message done + + assert(sysExPos < sizeof(sysExMessage)); + sysExMessage[sysExPos++] = sysExByte; + sysExChecksum -= sysExByte; + } + + // Calculate checksum + assert(sysExPos < sizeof(sysExMessage)); + sysExMessage[sysExPos++] = sysExChecksum & 0x7f; + + debugC(kDebugLevelMT32Driver, "MT32: uploading patch data, size %d", sysExPos); + + // Send SysEx + _driver->sysEx(sysExMessage, sysExPos); + + // Wait the time it takes to send the SysEx data + uint32 delay = (sysExPos + 2) * 1000 / 3125; + + // Plus an additional delay for the MT-32 rev00 + if (_nativeMT32) + delay += 40; + + g_system->delayMillis(delay); +} + +// MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php +void MidiDriver_MT32::send(uint32 b) { + byte command = b & 0xf0; + byte channel = b & 0xf; + + if (command == 0xF0) { + if (_driver) { + _driver->send(b); + } + return; + } + + if (_MIDIchannelActive[channel]) { + // Only forward MIDI-data in case the channel is currently enabled via music-data + if (_driver) { + _driver->send(b); + } + } +} + +MidiDriver *MidiDriver_MT32_create() { + return new MidiDriver_MT32(); +} + +void MidiDriver_MT32_newMusicData(MidiDriver *driver, byte *musicData, int32 musicDataSize) { + static_cast(driver)->newMusicData(musicData, musicDataSize); +} + +void MidiDriver_MT32_uploadPatches(MidiDriver *driver, byte *driverData, int32 driverSize) { + static_cast(driver)->uploadMT32Patches(driverData, driverSize); +} + +} // End of namespace Sci -- cgit v1.2.3