diff options
author | Jamieson Christian | 2006-03-12 18:06:22 +0000 |
---|---|---|
committer | Jamieson Christian | 2006-03-12 18:06:22 +0000 |
commit | 4d5a3e4c45b19a96e55ff8a3c67ff7ab9734fd3b (patch) | |
tree | 23d4c7e78d45aaea3d95b2e59c83bf067904cc69 /engines/scumm | |
parent | 20095d8e93085419385efbe82d6607201d1d38c6 (diff) | |
download | scummvm-rg350-4d5a3e4c45b19a96e55ff8a3c67ff7ab9734fd3b.tar.gz scummvm-rg350-4d5a3e4c45b19a96e55ff8a3c67ff7ab9734fd3b.tar.bz2 scummvm-rg350-4d5a3e4c45b19a96e55ff8a3c67ff7ab9734fd3b.zip |
IMuse SysEx processing now handled by client-specified callbacks. This removes all game-specific references from the Player class. Bloodshed Dev-C++ project file updated.
svn-id: r21241
Diffstat (limited to 'engines/scumm')
-rw-r--r-- | engines/scumm/imuse/imuse.cpp | 16 | ||||
-rw-r--r-- | engines/scumm/imuse/imuse.h | 4 | ||||
-rw-r--r-- | engines/scumm/imuse/imuse_internal.h | 27 | ||||
-rw-r--r-- | engines/scumm/imuse/imuse_player.cpp | 181 | ||||
-rw-r--r-- | engines/scumm/imuse/sysex.h | 39 | ||||
-rw-r--r-- | engines/scumm/imuse/sysex_samnmax.cpp | 78 | ||||
-rw-r--r-- | engines/scumm/imuse/sysex_scumm.cpp | 200 | ||||
-rw-r--r-- | engines/scumm/scumm.cpp | 4 |
8 files changed, 369 insertions, 180 deletions
diff --git a/engines/scumm/imuse/imuse.cpp b/engines/scumm/imuse/imuse.cpp index fd96a77221..b39e7da177 100644 --- a/engines/scumm/imuse/imuse.cpp +++ b/engines/scumm/imuse/imuse.cpp @@ -46,9 +46,10 @@ IMuseInternal::IMuseInternal() : _native_mt32(false), _enable_gs(false), _sc55(false), -_midi_adlib(0), -_midi_native(0), -_base_sounds(0), +_midi_adlib(NULL), +_midi_native(NULL), +_base_sounds(NULL), +_sysex(NULL), _paused(false), _initialized(false), _tempoFactor(0), @@ -451,6 +452,15 @@ uint32 IMuseInternal::property(int prop, uint32 value) { return 0; } +void IMuseInternal::addSysexHandler (byte mfgID, sysexfunc handler) { + // TODO: Eventually support multiple sysEx handlers and pay + // attention to the client-supplied manufacturer ID. + Common::StackLock lock(_mutex, "IMuseInternal::property()"); + _sysex = handler; +} + + + //////////////////////////////////////// // // MusicEngine interface methods diff --git a/engines/scumm/imuse/imuse.h b/engines/scumm/imuse/imuse.h index 4f25d4b897..a82d82cca7 100644 --- a/engines/scumm/imuse/imuse.h +++ b/engines/scumm/imuse/imuse.h @@ -34,9 +34,12 @@ class OSystem; namespace Scumm { class IMuseInternal; +class Player; class ScummEngine; class Serializer; +typedef void (*sysexfunc) (Player *, const byte *, uint16); + /** * iMuse implementation interface. * MusicEngine derivative for state-tracked, interactive, @@ -66,6 +69,7 @@ public: virtual int clear_queue() = 0; virtual void setBase(byte **base) = 0; virtual uint32 property(int prop, uint32 value) = 0; + virtual void addSysexHandler (byte mfgID, sysexfunc handler) = 0; public: // MusicEngine base class methods. diff --git a/engines/scumm/imuse/imuse_internal.h b/engines/scumm/imuse/imuse_internal.h index e82da1ad5b..e19e72cd23 100644 --- a/engines/scumm/imuse/imuse_internal.h +++ b/engines/scumm/imuse/imuse_internal.h @@ -154,6 +154,16 @@ struct CommandQueue { ////////////////////////////////////////////////// class Player : public MidiDriver { +/* + * External SysEx handler functions shall each be defined in + * a separate file. This header file shall be included at the + * top of the file immediately following this special #define: + * #define SYSEX_CALLBACK_FUNCTION nameOfHandlerFunction + */ +#ifdef SYSEX_CALLBACK_FUNCTION + friend void SYSEX_CALLBACK_FUNCTION (Player *, const byte *, uint16); +#endif + protected: // Moved from IMuseInternal. // This is only used by one player at a time. @@ -367,6 +377,16 @@ class IMuseInternal : public IMuse { friend class Player; friend struct Part; +/* + * External SysEx handler functions shall each be defined in + * a separate file. This header file shall be included at the + * top of the file immediately following this special #define: + * #define SYSEX_CALLBACK_FUNCTION nameOfHandlerFunction + */ +#ifdef SYSEX_CALLBACK_FUNCTION + friend void SYSEX_CALLBACK_FUNCTION (Player *, const byte *, uint16); +#endif + protected: bool _native_mt32; bool _enable_gs; @@ -379,6 +399,12 @@ protected: uint32 _game_id; byte **_base_sounds; + // Plug-in SysEx handling. Right now this only supports one + // custom SysEx handler for the hardcoded IMUSE_SYSEX_ID + // manufacturer code. TODO: Expand this to support multiple + // SysEx handlers for client-specified manufacturer codes. + sysexfunc _sysex; + OSystem *_system; Common::Mutex _mutex; @@ -488,6 +514,7 @@ public: int32 doCommand (int numargs, int args[]); void setBase(byte **base); uint32 property(int prop, uint32 value); + virtual void addSysexHandler (byte mfgID, sysexfunc handler); public: // MusicEngine interface diff --git a/engines/scumm/imuse/imuse_player.cpp b/engines/scumm/imuse/imuse_player.cpp index fddba2fcc9..ff12e4d94a 100644 --- a/engines/scumm/imuse/imuse_player.cpp +++ b/engines/scumm/imuse/imuse_player.cpp @@ -58,10 +58,10 @@ uint16 Player::_active_notes[128]; ////////////////////////////////////////////////// Player::Player() : - _midi(0), - _parser(0), + _midi(NULL), + _parser(NULL), _passThrough(0), - _parts(0), + _parts(NULL), _active(false), _scanning(false), _id(0), @@ -393,180 +393,7 @@ void Player::sysEx(const byte *p, uint16 len) { debugC(DEBUG_IMUSE, "[%02d] SysEx:%s", _id, buf); } - switch (code = *p++) { - case 0: - if (_se->_game_id != GID_SAMNMAX) { - // There are 17 bytes of useful information beyond - // what we've read so far. All we know about them is - // as follows: - // BYTE 00: Channel # - // BYTE 02: BIT 01(0x01): Part on?(1 = yes) - // BIT 02(0x02): Reverb? (1 = yes) [bug #1088045] - // BYTE 04: Priority adjustment [guessing] - // BYTE 05: Volume(upper 4 bits) [guessing] - // BYTE 06: Volume(lower 4 bits) [guessing] - // BYTE 07: Pan(upper 4 bits) [bug #1088045] - // BYTE 08: Pan(lower 4 bits) [bug #1088045] - // BYTE 09: BIT 04(0x08): Percussion?(1 = yes) - // BYTE 13: Pitchbend range(upper 4 bits) [bug #1088045] - // BYTE 14: Pitchbend range(lower 4 bits) [bug #1088045] - // BYTE 15: Program(upper 4 bits) - // BYTE 16: Program(lower 4 bits) - part = getPart(p[0] & 0x0F); - if (part) { - part->set_onoff(p[2] & 0x01); - part->effectLevel ((p[2] & 0x02) ? 127 : 0); - part->set_pri(p[4]); - part->volume((p[5] & 0x0F) << 4 |(p[6] & 0x0F)); - part->set_pan((p[7] & 0x0F) << 4 | (p[8] & 0x0F)); - part->_percussion = _isMIDI ? ((p[9] & 0x08) > 0) : false; - part->pitchBendFactor ((p[13] & 0x0F) << 4 | (p[14] & 0x0F)); - if (part->_percussion) { - if (part->_mc) { - part->off(); - _se->reallocateMidiChannels(_midi); - } - } else { - // Even in cases where a program does not seem to be specified, - // i.e. bytes 15 and 16 are 0, we send a program change because - // 0 is a valid program number. MI2 tests show that in such - // cases, a regular program change message always seems to follow - // anyway. - if (_isMIDI) - part->_instrument.program((p[15] & 0x0F) << 4 |(p[16] & 0x0F), _isMT32); - part->sendAll(); - } - } - } else { - // Sam & Max: Trigger Event - // Triggers are set by doCommand(ImSetTrigger). - // When a SysEx marker is encountered whose sound - // ID and marker ID match what was set by ImSetTrigger, - // something magical is supposed to happen.... - for (a = 0; a < ARRAYSIZE(_se->_snm_triggers); ++a) { - if (_se->_snm_triggers[a].sound == _id && - _se->_snm_triggers[a].id == *p) - { - _se->_snm_triggers[a].sound = _se->_snm_triggers[a].id = 0; - _se->doCommand(8, _se->_snm_triggers[a].command); - break; - } - } - } // end if - break; - - case 1: - if (_se->_game_id != GID_SAMNMAX) { - // Shut down a part. [Bug 1088045, comments] - part = getPart (p[0]); - if (part != NULL) part->uninit(); - } else { - // Sam & Max: maybe_jump. - if (_scanning) - break; - maybe_jump(p[0], p[1] - 1, (READ_BE_UINT16(p + 2) - 1) * 4 + p[4], ((p[5] * TICKS_PER_BEAT) >> 2) + p[6]); - } - break; - - case 2: // Start of song. Ignore for now. - break; - - case 16: // Adlib instrument definition(Part) - a = *p++ & 0x0F; - ++p; // Skip hardware type - part = getPart(a); - if (part) { - if (len == 63) { - decode_sysex_bytes(p, buf, len - 3); - part->set_instrument((byte *)buf); - } else { - // SPK tracks have len == 49 here, and are not supported - part->programChange(254); // Must be invalid, but not 255 (which is reserved) - } - } - break; - - case 17: // Adlib instrument definition(Global) - p += 2; // Skip hardware type and... whatever came right before it - a = *p++; - decode_sysex_bytes(p, buf, len - 4); - _se->setGlobalAdlibInstrument(a, buf); - break; - - case 33: // Parameter adjust - a = *p++ & 0x0F; - ++p; // Skip hardware type - decode_sysex_bytes(p, buf, len - 3); - part = getPart(a); - if (part) - part->set_param(READ_BE_UINT16(buf), READ_BE_UINT16(buf + 2)); - break; - - case 48: // Hook - jump - if (_scanning) - break; - decode_sysex_bytes(p + 1, buf, len - 2); - maybe_jump(buf[0], READ_BE_UINT16(buf + 1), READ_BE_UINT16(buf + 3), READ_BE_UINT16(buf + 5)); - break; - - case 49: // Hook - global transpose - decode_sysex_bytes(p + 1, buf, len - 2); - maybe_set_transpose(buf); - break; - - case 50: // Hook - part on/off - buf[0] = *p++ & 0x0F; - decode_sysex_bytes(p, buf + 1, len - 2); - maybe_part_onoff(buf); - break; - - case 51: // Hook - set volume - buf[0] = *p++ & 0x0F; - decode_sysex_bytes(p, buf + 1, len - 2); - maybe_set_volume(buf); - break; - - case 52: // Hook - set program - buf[0] = *p++ & 0x0F; - decode_sysex_bytes(p, buf + 1, len - 2); - maybe_set_program(buf); - break; - - case 53: // Hook - set transpose - buf[0] = *p++ & 0x0F; - decode_sysex_bytes(p, buf + 1, len - 2); - maybe_set_transpose_part(buf); - break; - - case 64: // Marker - p++; - len -= 2; - while (len--) { - _se->handle_marker(_id, *p++); - } - break; - - case 80: // Loop - decode_sysex_bytes(p + 1, buf, len - 2); - setLoop(READ_BE_UINT16(buf), READ_BE_UINT16(buf + 2), - READ_BE_UINT16(buf + 4), READ_BE_UINT16(buf + 6), - READ_BE_UINT16(buf + 8)); - break; - - case 81: // End loop - clearLoop(); - break; - - case 96: // Set instrument - part = getPart(p[0] & 0x0F); - b = (p[1] & 0x0F) << 12 |(p[2] & 0x0F) << 8 |(p[4] & 0x0F) << 4 |(p[4] & 0x0F); - if (part) - part->set_instrument(b); - break; - - default: - error("Unknown SysEx command %d", (int)code); - } + if (_se->_sysex) (*_se->_sysex) (this, p, len); } void Player::decode_sysex_bytes(const byte *src, byte *dst, int len) { diff --git a/engines/scumm/imuse/sysex.h b/engines/scumm/imuse/sysex.h new file mode 100644 index 0000000000..7e33295b62 --- /dev/null +++ b/engines/scumm/imuse/sysex.h @@ -0,0 +1,39 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * 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 DEFINED_SYSEX_H +#define DEFINED_SYSEX_H + +#include "common/stdafx.h" +#include "common/util.h" + +namespace Scumm { + +class Player; + +extern void sysexHandler_Scumm (Player *, const byte *, uint16); +extern void sysexHandler_SamNMax (Player *, const byte *, uint16); + +} // End of namespace Scumm + +#endif + diff --git a/engines/scumm/imuse/sysex_samnmax.cpp b/engines/scumm/imuse/sysex_samnmax.cpp new file mode 100644 index 0000000000..837fc65afa --- /dev/null +++ b/engines/scumm/imuse/sysex_samnmax.cpp @@ -0,0 +1,78 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * 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 "common/stdafx.h" +#include "common/util.h" + +/* + * SysEx command handlers must have full access to the + * internal IMuse implementation classes. Before including + * the relevant header file, two things must happen: + * 1. A function declaration must be made. + * 2. The following #define must be established: + * #define SYSEX_CALLBACK_FUNCTION functionName + */ +#define SYSEX_CALLBACK_FUNCTION sysexHandler_SamNMax +#include "scumm/imuse/imuse_internal.h" + +namespace Scumm { + +extern void sysexHandler_Scumm (Player *, const byte *, uint16); + +void sysexHandler_SamNMax (Player *player, const byte *msg, uint16 len) { + Part *part; + byte a; + + IMuseInternal *se = player->_se; + const byte *p = msg; + + switch (*p++) { + case 0: + // Trigger Event + // Triggers are set by doCommand(ImSetTrigger). + // When a SysEx marker is encountered whose sound + // ID and marker ID match what was set by ImSetTrigger, + // something magical is supposed to happen.... + for (a = 0; a < ARRAYSIZE(se->_snm_triggers); ++a) { + if (se->_snm_triggers[a].sound == player->_id && + se->_snm_triggers[a].id == *p) + { + se->_snm_triggers[a].sound = se->_snm_triggers[a].id = 0; + se->doCommand(8, se->_snm_triggers[a].command); + break; + } + } + break; + + case 1: + // maybe_jump. + if (player->_scanning) + break; + player->maybe_jump(p[0], p[1] - 1, (READ_BE_UINT16(p + 2) - 1) * 4 + p[4], ((p[5] * TICKS_PER_BEAT) >> 2) + p[6]); + break; + + default: + sysexHandler_Scumm (player, msg, len); + } +} + +} // End of namespace Scumm diff --git a/engines/scumm/imuse/sysex_scumm.cpp b/engines/scumm/imuse/sysex_scumm.cpp new file mode 100644 index 0000000000..2b11878522 --- /dev/null +++ b/engines/scumm/imuse/sysex_scumm.cpp @@ -0,0 +1,200 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * 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 "common/stdafx.h" +#include "common/util.h" + +/* + * SysEx command handlers must have full access to the + * internal IMuse implementation classes. Before including + * the relevant header file, two things must happen: + * 1. A function declaration must be made. + * 2. The following #define must be established: + * #define SYSEX_CALLBACK_FUNCTION functionName + */ +#define SYSEX_CALLBACK_FUNCTION sysexHandler_Scumm +#include "scumm/imuse/imuse_internal.h" + +namespace Scumm { + +void sysexHandler_Scumm (Player *player, const byte *msg, uint16 len) { + Part *part; + byte a; + byte buf[128]; + + IMuseInternal *se = player->_se; + const byte *p = msg; + + switch (byte code = *p++) { + case 0: + // Allocate new part. + // There are 17 bytes of useful information here. + // Here is what we know about them so far: + // BYTE 00: Channel # + // BYTE 02: BIT 01(0x01): Part on?(1 = yes) + // BIT 02(0x02): Reverb? (1 = yes) [bug #1088045] + // BYTE 04: Priority adjustment [guessing] + // BYTE 05: Volume(upper 4 bits) [guessing] + // BYTE 06: Volume(lower 4 bits) [guessing] + // BYTE 07: Pan(upper 4 bits) [bug #1088045] + // BYTE 08: Pan(lower 4 bits) [bug #1088045] + // BYTE 09: BIT 04(0x08): Percussion?(1 = yes) + // BYTE 13: Pitchbend range(upper 4 bits) [bug #1088045] + // BYTE 14: Pitchbend range(lower 4 bits) [bug #1088045] + // BYTE 15: Program(upper 4 bits) + // BYTE 16: Program(lower 4 bits) + part = player->getPart(p[0] & 0x0F); + if (part) { + part->set_onoff(p[2] & 0x01); + part->effectLevel ((p[2] & 0x02) ? 127 : 0); + part->set_pri(p[4]); + part->volume((p[5] & 0x0F) << 4 |(p[6] & 0x0F)); + part->set_pan((p[7] & 0x0F) << 4 | (p[8] & 0x0F)); + part->_percussion = player->_isMIDI ? ((p[9] & 0x08) > 0) : false; + part->pitchBendFactor ((p[13] & 0x0F) << 4 | (p[14] & 0x0F)); + if (part->_percussion) { + if (part->_mc) { + part->off(); + se->reallocateMidiChannels(player->_midi); + } + } else { + // Even in cases where a program does not seem to be specified, + // i.e. bytes 15 and 16 are 0, we send a program change because + // 0 is a valid program number. MI2 tests show that in such + // cases, a regular program change message always seems to follow + // anyway. + if (player->_isMIDI) + part->_instrument.program((p[15] & 0x0F) << 4 |(p[16] & 0x0F), player->_isMT32); + part->sendAll(); + } + } + break; + + case 1: + // Shut down a part. [Bug 1088045, comments] + part = player->getPart (p[0]); + if (part != NULL) part->uninit(); + break; + + case 2: // Start of song. Ignore for now. + break; + + case 16: // Adlib instrument definition(Part) + a = *p++ & 0x0F; + ++p; // Skip hardware type + part = player->getPart(a); + if (part) { + if (len == 63) { + player->decode_sysex_bytes(p, buf, len - 3); + part->set_instrument((byte *)buf); + } else { + // SPK tracks have len == 49 here, and are not supported + part->programChange(254); // Must be invalid, but not 255 (which is reserved) + } + } + break; + + case 17: // Adlib instrument definition(Global) + p += 2; // Skip hardware type and... whatever came right before it + a = *p++; + player->decode_sysex_bytes(p, buf, len - 4); + se->setGlobalAdlibInstrument(a, buf); + break; + + case 33: // Parameter adjust + a = *p++ & 0x0F; + ++p; // Skip hardware type + player->decode_sysex_bytes(p, buf, len - 3); + part = player->getPart(a); + if (part) + part->set_param(READ_BE_UINT16(buf), READ_BE_UINT16(buf + 2)); + break; + + case 48: // Hook - jump + if (player->_scanning) + break; + player->decode_sysex_bytes(p + 1, buf, len - 2); + player->maybe_jump(buf[0], READ_BE_UINT16(buf + 1), READ_BE_UINT16(buf + 3), READ_BE_UINT16(buf + 5)); + break; + + case 49: // Hook - global transpose + player->decode_sysex_bytes(p + 1, buf, len - 2); + player->maybe_set_transpose(buf); + break; + + case 50: // Hook - part on/off + buf[0] = *p++ & 0x0F; + player->decode_sysex_bytes(p, buf + 1, len - 2); + player->maybe_part_onoff(buf); + break; + + case 51: // Hook - set volume + buf[0] = *p++ & 0x0F; + player->decode_sysex_bytes(p, buf + 1, len - 2); + player->maybe_set_volume(buf); + break; + + case 52: // Hook - set program + buf[0] = *p++ & 0x0F; + player->decode_sysex_bytes(p, buf + 1, len - 2); + player->maybe_set_program(buf); + break; + + case 53: // Hook - set transpose + buf[0] = *p++ & 0x0F; + player->decode_sysex_bytes(p, buf + 1, len - 2); + player->maybe_set_transpose_part(buf); + break; + + case 64: // Marker + p++; + len -= 2; + while (len--) { + se->handle_marker(player->_id, *p++); + } + break; + + case 80: // Loop + player->decode_sysex_bytes(p + 1, buf, len - 2); + player->setLoop + (READ_BE_UINT16(buf), READ_BE_UINT16(buf + 2), + READ_BE_UINT16(buf + 4), READ_BE_UINT16(buf + 6), + READ_BE_UINT16(buf + 8)); + break; + + case 81: // End loop + player->clearLoop(); + break; + + case 96: // Set instrument + part = player->getPart(p[0] & 0x0F); + a = (p[1] & 0x0F) << 12 |(p[2] & 0x0F) << 8 |(p[4] & 0x0F) << 4 |(p[4] & 0x0F); + if (part) + part->set_instrument(a); + break; + + default: + error("Unknown SysEx command %d", (int)code); + } +} + +} // End of namespace Scumm diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index 3bfefb1410..58b9c97dd7 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -56,6 +56,7 @@ #include "scumm/he/resource_he.h" #include "scumm/scumm.h" #include "scumm/sound.h" +#include "scumm/imuse/sysex.h" #include "scumm/he/sprite_he.h" #include "scumm/util.h" #include "scumm/verbs.h" @@ -1703,6 +1704,9 @@ void ScummEngine::setupMusic(int midi) { _musicEngine = _imuse = IMuse::create(_system, nativeMidiDriver, adlibMidiDriver); if (_imuse) { + _imuse->addSysexHandler + (/*IMUSE_SYSEX_ID*/ 0x7D, + (_game.id == GID_SAMNMAX) ? sysexHandler_SamNMax : sysexHandler_Scumm); _imuse->property(IMuse::PROP_GAME_ID, _game.id); if (ConfMan.hasKey("tempo")) _imuse->property(IMuse::PROP_TEMPO_BASE, ConfMan.getInt("tempo")); |