[Scummvm-cvs-logs] SF.net SVN: scummvm: [20801] scummvm/trunk

fingolfin at users.sourceforge.net fingolfin at users.sourceforge.net
Mon Feb 20 12:59:01 CET 2006


Revision: 20801
Author:   fingolfin
Date:     2006-02-20 12:57:26 -0800 (Mon, 20 Feb 2006)
ViewCVS:  http://svn.sourceforge.net/scummvm?rev=20801&view=rev

Log Message:
-----------
Moved iMUSE code to the new directory engines/scumm/imuse/

Modified Paths:
--------------
    scummvm/trunk/TODO
    scummvm/trunk/engines/scumm/akos.cpp
    scummvm/trunk/engines/scumm/debugger.cpp
    scummvm/trunk/engines/scumm/dialogs.cpp
    scummvm/trunk/engines/scumm/he/script_v60he.cpp
    scummvm/trunk/engines/scumm/he/sound_he.cpp
    scummvm/trunk/engines/scumm/input.cpp
    scummvm/trunk/engines/scumm/insane/insane.cpp
    scummvm/trunk/engines/scumm/module.mk
    scummvm/trunk/engines/scumm/resource.cpp
    scummvm/trunk/engines/scumm/saveload.cpp
    scummvm/trunk/engines/scumm/script_v6.cpp
    scummvm/trunk/engines/scumm/scumm.cpp
    scummvm/trunk/engines/scumm/smush/smush_mixer.cpp
    scummvm/trunk/engines/scumm/smush/smush_player.cpp
    scummvm/trunk/engines/scumm/sound.cpp

Added Paths:
-----------
    scummvm/trunk/engines/scumm/imuse/
    scummvm/trunk/engines/scumm/imuse/imuse.cpp
    scummvm/trunk/engines/scumm/imuse/imuse.h
    scummvm/trunk/engines/scumm/imuse/imuse_internal.h
    scummvm/trunk/engines/scumm/imuse/imuse_player.cpp
    scummvm/trunk/engines/scumm/imuse/instrument.cpp
    scummvm/trunk/engines/scumm/imuse/instrument.h

Removed Paths:
-------------
    scummvm/trunk/engines/scumm/imuse.cpp
    scummvm/trunk/engines/scumm/imuse.h
    scummvm/trunk/engines/scumm/imuse_internal.h
    scummvm/trunk/engines/scumm/imuse_player.cpp
    scummvm/trunk/engines/scumm/instrument.cpp
    scummvm/trunk/engines/scumm/instrument.h
Modified: scummvm/trunk/TODO
===================================================================
--- scummvm/trunk/TODO	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/TODO	2006-02-20 20:57:26 UTC (rev 20801)
@@ -115,7 +115,6 @@
   - consider moving the MIDI stuff from sound/ to sound/midi/ 
   - move fmopl code to softsynth dir
   - maybe common/system.h / system.cpp should go to backends/, too ?
-  - move the iMuse source files in scumm/ to a new dir scumm/imuse/
 * The following things should be put into namespaces:
   - AudioStream and subclasses into Audio
   - MIDI related classes either to Audio, or a new "MIDI" namespace

Modified: scummvm/trunk/engines/scumm/akos.cpp
===================================================================
--- scummvm/trunk/engines/scumm/akos.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/akos.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -26,7 +26,7 @@
 #include "scumm/actor.h"
 #include "scumm/akos.h"
 #include "scumm/bomp.h"
-#include "scumm/imuse.h"
+#include "scumm/imuse/imuse.h"
 #include "scumm/imuse_digi/dimuse.h"
 #include "scumm/intern.h"
 #include "scumm/he/intern_he.h"

Modified: scummvm/trunk/engines/scumm/debugger.cpp
===================================================================
--- scummvm/trunk/engines/scumm/debugger.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/debugger.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -30,7 +30,7 @@
 #include "scumm/actor.h"
 #include "scumm/boxes.h"
 #include "scumm/debugger.h"
-#include "scumm/imuse.h"
+#include "scumm/imuse/imuse.h"
 #include "scumm/object.h"
 #include "scumm/player_v2.h"
 #include "scumm/scumm.h"

Modified: scummvm/trunk/engines/scumm/dialogs.cpp
===================================================================
--- scummvm/trunk/engines/scumm/dialogs.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/dialogs.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -35,7 +35,7 @@
 #include "scumm/dialogs.h"
 #include "scumm/sound.h"
 #include "scumm/scumm.h"
-#include "scumm/imuse.h"
+#include "scumm/imuse/imuse.h"
 #include "scumm/imuse_digi/dimuse.h"
 #include "scumm/player_v2.h"
 #include "scumm/verbs.h"

Modified: scummvm/trunk/engines/scumm/he/script_v60he.cpp
===================================================================
--- scummvm/trunk/engines/scumm/he/script_v60he.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/he/script_v60he.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -26,7 +26,7 @@
 
 #include "scumm/actor.h"
 #include "scumm/charset.h"
-#include "scumm/imuse.h"
+#include "scumm/imuse/imuse.h"
 #include "scumm/he/intern_he.h"
 #include "scumm/object.h"
 #include "scumm/resource.h"

Modified: scummvm/trunk/engines/scumm/he/sound_he.cpp
===================================================================
--- scummvm/trunk/engines/scumm/he/sound_he.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/he/sound_he.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -23,7 +23,7 @@
 
 #include "common/stdafx.h"
 #include "scumm/actor.h"
-#include "scumm/imuse.h"
+#include "scumm/imuse/imuse.h"
 #include "scumm/scumm.h"
 #include "scumm/sound.h"
 #include "scumm/util.h"


Property changes on: scummvm/trunk/engines/scumm/imuse
___________________________________________________________________
Name: svn:ignore
   + .deps
*.o
lib*.a


Copied: scummvm/trunk/engines/scumm/imuse/imuse.cpp (from rev 20795, scummvm/trunk/engines/scumm/imuse.cpp)
===================================================================
--- scummvm/trunk/engines/scumm/imuse/imuse.cpp	                        (rev 0)
+++ scummvm/trunk/engines/scumm/imuse/imuse.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -0,0 +1,2043 @@
+/* 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 "base/version.h"
+
+#include "common/util.h"
+#include "common/system.h"
+
+#include "scumm/imuse/imuse.h"
+#include "scumm/imuse/imuse_internal.h"
+#include "scumm/imuse/instrument.h"
+#include "scumm/saveload.h"
+#include "scumm/scumm.h"
+#include "scumm/util.h"
+
+#include "sound/mididrv.h"
+
+
+namespace Scumm {
+
+////////////////////////////////////////
+//
+//  IMuseInternal implementation
+//
+////////////////////////////////////////
+
+IMuseInternal::IMuseInternal() :
+_native_mt32(false),
+_enable_gs(false),
+_sc55(false),
+_midi_adlib(0),
+_midi_native(0),
+_base_sounds(0),
+_paused(false),
+_initialized(false),
+_tempoFactor(0),
+_player_limit(ARRAYSIZE(_players)),
+_recycle_players(false),
+_direct_passthrough(false),
+_queue_end(0),
+_queue_pos(0),
+_queue_sound(0),
+_queue_adding(0),
+_queue_marker(0),
+_queue_cleared(0),
+_master_volume(0),
+_music_volume(0),
+_trigger_count(0),
+_snm_trigger_index(0) {
+	memset(_channel_volume,0,sizeof(_channel_volume));
+	memset(_channel_volume_eff,0,sizeof(_channel_volume_eff));
+	memset(_volchan_table,0,sizeof(_volchan_table));
+}
+
+byte *IMuseInternal::findStartOfSound(int sound) {
+	byte *ptr = NULL;
+	int32 size, pos;
+
+	if (_base_sounds)
+		ptr = _base_sounds[sound];
+
+	if (ptr == NULL) {
+		debug(1, "IMuseInternal::findStartOfSound(): Sound %d doesn't exist!", sound);
+		return NULL;
+	}
+
+	// Check for old-style headers first, like 'RO'
+	if (ptr[4] == 'R' && ptr[5] == 'O'&& ptr[6] != 'L')
+		return ptr + 4;
+	if (ptr[8] == 'S' && ptr[9] == 'O')
+		return ptr + 8;
+
+	ptr += 8;
+	size = READ_BE_UINT32(ptr);
+	ptr += 4;
+
+	// Okay, we're looking for one of those things: either
+	// an 'MThd' tag (for SMF), or a 'FORM' tag (for XMIDI).
+	size = 48; // Arbitrary; we should find our tag within the first 48 bytes of the resource
+	pos = 0;
+	while (pos < size) {
+		if (!memcmp(ptr + pos, "MThd", 4) || !memcmp(ptr + pos, "FORM", 4))
+			return ptr + pos;
+		++pos; // We could probably iterate more intelligently
+	}
+
+	debug(3, "IMuseInternal::findStartOfSound(): Failed to align on sound %d!", sound);
+	return 0;
+}
+
+bool IMuseInternal::isMT32(int sound) {
+	byte *ptr = NULL;
+	uint32 tag;
+
+	if (_base_sounds)
+		ptr = _base_sounds[sound];
+
+	if (ptr == NULL)
+		return false;
+
+	tag = *(((uint32 *)ptr) + 1);
+	switch (tag) {
+	case MKID('ADL '):
+	case MKID('ASFX'): // Special AD class for old Adlib sound effects
+	case MKID('SPK '):
+		return false;
+
+	case MKID('AMI '):
+	case MKID('ROL '):
+		return true;
+
+	case MKID('MAC '):	// Occurs in the Mac version of FOA and MI2
+		return true;
+
+	case MKID('GMD '):
+	case MKID('MIDI'):	// Occurs in Sam & Max
+		return false;
+	}
+
+	// Old style 'RO' has equivalent properties to 'ROL'
+	if (ptr[4] == 'R' && ptr[5] == 'O')
+		return true;
+	// Euphony tracks show as 'SO' and have equivalent properties to 'ADL'
+	if (ptr[8] == 'S' && ptr[9] == 'O')
+		return false;
+
+	error("Unknown music type: '%s'", tag2str(tag));
+
+	return false;
+}
+
+bool IMuseInternal::isMIDI(int sound) {
+	byte *ptr = NULL;
+	uint32 tag;
+
+	if (_base_sounds)
+		ptr = _base_sounds[sound];
+
+	if (ptr == NULL)
+		return false;
+
+	tag = *(((uint32 *)ptr) + 1);
+	switch (tag) {
+	case MKID('ADL '):
+	case MKID('ASFX'): // Special AD class for old Adlib sound effects
+	case MKID('SPK '):
+		return false;
+
+	case MKID('AMI '):
+	case MKID('ROL '):
+		return true;
+
+	case MKID('MAC '):	// Occurs in the Mac version of FOA and MI2
+		return true;
+
+	case MKID('GMD '):
+	case MKID('MIDI'):	// Occurs in Sam & Max
+		return true;
+	}
+
+	// Old style 'RO' has equivalent properties to 'ROL'
+	if (ptr[4] == 'R' && ptr[5] == 'O')
+		return true;
+	// Euphony tracks show as 'SO' and have equivalent properties to 'ADL'
+	// FIXME: Right now we're pretending it's GM.
+	if (ptr[8] == 'S' && ptr[9] == 'O')
+		return true;
+
+	error("Unknown music type: '%s'", tag2str(tag));
+
+	return false;
+}
+
+MidiDriver *IMuseInternal::getBestMidiDriver(int sound) {
+	MidiDriver *driver = NULL;
+
+	if (isMIDI(sound)) {
+		if (_midi_native) {
+			driver = _midi_native;
+		} else {
+			// Route it through Adlib anyway.
+			driver = _midi_adlib;
+		}
+	} else {
+		driver = _midi_adlib;
+	}
+	return driver;
+}
+
+bool IMuseInternal::startSound(int sound) {
+	Player *player;
+	void *ptr;
+
+	// Do not start a sound if it is already set to start on an ImTrigger
+	// event. This fixes carnival music problems where a sound has been set
+	// to trigger at the right time, but then is started up immediately
+	// anyway, only to be restarted later when the trigger occurs.
+	//
+	// However, we have to make sure the sound with the trigger is actually
+	// playing, otherwise the music may stop when Sam and Max are thrown
+	// out of Bumpusville, because entering the mansion sets up a trigger
+	// for a sound that isn't necessarily playing. This is somewhat related
+	// to bug #780918.
+
+	int i;
+	ImTrigger *trigger = _snm_triggers;
+	for (i = ARRAYSIZE(_snm_triggers); i; --i, ++trigger) {
+		if (trigger->sound && trigger->id && trigger->command[0] == 8 && trigger->command[1] == sound && getSoundStatus(trigger->sound))
+			return false;
+	}
+
+	ptr = findStartOfSound(sound);
+	if (!ptr) {
+		debug(2, "IMuseInternal::startSound(): Couldn't find sound %d!", sound);
+		return false;
+	}
+
+	// Check which MIDI driver this track should use.
+	// If it's NULL, it ain't something we can play.
+	MidiDriver *driver = getBestMidiDriver(sound);
+	if (!driver)
+		return false;
+
+	// If the requested sound is already playing, start it over
+	// from scratch. This was originally a hack to prevent Sam & Max
+	// iMuse messiness while upgrading the iMuse engine, but it
+	// is apparently necessary to deal with fade-and-restart
+	// race conditions that were observed in MI2. Reference
+	// Bug #590511 and Patch #607175 (which was reversed to fix
+	// an FOA regression: Bug #622606).
+	player = findActivePlayer(sound);
+	if (!player)
+		player = allocate_player(128);
+	if (!player)
+		return false;
+
+	// HACK: This is to work around a problem at the Dino Bungie Memorial.
+	// There are three pieces of music involved here:
+	//
+	// 80 - Main theme (looping)
+	// 81 - Music when entering Rex's and Wally's room (not looping)
+	// 82 - Music when listening to Rex or Wally
+	//
+	// When entering, tune 81 starts, tune 80 is faded down (not out) and
+	// a trigger is set in tune 81 to fade tune 80 back up.
+	//
+	// When listening to Rex or Wally, tune 82 is started, tune 81 is faded
+	// out and tune 80 is faded down even further.
+	//
+	// However, when tune 81 is faded out its trigger will cause tune 80 to
+	// fade back up, resulting in two tunes being played simultaneously at
+	// full blast. It's no use trying to keep tune 81 playing at volume 0.
+	// It doesn't loop, so eventually it will terminate on its own.
+	//
+	// I don't know how the original interpreter handled this - or even if
+	// it handled it at all - but it looks like sloppy scripting to me. Our
+	// workaround is to clear the trigger if the player listens to Rex or
+	// Wally before tune 81 has finished on its own.
+
+	if (g_scumm->_game.id == GID_SAMNMAX && sound == 82 && getSoundStatus(81, false))
+		ImClearTrigger(81, 1);
+
+	player->clear();
+	return player->startSound(sound, driver, _direct_passthrough);
+}
+
+
+Player *IMuseInternal::allocate_player(byte priority) {
+	Player *player = _players, *best = NULL;
+	int i;
+	byte bestpri = 255;
+
+	for (i = _player_limit; i != 0; i--, player++) {
+		if (!player->isActive())
+			return player;
+		if (player->getPriority() < bestpri) {
+			best = player;
+			bestpri = player->getPriority();
+		}
+	}
+
+	if (bestpri < priority || _recycle_players)
+		return best;
+
+	debug(1, "Denying player request");
+	return NULL;
+}
+
+void IMuseInternal::init_players() {
+	Player *player = _players;
+	int i;
+
+	for (i = ARRAYSIZE(_players); i != 0; i--, player++) {
+		player->_se = this;
+		player->clear(); // Used to just set _active to false
+	}
+}
+
+void IMuseInternal::init_parts() {
+	Part *part;
+	int i;
+
+	for (i = 0, part = _parts; i != ARRAYSIZE(_parts); i++, part++) {
+		part->init();
+		part->_se = this;
+		part->_slot = i;
+	}
+}
+
+int IMuseInternal::stopSound(int sound) {
+	int r = -1;
+	Player *player = findActivePlayer(sound);
+	if (player) {
+		player->clear();
+		r = 0;
+	}
+	return r;
+}
+
+int IMuseInternal::stopAllSounds() {
+	Player *player = _players;
+	int i;
+
+	for (i = ARRAYSIZE(_players); i != 0; i--, player++) {
+		if (player->isActive())
+			player->clear();
+	}
+	return 0;
+}
+
+void IMuseInternal::on_timer(MidiDriver *midi) {
+	if (_paused || !_initialized)
+		return;
+
+	if (midi == _midi_native || !_midi_native)
+		handleDeferredCommands(midi);
+	sequencer_timers(midi);
+}
+
+int IMuseInternal::getMusicTimer() const {
+	int best_time = 0;
+	const Player *player = _players;
+	int i;
+
+	for (i = ARRAYSIZE(_players); i != 0; i--, player++) {
+		if (player->isActive()) {
+			int timer = player->getMusicTimer();
+			if (timer > best_time)
+				best_time = timer;
+		}
+	}
+	return best_time;
+}
+
+void IMuseInternal::sequencer_timers(MidiDriver *midi) {
+	Player *player = _players;
+	int i;
+	for (i = ARRAYSIZE(_players); i != 0; i--, player++) {
+		if (player->isActive() && player->getMidiDriver() == midi) {
+			player->onTimer();
+		}
+	}
+}
+
+void IMuseInternal::handle_marker(uint id, byte data) {
+	uint16 *p = 0;
+	uint pos;
+
+	if (_queue_adding && _queue_sound == id && data == _queue_marker)
+		return;
+
+	// Fix for bug #733401, revised for bug #761637:
+	// It would seem that sometimes a marker is in the queue
+	// but not at the head position. In the case of our bug,
+	// this seems to be the result of commands in the queue
+	// for songs that are no longer playing. So we skip
+	// ahead to the appropriate marker, effectively chomping
+	// anything in the queue before it. This fixes the FOA
+	// end credits music, but needs to be tested for inappopriate
+	// behavior elsewhere.
+	pos = _queue_end;
+	while (pos != _queue_pos) {
+		p = _cmd_queue[pos].array;
+		if (p[0] == TRIGGER_ID && p[1] == id && p[2] == data)
+			break;
+		pos = (pos + 1) % ARRAYSIZE(_cmd_queue);
+	}
+
+	if (pos == _queue_pos)
+		return;
+
+	if (pos != _queue_end)
+		debug(0, "Skipping entries in iMuse command queue to reach marker");
+
+	_trigger_count--;
+	_queue_cleared = false;
+	do {
+		pos = (pos + 1) % ARRAYSIZE(_cmd_queue);
+		if (_queue_pos == pos)
+			break;
+		p = _cmd_queue[pos].array;
+		if (*p++ != COMMAND_ID)
+			break;
+		_queue_end = pos;
+
+		doCommand(p[0], p[1], p[2], p[3], p[4], p[5], p[6], 0);
+
+		if (_queue_cleared)
+			return;
+		pos = _queue_end;
+	} while (1);
+
+	_queue_end = pos;
+}
+
+int IMuseInternal::get_channel_volume(uint a) {
+	if (a < 8)
+		return _channel_volume_eff[a];
+	return (_master_volume * _music_volume / 255) / 2;
+}
+
+Part *IMuseInternal::allocate_part(byte pri, MidiDriver *midi) {
+	Part *part, *best = NULL;
+	int i;
+
+	for (i = ARRAYSIZE(_parts), part = _parts; i != 0; i--, part++) {
+		if (!part->_player)
+			return part;
+		if (pri >= part->_pri_eff) {
+			pri = part->_pri_eff;
+			best = part;
+		}
+	}
+
+	if (best) {
+		best->uninit();
+		reallocateMidiChannels(midi);
+	} else {
+		debug(1, "Denying part request");
+	}
+	return best;
+}
+
+int IMuseInternal::getSoundStatus(int sound, bool ignoreFadeouts) const {
+	int i;
+	const Player *player = _players;
+
+	for (i = ARRAYSIZE(_players); i != 0; i--, player++) {
+		if (player->isActive() && (!ignoreFadeouts || !player->isFadingOut())) {
+			if (sound == -1)
+				return player->getID();
+			else if (player->getID() == (uint16)sound)
+				return 1;
+		}
+	}
+	return (sound == -1) ? 0 : get_queue_sound_status(sound);
+}
+
+int IMuseInternal::get_queue_sound_status(int sound) const {
+	const uint16 *a;
+	int i, j;
+
+	j = _queue_pos;
+	i = _queue_end;
+
+	while (i != j) {
+		a = _cmd_queue[i].array;
+		if (a[0] == COMMAND_ID && a[1] == 8 && a[2] == (uint16)sound)
+			return 2;
+		i = (i + 1) % ARRAYSIZE(_cmd_queue);
+	}
+
+	for (i = 0; i < ARRAYSIZE (_deferredCommands); ++i) {
+		if (_deferredCommands[i].time_left && _deferredCommands[i].a == 8 &&
+			_deferredCommands[i].b == sound) {
+			return 2;
+		}
+	}
+
+	return 0;
+}
+
+int IMuseInternal::set_volchan(int sound, int volchan) {
+	int r;
+	int i;
+	int num;
+	Player *player, *best, *sameid;
+
+	r = get_volchan_entry(volchan);
+	if (r == -1)
+		return -1;
+
+	if (r >= 8) {
+		player = findActivePlayer(sound);
+		if (player && player->_vol_chan != (uint16)volchan) {
+			player->_vol_chan = volchan;
+			player->setVolume(player->getVolume());
+			return 0;
+		}
+		return -1;
+	} else {
+		best = NULL;
+		num = 0;
+		sameid = NULL;
+		for (i = ARRAYSIZE(_players), player = _players; i != 0; i--, player++) {
+			if (player->isActive()) {
+				if (player->_vol_chan == (uint16)volchan) {
+					num++;
+					if (!best || player->getPriority() <= best->getPriority())
+						best = player;
+				} else if (player->getID() == (uint16)sound) {
+					sameid = player;
+				}
+			}
+		}
+		if (sameid == NULL)
+			return -1;
+		if (num >= r)
+			best->clear();
+		player->_vol_chan = volchan;
+		player->setVolume(player->getVolume());
+		return 0;
+	}
+}
+
+int IMuseInternal::clear_queue() {
+	_queue_adding = false;
+	_queue_cleared = true;
+	_queue_pos = 0;
+	_queue_end = 0;
+	_trigger_count = 0;
+	return 0;
+}
+
+int IMuseInternal::enqueue_command(int a, int b, int c, int d, int e, int f, int g) {
+	uint16 *p;
+	uint i;
+
+	i = _queue_pos;
+
+	if (i == _queue_end)
+		return -1;
+
+	if (a == -1) {
+		_queue_adding = false;
+		_trigger_count++;
+		return 0;
+	}
+
+	p = _cmd_queue[_queue_pos].array;
+	p[0] = COMMAND_ID;
+	p[1] = a;
+	p[2] = b;
+	p[3] = c;
+	p[4] = d;
+	p[5] = e;
+	p[6] = f;
+	p[7] = g;
+
+	i = (i + 1) % ARRAYSIZE(_cmd_queue);
+
+	if (_queue_end != i) {
+		_queue_pos = i;
+		return 0;
+	} else {
+		_queue_pos = (i - 1) % ARRAYSIZE(_cmd_queue);
+		return -1;
+	}
+}
+
+int IMuseInternal::query_queue(int param) {
+	switch (param) {
+	case 0: // Get trigger count
+		return _trigger_count;
+	case 1: // Get trigger type
+		if (_queue_end == _queue_pos)
+			return -1;
+		return _cmd_queue[_queue_end].array[1];
+	case 2: // Get trigger sound
+		if (_queue_end == _queue_pos)
+			return 0xFF;
+		return _cmd_queue[_queue_end].array[2];
+	default:
+		return -1;
+	}
+}
+
+int IMuseInternal::setMusicVolume(uint vol) {
+	if (vol > 255)
+		vol = 255;
+	if (_music_volume == vol)
+		return 0;
+	_music_volume = vol;
+	vol = _master_volume * _music_volume / 255;
+	for (uint i = 0; i < ARRAYSIZE(_channel_volume); i++) {
+		_channel_volume_eff[i] = _channel_volume[i] * vol / 255;
+	}
+	if (!_paused)
+		update_volumes();
+	return 0;
+}
+
+int IMuseInternal::setImuseMasterVolume(uint vol) {
+	if (vol > 255)
+		vol = 255;
+	if (_master_volume == vol)
+		return 0;
+	_master_volume = vol;
+	vol = _master_volume * _music_volume / 255;
+	for (uint i = 0; i < ARRAYSIZE(_channel_volume); i++) {
+		_channel_volume_eff[i] = _channel_volume[i] * vol / 255;
+	}
+	if (!_paused)
+		update_volumes();
+	return 0;
+}
+
+int IMuseInternal::terminate1() {
+	_initialized = false;
+	stopAllSounds();
+	return 0;
+}
+
+// This is the stuff that has to be done
+// outside the monitor's mutex, otherwise
+// a deadlock occurs.
+int IMuseInternal::terminate2() {
+	if (_midi_adlib) {
+		_midi_adlib->close();
+		delete _midi_adlib;
+		_midi_adlib = 0;
+	}
+
+	if (_midi_native) {
+		_midi_native->close();
+		delete _midi_native;
+		_midi_native = 0;
+	}
+
+	return 0;
+}
+
+int IMuseInternal::enqueue_trigger(int sound, int marker) {
+	uint16 *p;
+	uint pos;
+
+	pos = _queue_pos;
+
+	p = _cmd_queue[pos].array;
+	p[0] = TRIGGER_ID;
+	p[1] = sound;
+	p[2] = marker;
+
+	pos = (pos + 1) % ARRAYSIZE(_cmd_queue);
+	if (_queue_end == pos) {
+		_queue_pos = (pos - 1) % ARRAYSIZE(_cmd_queue);
+		return -1;
+	}
+
+	_queue_pos = pos;
+	_queue_adding = true;
+	_queue_sound = sound;
+	_queue_marker = marker;
+	return 0;
+}
+
+int32 IMuseInternal::doCommand(int a, int b, int c, int d, int e, int f, int g, int h) {
+	int args[8];
+	args[0] = a;
+	args[1] = b;
+	args[2] = c;
+	args[3] = d;
+	args[4] = e;
+	args[5] = f;
+	args[6] = g;
+	args[7] = h;
+	return doCommand(8, args);
+}
+
+int32 IMuseInternal::doCommand(int numargs, int a[]) {
+	int i;
+
+	if (numargs < 1)
+		return -1;
+	byte cmd = a[0] & 0xFF;
+	byte param = a[0] >> 8;
+	Player *player = NULL;
+
+	if (!_initialized && (cmd || param))
+		return -1;
+
+#ifdef IMUSE_DEBUG
+	{
+		char string[128];
+		sprintf(string, "doCommand - %d (%d/%d)", a[0], (int)param, (int)cmd);
+		for (i = 1; i < numargs; ++i)
+			sprintf(string + strlen(string), ", %d", a[i]);
+		debug(0, string);
+	}
+#endif
+
+	if (param == 0) {
+		switch (cmd) {
+		case 6:
+			if (a[1] > 127)
+				return -1;
+			else {
+				debug(0, "IMuse doCommand(6) - setImuseMasterVolume (%d)", a[1]);
+				return setImuseMasterVolume((a[1] << 1) | (a[1] ? 0 : 1)); // Convert from 0-127 to 0-255
+			}
+		case 7:
+			debug(0, "IMuse doCommand(7) - getMasterVolume (%d)", a[1]);
+			return _master_volume / 2; // Convert from 0-255 to 0-127
+		case 8:
+			return startSound(a[1]) ? 0 : -1;
+		case 9:
+			return stopSound(a[1]);
+		case 10: // FIXME: Sam and Max - Not sure if this is correct
+			return stopAllSounds();
+		case 11:
+			return stopAllSounds();
+		case 12:
+			// Sam & Max: Player-scope commands
+			player = findActivePlayer(a[1]);
+			if (!player)
+				return -1;
+
+			switch (a[3]) {
+			case 6:
+				// Set player volume.
+				return player->setVolume(a[4]);
+			default:
+				error("IMuseInternal::doCommand(12) unsupported sub-command %d", a[3]);
+			}
+			return -1;
+		case 13:
+			return getSoundStatus(a[1]);
+		case 14:
+			// Sam and Max: Parameter fade
+			player = findActivePlayer(a[1]);
+			if (player)
+				return player->addParameterFader(a[3], a[4], a[5]);
+			return -1;
+
+		case 15:
+			// Sam & Max: Set hook for a "maybe" jump
+			player = findActivePlayer(a[1]);
+			if (player) {
+				player->setHook(0, a[3], 0);
+				return 0;
+			}
+			return -1;
+		case 16:
+			debug(0, "IMuse doCommand(16) - set_volchan (%d, %d)", a[1], a[2]);
+			return set_volchan(a[1], a[2]);
+		case 17:
+			if (g_scumm->_game.id != GID_SAMNMAX) {
+				debug(0, "IMuse doCommand(17) - set_channel_volume (%d, %d)", a[1], a[2]);
+				return set_channel_volume(a[1], a[2]);
+			} else {
+				if (a[4]) {
+					int b[16];
+					memset(b, 0, sizeof(b));
+					for (i = 0; i < numargs; ++i)
+						b[i] = a[i];
+					return ImSetTrigger(b[1], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11]);
+				} else {
+					return ImClearTrigger(a[1], a[3]);
+				}
+			}
+		case 18:
+			if (g_scumm->_game.id != GID_SAMNMAX) {
+				return set_volchan_entry(a[1], a[2]);
+			} else {
+				// Sam & Max: ImCheckTrigger.
+				// According to Mike's notes to Ender,
+				// this function returns the number of triggers
+				// associated with a particular player ID and
+				// trigger ID.
+				a[0] = 0;
+				for (i = 0; i < ARRAYSIZE(_snm_triggers); ++i) {
+					if (_snm_triggers[i].sound == a[1] && _snm_triggers[i].id &&
+					   (a[3] == -1 || _snm_triggers[i].id == a[3]))
+					{
+						++a[0];
+					}
+				}
+				return a[0];
+			}
+		case 19:
+			// Sam & Max: ImClearTrigger
+			// This should clear a trigger that's been set up
+			// with ImSetTrigger(cmd == 17). Seems to work....
+			return ImClearTrigger(a[1], a[3]);
+		case 20:
+			// Sam & Max: Deferred Command
+			addDeferredCommand(a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
+			return 0;
+		case 2:
+		case 3:
+			return 0;
+		default:
+			error("doCommand(%d [%d/%d], %d, %d, %d, %d, %d, %d, %d) unsupported", a[0], param, cmd, a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
+		}
+	} else if (param == 1) {
+		if ((1 << cmd) & 0x783FFF) {
+			player = findActivePlayer(a[1]);
+			if (!player)
+				return -1;
+			if ((1 << cmd) & (1 << 11 | 1 << 22)) {
+				assert(a[2] >= 0 && a[2] <= 15);
+				player = (Player *)player->getPart(a[2]);
+				if (!player)
+					return -1;
+			}
+		}
+
+		switch (cmd) {
+		case 0:
+			if (g_scumm->_game.id == GID_SAMNMAX) {
+				if (a[3] == 1) // Measure number
+					return ((player->getBeatIndex() - 1) >> 2) + 1;
+				else if (a[3] == 2) // Beat number
+					return player->getBeatIndex();
+				return -1;
+			} else {
+				return player->getParam(a[2], a[3]);
+			}
+		case 1:
+			if (g_scumm->_game.id == GID_SAMNMAX) {
+				// FIXME: Could someone verify this?
+				//
+				// This jump instruction is known to be used in
+				// the following cases:
+				//
+				// 1) Going anywhere on the USA map
+				// 2) Winning the Wak-A-Rat game
+				// 3) Losing or quitting the Wak-A-Rat game
+				// 4) Conroy hitting Max with a golf club
+				//
+				// For all these cases the position parameters
+				// are always the same: 2, 1, 0, 0.
+				//
+				// 5) When leaving the bigfoot party. The
+				//    position parameters are: 3, 4, 300, 0
+				// 6) At Frog Rock, when the UFO appears. The
+				//    position parameters are: 10, 4, 400, 1
+				//
+				// The last two cases used to be buggy, so I
+				// have made a change to how the last two
+				// position parameters are handled. I still do
+				// not know if it's correct, but it sounds
+				// good to me at least.
+
+				debug(0, "doCommand(%d [%d/%d], %d, %d, %d, %d, %d, %d, %d)", a[0], param, cmd, a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
+				player->jump(a[3] - 1, (a[4] - 1) * 4 + a[5], a[6] + ((a[7] * player->getTicksPerBeat()) >> 2));
+			} else
+				player->setPriority(a[2]);
+			return 0;
+		case 2:
+			return player->setVolume(a[2]);
+		case 3:
+			player->setPan(a[2]);
+			return 0;
+		case 4:
+			return player->setTranspose(a[2], a[3]);
+		case 5:
+			player->setDetune(a[2]);
+			return 0;
+		case 6:
+			player->setSpeed(a[2]);
+			return 0;
+		case 7:
+			return player->jump(a[2], a[3], a[4]) ? 0 : -1;
+		case 8:
+			return player->scan(a[2], a[3], a[4]);
+		case 9:
+			return player->setLoop(a[2], a[3], a[4], a[5], a[6]) ? 0 : -1;
+		case 10:
+			player->clearLoop();
+			return 0;
+		case 11:
+			((Part *)player)->set_onoff(a[3] != 0);
+			return 0;
+		case 12:
+			return player->setHook(a[2], a[3], a[4]);
+		case 13:
+			return player->addParameterFader(ParameterFader::pfVolume, a[2], a[3]);
+		case 14:
+			return enqueue_trigger(a[1], a[2]);
+		case 15:
+			return enqueue_command(a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
+		case 16:
+			return clear_queue();
+		case 19:
+			return player->getParam(a[2], a[3]);
+		case 20:
+			return player->setHook(a[2], a[3], a[4]);
+		case 21:
+			return -1;
+		case 22:
+			((Part *)player)->volume(a[3]);
+			return 0;
+		case 23:
+			return query_queue(a[1]);
+		case 24:
+			return 0;
+		default:
+			error("doCommand(%d [%d/%d], %d, %d, %d, %d, %d, %d, %d) unsupported", a[0], param, cmd, a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
+			return -1;
+		}
+	}
+
+	return -1;
+}
+
+int32 IMuseInternal::ImSetTrigger(int sound, int id, int a, int b, int c, int d, int e, int f, int g, int h) {
+	// Sam & Max: ImSetTrigger.
+	// Sets a trigger for a particular player and
+	// marker ID, along with doCommand parameters
+	// to invoke at the marker. The marker is
+	// represented by MIDI SysEx block 00 xx(F7)
+	// where "xx" is the marker ID.
+	uint16 oldest_trigger = 0;
+	ImTrigger *oldest_ptr = NULL;
+
+	int i;
+	ImTrigger *trig = _snm_triggers;
+	for (i = ARRAYSIZE(_snm_triggers); i; --i, ++trig) {
+		if (!trig->id)
+			break;
+		// We used to only compare 'id' and 'sound' here, but at least
+		// at the Dino Bungie Memorial that causes the music to stop
+		// after getting the T-Rex tooth. See bug #888161.
+		if (trig->id == id && trig->sound == sound && trig->command[0] == a)
+			break;
+
+		uint16 diff;
+		if (trig->expire <= _snm_trigger_index)
+			diff = _snm_trigger_index - trig->expire;
+		else
+			diff = 0x10000 - trig->expire + _snm_trigger_index;
+
+		if (!oldest_ptr || oldest_trigger < diff) {
+			oldest_ptr = trig;
+			oldest_trigger = diff;
+		}
+	}
+
+	// If we didn't find a trigger, see if we can expire one.
+	if (!i) {
+		if (!oldest_ptr)
+			return -1;
+		trig = oldest_ptr;
+	}
+
+	trig->id = id;
+	trig->sound = sound;
+	trig->expire = (++_snm_trigger_index & 0xFFFF);
+	trig->command[0] = a;
+	trig->command[1] = b;
+	trig->command[2] = c;
+	trig->command[3] = d;
+	trig->command[4] = e;
+	trig->command[5] = f;
+	trig->command[6] = g;
+	trig->command[7] = h;
+
+	// If the command is to start a sound, stop that sound if it's already playing.
+	// This fixes some carnival music problems.
+	// NOTE: We ONLY do this if the sound that will trigger the command is actually
+	// playing. Otherwise, there's a problem when exiting and re-entering the
+	// Bumpusville mansion. Ref Bug #780918.
+	if (trig->command[0] == 8 && getSoundStatus(trig->command[1]) && getSoundStatus(sound))
+		stopSound(trig->command[1]);
+	return 0;
+}
+
+int32 IMuseInternal::ImClearTrigger(int sound, int id) {
+	int count = 0;
+	int i;
+	ImTrigger *trig = _snm_triggers;
+	for (i = ARRAYSIZE(_snm_triggers); i; --i, ++trig) {
+		if ((sound == -1 || trig->sound == sound) && trig->id && (id == -1 || trig->id == id)) {
+			trig->sound = trig->id = 0;
+			++count;
+		}
+	}
+	return (count > 0) ? 0 : -1;
+}
+
+int32 IMuseInternal::ImFireAllTriggers(int sound) {
+	if (!sound)
+		return 0;
+	int count = 0;
+	int i;
+	for (i = 0; i < ARRAYSIZE(_snm_triggers); ++i) {
+		if (_snm_triggers[i].sound == sound) {
+			_snm_triggers[i].sound = _snm_triggers[i].id = 0;
+			doCommand(8, _snm_triggers[i].command);
+			++count;
+		}
+	}
+	return (count > 0) ? 0 : -1;
+}
+
+int IMuseInternal::set_channel_volume(uint chan, uint vol)
+{
+	if (chan >= 8 || vol > 127)
+		return -1;
+
+	_channel_volume[chan] = vol;
+	_channel_volume_eff[chan] = _master_volume * _music_volume * vol / 255 / 255;
+	update_volumes();
+	return 0;
+}
+
+void IMuseInternal::update_volumes() {
+	Player *player;
+	int i;
+
+	for (i = ARRAYSIZE(_players), player = _players; i != 0; i--, player++) {
+		if (player->isActive())
+			player->setVolume(player->getVolume());
+	}
+}
+
+int IMuseInternal::set_volchan_entry(uint a, uint b) {
+	if (a >= 8)
+		return -1;
+	_volchan_table[a] = b;
+	return 0;
+}
+
+int HookDatas::query_param(int param, byte chan) {
+	switch (param) {
+	case 18:
+		return _jump[0];
+	case 19:
+		return _transpose;
+	case 20:
+		return _part_onoff[chan];
+	case 21:
+		return _part_volume[chan];
+	case 22:
+		return _part_program[chan];
+	case 23:
+		return _part_transpose[chan];
+	default:
+		return -1;
+	}
+}
+
+int HookDatas::set(byte cls, byte value, byte chan) {
+	switch (cls) {
+	case 0:
+		if (value != _jump[0]) {
+			_jump[1] = _jump[0];
+			_jump[0] = value;
+		}
+		break;
+	case 1:
+		_transpose = value;
+		break;
+	case 2:
+		if (chan < 16)
+			_part_onoff[chan] = value;
+		else if (chan == 16)
+			memset(_part_onoff, value, 16);
+		break;
+	case 3:
+		if (chan < 16)
+			_part_volume[chan] = value;
+		else if (chan == 16)
+			memset(_part_volume, value, 16);
+		break;
+	case 4:
+		if (chan < 16)
+			_part_program[chan] = value;
+		else if (chan == 16)
+			memset(_part_program, value, 16);
+		break;
+	case 5:
+		if (chan < 16)
+			_part_transpose[chan] = value;
+		else if (chan == 16)
+			memset(_part_transpose, value, 16);
+		break;
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+Player *IMuseInternal::findActivePlayer(int id) {
+	int i;
+	Player *player = _players;
+
+	for (i = ARRAYSIZE(_players); i != 0; i--, player++) {
+		if (player->isActive() && player->getID() == (uint16)id)
+			return player;
+	}
+	return NULL;
+}
+
+int IMuseInternal::get_volchan_entry(uint a) {
+	if (a < 8)
+		return _volchan_table[a];
+	return -1;
+}
+
+uint32 IMuseInternal::property(int prop, uint32 value) {
+	switch (prop) {
+	case IMuse::PROP_TEMPO_BASE:
+		// This is a specified as a percentage of normal
+		// music speed. The number must be an integer
+		// ranging from 50 to 200(for 50% to 200% normal speed).
+		if (value >= 50 && value <= 200)
+			_tempoFactor = value;
+		break;
+
+	case IMuse::PROP_NATIVE_MT32:
+		_native_mt32 = (value > 0);
+		Instrument::nativeMT32(_native_mt32);
+		if (_midi_native && _native_mt32)
+			initMT32(_midi_native);
+		break;
+
+	case IMuse::PROP_GS:
+		_enable_gs = (value > 0);
+
+		// If True Roland MT-32 is not selected, run in GM or GS mode.
+		// If it is selected, change the Roland GS synth to MT-32 mode.
+		if (_midi_native && !_native_mt32)
+			initGM(_midi_native);
+		else if (_midi_native && _native_mt32 && _enable_gs) {
+			_sc55 = true;
+			initGM(_midi_native);
+		}
+		break;
+
+	case IMuse::PROP_LIMIT_PLAYERS:
+		if (value > 0 && value <= ARRAYSIZE(_players))
+			_player_limit = (int)value;
+		break;
+
+	case IMuse::PROP_RECYCLE_PLAYERS:
+		_recycle_players = (value != 0);
+		break;
+
+	case IMuse::PROP_DIRECT_PASSTHROUGH:
+		_direct_passthrough = (value != 0);
+		break;
+	}
+
+	return 0;
+}
+
+void IMuseInternal::setBase(byte **base) {
+	_base_sounds = base;
+}
+
+IMuseInternal *IMuseInternal::create(OSystem *syst, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver) {
+	IMuseInternal *i = new IMuseInternal;
+	i->initialize(syst, nativeMidiDriver, adlibMidiDriver);
+	return i;
+}
+
+int IMuseInternal::initialize(OSystem *syst, MidiDriver *native_midi, MidiDriver *adlib_midi) {
+	int i;
+
+	_midi_native = native_midi;
+	_midi_adlib = adlib_midi;
+	if (native_midi != NULL)
+		initMidiDriver(native_midi);
+	if (adlib_midi != NULL)
+		initMidiDriver(adlib_midi);
+
+	if (!_tempoFactor)
+		_tempoFactor = 100;
+	_master_volume = 255;
+
+	for (i = 0; i != 8; i++)
+		_channel_volume[i] = _channel_volume_eff[i] = _volchan_table[i] = 127;
+
+	init_players();
+	init_queue();
+	init_parts();
+
+	_initialized = true;
+
+	return 0;
+}
+
+void IMuseInternal::initMidiDriver(MidiDriver *midi) {
+	// Open MIDI driver
+	int result = midi->open();
+	if (result)
+		error("IMuse initialization - %s", MidiDriver::getErrorName(result));
+
+	// Connect to the driver's timer
+	midi->setTimerCallback(midi, &IMuseInternal::midiTimerCallback);
+}
+
+void IMuseInternal::initMT32(MidiDriver *midi) {
+	byte buffer[52];
+	char info[256] = "ScummVM ";
+	int len;
+
+	// Reset the MT-32
+	memcpy(&buffer[0], "\x41\x10\x16\x12\x7f\x00\x00\x01\x00", 9);
+	midi->sysEx(buffer, 9);
+	g_system->delayMillis(100);
+
+	// Compute version string (truncated to 20 chars max.)
+	strcat(info, gScummVMVersion);
+	len = strlen(info);
+	if (len > 20)
+		len = 20;
+
+	// Display a welcome message on MT-32 displays.
+	memcpy(&buffer[4], "\x20\x00\x00", 3);
+	memcpy(&buffer[7], "                    ", 20);
+	memcpy(buffer + 7 +(20 - len) / 2, info, len);
+	byte checksum = 0;
+	for (int i = 4; i < 27; ++i)
+		checksum -= buffer[i];
+	buffer[27] = checksum & 0x7F;
+	midi->sysEx(buffer, 28);
+	g_system->delayMillis(500);
+
+	// Setup master tune, reverb mode, reverb time, reverb level,
+	// channel mapping, partial reserve and master volume
+	memcpy(&buffer[4], "\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", 27);
+	midi->sysEx(buffer, 31);
+	g_system->delayMillis(250);
+
+	// Map percussion to notes 24 - 34 without reverb
+	memcpy(&buffer[4], "\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", 48);
+	midi->sysEx(buffer, 52);
+	g_system->delayMillis(250);
+}
+
+void IMuseInternal::initGM(MidiDriver *midi) {
+	byte buffer[11];
+	int i;
+
+	// General MIDI System On message
+	// Resets all GM devices to default settings
+	memcpy(&buffer[0], "\xF0\x7E\x7F\x09\x01\xF7", 6);
+	midi->sysEx(buffer, 6);
+	debug(2, "GM SysEx: GM System On");
+	g_system->delayMillis(200);
+
+	if (_enable_gs) {
+
+		// All GS devices recognize the GS Reset command,
+		// even with 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], "\xF0\x41\x10\x42\x12", 5);
+
+		// GS Reset
+		memcpy(&buffer[5], "\x40\x00\x7F\x00\x41\xF7", 6);
+		midi->sysEx(buffer, 11);
+		debug(2, "GS SysEx: GS Reset");
+		g_system->delayMillis(200);
+
+		if (_sc55) {
+			// This mode is for GS devices that support an MT-32-compatible
+			// Map, such as the Roland Sound Canvas line of modules. It
+			// will allow them to work with True MT-32 mode, but will
+			// obviously still ignore MT-32 SysEx (and thus custom
+			// instruments).
+
+			// 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[5], "\x40\x01\x3A\x00\x05\xF7", 6);
+		midi->sysEx(buffer, 11);
+		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->send((  0    << 16) | (100 << 8) | (0xB0 | i));
+			midi->send((  0    << 16) | (101 << 8) | (0xB0 | i));
+			midi->send((  12   << 16) | (6   << 8) | (0xB0 | i));
+			midi->send((  0    << 16) | (38  << 8) | (0xB0 | i));
+			midi->send((  127  << 16) | (100 << 8) | (0xB0 | i));
+			midi->send((  127  << 16) | (101 << 8) | (0xB0 | i));
+		}
+		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[5], "\x40\x20\x04\x04\x18\xF7", 6);
+		midi->sysEx(buffer, 11);
+		memcpy(&buffer[5], "\x40\x21\x04\x04\x17\xF7", 6);
+		midi->sysEx(buffer, 11);
+		memcpy(&buffer[5], "\x40\x22\x04\x04\x16\xF7", 6);
+		midi->sysEx(buffer, 11);
+		memcpy(&buffer[5], "\x40\x23\x04\x04\x15\xF7", 6);
+		midi->sysEx(buffer, 11);
+		memcpy(&buffer[5], "\x40\x24\x04\x04\x14\xF7", 6);
+		midi->sysEx(buffer, 11);
+		memcpy(&buffer[5], "\x40\x25\x04\x04\x13\xF7", 6);
+		midi->sysEx(buffer, 11);
+		memcpy(&buffer[5], "\x40\x26\x04\x04\x12\xF7", 6);
+		midi->sysEx(buffer, 11);
+		memcpy(&buffer[5], "\x40\x27\x04\x04\x11\xF7", 6);
+		midi->sysEx(buffer, 11);
+		memcpy(&buffer[5], "\x40\x28\x04\x04\x10\xF7", 6);
+		midi->sysEx(buffer, 11);
+		memcpy(&buffer[5], "\x40\x29\x04\x04\x0F\xF7", 6);
+		midi->sysEx(buffer, 11);
+		memcpy(&buffer[5], "\x40\x2A\x04\x04\x0E\xF7", 6);
+		midi->sysEx(buffer, 11);
+		memcpy(&buffer[5], "\x40\x2B\x04\x04\x0D\xF7", 6);
+		midi->sysEx(buffer, 11);
+		memcpy(&buffer[5], "\x40\x2C\x04\x04\x0C\xF7", 6);
+		midi->sysEx(buffer, 11);
+		memcpy(&buffer[5], "\x40\x2D\x04\x04\x0B\xF7", 6);
+		midi->sysEx(buffer, 11);
+		memcpy(&buffer[5], "\x40\x2E\x04\x04\x0A\xF7", 6);
+		midi->sysEx(buffer, 11);
+		memcpy(&buffer[5], "\x40\x2F\x04\x04\x09\xF7", 6);
+		midi->sysEx(buffer, 11);
+		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[5], "\x40\x10\x0E\x00\x22\xF7", 6);
+		midi->sysEx(buffer, 11);
+		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[5], "\x40\x01\x31\x00\x0E\xF7", 6);
+		midi->sysEx(buffer, 11);
+		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[5], "\x40\x01\x32\x04\x09\xF7", 6);
+		midi->sysEx(buffer, 11);
+		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[5], "\x40\x01\x34\x6A\x21\xF7", 6);
+		midi->sysEx(buffer, 11);
+		debug(2, "GS SysEx: Reverb Time is 106");
+	}
+}
+
+void IMuseInternal::init_queue() {
+	_queue_adding = false;
+	_queue_pos = 0;
+	_queue_end = 0;
+	_trigger_count = 0;
+}
+
+void IMuseInternal::pause(bool paused) {
+	if (_paused == paused)
+		return;
+	int vol = _music_volume;
+	if (paused)
+		_music_volume = 0;
+	update_volumes();
+	_music_volume = vol;
+
+	// Fix for Bug #817871. The MT-32 apparently fails
+	// sometimes to respond to a channel volume message
+	// (or only uses it for subsequent note events).
+	// The result is hanging notes on pause. Reportedly
+	// happens in the original distro, too. To fix that,
+	// just send AllNotesOff to the channels.
+	if (_midi_native && _native_mt32) {
+		for (int i = 0; i < 16; ++i)
+			_midi_native->send(123 << 8 | 0xB0 | i);
+	}
+
+	_paused = paused;
+}
+
+void IMuseInternal::handleDeferredCommands(MidiDriver *midi) {
+	uint32 advance = midi->getBaseTempo();
+
+	DeferredCommand *ptr = &_deferredCommands[0];
+	int i;
+	for (i = ARRAYSIZE(_deferredCommands); i; --i, ++ptr) {
+		if (!ptr->time_left)
+			continue;
+		if (ptr->time_left <= advance) {
+			doCommand(ptr->a, ptr->b, ptr->c, ptr->d, ptr->e, ptr->f, 0, 0);
+			ptr->time_left = advance;
+		}
+		ptr->time_left -= advance;
+	}
+}
+
+// "time" is interpreted as hundredths of a second.
+// FIXME: Is that correct?
+// We convert it to microseconds before prceeding
+void IMuseInternal::addDeferredCommand(int time, int a, int b, int c, int d, int e, int f) {
+	DeferredCommand *ptr = &_deferredCommands[0];
+	int i;
+	for (i = ARRAYSIZE(_deferredCommands); i; --i, ++ptr) {
+		if (!ptr->time_left)
+			break;
+	}
+
+	if (i) {
+		ptr->time_left = time * 10000;
+		ptr->a = a;
+		ptr->b = b;
+		ptr->c = c;
+		ptr->d = d;
+		ptr->e = e;
+		ptr->f = f;
+	}
+}
+
+////////////////////////////////////////////////////////////
+//
+// IMuseInternal load/save implementation
+//
+////////////////////////////////////////////////////////////
+
+int IMuseInternal::save_or_load(Serializer *ser, ScummEngine *scumm) {
+	const SaveLoadEntry mainEntries[] = {
+		MKLINE(IMuseInternal, _queue_end, sleUint8, VER(8)),
+		MKLINE(IMuseInternal, _queue_pos, sleUint8, VER(8)),
+		MKLINE(IMuseInternal, _queue_sound, sleUint16, VER(8)),
+		MKLINE(IMuseInternal, _queue_adding, sleByte, VER(8)),
+		MKLINE(IMuseInternal, _queue_marker, sleByte, VER(8)),
+		MKLINE(IMuseInternal, _queue_cleared, sleByte, VER(8)),
+		MKLINE(IMuseInternal, _master_volume, sleByte, VER(8)),
+		MKLINE(IMuseInternal, _trigger_count, sleUint16, VER(8)),
+		MKLINE(IMuseInternal, _snm_trigger_index, sleUint16, VER(54)),
+		MKARRAY(IMuseInternal, _channel_volume[0], sleUint16, 8, VER(8)),
+		MKARRAY(IMuseInternal, _volchan_table[0], sleUint16, 8, VER(8)),
+		MKEND()
+	};
+
+	const SaveLoadEntry cmdQueueEntries[] = {
+		MKARRAY(CommandQueue, array[0], sleUint16, 8, VER(23)),
+		MKEND()
+	};
+
+	// VolumeFader is obsolete.
+	const SaveLoadEntry volumeFaderEntries[] = {
+		MK_OBSOLETE(VolumeFader, player, sleUint16, VER(8), VER(16)),
+		MK_OBSOLETE(VolumeFader, active, sleUint8, VER(8), VER(16)),
+		MK_OBSOLETE(VolumeFader, curvol, sleUint8, VER(8), VER(16)),
+		MK_OBSOLETE(VolumeFader, speed_lo_max, sleUint16, VER(8), VER(16)),
+		MK_OBSOLETE(VolumeFader, num_steps, sleUint16, VER(8), VER(16)),
+		MK_OBSOLETE(VolumeFader, speed_hi, sleInt8, VER(8), VER(16)),
+		MK_OBSOLETE(VolumeFader, direction, sleInt8, VER(8), VER(16)),
+		MK_OBSOLETE(VolumeFader, speed_lo, sleInt8, VER(8), VER(16)),
+		MK_OBSOLETE(VolumeFader, speed_lo_counter, sleUint16, VER(8), VER(16)),
+		MKEND()
+	};
+
+	const SaveLoadEntry snmTriggerEntries[] = {
+		MKLINE(ImTrigger, sound, sleInt16, VER(54)),
+		MKLINE(ImTrigger, id, sleByte, VER(54)),
+		MKLINE(ImTrigger, expire, sleUint16, VER(54)),
+		MKARRAY(ImTrigger, command[0], sleUint16, 8, VER(54)),
+		MKEND()
+	};
+
+	int i;
+
+	ser->saveLoadEntries(this, mainEntries);
+	ser->saveLoadArrayOf(_cmd_queue, ARRAYSIZE(_cmd_queue), sizeof(_cmd_queue[0]), cmdQueueEntries);
+	ser->saveLoadArrayOf(_snm_triggers, ARRAYSIZE(_snm_triggers), sizeof(_snm_triggers[0]), snmTriggerEntries);
+
+	// The players
+	for (i = 0; i < ARRAYSIZE(_players); ++i)
+		_players[i].saveLoadWithSerializer(ser);
+	
+	// The parts
+	for (i = 0; i < ARRAYSIZE(_parts); ++i)
+		_parts[i].saveLoadWithSerializer(ser);
+
+	{ // Load/save the instrument definitions, which were revamped with V11.
+		Part *part = &_parts[0];
+		if (ser->getVersion() >= VER(11)) {
+			for (i = ARRAYSIZE(_parts); i; --i, ++part) {
+				part->_instrument.saveOrLoad(ser);
+			}
+		} else {
+			for (i = ARRAYSIZE(_parts); i; --i, ++part)
+				part->_instrument.clear();
+		}
+	}
+
+	// VolumeFader has been replaced with the more generic ParameterFader.
+	// FIXME: replace this loop by something like
+	// if (loading && version <= 16)  ser->skip(XXX bytes);
+	for (i = 0; i < 8; ++i)
+		ser->saveLoadEntries(0, volumeFaderEntries);
+
+	if (ser->isLoading()) {
+		// Load all sounds that we need
+		fix_players_after_load(scumm);
+		fix_parts_after_load();
+		setImuseMasterVolume(_master_volume);
+
+		if (_midi_native)
+			reallocateMidiChannels(_midi_native);
+		if (_midi_adlib)
+			reallocateMidiChannels(_midi_adlib);
+	}
+
+	return 0;
+}
+
+void IMuseInternal::fix_parts_after_load() {
+	Part *part;
+	int i;
+
+	for (i = ARRAYSIZE(_parts), part = _parts; i != 0; i--, part++) {
+		if (part->_player)
+			part->fix_after_load();
+	}
+}
+
+// Only call this routine from the main thread,
+// since it uses getResourceAddress
+void IMuseInternal::fix_players_after_load(ScummEngine *scumm) {
+	Player *player = _players;
+	int i;
+
+	for (i = ARRAYSIZE(_players); i != 0; i--, player++) {
+		if (player->isActive()) {
+			scumm->getResourceAddress(rtSound, player->getID());
+			player->fixAfterLoad();
+		}
+	}
+}
+
+Part::Part() {
+	_slot = 0;
+	_next = 0;
+	_prev = 0;
+	_mc = 0;
+	_player = 0;
+	_pitchbend = 0;
+	_pitchbend_factor = 0;
+	_transpose = 0;
+	_transpose_eff = 0;
+	_vol = 0;
+	_vol_eff = 0;
+	_detune = 0;
+	_detune_eff = 0;
+	_pan = 0;
+	_pan_eff = 0;
+	_on = false;
+	_modwheel = 0;
+	_pedal = false;
+	_pri = 0;
+	_pri_eff = 0;
+	_chan = 0;
+	_effect_level = 0;
+	_chorus = 0;
+	_percussion = 0;
+	_bank = 0;
+	_unassigned_instrument = false;
+}
+
+void Part::saveLoadWithSerializer(Serializer *ser) {
+	const SaveLoadEntry partEntries[] = {
+		MKLINE(Part, _pitchbend, sleInt16, VER(8)),
+		MKLINE(Part, _pitchbend_factor, sleUint8, VER(8)),
+		MKLINE(Part, _transpose, sleInt8, VER(8)),
+		MKLINE(Part, _vol, sleUint8, VER(8)),
+		MKLINE(Part, _detune, sleInt8, VER(8)),
+		MKLINE(Part, _pan, sleInt8, VER(8)),
+		MKLINE(Part, _on, sleUint8, VER(8)),
+		MKLINE(Part, _modwheel, sleUint8, VER(8)),
+		MKLINE(Part, _pedal, sleUint8, VER(8)),
+		MK_OBSOLETE(Part, _program, sleUint8, VER(8), VER(16)),
+		MKLINE(Part, _pri, sleUint8, VER(8)),
+		MKLINE(Part, _chan, sleUint8, VER(8)),
+		MKLINE(Part, _effect_level, sleUint8, VER(8)),
+		MKLINE(Part, _chorus, sleUint8, VER(8)),
+		MKLINE(Part, _percussion, sleUint8, VER(8)),
+		MKLINE(Part, _bank, sleUint8, VER(8)),
+		MKEND()
+	};
+
+	int num;
+	if (ser->isSaving()) {
+		num = (_next ? (_next - _se->_parts + 1) : 0);
+		ser->saveUint16(num);
+
+		num = (_prev ? (_prev - _se->_parts + 1) : 0);
+		ser->saveUint16(num);
+
+		num = (_player ? (_player - _se->_players + 1) : 0);
+		ser->saveUint16(num);
+	} else {
+		num = ser->loadUint16();
+		_next = (num ? &_se->_parts[num - 1] : 0);
+
+		num = ser->loadUint16();
+		_prev = (num ? &_se->_parts[num - 1] : 0);
+
+		num = ser->loadUint16();
+		_player = (num ? &_se->_players[num - 1] : 0);
+	}
+	ser->saveLoadEntries(this, partEntries);
+}
+
+void Part::set_detune(int8 detune) {
+	_detune_eff = clamp((_detune = detune) + _player->getDetune(), -128, 127);
+	if (_mc)
+		sendPitchBend();
+}
+
+void Part::pitchBend(int16 value) {
+	_pitchbend = value;
+	if (_mc)
+		sendPitchBend();
+}
+
+void Part::volume(byte value) {
+	_vol_eff = ((_vol = value) + 1) * _player->getEffectiveVolume() >> 7;
+	if (_mc)
+		_mc->volume(_vol_eff);
+}
+
+void Part::set_pri(int8 pri) {
+	_pri_eff = clamp((_pri = pri) + _player->getPriority(), 0, 255);
+	if (_mc)
+		_mc->priority(_pri_eff);
+}
+
+void Part::set_pan(int8 pan) {
+	_pan_eff = clamp((_pan = pan) + _player->getPan(), -64, 63);
+	if (_mc)
+		_mc->panPosition(_pan_eff + 0x40);
+}
+
+void Part::set_transpose(int8 transpose) {
+	_transpose_eff = transpose_clamp((_transpose = transpose) + _player->getTranspose(), -24, 24);
+	if (_mc)
+		sendPitchBend();
+}
+
+void Part::sustain(bool value) {
+	_pedal = value;
+	if (_mc)
+		_mc->sustain(value);
+}
+
+void Part::modulationWheel(byte value) {
+	_modwheel = value;
+	if (_mc)
+		_mc->modulationWheel(value);
+}
+
+void Part::chorusLevel(byte value) {
+	_chorus = value;
+	if (_mc)
+		_mc->chorusLevel(value);
+}
+
+void Part::effectLevel(byte value)
+{
+	_effect_level = value;
+	if (_mc)
+		_mc->effectLevel(value);
+}
+
+void Part::fix_after_load() {
+	set_transpose(_transpose);
+	volume(_vol);
+	set_detune(_detune);
+	set_pri(_pri);
+	set_pan(_pan);
+	sendAll();
+}
+
+void Part::pitchBendFactor(byte value) {
+	if (value > 12)
+		return;
+	pitchBend(0);
+	_pitchbend_factor = value;
+	if (_mc)
+		_mc->pitchBendFactor(value);
+}
+
+void Part::set_onoff(bool on) {
+	if (_on != on) {
+		_on = on;
+		if (!on)
+			off();
+		if (!_percussion)
+			_player->_se->reallocateMidiChannels(_player->getMidiDriver());
+	}
+}
+
+void Part::set_instrument(byte * data) {
+	_instrument.adlib(data);
+	if (clearToTransmit())
+		_instrument.send(_mc);
+}
+
+void Part::load_global_instrument(byte slot) {
+	_player->_se->copyGlobalAdlibInstrument(slot, &_instrument);
+	if (clearToTransmit())
+		_instrument.send(_mc);
+}
+
+void Part::noteOn(byte note, byte velocity) {
+	if (!_on)
+		return;
+
+	MidiChannel *mc = _mc;
+
+	// DEBUG
+	if (_unassigned_instrument && !_percussion) {
+		_unassigned_instrument = false;
+		if (!_instrument.isValid()) {
+			debug(0, "[%02d] No instrument specified", (int)_chan);
+			return;
+		}
+	}
+
+	if (mc && _instrument.isValid()) {
+		mc->noteOn(note, velocity);
+	} else if (_percussion) {
+		mc = _player->getMidiDriver()->getPercussionChannel();
+		if (!mc)
+			return;
+		static byte prev_vol_eff = 128;
+		if (_vol_eff != prev_vol_eff){
+			mc->volume(_vol_eff);
+			prev_vol_eff = _vol_eff;
+		}
+		if ((note < 35) && (!_player->_se->isNativeMT32()))
+			note = Instrument::_gmRhythmMap[note];
+
+		mc->noteOn(note, velocity);
+	}
+}
+
+void Part::noteOff(byte note) {
+	if (!_on)
+		return;
+
+	MidiChannel *mc = _mc;
+	if (mc) {
+		mc->noteOff(note);
+	} else if (_percussion) {
+		mc = _player->getMidiDriver()->getPercussionChannel();
+		if (mc)
+			mc->noteOff(note);
+	}
+}
+
+void Part::init() {
+	_player = NULL;
+	_next = NULL;
+	_prev = NULL;
+	_mc = NULL;
+}
+
+void Part::setup(Player *player) {
+	_player = player;
+
+	_percussion = (player->isMIDI() && _chan == 9); // true;
+	_on = true;
+	_pri_eff = player->getPriority();
+	_pri = 0;
+	_vol = 127;
+	_vol_eff = player->getEffectiveVolume();
+	_pan = clamp(player->getPan(), -64, 63);
+	_transpose_eff = player->getTranspose();
+	_transpose = 0;
+	_detune = 0;
+	_detune_eff = player->getDetune();
+	_pitchbend_factor = 2;
+	_pitchbend = 0;
+	_effect_level = 64;
+	_instrument.clear();
+	_unassigned_instrument = true;
+	_chorus = 0;
+	_modwheel = 0;
+	_bank = 0;
+	_pedal = false;
+	_mc = NULL;
+}
+
+void Part::uninit() {
+	if (!_player)
+		return;
+	off();
+	_player->removePart(this);
+	_player = NULL;
+}
+
+void Part::off() {
+	if (_mc) {
+		_mc->allNotesOff();
+		_mc->release();
+		_mc = NULL;
+	}
+}
+
+bool Part::clearToTransmit() {
+	if (_mc)
+		return true;
+	if (_instrument.isValid())
+		_player->_se->reallocateMidiChannels(_player->getMidiDriver());
+	return false;
+}
+
+void Part::sendAll() {
+	if (!clearToTransmit())
+		return;
+	_mc->pitchBendFactor(_pitchbend_factor);
+	sendPitchBend();
+	_mc->volume(_vol_eff);
+	_mc->sustain(_pedal);
+	_mc->modulationWheel(_modwheel);
+	_mc->panPosition(_pan_eff + 0x40);
+	_mc->effectLevel(_effect_level);
+	if (_instrument.isValid())
+		_instrument.send(_mc);
+	_mc->chorusLevel(_chorus);
+	_mc->priority(_pri_eff);
+}
+
+void Part::sendPitchBend() {
+	int16 bend = _pitchbend;
+	// RPN-based pitchbend range doesn't work for the MT32,
+	// so we'll do the scaling ourselves.
+	if (_player->_se->isNativeMT32())
+		bend = bend * _pitchbend_factor / 12;
+	_mc->pitchBend(clamp(bend + (_detune_eff * 64 / 12) + (_transpose_eff * 8192 / 12), -8192, 8191));
+}
+
+void Part::programChange(byte value) {
+	_bank = 0;
+	_instrument.program(value, _player->isMT32());
+	if (clearToTransmit())
+		_instrument.send(_mc);
+}
+
+void Part::set_instrument(uint b) {
+	_bank = (byte)(b >> 8);
+	if (_bank)
+		error("Non-zero instrument bank selection. Please report this");
+	_instrument.program((byte)b, _player->isMT32());
+	if (clearToTransmit())
+		_instrument.send(_mc);
+}
+
+void Part::allNotesOff() {
+	if (!_mc)
+		return;
+	_mc->allNotesOff();
+}
+
+////////////////////////////////////////
+//
+// Some more IMuseInternal stuff
+//
+////////////////////////////////////////
+
+void IMuseInternal::midiTimerCallback(void *data) {
+	MidiDriver *driver = (MidiDriver *)data;
+	if (g_scumm->_imuse)
+		g_scumm->_imuse->on_timer(driver);
+}
+
+void IMuseInternal::reallocateMidiChannels(MidiDriver *midi) {
+	Part *part, *hipart;
+	int i;
+	byte hipri, lopri;
+	Part *lopart;
+
+	while (true) {
+		hipri = 0;
+		hipart = NULL;
+		for (i = 32, part = _parts; i; i--, part++) {
+			if (part->_player && part->_player->getMidiDriver() == midi &&
+						!part->_percussion && part->_on &&
+						!part->_mc && part->_pri_eff >= hipri) {
+				hipri = part->_pri_eff;
+				hipart = part;
+			}
+		}
+
+		if (!hipart)
+			return;
+
+		if ((hipart->_mc = midi->allocateChannel()) == NULL) {
+			lopri = 255;
+			lopart = NULL;
+			for (i = 32, part = _parts; i; i--, part++) {
+				if (part->_mc && part->_mc->device() == midi && part->_pri_eff <= lopri) {
+					lopri = part->_pri_eff;
+					lopart = part;
+				}
+			}
+
+			if (lopart == NULL || lopri >= hipri)
+				return;
+			lopart->off();
+
+			if ((hipart->_mc = midi->allocateChannel()) == NULL)
+				return;
+		}
+		hipart->sendAll();
+	}
+}
+
+void IMuseInternal::setGlobalAdlibInstrument(byte slot, byte *data) {
+	if (slot < 32) {
+		_global_adlib_instruments[slot].adlib(data);
+	}
+}
+
+void IMuseInternal::copyGlobalAdlibInstrument(byte slot, Instrument *dest) {
+	if (slot >= 32)
+		return;
+	_global_adlib_instruments[slot].copy_to(dest);
+}
+
+////////////////////////////////////////////////////////////
+//
+// IMuse implementation
+//
+// IMuse actually serves as a concurency monitor front-end
+// to IMuseInternal and ensures that only one thread
+// accesses the object at a time. This is necessary to
+// prevent scripts and the MIDI parser from yanking objects
+// out from underneath each other.
+//
+////////////////////////////////////////////////////////////
+
+IMuse::IMuse(OSystem *system, IMuseInternal *target)
+	: _system(system), _target(target) {
+	_mutex = system->createMutex();
+}
+
+IMuse::~IMuse() {
+	if (_mutex)
+		_system->deleteMutex(_mutex);
+	if (_target)
+		delete _target;
+}
+
+inline void IMuse::in() const {
+	_system->lockMutex(_mutex);
+}
+inline void IMuse::out() const {
+	_system->unlockMutex(_mutex);
+}
+
+void IMuse::on_timer(MidiDriver *midi) { in(); _target->on_timer(midi); out(); }
+void IMuse::pause(bool paused) { in(); _target->pause(paused); out(); }
+int IMuse::save_or_load(Serializer *ser, ScummEngine *scumm) { in(); int ret = _target->save_or_load(ser, scumm); out(); return ret; }
+void IMuse::setMusicVolume(int vol) { in(); _target->setMusicVolume(vol); out(); }
+void IMuse::startSound(int sound) { in(); _target->startSound(sound); out(); }
+void IMuse::stopSound(int sound) { in(); _target->stopSound(sound); out(); }
+void IMuse::stopAllSounds() { in(); _target->stopAllSounds(); out(); }
+int IMuse::getSoundStatus(int sound) const { in(); int ret = _target->getSoundStatus(sound, true); out(); return ret; }
+bool IMuse::get_sound_active(int sound) const { in(); bool ret = _target->getSoundStatus(sound, false) ? 1 : 0; out(); return ret; }
+int IMuse::getMusicTimer() const { in(); int ret = _target->getMusicTimer(); out(); return ret; }
+int32 IMuse::doCommand(int a, int b, int c, int d, int e, int f, int g, int h) { in(); int32 ret = _target->doCommand(a,b,c,d,e,f,g,h); out(); return ret; }
+int32 IMuse::doCommand(int numargs, int args[]) { in(); int32 ret = _target->doCommand(numargs, args); out(); return ret; }
+int IMuse::clear_queue() { in(); int ret = _target->clear_queue(); out(); return ret; }
+void IMuse::setBase(byte **base) { in(); _target->setBase(base); out(); }
+uint32 IMuse::property(int prop, uint32 value) { in(); uint32 ret = _target->property(prop, value); out(); return ret; }
+void IMuse::terminate() { in(); _target->terminate1(); out(); _target->terminate2(); }
+
+// The IMuse::create method provides a front-end factory
+// for creating IMuseInternal without exposing that class
+// to the client.
+IMuse *IMuse::create(OSystem *syst, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver) {
+	IMuseInternal *engine = IMuseInternal::create(syst, nativeMidiDriver, adlibMidiDriver);
+	return new IMuse(syst, engine);
+}
+
+} // End of namespace Scumm

Copied: scummvm/trunk/engines/scumm/imuse/imuse.h (from rev 20787, scummvm/trunk/engines/scumm/imuse.h)
===================================================================
--- scummvm/trunk/engines/scumm/imuse/imuse.h	                        (rev 0)
+++ scummvm/trunk/engines/scumm/imuse/imuse.h	2006-02-20 20:57:26 UTC (rev 20801)
@@ -0,0 +1,85 @@
+/* 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 IMUSE_H
+#define IMUSE_H
+
+#include "common/scummsys.h"
+#include "common/mutex.h"
+#include "scumm/music.h"
+
+class MidiDriver;
+class OSystem;
+
+namespace Scumm {
+
+class IMuseInternal;
+class ScummEngine;
+class Serializer;
+
+class IMuse : public MusicEngine {
+private:
+	OSystem *_system;
+	IMuseInternal *_target;
+	mutable Common::MutexRef _mutex;
+
+	IMuse(OSystem *system, IMuseInternal *target);
+	void in() const;
+	void out() const;
+
+public:
+	~IMuse();
+
+	enum {
+		PROP_TEMPO_BASE,
+		PROP_NATIVE_MT32,
+		PROP_GS,
+		PROP_LIMIT_PLAYERS,
+		PROP_RECYCLE_PLAYERS,
+		PROP_DIRECT_PASSTHROUGH
+	};
+
+	void on_timer(MidiDriver *midi);
+	void pause(bool paused);
+	int save_or_load(Serializer *ser, ScummEngine *scumm);
+	void setMusicVolume(int vol);
+	void startSound(int sound);
+	void stopSound(int sound);
+	void stopAllSounds();
+	int getSoundStatus(int sound) const;
+	bool get_sound_active(int sound) const;
+	int getMusicTimer() const;
+	int32 doCommand(int a, int b, int c, int d, int e, int f, int g, int h);
+	int32 doCommand(int numargs, int args[]);
+	int clear_queue();
+	void setBase(byte **base);
+	uint32 property(int prop, uint32 value);
+	void terminate();
+
+	// Factory methods
+	static IMuse *create(OSystem *syst, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver);
+};
+
+} // End of namespace Scumm
+
+#endif

Copied: scummvm/trunk/engines/scumm/imuse/imuse_internal.h (from rev 20787, scummvm/trunk/engines/scumm/imuse_internal.h)
===================================================================
--- scummvm/trunk/engines/scumm/imuse/imuse_internal.h	                        (rev 0)
+++ scummvm/trunk/engines/scumm/imuse/imuse_internal.h	2006-02-20 20:57:26 UTC (rev 20801)
@@ -0,0 +1,472 @@
+/* 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_IMUSE_INTERNAL
+#define DEFINED_IMUSE_INTERNAL
+
+#include "common/scummsys.h"
+#include "scumm/imuse/instrument.h"
+#include "scumm/saveload.h"
+#include "sound/mididrv.h"
+
+class MidiParser;
+class OSystem;
+
+namespace Scumm {
+
+// Unremark this statement to activate some of
+// the most common iMuse diagnostic messages.
+// #define IMUSE_DEBUG
+
+struct ParameterFader;
+struct DeferredCommand;
+struct ImTrigger;
+struct SustainingNotes;
+struct CommandQueue;
+struct IsNoteCmdData;
+class  Player;
+struct Part;
+class  IMuseInternal;
+
+// Some entities also referenced
+class ScummEngine;
+
+
+
+//////////////////////////////////////////////////
+//
+// Some constants
+//
+//////////////////////////////////////////////////
+
+#define TICKS_PER_BEAT 480
+
+#define TRIGGER_ID 0
+#define COMMAND_ID 1
+
+#define MDPG_TAG "MDpg"
+
+
+////////////////////////////////////////
+//
+//  Helper functions
+//
+////////////////////////////////////////
+
+inline int clamp(int val, int min, int max) {
+	if (val < min)
+		return min;
+	if (val > max)
+		return max;
+	return val;
+}
+
+inline int transpose_clamp(int a, int b, int c) {
+	if (b > a)
+		a += (b - a + 11) / 12 * 12;
+	if (c < a)
+		a -= (a - c + 11) / 12 * 12;
+	return a;
+}
+
+
+
+//////////////////////////////////////////////////
+//
+// Entity declarations
+//
+//////////////////////////////////////////////////
+
+struct HookDatas {
+	byte _jump[2];
+	byte _transpose;
+	byte _part_onoff[16];
+	byte _part_volume[16];
+	byte _part_program[16];
+	byte _part_transpose[16];
+
+	int query_param(int param, byte chan);
+	int set(byte cls, byte value, byte chan);
+	HookDatas() { memset(this, 0, sizeof(HookDatas)); }
+};
+
+struct ParameterFader {
+	enum {
+		pfVolume = 1,
+		pfTranspose = 3,
+		pfSpeed = 4
+	};
+
+	int param;
+	int start;
+	int end;
+	uint32 total_time;
+	uint32 current_time;
+
+	ParameterFader() { param = 0; }
+	void init() { param = 0; }
+};
+
+struct DeferredCommand {
+	uint32 time_left;
+	int a, b, c, d, e, f;
+	DeferredCommand() { memset(this, 0, sizeof(DeferredCommand)); }
+};
+
+struct ImTrigger {
+	int sound;
+	byte id;
+	uint16 expire;
+	int command [8];
+	ImTrigger() { memset(this, 0, sizeof(ImTrigger)); }
+};
+
+struct CommandQueue {
+	uint16 array[8];
+	CommandQueue() { memset(this, 0, sizeof(CommandQueue)); }
+};
+
+class Player : public MidiDriver {
+protected:
+	// Moved from IMuseInternal.
+	// This is only used by one player at a time.
+	static uint16 _active_notes[128];
+
+protected:
+	MidiDriver *_midi;
+	MidiParser *_parser;
+	bool _passThrough; // Only respond to EOT, all else direct to MidiDriver
+
+	Part *_parts;
+	bool _active;
+	bool _scanning;
+	int _id;
+	byte _priority;
+	byte _volume;
+	int8 _pan;
+	int8 _transpose;
+	int8 _detune;
+	byte _vol_eff;
+
+	uint _track_index;
+	uint _loop_to_beat;
+	uint _loop_from_beat;
+	uint _loop_counter;
+	uint _loop_to_tick;
+	uint _loop_from_tick;
+	byte _speed;
+	bool _abort;
+
+	// This does not get used by us! It is only
+	// here for save/load purposes, and gets
+	// passed on to the MidiParser during
+	// fixAfterLoad().
+	uint32 _music_tick;
+
+	HookDatas _hook;
+	ParameterFader _parameterFaders[4];
+
+	bool _isMT32;
+	bool _isMIDI;
+
+protected:
+	// Player part
+	void hook_clear();
+	void uninit_parts();
+	byte *parse_midi(byte *s);
+	void part_set_transpose(uint8 chan, byte relative, int8 b);
+	void parse_sysex(byte *p, uint len);
+	void maybe_jump(byte cmd, uint track, uint beat, uint tick);
+	void maybe_set_transpose(byte *data);
+	void maybe_part_onoff(byte *data);
+	void maybe_set_volume(byte *data);
+	void maybe_set_program(byte *data);
+	void maybe_set_transpose_part(byte *data);
+	void turn_off_pedals();
+	int  query_part_param(int param, byte chan);
+	void turn_off_parts();
+	void play_active_notes();
+
+	void transitionParameters();
+
+	static void decode_sysex_bytes(const byte *src, byte *dst, int len);
+
+	// Sequencer part
+	int start_seq_sound(int sound, bool reset_vars = true);
+	int query_param(int param);
+
+public:
+	IMuseInternal *_se;
+	uint _vol_chan;
+
+public:
+	Player();
+	virtual ~Player();
+
+	int	 addParameterFader(int param, int target, int time);
+	void clear();
+	void clearLoop();
+	void fixAfterLoad();
+	Part * getActivePart(uint8 part);
+	uint getBeatIndex();
+	int8 getDetune() const { return _detune; }
+	byte getEffectiveVolume() const { return _vol_eff; }
+	int getID() const { return _id; }
+	MidiDriver *getMidiDriver() const { return _midi; }
+	int getParam(int param, byte chan);
+	int8 getPan() const { return _pan; }
+	Part * getPart(uint8 part);
+	byte getPriority() const { return _priority; }
+	uint getTicksPerBeat() const { return TICKS_PER_BEAT; }
+	int8 getTranspose() const { return _transpose; }
+	byte getVolume() const { return _volume; }
+	bool isActive() const { return _active; }
+	bool isFadingOut() const;
+	bool isMIDI() const { return _isMIDI; }
+	bool isMT32() const { return _isMT32; }
+	bool jump(uint track, uint beat, uint tick);
+	void onTimer();
+	void removePart(Part *part);
+	int scan(uint totrack, uint tobeat, uint totick);
+	void saveLoadWithSerializer(Serializer *ser);
+	int setHook(byte cls, byte value, byte chan) { return _hook.set(cls, value, chan); }
+	void setDetune(int detune);
+	bool setLoop(uint count, uint tobeat, uint totick, uint frombeat, uint fromtick);
+	void setPan(int pan);
+	void setPriority(int pri);
+	void setSpeed(byte speed);
+	int setTranspose(byte relative, int b);
+	int setVolume(byte vol);
+	bool startSound(int sound, MidiDriver *midi, bool passThrough);
+	int getMusicTimer() const;
+
+public:
+	// MidiDriver interface
+	int open() { return 0; }
+	void close() { }
+	void send(uint32 b);
+	const char *getErrorName(int error_code) { return "Unknown"; }
+	void sysEx(byte *msg, uint16 length);
+	void metaEvent(byte type, byte *data, uint16 length);
+	void setTimerCallback(void *timer_param, void(*timer_proc)(void *)) { }
+	uint32 getBaseTempo();
+	MidiChannel *allocateChannel() { return 0; }
+	MidiChannel *getPercussionChannel() { return 0; }
+};
+
+struct Part : public Serializable {
+	IMuseInternal *_se;
+	int _slot;
+	Part *_next, *_prev;
+	MidiChannel *_mc;
+	Player *_player;
+	int16 _pitchbend;
+	byte _pitchbend_factor;
+	int8 _transpose, _transpose_eff;
+	byte _vol, _vol_eff;
+	int8 _detune, _detune_eff;
+	int8 _pan, _pan_eff;
+	bool _on;
+	byte _modwheel;
+	bool _pedal;
+	int8 _pri;
+	byte _pri_eff;
+	byte _chan;
+	byte _effect_level;
+	byte _chorus;
+	byte _percussion;
+	byte _bank;
+
+	// New abstract instrument definition
+	Instrument _instrument;
+	bool _unassigned_instrument; // For diagnostic reporting purposes only
+
+	// MidiChannel interface
+	// (We don't currently derive from MidiChannel,
+	//  but if we ever do, this will make it easy.)
+	void noteOff(byte note);
+	void noteOn(byte note, byte velocity);
+	void programChange(byte value);
+	void pitchBend(int16 value);
+	void modulationWheel(byte value);
+	void volume(byte value);
+	void pitchBendFactor(byte value);
+	void sustain(bool value);
+	void effectLevel(byte value);
+	void chorusLevel(byte value);
+	void allNotesOff();
+
+	void set_param(byte param, int value) { }
+	void init();
+	void setup(Player *player);
+	void uninit();
+	void off();
+	void set_instrument(uint b);
+	void set_instrument(byte *data);
+	void load_global_instrument(byte b);
+
+	void set_transpose(int8 transpose);
+	void set_detune(int8 detune);
+	void set_pri(int8 pri);
+	void set_pan(int8 pan);
+
+	void set_onoff(bool on);
+	void fix_after_load();
+
+	void sendAll();
+	void sendPitchBend();
+	bool clearToTransmit();
+
+	Part();
+
+	void saveLoadWithSerializer(Serializer *ser);
+};
+
+// WARNING: This is the internal variant of the IMUSE class.
+// imuse.h contains a public version of the same class.
+// the public version, only contains a set of methods.
+class IMuseInternal {
+	friend class Player;
+	friend struct Part;
+
+protected:
+	bool _native_mt32;
+	bool _enable_gs;
+	bool _sc55;
+	MidiDriver *_midi_adlib;
+	MidiDriver *_midi_native;
+
+	byte **_base_sounds;
+
+protected:
+	bool _paused;
+	bool _initialized;
+
+	int _tempoFactor;
+
+	int  _player_limit;       // Limits how many simultaneous music tracks are played
+	bool _recycle_players;    // Can we stop a player in order to start another one?
+	bool _direct_passthrough; // Pass data direct to MidiDriver (no interactivity)
+
+	uint _queue_end, _queue_pos, _queue_sound;
+	byte _queue_adding;
+
+	byte _queue_marker;
+	byte _queue_cleared;
+	byte _master_volume; // Master volume. 0-255
+	byte _music_volume; // Global music volume. 0-255
+
+	uint16 _trigger_count;
+	ImTrigger _snm_triggers[16]; // Sam & Max triggers
+	uint16 _snm_trigger_index;
+
+	uint16 _channel_volume[8];
+	uint16 _channel_volume_eff[8]; // No Save
+	uint16 _volchan_table[8];
+
+	Player _players[8];
+	Part _parts[32];
+
+	Instrument _global_adlib_instruments[32];
+	CommandQueue _cmd_queue[64];
+	DeferredCommand _deferredCommands[4];
+
+protected:
+	byte *findStartOfSound(int sound);
+	bool isMT32(int sound);
+	bool isMIDI(int sound);
+	int get_queue_sound_status(int sound) const;
+	void handle_marker(uint id, byte data);
+	int get_channel_volume(uint a);
+	void initMidiDriver(MidiDriver *midi);
+	void initGM(MidiDriver *midi);
+	void initMT32(MidiDriver *midi);
+	void init_players();
+	void init_parts();
+	void init_queue();
+
+	void sequencer_timers(MidiDriver *midi);
+
+	MidiDriver *getBestMidiDriver(int sound);
+	Player *allocate_player(byte priority);
+	Part *allocate_part(byte pri, MidiDriver *midi);
+
+	int32 ImSetTrigger(int sound, int id, int a, int b, int c, int d, int e, int f, int g, int h);
+	int32 ImClearTrigger(int sound, int id);
+	int32 ImFireAllTriggers(int sound);
+
+	void addDeferredCommand(int time, int a, int b, int c, int d, int e, int f);
+	void handleDeferredCommands(MidiDriver *midi);
+
+	int enqueue_command(int a, int b, int c, int d, int e, int f, int g);
+	int enqueue_trigger(int sound, int marker);
+	int query_queue(int param);
+	Player *findActivePlayer(int id);
+
+	int get_volchan_entry(uint a);
+	int set_volchan_entry(uint a, uint b);
+	int set_channel_volume(uint chan, uint vol);
+	void update_volumes();
+	void reset_tick();
+
+	int set_volchan(int sound, int volchan);
+
+	void fix_parts_after_load();
+	void fix_players_after_load(ScummEngine *scumm);
+
+	static void midiTimerCallback(void *data);
+
+public:
+	IMuseInternal();
+
+	int initialize(OSystem *syst, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver);
+	void reallocateMidiChannels(MidiDriver *midi);
+	void setGlobalAdlibInstrument(byte slot, byte *data);
+	void copyGlobalAdlibInstrument(byte slot, Instrument *dest);
+	bool isNativeMT32() { return _native_mt32; }
+
+	// IMuse interface
+
+	void on_timer(MidiDriver *midi);
+	void pause(bool paused);
+	int terminate1();
+	int terminate2();
+	int save_or_load(Serializer *ser, ScummEngine *scumm);
+	int setMusicVolume(uint vol);
+	int setImuseMasterVolume(uint vol);
+	bool startSound(int sound);
+	int stopSound(int sound);
+	int stopAllSounds();
+	int getSoundStatus(int sound, bool ignoreFadeouts = true) const;
+	int getMusicTimer() const;
+	int32 doCommand (int a, int b, int c, int d, int e, int f, int g, int h);
+	int32 doCommand (int numargs, int args[]);
+	int clear_queue();
+	void setBase(byte **base);
+	uint32 property(int prop, uint32 value);
+
+	static IMuseInternal *create(OSystem *syst, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver);
+};
+
+} // End of namespace Scumm
+
+#endif

Copied: scummvm/trunk/engines/scumm/imuse/imuse_player.cpp (from rev 20795, scummvm/trunk/engines/scumm/imuse_player.cpp)
===================================================================
--- scummvm/trunk/engines/scumm/imuse/imuse_player.cpp	                        (rev 0)
+++ scummvm/trunk/engines/scumm/imuse/imuse_player.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -0,0 +1,1241 @@
+/* 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"
+#include "base/engine.h"
+
+#include "scumm/imuse/imuse_internal.h"
+#include "scumm/saveload.h"
+#include "scumm/scumm.h"
+
+#include "sound/midiparser.h"
+
+namespace Scumm {
+
+////////////////////////////////////////
+//
+//  Miscellaneous
+//
+////////////////////////////////////////
+
+#define IMUSE_SYSEX_ID 0x7D
+#define YM2612_SYSEX_ID 0x7C
+#define ROLAND_SYSEX_ID 0x41
+#define PERCUSSION_CHANNEL 9
+
+extern MidiParser *MidiParser_createRO();
+extern MidiParser *MidiParser_createEUP();
+
+uint16 Player::_active_notes[128];
+
+
+
+//////////////////////////////////////////////////
+//
+// IMuse Player implementation
+//
+//////////////////////////////////////////////////
+
+Player::Player() :
+	_midi(0),
+	_parser(0),
+	_passThrough(0),
+	_parts(0),
+	_active(false),
+	_scanning(false),
+	_id(0),
+	_priority(0),
+	_volume(0),
+	_pan(0),
+	_transpose(0),
+	_detune(0),
+	_vol_eff(0),
+	_track_index(0),
+	_loop_to_beat(0),
+	_loop_from_beat(0),
+	_loop_counter(0),
+	_loop_to_tick(0),
+	_loop_from_tick(0),
+	_speed(128),
+	_isMT32(false),
+	_isMIDI(false),
+	_se(0),
+	_vol_chan(0){
+}
+
+Player::~Player() {
+	if (_parser) {
+		delete _parser;
+		_parser = 0;
+	}
+}
+
+bool Player::startSound(int sound, MidiDriver *midi, bool passThrough) {
+	void *ptr;
+	int i;
+
+	// Not sure what the old code was doing,
+	// but we'll go ahead and do a similar check.
+	ptr = _se->findStartOfSound(sound);
+	if (!ptr) {
+		error("Player::startSound(): Couldn't find start of sound %d!", sound);
+		return false;
+	}
+
+	_isMT32 = _se->isMT32(sound);
+	_isMIDI = _se->isMIDI(sound);
+
+	_parts = NULL;
+	_active = true;
+	_midi = midi;
+	_id = sound;
+	_priority = 0x80;
+	_volume = 0x7F;
+	_vol_chan = 0xFFFF;
+	_vol_eff = (_se->get_channel_volume(0xFFFF) << 7) >> 7;
+	_pan = 0;
+	_transpose = 0;
+	_detune = 0;
+	_passThrough = passThrough;
+
+	for (i = 0; i < ARRAYSIZE(_parameterFaders); ++i)
+		_parameterFaders[i].init();
+	hook_clear();
+
+	if (start_seq_sound(sound) != 0) {
+		_active = false;
+		_midi = NULL;
+		return false;
+	}
+
+#ifdef IMUSE_DEBUG
+	debug(0, "Starting music %d", sound);
+#endif
+	return true;
+}
+
+int Player::getMusicTimer() const {
+	return _parser ? (_parser->getTick() * 2 / _parser->getPPQN()) : 0;
+}
+
+bool Player::isFadingOut() const {
+	int i;
+	for (i = 0; i < ARRAYSIZE(_parameterFaders); ++i) {
+		if (_parameterFaders[i].param == ParameterFader::pfVolume &&
+						_parameterFaders[i].end == 0) {
+			return true;
+		}
+	}
+	return false;
+}
+
+void Player::clear() {
+	if (!_active)
+		return;
+
+#ifdef IMUSE_DEBUG
+	debug(0, "Stopping music %d", _id);
+#endif
+
+	if (_parser) {
+		_parser->unloadMusic();
+		delete _parser;
+		_parser = 0;
+	}
+	uninit_parts();
+	_se->ImFireAllTriggers(_id);
+	_active = false;
+	_midi = NULL;
+	_id = 0;
+}
+
+void Player::hook_clear() {
+	memset(&_hook, 0, sizeof(_hook));
+}
+
+int Player::start_seq_sound(int sound, bool reset_vars) {
+	byte *ptr;
+
+	if (reset_vars) {
+		_loop_to_beat = 1;
+		_loop_from_beat = 1;
+		_track_index = 0;
+		_loop_counter = 0;
+		_loop_to_tick = 0;
+		_loop_from_tick = 0;
+	}
+
+	ptr = _se->findStartOfSound(sound);
+	if (ptr == NULL)
+		return -1;
+	if (_parser)
+		delete _parser;
+
+	if (!memcmp(ptr, "RO", 2)) {
+		// Old style 'RO' resource
+		_parser = MidiParser_createRO();
+	} else if (!memcmp(ptr, "SO", 2)) {
+		// Euphony (FM-TOWNS) resource
+		_parser = MidiParser_createEUP();
+	} else if (!memcmp(ptr, "FORM", 4)) {
+		// Humongous Games XMIDI resource
+		_parser = MidiParser::createParser_XMIDI();
+	} else {
+		// SCUMM SMF resource
+		_parser = MidiParser::createParser_SMF();
+	}
+
+	_parser->setMidiDriver(this);
+	_parser->property(MidiParser::mpSmartJump, 1);
+	_parser->loadMusic(ptr, 0);
+	_parser->setTrack(_track_index);
+	setSpeed(reset_vars ? 128 : _speed);
+
+	return 0;
+}
+
+void Player::uninit_parts() {
+	if (_parts && _parts->_player != this)
+		error("asd");
+	while (_parts)
+		_parts->uninit();
+
+	// In case another player is waiting to allocate parts
+	if (_midi)
+		_se->reallocateMidiChannels(_midi);
+}
+
+void Player::setSpeed(byte speed) {
+	_speed = speed;
+	if (_parser)
+		_parser->setTimerRate(((_midi->getBaseTempo() * speed) >> 7) * _se->_tempoFactor / 100);
+}
+
+void Player::send(uint32 b) {
+	if (_passThrough) {
+		_midi->send(b);
+		return;
+	}
+
+	byte cmd = (byte)(b & 0xF0);
+	byte chan = (byte)(b & 0x0F);
+	byte param1 = (byte)((b >> 8) & 0xFF);
+	byte param2 = (byte)((b >> 16) & 0xFF);
+	Part *part;
+
+	switch (cmd >> 4) {
+	case 0x8: // Key Off
+		if (!_scanning) {
+			if ((part = getPart(chan)) != 0)
+				part->noteOff(param1);
+		} else {
+			_active_notes[param1] &= ~(1 << chan);
+		}
+		break;
+
+	case 0x9: // Key On
+		if (!_scanning) {
+			if (_isMT32 && !_se->isNativeMT32())
+				param2 = (((param2 * 3) >> 2) + 32) & 0x7F;
+			if ((part = getPart(chan)) != 0)
+				part->noteOn(param1, param2);
+		} else {
+			_active_notes[param1] |= (1 << chan);
+		}
+		break;
+
+	case 0xB: // Control Change
+		part = (param1 == 123 ? getActivePart(chan) : getPart(chan));
+		if (!part)
+			break;
+
+		switch (param1) {
+		case 0: // Bank select. Not supported
+			break;
+		case 1: // Modulation Wheel
+			part->modulationWheel(param2);
+			break;
+		case 7: // Volume
+			part->volume(param2);
+			break;
+		case 10: // Pan Position
+			part->set_pan(param2 - 0x40);
+			break;
+		case 16: // Pitchbend Factor(non-standard)
+			part->pitchBendFactor(param2);
+			break;
+		case 17: // GP Slider 2
+			part->set_detune(param2 - 0x40);
+			break;
+		case 18: // GP Slider 3
+			part->set_pri(param2 - 0x40);
+			_se->reallocateMidiChannels(_midi);
+			break;
+		case 64: // Sustain Pedal
+			part->sustain(param2 != 0);
+			break;
+		case 91: // Effects Level
+			part->effectLevel(param2);
+			break;
+		case 93: // Chorus Level
+			part->chorusLevel(param2);
+			break;
+		case 116: // XMIDI For Loop. Not supported
+			// Used in the ending sequence of puttputt
+			break;
+		case 117: // XMIDI Next/Break. Not supported
+			// Used in the ending sequence of puttputt
+			break;
+		case 123: // All Notes Off
+			part->allNotesOff();
+			break;
+		default:
+			error("Player::send(): Invalid control change %d", param1);
+		}
+		break;
+
+	case 0xC: // Program Change
+		part = getPart(chan);
+		if (part) {
+			if (_isMIDI) {
+				if (param1 < 128)
+					part->programChange(param1);
+			} else {
+				if (param1 < 32)
+					part->load_global_instrument(param1);
+			}
+		}
+		break;
+
+	case 0xE: // Pitch Bend
+		part = getPart(chan);
+		if (part)
+			part->pitchBend(((param2 << 7) | param1) - 0x2000);
+		break;
+
+	case 0xA: // Aftertouch
+	case 0xD: // Channel Pressure
+	case 0xF: // Sequence Controls
+		break;
+
+	default:
+		if (!_scanning) {
+			error("Player::send(): Invalid command %d", cmd);
+			clear();
+		}
+	}
+	return;
+}
+
+void Player::sysEx(byte *p, uint16 len) {
+	byte code;
+	byte a;
+	uint b;
+	byte buf[128];
+	Part *part;
+
+	if (_passThrough) {
+		_midi->sysEx(p, len);
+		return;
+	}
+
+	// Check SysEx manufacturer.
+	a = *p++;
+	--len;
+	if (a != IMUSE_SYSEX_ID) {
+		if (a == ROLAND_SYSEX_ID) {
+			// Roland custom instrument definition.
+			part = getPart(p[0] & 0x0F);
+			if (part) {
+				part->_instrument.roland(p - 1);
+				if (part->clearToTransmit())
+					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 {
+			error("Unknown SysEx manufacturer 0x%02X", (int)a);
+		}
+		return;
+	}
+	--len;
+
+	// Too big?
+	if (len >= sizeof(buf) * 2)
+		return;
+
+#ifdef IMUSE_DEBUG
+	if (!_scanning) {
+		for (a = 0; a < len + 1 && a < 19; ++a) {
+			sprintf((char *)&buf[a*3], " %02X", p[a]);
+		} // next for
+		if (a < len + 1) {
+			buf[a*3] = buf[a*3+1] = buf[a*3+2] = '.';
+			++a;
+		} // end if
+		buf[a*3] = '\0';
+		debug(0, "[%02d] SysEx:%s", _id, buf);
+	}
+#endif
+
+	switch (code = *p++) {
+	case 0:
+		if (g_scumm->_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)
+			//   BYTE 04: Priority adjustment [guessing]
+			//   BYTE 05: Volume(upper 4 bits) [guessing]
+			//   BYTE 06: Volume(lower 4 bits) [guessing]
+			//   BYTE 09: BIT 04(0x08): Percussion?(1 = yes)
+			//   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->set_pri(p[4]);
+				part->volume((p[5] & 0x0F) << 4 |(p[6] & 0x0F));
+				part->_percussion = _isMIDI ? ((p[9] & 0x08) > 0) : false;
+				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:
+		// This SysEx is used in Sam & Max for 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);
+	}
+}
+
+void Player::decode_sysex_bytes(const byte *src, byte *dst, int len) {
+	while (len >= 0) {
+		*dst++ = ((src[0] << 4)&0xFF) | (src[1] & 0xF);
+		src += 2;
+		len -= 2;
+	}
+}
+
+void Player::maybe_jump(byte cmd, uint track, uint beat, uint tick) {
+	// Is this the hook I'm waiting for?
+	if (cmd && _hook._jump[0] != cmd)
+		return;
+
+	// Reset hook?
+	if (cmd != 0 && cmd < 0x80) {
+		_hook._jump[0] = _hook._jump[1];
+		_hook._jump[1] = 0;
+	}
+
+	jump(track, beat, tick);
+}
+
+void Player::maybe_set_transpose(byte *data) {
+	byte cmd;
+
+	cmd = data[0];
+
+	// Is this the hook I'm waiting for?
+	if (cmd && _hook._transpose != cmd)
+		return;
+
+	// Reset hook?
+	if (cmd != 0 && cmd < 0x80)
+		_hook._transpose = 0;
+
+	setTranspose(data[1], (int8)data[2]);
+}
+
+void Player::maybe_part_onoff(byte *data) {
+	byte cmd, *p;
+	uint chan;
+	Part *part;
+
+	cmd = data[1];
+	chan = data[0];
+
+	p = &_hook._part_onoff[chan];
+
+	// Is this the hook I'm waiting for?
+	if (cmd && *p != cmd)
+		return;
+
+	if (cmd != 0 && cmd < 0x80)
+		*p = 0;
+
+	part = getPart(chan);
+	if (part)
+		part->set_onoff(data[2] != 0);
+}
+
+void Player::maybe_set_volume(byte *data) {
+	byte cmd;
+	byte *p;
+	uint chan;
+	Part *part;
+
+	cmd = data[1];
+	chan = data[0];
+
+	p = &_hook._part_volume[chan];
+
+	// Is this the hook I'm waiting for?
+	if (cmd && *p != cmd)
+		return;
+
+	// Reset hook?
+	if (cmd != 0 && cmd < 0x80)
+		*p = 0;
+
+	part = getPart(chan);
+	if (part)
+		part->volume(data[2]);
+}
+
+void Player::maybe_set_program(byte *data) {
+	byte cmd;
+	byte *p;
+	uint chan;
+	Part *part;
+
+	cmd = data[1];
+	chan = data[0];
+
+	// Is this the hook I'm waiting for?
+	p = &_hook._part_program[chan];
+
+	if (cmd && *p != cmd)
+		return;
+
+	if (cmd != 0 && cmd < 0x80)
+		*p = 0;
+
+	part = getPart(chan);
+	if (part)
+		part->programChange(data[2]);
+}
+
+void Player::maybe_set_transpose_part(byte *data) {
+	byte cmd;
+	byte *p;
+	uint chan;
+
+	cmd = data[1];
+	chan = data[0];
+
+	// Is this the hook I'm waiting for?
+	p = &_hook._part_transpose[chan];
+
+	if (cmd && *p != cmd)
+		return;
+
+	// Reset hook?
+	if (cmd != 0 && cmd < 0x80)
+		*p = 0;
+
+	part_set_transpose(chan, data[2], (int8)data[3]);
+}
+
+int Player::setTranspose(byte relative, int b) {
+	Part *part;
+
+	if (b > 24 || b < -24 || relative > 1)
+		return -1;
+	if (relative)
+		b = transpose_clamp(_transpose + b, -24, 24);
+
+	_transpose = b;
+
+	for (part = _parts; part; part = part->_next) {
+		part->set_transpose(part->_transpose);
+	}
+
+	return 0;
+}
+
+void Player::part_set_transpose(uint8 chan, byte relative, int8 b) {
+	Part *part;
+
+	if (b > 24 || b < -24)
+		return;
+
+	part = getPart(chan);
+	if (!part)
+		return;
+	if (relative)
+		b = transpose_clamp(b + part->_transpose, -7, 7);
+	part->set_transpose(b);
+}
+
+bool Player::jump(uint track, uint beat, uint tick) {
+	if (!_parser)
+		return false;
+	if (_parser->setTrack(track))
+		_track_index = track;
+	if (!_parser->jumpToTick((beat - 1) * TICKS_PER_BEAT + tick))
+		return false;
+	turn_off_pedals();
+	return true;
+}
+
+bool Player::setLoop(uint count, uint tobeat, uint totick, uint frombeat, uint fromtick) {
+	if (tobeat + 1 >= frombeat)
+		return false;
+
+	if (tobeat == 0)
+		tobeat = 1;
+
+	_loop_counter = 0; // Because of possible interrupts
+	_loop_to_beat = tobeat;
+	_loop_to_tick = totick;
+	_loop_from_beat = frombeat;
+	_loop_from_tick = fromtick;
+	_loop_counter = count;
+
+	return true;
+}
+
+void Player::clearLoop() {
+	_loop_counter = 0;
+}
+
+void Player::turn_off_pedals() {
+	Part *part;
+
+	for (part = _parts; part; part = part->_next) {
+		if (part->_pedal)
+			part->sustain(false);
+	}
+}
+
+Part *Player::getActivePart(uint8 chan) {
+	Part *part = _parts;
+	while (part) {
+		if (part->_chan == chan)
+			return part;
+		part = part->_next;
+	}
+	return 0;
+}
+
+Part *Player::getPart(uint8 chan) {
+	Part *part = getActivePart(chan);
+	if (part)
+		return part;
+
+	part = _se->allocate_part(_priority, _midi);
+	if (!part) {
+		debug(1, "No parts available");
+		return NULL;
+	}
+
+	// Insert part into front of parts list
+	part->_prev = NULL;
+	part->_next = _parts;
+	if (_parts)
+		_parts->_prev = part;
+	_parts = part;
+
+
+	part->_chan = chan;
+	part->setup(this);
+
+	return part;
+}
+
+void Player::setPriority(int pri) {
+	Part *part;
+
+	_priority = pri;
+	for (part = _parts; part; part = part->_next) {
+		part->set_pri(part->_pri);
+	}
+	_se->reallocateMidiChannels(_midi);
+}
+
+void Player::setPan(int pan) {
+	Part *part;
+
+	_pan = pan;
+	for (part = _parts; part; part = part->_next) {
+		part->set_pan(part->_pan);
+	}
+}
+
+void Player::setDetune(int detune) {
+	Part *part;
+
+	_detune = detune;
+	for (part = _parts; part; part = part->_next) {
+		part->set_detune(part->_detune);
+	}
+}
+
+int Player::scan(uint totrack, uint tobeat, uint totick) {
+	if (!_active || !_parser)
+		return -1;
+
+	if (tobeat == 0)
+		tobeat++;
+
+	turn_off_parts();
+	memset(_active_notes, 0, sizeof(_active_notes));
+	_scanning = true;
+
+	// If the scan involves a track switch, scan to the end of
+	// the current track so that our state when starting the
+	// new track is fully up to date.
+	if (totrack != _track_index)
+		_parser->jumpToTick((uint32)-1, true);
+	_parser->setTrack(totrack);
+	if (!_parser->jumpToTick((tobeat - 1) * TICKS_PER_BEAT + totick, true)) {
+		_scanning = false;
+		return -1;
+	}
+
+	_scanning = false;
+	_se->reallocateMidiChannels(_midi);
+	play_active_notes();
+
+	if (_track_index != totrack) {
+		_track_index = totrack;
+		_loop_counter = 0;
+	}
+	return 0;
+}
+
+void Player::turn_off_parts() {
+	Part *part;
+
+	for (part = _parts; part; part = part->_next)
+		part->off();
+	_se->reallocateMidiChannels(_midi);
+}
+
+void Player::play_active_notes() {
+	int i, j;
+	uint mask;
+	Part *part;
+
+	for (i = 0; i < 16; ++i) {
+		part = getPart(i);
+		if (part) {
+			mask = 1 << i;
+			for (j = 0; j < 128; ++j) {
+				if (_active_notes[j] & mask)
+					part->noteOn(j, 80);
+			}
+		}
+	}
+}
+
+int Player::setVolume(byte vol) {
+	Part *part;
+
+	if (vol > 127)
+		return -1;
+
+	_volume = vol;
+	_vol_eff = _se->get_channel_volume(_vol_chan) * (vol + 1) >> 7;
+
+	for (part = _parts; part; part = part->_next) {
+		part->volume(part->_vol);
+	}
+
+	return 0;
+}
+
+int Player::getParam(int param, byte chan) {
+	switch (param) {
+	case 0:
+		return (byte)_priority;
+	case 1:
+		return (byte)_volume;
+	case 2:
+		return (byte)_pan;
+	case 3:
+		return (byte)_transpose;
+	case 4:
+		return (byte)_detune;
+	case 5:
+		return _speed;
+	case 6:
+		return _track_index;
+	case 7:
+		return getBeatIndex();
+	case 8:
+		return (_parser ? _parser->getTick() % TICKS_PER_BEAT : 0); // _tick_index;
+	case 9:
+		return _loop_counter;
+	case 10:
+		return _loop_to_beat;
+	case 11:
+		return _loop_to_tick;
+	case 12:
+		return _loop_from_beat;
+	case 13:
+		return _loop_from_tick;
+	case 14:
+	case 15:
+	case 16:
+	case 17:
+		return query_part_param(param, chan);
+	case 18:
+	case 19:
+	case 20:
+	case 21:
+	case 22:
+	case 23:
+		return _hook.query_param(param, chan);
+	default:
+		return -1;
+	}
+}
+
+int Player::query_part_param(int param, byte chan) {
+	Part *part;
+
+	part = _parts;
+	while (part) {
+		if (part->_chan == chan) {
+			switch (param) {
+			case 14:
+				return part->_on;
+			case 15:
+				return part->_vol;
+			case 16:
+// FIXME: Need to know where this occurs...
+error("Trying to cast instrument (%d, %d) -- please tell Fingolfin\n", param, chan);
+// In old versions of the code, this used to return part->_program.
+// This was changed in revision 2.29 of imuse.cpp (where this code used
+// to reside).
+//				return (int)part->_instrument;
+			case 17:
+				return part->_transpose;
+			default:
+				return -1;
+			}
+		}
+		part = part->_next;
+	}
+	return 129;
+}
+
+void Player::onTimer() {
+	// First handle any parameter transitions
+	// that are occuring.
+	transitionParameters();
+
+	// Since the volume parameter can cause
+	// the player to be deactivated, check
+	// to make sure we're still active.
+	if (!_active || !_parser)
+		return;
+
+	uint32 target_tick = _parser->getTick();
+	uint beat_index = target_tick / TICKS_PER_BEAT + 1;
+	uint tick_index = target_tick % TICKS_PER_BEAT;
+
+	if (_loop_counter &&(beat_index > _loop_from_beat ||
+	   (beat_index == _loop_from_beat && tick_index >= _loop_from_tick)))
+	{
+		_loop_counter--;
+		jump(_track_index, _loop_to_beat, _loop_to_tick);
+	}
+	_parser->onTimer();
+}
+
+// "time" is referenced as hundredths of a second.
+// IS THAT CORRECT??
+// We convert it to microseconds before proceeding
+int Player::addParameterFader(int param, int target, int time) {
+	int start;
+
+	switch (param) {
+	case ParameterFader::pfVolume:
+		// HACK: If volume is set to 0 with 0 time,
+		// set it so immediately but DON'T clear
+		// the player. This fixes a problem with
+		// music being cleared inappropriately
+		// in S&M when playing with the Dinosaur.
+		if (!target && !time) {
+			setVolume(0);
+			return 0;
+		}
+
+		// Volume fades are handled differently.
+		start = _volume;
+		break;
+
+	case ParameterFader::pfTranspose:
+		// FIXME: Is this transpose? And what's the scale?
+		// It's set to fade to -2400 in the tunnel of love.
+//		debug(0, "parameterTransition(3) outside Tunnel of Love?");
+		start = _transpose;
+//		target /= 200;
+		break;
+
+	case ParameterFader::pfSpeed: // impSpeed
+		// FIXME: Is the speed from 0-100?
+		// Right now I convert it to 0-128.
+		start = _speed;
+//		target = target * 128 / 100;
+		break;
+
+	case 127:
+		{ // FIXME? I *think* this clears all parameter faders.
+			ParameterFader *ptr = &_parameterFaders[0];
+			int i;
+			for (i = ARRAYSIZE(_parameterFaders); i; --i, ++ptr)
+				ptr->param = 0;
+			return 0;
+		}
+		break;
+
+	default:
+		debug(0, "Player::addParameterFader (%d, %d, %d): Unknown parameter", param, target, time);
+		return 0; // Should be -1, but we'll let the script think it worked.
+	}
+
+	ParameterFader *ptr = &_parameterFaders[0];
+	ParameterFader *best = 0;
+	int i;
+	for (i = ARRAYSIZE(_parameterFaders); i; --i, ++ptr) {
+		if (ptr->param == param) {
+			best = ptr;
+			start = ptr->end;
+			break;
+		} else if (!ptr->param) {
+			best = ptr;
+		}
+	}
+
+	if (best) {
+		best->param = param;
+		best->start = start;
+		best->end = target;
+		if (!time)
+			best->total_time = 1;
+		else
+			best->total_time = (uint32)time * 10000;
+		best->current_time = 0;
+	} else {
+		debug(0, "IMuse Player %d: Out of parameter faders", _id);
+		return -1;
+	}
+
+	return 0;
+}
+
+void Player::transitionParameters() {
+	uint32 advance = _midi->getBaseTempo();
+	int value;
+
+	ParameterFader *ptr = &_parameterFaders[0];
+	int i;
+	for (i = ARRAYSIZE(_parameterFaders); i; --i, ++ptr) {
+		if (!ptr->param)
+			continue;
+
+		ptr->current_time += advance;
+		if (ptr->current_time > ptr->total_time)
+			ptr->current_time = ptr->total_time;
+		value = (int32)ptr->start + (int32)(ptr->end - ptr->start) * (int32)ptr->current_time / (int32)ptr->total_time;
+
+		switch (ptr->param) {
+		case ParameterFader::pfVolume:
+			// Volume.
+			if (!value && !ptr->end) {
+				clear();
+				return;
+			}
+			setVolume((byte)value);
+			break;
+
+		case ParameterFader::pfTranspose:
+			// FIXME: Is this really transpose?
+			setTranspose(0, value / 100);
+			setDetune(value % 100);
+			break;
+
+		case ParameterFader::pfSpeed: // impSpeed:
+			// Speed.
+			setSpeed((byte)value);
+			break;
+
+		default:
+			ptr->param = 0;
+		}
+
+		if (ptr->current_time >= ptr->total_time)
+			ptr->param = 0;
+	}
+}
+
+uint Player::getBeatIndex() {
+	return (_parser ? (_parser->getTick() / TICKS_PER_BEAT + 1) : 0);
+}
+
+void Player::removePart(Part *part) {
+	// Unlink
+	if (part->_next)
+		part->_next->_prev = part->_prev;
+	if (part->_prev)
+		part->_prev->_next = part->_next;
+	else
+		_parts = part->_next;
+	part->_next = part->_prev = 0;
+}
+
+void Player::fixAfterLoad() {
+	_midi = _se->getBestMidiDriver(_id);
+	if (!_midi) {
+		clear();
+	} else {
+		start_seq_sound(_id, false);
+		setSpeed(_speed);
+		if (_parser)
+			_parser->jumpToTick(_music_tick); // start_seq_sound already switched tracks
+		_isMT32 = _se->isMT32(_id);
+		_isMIDI = _se->isMIDI(_id);
+	}
+}
+
+uint32 Player::getBaseTempo() {
+	return (_midi ? _midi->getBaseTempo() : 0);
+}
+
+void Player::metaEvent(byte type, byte *msg, uint16 len) {
+	if (type == 0x2F)
+		clear();
+}
+
+
+
+////////////////////////////////////////
+//
+//  Player save/load functions
+//
+////////////////////////////////////////
+
+void Player::saveLoadWithSerializer(Serializer *ser) {
+	static const SaveLoadEntry playerEntries[] = {
+		MKLINE(Player, _active, sleByte, VER(8)),
+		MKLINE(Player, _id, sleUint16, VER(8)),
+		MKLINE(Player, _priority, sleByte, VER(8)),
+		MKLINE(Player, _volume, sleByte, VER(8)),
+		MKLINE(Player, _pan, sleInt8, VER(8)),
+		MKLINE(Player, _transpose, sleByte, VER(8)),
+		MKLINE(Player, _detune, sleInt8, VER(8)),
+		MKLINE(Player, _vol_chan, sleUint16, VER(8)),
+		MKLINE(Player, _vol_eff, sleByte, VER(8)),
+		MKLINE(Player, _speed, sleByte, VER(8)),
+		MK_OBSOLETE(Player, _song_index, sleUint16, VER(8), VER(19)),
+		MKLINE(Player, _track_index, sleUint16, VER(8)),
+		MK_OBSOLETE(Player, _timer_counter, sleUint16, VER(8), VER(17)),
+		MKLINE(Player, _loop_to_beat, sleUint16, VER(8)),
+		MKLINE(Player, _loop_from_beat, sleUint16, VER(8)),
+		MKLINE(Player, _loop_counter, sleUint16, VER(8)),
+		MKLINE(Player, _loop_to_tick, sleUint16, VER(8)),
+		MKLINE(Player, _loop_from_tick, sleUint16, VER(8)),
+		MK_OBSOLETE(Player, _tempo, sleUint32, VER(8), VER(19)),
+		MK_OBSOLETE(Player, _cur_pos, sleUint32, VER(8), VER(17)),
+		MK_OBSOLETE(Player, _next_pos, sleUint32, VER(8), VER(17)),
+		MK_OBSOLETE(Player, _song_offset, sleUint32, VER(8), VER(17)),
+		MK_OBSOLETE(Player, _tick_index, sleUint16, VER(8), VER(17)),
+		MK_OBSOLETE(Player, _beat_index, sleUint16, VER(8), VER(17)),
+		MK_OBSOLETE(Player, _ticks_per_beat, sleUint16, VER(8), VER(17)),
+		MKLINE(Player, _music_tick, sleUint32, VER(19)),
+		MKLINE(Player, _hook._jump[0], sleByte, VER(8)),
+		MKLINE(Player, _hook._transpose, sleByte, VER(8)),
+		MKARRAY(Player, _hook._part_onoff[0], sleByte, 16, VER(8)),
+		MKARRAY(Player, _hook._part_volume[0], sleByte, 16, VER(8)),
+		MKARRAY(Player, _hook._part_program[0], sleByte, 16, VER(8)),
+		MKARRAY(Player, _hook._part_transpose[0], sleByte, 16, VER(8)),
+		MKEND()
+	};
+
+	const SaveLoadEntry parameterFaderEntries[] = {
+		MKLINE(ParameterFader, param,        sleInt16,  VER(17)),
+		MKLINE(ParameterFader, start,        sleInt16,  VER(17)),
+		MKLINE(ParameterFader, end,          sleInt16,  VER(17)),
+		MKLINE(ParameterFader, total_time,   sleUint32, VER(17)),
+		MKLINE(ParameterFader, current_time, sleUint32, VER(17)),
+		MKEND()
+	};
+
+	if (!ser->isSaving() && _parser) {
+		delete _parser;
+		_parser = 0;
+	}
+	_music_tick = _parser ? _parser->getTick() : 0;
+
+	int num;
+	if (ser->isSaving()) {
+		num = (_parts ? (_parts - _se->_parts + 1) : 0);
+		ser->saveUint16(num);
+	} else {
+		num = ser->loadUint16();
+		_parts = (num ? &_se->_parts[num - 1] : 0);
+	}
+	ser->saveLoadEntries(this, playerEntries);
+	ser->saveLoadArrayOf(_parameterFaders, ARRAYSIZE(_parameterFaders),
+						sizeof(ParameterFader), parameterFaderEntries);
+	return;
+}
+
+} // End of namespace Scumm

Copied: scummvm/trunk/engines/scumm/imuse/instrument.cpp (from rev 20787, scummvm/trunk/engines/scumm/instrument.cpp)
===================================================================
--- scummvm/trunk/engines/scumm/imuse/instrument.cpp	                        (rev 0)
+++ scummvm/trunk/engines/scumm/imuse/instrument.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -0,0 +1,462 @@
+/* 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 "scumm/scumm.h"
+#include "scumm/saveload.h"
+#include "scumm/imuse/instrument.h"
+#include "sound/mididrv.h"
+
+namespace Scumm {
+
+static bool _native_mt32 = false;
+
+static struct {
+	const char *name;
+	byte program;
+}
+
+roland_to_gm_map [] = {
+	// Monkey Island 2 instruments
+	// TODO: Complete
+	{ "badspit   ",  62 },
+	{ "Big Drum  ", 116 },
+	{ "burp      ",  58 },
+//	{ "dinkfall  ", ??? },
+//	{ "Fire Pit  ", ??? },
+	{ "foghorn   ",  60 },
+	{ "glop      ",  39 },
+//	{ "jacob's la", ??? },
+	{ "LeshBass  ",  33 },
+//	{ "lowsnort  ", ??? },
+	{ "ML explosn", 127 },
+	{ "ReggaeBass",  32 },
+//	{ "rope fall ", ??? },
+	{ "rumble    ",  89 },
+	{ "SdTrk Bend",  97 },
+//	{ "snort     ", ??? },
+	{ "spitting  ",  62 },
+	{ "Swell 1   ",  95 },
+	{ "Swell 2   ",  95 },
+	{ "thnderclap", 127 }
+
+	// Fate of Atlantis instruments
+	// TODO: Build
+//	{ "*aah!     ", ??? },
+//	{ "*ooh!     ", ??? },
+//	{ "*ShotFar4 ", ??? },
+//	{ "*splash3  ", ??? },
+//	{ "*torpedo5 ", ??? },
+//	{ "*whip3    ", ??? },
+//	{ "*woodknock", ??? },
+//	{ "35 lavabub", ??? },
+//	{ "49 bzzt!  ", ??? },
+//	{ "applause  ", ??? },
+//	{ "Arabongo  ", ??? },
+//	{ "Big Drum  ", ??? }, // DUPLICATE (todo: confirm)
+//	{ "bodythud1 ", ??? },
+//	{ "boneKLOK2 ", ??? },
+//	{ "boom10    ", ??? },
+//	{ "boom11    ", ??? },
+//	{ "boom15    ", ??? },
+//	{ "boxclik1a ", ??? },
+//	{ "brassbonk3", ??? },
+//	{ "carstart  ", ??? },
+//	{ "cb tpt 2  ", ??? },
+//	{ "cell door ", ??? },
+//	{ "chains    ", ??? },
+//	{ "crash     ", ??? },
+//	{ "crsrt/idl3", ??? },
+//	{ "Fire Pit  ", ??? }, // DUPLICATE (todo: confirm)
+//	{ "Fzooom    ", ??? },
+//	{ "Fzooom 2  ", ??? },
+//	{ "ghostwhosh", ??? },
+//	{ "glasssmash", ??? },
+//	{ "gloop2    ", ??? },
+//	{ "gunShotNea", ??? },
+//	{ "idoorclse ", ??? },
+//	{ "knife     ", ??? },
+//	{ "lavacmbl4 ", ??? },
+//	{ "Mellow Str", ??? },
+//	{ "mtlheater1", ??? },
+//	{ "pachinko5 ", ??? },
+//	{ "Ping1     ", ??? },
+//	{ "rockcrunch", ??? },
+//	{ "rumble    ", ??? }, // DUPLICATE (todo: confirm)
+//	{ "runngwatr ", ??? },
+//	{ "scrape2   ", ??? },
+//	{ "snakeHiss ", ??? },
+//	{ "snort     ", ??? }, // DUPLICATE (todo: confirm)
+//	{ "spindle4  ", ??? },
+//	{ "splash2   ", ??? },
+//	{ "squirel   ", ??? },
+//	{ "steam3    ", ??? },
+//	{ "stonwheel6", ??? },
+//	{ "street    ", ??? },
+//	{ "trickle4  ", ??? }
+};
+
+const byte Instrument::_gmRhythmMap[35] = {
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0, 36, 37, 38, 39, 40, 41, 66, 47,
+	 65, 48, 56};
+       // This emulates the percussion bank setup LEC used with the MT-32,
+       // where notes 24 - 34 were assigned instruments without reverb.
+       // It also fixes problems on GS devices that map sounds to these
+       // notes by default.
+
+class Instrument_Program : public InstrumentInternal {
+private:
+	byte _program;
+	bool _mt32;
+
+public:
+	Instrument_Program (byte program, bool mt32);
+	Instrument_Program (Serializer *s);
+	void saveOrLoad (Serializer *s);
+	void send (MidiChannel *mc);
+	void copy_to (Instrument *dest) { dest->program (_program, _mt32); }
+	bool is_valid() {
+		return (_program < 128) &&
+			((_native_mt32 == _mt32) || _native_mt32
+				? (MidiDriver::_gmToMt32[_program] < 128)
+				: (MidiDriver::_mt32ToGm[_program] < 128)); }
+};
+
+class Instrument_Adlib : public InstrumentInternal {
+private:
+	struct {
+		byte flags_1;
+		byte oplvl_1;
+		byte atdec_1;
+		byte sustrel_1;
+		byte waveform_1;
+		byte flags_2;
+		byte oplvl_2;
+		byte atdec_2;
+		byte sustrel_2;
+		byte waveform_2;
+		byte feedback;
+		byte flags_a;
+		struct { byte a,b,c,d,e,f,g,h; } extra_a;
+		byte flags_b;
+		struct { byte a,b,c,d,e,f,g,h; } extra_b;
+		byte duration;
+	} _instrument;
+
+public:
+	Instrument_Adlib (byte *data);
+	Instrument_Adlib (Serializer *s);
+	void saveOrLoad (Serializer *s);
+	void send (MidiChannel *mc);
+	void copy_to (Instrument *dest) { dest->adlib ((byte *) &_instrument); }
+	bool is_valid() { return true; }
+};
+
+class Instrument_Roland : public InstrumentInternal {
+private:
+	struct RolandInstrument {
+		byte roland_id;
+		byte device_id;
+		byte model_id;
+		byte command;
+		byte address[3];
+		struct {
+			byte name[10];
+			byte partial_struct12;
+			byte partial_struct34;
+			byte partial_mute;
+			byte env_mode;
+		} common;
+		struct {
+			byte wg_pitch_coarse;
+			byte wg_pitch_fine;
+			byte wg_pitch_keyfollow;
+			byte wg_pitch_bender_sw;
+			byte wg_waveform_pcm_bank;
+			byte wg_pcm_wave_num;
+			byte wg_pulse_width;
+			byte wg_pw_velo_sens;
+			byte p_env_depth;
+			byte p_evn_velo_sens;
+			byte p_env_time_keyf;
+			byte p_env_time[4];
+			byte p_env_level[3];
+			byte p_env_sustain_level;
+			byte end_level;
+			byte p_lfo_rate;
+			byte p_lfo_depth;
+			byte p_lfo_mod_sens;
+			byte tvf_cutoff_freq;
+			byte tvf_resonance;
+			byte tvf_keyfollow;
+			byte tvf_bias_point_dir;
+			byte tvf_bias_level;
+			byte tvf_env_depth;
+			byte tvf_env_velo_sens;
+			byte tvf_env_depth_keyf;
+			byte tvf_env_time_keyf;
+			byte tvf_env_time[5];
+			byte tvf_env_level[3];
+			byte tvf_env_sustain_level;
+			byte tva_level;
+			byte tva_velo_sens;
+			byte tva_bias_point_1;
+			byte tva_bias_level_1;
+			byte tva_bias_point_2;
+			byte tva_bias_level_2;
+			byte tva_env_time_keyf;
+			byte tva_env_time_v_follow;
+			byte tva_env_time[5];
+			byte tva_env_level[3];
+			byte tva_env_sustain_level;
+		} partial[4];
+		byte checksum;
+	} GNUPACK;
+	RolandInstrument _instrument;
+
+	char _instrument_name [11];
+
+	uint8 getEquivalentGM();
+
+public:
+	Instrument_Roland (byte *data);
+	Instrument_Roland (Serializer *s);
+	void saveOrLoad (Serializer *s);
+	void send (MidiChannel *mc);
+	void copy_to (Instrument *dest) { dest->roland ((byte *) &_instrument); }
+	bool is_valid() { return (_native_mt32 ? true : (_instrument_name[0] != '\0')); }
+};
+
+////////////////////////////////////////
+//
+// Instrument class members
+//
+////////////////////////////////////////
+
+void Instrument::nativeMT32 (bool native) {
+	_native_mt32 = native;
+}
+
+void Instrument::clear() {
+	if (_instrument)
+		delete _instrument;
+	_instrument = NULL;
+	_type = itNone;
+}
+
+void Instrument::program (byte prog, bool mt32) {
+	clear();
+	if (prog > 127)
+		return;
+	_type = itProgram;
+	_instrument = new Instrument_Program (prog, mt32);
+}
+
+void Instrument::adlib (byte *instrument) {
+	clear();
+	if (!instrument)
+		return;
+	_type = itAdlib;
+	_instrument = new Instrument_Adlib (instrument);
+}
+
+void Instrument::roland (byte *instrument) {
+	clear();
+	if (!instrument)
+		return;
+	_type = itRoland;
+	_instrument = new Instrument_Roland (instrument);
+}
+
+void Instrument::saveOrLoad (Serializer *s) {
+	if (s->isSaving()) {
+		s->saveByte (_type);
+		if (_instrument)
+			_instrument->saveOrLoad (s);
+	} else {
+		clear();
+		_type = s->loadByte();
+		switch (_type) {
+		case itNone:
+			break;
+		case itProgram:
+			_instrument = new Instrument_Program (s);
+			break;
+		case itAdlib:
+			_instrument = new Instrument_Adlib (s);
+			break;
+		case itRoland:
+			_instrument = new Instrument_Roland (s);
+			break;
+		default:
+			warning ("No known instrument classification #%d", (int) _type);
+			_type = itNone;
+		}
+	}
+}
+
+////////////////////////////////////////
+//
+// Instrument_Program class members
+//
+////////////////////////////////////////
+
+Instrument_Program::Instrument_Program (byte program, bool mt32) :
+_program (program),
+_mt32 (mt32) {
+	if (program > 127)
+		_program = 255;
+}
+
+Instrument_Program::Instrument_Program (Serializer *s) {
+	_program = 255;
+	if (!s->isSaving())
+		saveOrLoad (s);
+}
+
+void Instrument_Program::saveOrLoad (Serializer *s) {
+	if (s->isSaving()) {
+		s->saveByte (_program);
+		s->saveByte (_mt32 ? 1 : 0);
+	} else {
+		_program = s->loadByte();
+		_mt32 = (s->loadByte() > 0);
+	}
+}
+
+void Instrument_Program::send (MidiChannel *mc) {
+	if (_program > 127)
+		return;
+
+	byte program = _program;
+	if (_native_mt32 != _mt32)
+		program = _native_mt32 ? MidiDriver::_gmToMt32 [program] : MidiDriver::_mt32ToGm [program];
+	if (program < 128)
+		mc->programChange (program);
+}
+
+////////////////////////////////////////
+//
+// Instrument_Adlib class members
+//
+////////////////////////////////////////
+
+Instrument_Adlib::Instrument_Adlib (byte *data) {
+	memcpy (&_instrument, data, sizeof (_instrument));
+}
+
+Instrument_Adlib::Instrument_Adlib (Serializer *s) {
+	if (!s->isSaving())
+		saveOrLoad (s);
+	else
+		memset (&_instrument, 0, sizeof (_instrument));
+}
+
+void Instrument_Adlib::saveOrLoad (Serializer *s) {
+	if (s->isSaving())
+		s->saveBytes (&_instrument, sizeof (_instrument));
+	else
+		s->loadBytes (&_instrument, sizeof (_instrument));
+}
+
+void Instrument_Adlib::send (MidiChannel *mc) {
+	mc->sysEx_customInstrument ('ADL ', (byte *) &_instrument);
+}
+
+////////////////////////////////////////
+//
+// Instrument_Roland class members
+//
+////////////////////////////////////////
+
+Instrument_Roland::Instrument_Roland (byte *data) {
+	memcpy (&_instrument, data, sizeof (_instrument));
+	memcpy (&_instrument_name, &_instrument.common.name, sizeof (_instrument.common.name));
+	_instrument_name[10] = '\0';
+	if (!_native_mt32 && getEquivalentGM() >= 128) {
+		debug (0, "MT-32 instrument \"%s\" not supported yet", _instrument_name);
+		_instrument_name[0] = '\0';
+	}
+}
+
+Instrument_Roland::Instrument_Roland (Serializer *s) {
+	_instrument_name[0] = '\0';
+	if (!s->isSaving())
+		saveOrLoad (s);
+	else
+		memset (&_instrument, 0, sizeof (_instrument));
+}
+
+void Instrument_Roland::saveOrLoad (Serializer *s) {
+	if (s->isSaving()) {
+		s->saveBytes (&_instrument, sizeof (_instrument));
+	} else {
+		s->loadBytes (&_instrument, sizeof (_instrument));
+		memcpy (&_instrument_name, &_instrument.common.name, sizeof (_instrument.common.name));
+		_instrument_name[10] = '\0';
+		if (!_native_mt32 && getEquivalentGM() >= 128) {
+			debug (2, "MT-32 custom instrument \"%s\" not supported", _instrument_name);
+			_instrument_name[0] = '\0';
+		}
+	} // end if
+}
+
+void Instrument_Roland::send (MidiChannel *mc) {
+	if (_native_mt32) {
+		if (mc->getNumber() > 8)
+			return;
+		_instrument.device_id = mc->getNumber();
+
+		// Remap instrument to appropriate address space.
+		int address = 0x008000;
+		_instrument.address[0] = (address >> 14) & 0x7F;
+		_instrument.address[1] = (address >>  7) & 0x7F;
+		_instrument.address[2] = (address      ) & 0x7F;
+
+		// Recompute the checksum.
+		byte checksum = 0;
+		byte *ptr = (byte *) &_instrument + 4;
+		int i;
+		for (i = 4; i < (int)sizeof (_instrument) - 1; ++i)
+			checksum -= *ptr++;
+		_instrument.checksum = checksum & 0x7F;
+
+		mc->device()->sysEx ((byte *) &_instrument, sizeof (_instrument));
+	} else {
+		// Convert to a GM program change.
+		byte program = getEquivalentGM();
+		if (program < 128)
+			mc->programChange (program);
+	}
+}
+
+uint8 Instrument_Roland::getEquivalentGM() {
+	byte i;
+	for (i = 0; i != ARRAYSIZE(roland_to_gm_map); ++i) {
+		if (!memcmp (roland_to_gm_map[i].name, _instrument.common.name, 10))
+			return roland_to_gm_map[i].program;
+	}
+	return 255;
+}
+
+} // End of namespace Scumm

Copied: scummvm/trunk/engines/scumm/imuse/instrument.h (from rev 20787, scummvm/trunk/engines/scumm/instrument.h)
===================================================================
--- scummvm/trunk/engines/scumm/imuse/instrument.h	                        (rev 0)
+++ scummvm/trunk/engines/scumm/imuse/instrument.h	2006-02-20 20:57:26 UTC (rev 20801)
@@ -0,0 +1,79 @@
+/* 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 INSTRUMENT_H
+#define INSTRUMENT_H
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+
+class MidiChannel;
+
+namespace Scumm {
+
+class Serializer;
+class Instrument;
+
+class InstrumentInternal {
+public:
+	virtual ~InstrumentInternal() {}
+	virtual void saveOrLoad (Serializer *s) = 0;
+	virtual void send (MidiChannel *mc) = 0;
+	virtual void copy_to (Instrument *dest) = 0;
+	virtual bool is_valid() = 0;
+	virtual operator int() { return 255; }
+};
+
+class Instrument {
+private:
+	byte _type;
+	InstrumentInternal *_instrument;
+
+public:
+	enum {
+		itNone = 0,
+		itProgram = 1,
+		itAdlib = 2,
+		itRoland = 3
+	};
+
+	Instrument() : _type (0), _instrument (0) { }
+	~Instrument() { delete _instrument; }
+	static void nativeMT32 (bool native);
+	static const byte _gmRhythmMap[35];
+
+	void clear();
+	void copy_to (Instrument *dest) { if (_instrument) _instrument->copy_to (dest); else dest->clear(); }
+
+	void program (byte program, bool mt32);
+	void adlib (byte *instrument);
+	void roland (byte *instrument);
+
+	byte getType() { return _type; }
+	bool isValid() { return (_instrument ? _instrument->is_valid() : false); }
+	void saveOrLoad (Serializer *s);
+	void send (MidiChannel *mc) { if (_instrument) _instrument->send (mc); }
+};
+
+} // End of namespace Scumm
+
+#endif

Deleted: scummvm/trunk/engines/scumm/imuse.cpp
===================================================================
--- scummvm/trunk/engines/scumm/imuse.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/imuse.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -1,2043 +0,0 @@
-/* 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 "base/version.h"
-
-#include "common/util.h"
-#include "common/system.h"
-
-#include "scumm/imuse.h"
-#include "scumm/imuse_internal.h"
-#include "scumm/instrument.h"
-#include "scumm/saveload.h"
-#include "scumm/scumm.h"
-#include "scumm/util.h"
-
-#include "sound/mididrv.h"
-
-
-namespace Scumm {
-
-////////////////////////////////////////
-//
-//  IMuseInternal implementation
-//
-////////////////////////////////////////
-
-IMuseInternal::IMuseInternal() :
-_native_mt32(false),
-_enable_gs(false),
-_sc55(false),
-_midi_adlib(0),
-_midi_native(0),
-_base_sounds(0),
-_paused(false),
-_initialized(false),
-_tempoFactor(0),
-_player_limit(ARRAYSIZE(_players)),
-_recycle_players(false),
-_direct_passthrough(false),
-_queue_end(0),
-_queue_pos(0),
-_queue_sound(0),
-_queue_adding(0),
-_queue_marker(0),
-_queue_cleared(0),
-_master_volume(0),
-_music_volume(0),
-_trigger_count(0),
-_snm_trigger_index(0) {
-	memset(_channel_volume,0,sizeof(_channel_volume));
-	memset(_channel_volume_eff,0,sizeof(_channel_volume_eff));
-	memset(_volchan_table,0,sizeof(_volchan_table));
-}
-
-byte *IMuseInternal::findStartOfSound(int sound) {
-	byte *ptr = NULL;
-	int32 size, pos;
-
-	if (_base_sounds)
-		ptr = _base_sounds[sound];
-
-	if (ptr == NULL) {
-		debug(1, "IMuseInternal::findStartOfSound(): Sound %d doesn't exist!", sound);
-		return NULL;
-	}
-
-	// Check for old-style headers first, like 'RO'
-	if (ptr[4] == 'R' && ptr[5] == 'O'&& ptr[6] != 'L')
-		return ptr + 4;
-	if (ptr[8] == 'S' && ptr[9] == 'O')
-		return ptr + 8;
-
-	ptr += 8;
-	size = READ_BE_UINT32(ptr);
-	ptr += 4;
-
-	// Okay, we're looking for one of those things: either
-	// an 'MThd' tag (for SMF), or a 'FORM' tag (for XMIDI).
-	size = 48; // Arbitrary; we should find our tag within the first 48 bytes of the resource
-	pos = 0;
-	while (pos < size) {
-		if (!memcmp(ptr + pos, "MThd", 4) || !memcmp(ptr + pos, "FORM", 4))
-			return ptr + pos;
-		++pos; // We could probably iterate more intelligently
-	}
-
-	debug(3, "IMuseInternal::findStartOfSound(): Failed to align on sound %d!", sound);
-	return 0;
-}
-
-bool IMuseInternal::isMT32(int sound) {
-	byte *ptr = NULL;
-	uint32 tag;
-
-	if (_base_sounds)
-		ptr = _base_sounds[sound];
-
-	if (ptr == NULL)
-		return false;
-
-	tag = *(((uint32 *)ptr) + 1);
-	switch (tag) {
-	case MKID('ADL '):
-	case MKID('ASFX'): // Special AD class for old Adlib sound effects
-	case MKID('SPK '):
-		return false;
-
-	case MKID('AMI '):
-	case MKID('ROL '):
-		return true;
-
-	case MKID('MAC '):	// Occurs in the Mac version of FOA and MI2
-		return true;
-
-	case MKID('GMD '):
-	case MKID('MIDI'):	// Occurs in Sam & Max
-		return false;
-	}
-
-	// Old style 'RO' has equivalent properties to 'ROL'
-	if (ptr[4] == 'R' && ptr[5] == 'O')
-		return true;
-	// Euphony tracks show as 'SO' and have equivalent properties to 'ADL'
-	if (ptr[8] == 'S' && ptr[9] == 'O')
-		return false;
-
-	error("Unknown music type: '%s'", tag2str(tag));
-
-	return false;
-}
-
-bool IMuseInternal::isMIDI(int sound) {
-	byte *ptr = NULL;
-	uint32 tag;
-
-	if (_base_sounds)
-		ptr = _base_sounds[sound];
-
-	if (ptr == NULL)
-		return false;
-
-	tag = *(((uint32 *)ptr) + 1);
-	switch (tag) {
-	case MKID('ADL '):
-	case MKID('ASFX'): // Special AD class for old Adlib sound effects
-	case MKID('SPK '):
-		return false;
-
-	case MKID('AMI '):
-	case MKID('ROL '):
-		return true;
-
-	case MKID('MAC '):	// Occurs in the Mac version of FOA and MI2
-		return true;
-
-	case MKID('GMD '):
-	case MKID('MIDI'):	// Occurs in Sam & Max
-		return true;
-	}
-
-	// Old style 'RO' has equivalent properties to 'ROL'
-	if (ptr[4] == 'R' && ptr[5] == 'O')
-		return true;
-	// Euphony tracks show as 'SO' and have equivalent properties to 'ADL'
-	// FIXME: Right now we're pretending it's GM.
-	if (ptr[8] == 'S' && ptr[9] == 'O')
-		return true;
-
-	error("Unknown music type: '%s'", tag2str(tag));
-
-	return false;
-}
-
-MidiDriver *IMuseInternal::getBestMidiDriver(int sound) {
-	MidiDriver *driver = NULL;
-
-	if (isMIDI(sound)) {
-		if (_midi_native) {
-			driver = _midi_native;
-		} else {
-			// Route it through Adlib anyway.
-			driver = _midi_adlib;
-		}
-	} else {
-		driver = _midi_adlib;
-	}
-	return driver;
-}
-
-bool IMuseInternal::startSound(int sound) {
-	Player *player;
-	void *ptr;
-
-	// Do not start a sound if it is already set to start on an ImTrigger
-	// event. This fixes carnival music problems where a sound has been set
-	// to trigger at the right time, but then is started up immediately
-	// anyway, only to be restarted later when the trigger occurs.
-	//
-	// However, we have to make sure the sound with the trigger is actually
-	// playing, otherwise the music may stop when Sam and Max are thrown
-	// out of Bumpusville, because entering the mansion sets up a trigger
-	// for a sound that isn't necessarily playing. This is somewhat related
-	// to bug #780918.
-
-	int i;
-	ImTrigger *trigger = _snm_triggers;
-	for (i = ARRAYSIZE(_snm_triggers); i; --i, ++trigger) {
-		if (trigger->sound && trigger->id && trigger->command[0] == 8 && trigger->command[1] == sound && getSoundStatus(trigger->sound))
-			return false;
-	}
-
-	ptr = findStartOfSound(sound);
-	if (!ptr) {
-		debug(2, "IMuseInternal::startSound(): Couldn't find sound %d!", sound);
-		return false;
-	}
-
-	// Check which MIDI driver this track should use.
-	// If it's NULL, it ain't something we can play.
-	MidiDriver *driver = getBestMidiDriver(sound);
-	if (!driver)
-		return false;
-
-	// If the requested sound is already playing, start it over
-	// from scratch. This was originally a hack to prevent Sam & Max
-	// iMuse messiness while upgrading the iMuse engine, but it
-	// is apparently necessary to deal with fade-and-restart
-	// race conditions that were observed in MI2. Reference
-	// Bug #590511 and Patch #607175 (which was reversed to fix
-	// an FOA regression: Bug #622606).
-	player = findActivePlayer(sound);
-	if (!player)
-		player = allocate_player(128);
-	if (!player)
-		return false;
-
-	// HACK: This is to work around a problem at the Dino Bungie Memorial.
-	// There are three pieces of music involved here:
-	//
-	// 80 - Main theme (looping)
-	// 81 - Music when entering Rex's and Wally's room (not looping)
-	// 82 - Music when listening to Rex or Wally
-	//
-	// When entering, tune 81 starts, tune 80 is faded down (not out) and
-	// a trigger is set in tune 81 to fade tune 80 back up.
-	//
-	// When listening to Rex or Wally, tune 82 is started, tune 81 is faded
-	// out and tune 80 is faded down even further.
-	//
-	// However, when tune 81 is faded out its trigger will cause tune 80 to
-	// fade back up, resulting in two tunes being played simultaneously at
-	// full blast. It's no use trying to keep tune 81 playing at volume 0.
-	// It doesn't loop, so eventually it will terminate on its own.
-	//
-	// I don't know how the original interpreter handled this - or even if
-	// it handled it at all - but it looks like sloppy scripting to me. Our
-	// workaround is to clear the trigger if the player listens to Rex or
-	// Wally before tune 81 has finished on its own.
-
-	if (g_scumm->_game.id == GID_SAMNMAX && sound == 82 && getSoundStatus(81, false))
-		ImClearTrigger(81, 1);
-
-	player->clear();
-	return player->startSound(sound, driver, _direct_passthrough);
-}
-
-
-Player *IMuseInternal::allocate_player(byte priority) {
-	Player *player = _players, *best = NULL;
-	int i;
-	byte bestpri = 255;
-
-	for (i = _player_limit; i != 0; i--, player++) {
-		if (!player->isActive())
-			return player;
-		if (player->getPriority() < bestpri) {
-			best = player;
-			bestpri = player->getPriority();
-		}
-	}
-
-	if (bestpri < priority || _recycle_players)
-		return best;
-
-	debug(1, "Denying player request");
-	return NULL;
-}
-
-void IMuseInternal::init_players() {
-	Player *player = _players;
-	int i;
-
-	for (i = ARRAYSIZE(_players); i != 0; i--, player++) {
-		player->_se = this;
-		player->clear(); // Used to just set _active to false
-	}
-}
-
-void IMuseInternal::init_parts() {
-	Part *part;
-	int i;
-
-	for (i = 0, part = _parts; i != ARRAYSIZE(_parts); i++, part++) {
-		part->init();
-		part->_se = this;
-		part->_slot = i;
-	}
-}
-
-int IMuseInternal::stopSound(int sound) {
-	int r = -1;
-	Player *player = findActivePlayer(sound);
-	if (player) {
-		player->clear();
-		r = 0;
-	}
-	return r;
-}
-
-int IMuseInternal::stopAllSounds() {
-	Player *player = _players;
-	int i;
-
-	for (i = ARRAYSIZE(_players); i != 0; i--, player++) {
-		if (player->isActive())
-			player->clear();
-	}
-	return 0;
-}
-
-void IMuseInternal::on_timer(MidiDriver *midi) {
-	if (_paused || !_initialized)
-		return;
-
-	if (midi == _midi_native || !_midi_native)
-		handleDeferredCommands(midi);
-	sequencer_timers(midi);
-}
-
-int IMuseInternal::getMusicTimer() const {
-	int best_time = 0;
-	const Player *player = _players;
-	int i;
-
-	for (i = ARRAYSIZE(_players); i != 0; i--, player++) {
-		if (player->isActive()) {
-			int timer = player->getMusicTimer();
-			if (timer > best_time)
-				best_time = timer;
-		}
-	}
-	return best_time;
-}
-
-void IMuseInternal::sequencer_timers(MidiDriver *midi) {
-	Player *player = _players;
-	int i;
-	for (i = ARRAYSIZE(_players); i != 0; i--, player++) {
-		if (player->isActive() && player->getMidiDriver() == midi) {
-			player->onTimer();
-		}
-	}
-}
-
-void IMuseInternal::handle_marker(uint id, byte data) {
-	uint16 *p = 0;
-	uint pos;
-
-	if (_queue_adding && _queue_sound == id && data == _queue_marker)
-		return;
-
-	// Fix for bug #733401, revised for bug #761637:
-	// It would seem that sometimes a marker is in the queue
-	// but not at the head position. In the case of our bug,
-	// this seems to be the result of commands in the queue
-	// for songs that are no longer playing. So we skip
-	// ahead to the appropriate marker, effectively chomping
-	// anything in the queue before it. This fixes the FOA
-	// end credits music, but needs to be tested for inappopriate
-	// behavior elsewhere.
-	pos = _queue_end;
-	while (pos != _queue_pos) {
-		p = _cmd_queue[pos].array;
-		if (p[0] == TRIGGER_ID && p[1] == id && p[2] == data)
-			break;
-		pos = (pos + 1) % ARRAYSIZE(_cmd_queue);
-	}
-
-	if (pos == _queue_pos)
-		return;
-
-	if (pos != _queue_end)
-		debug(0, "Skipping entries in iMuse command queue to reach marker");
-
-	_trigger_count--;
-	_queue_cleared = false;
-	do {
-		pos = (pos + 1) % ARRAYSIZE(_cmd_queue);
-		if (_queue_pos == pos)
-			break;
-		p = _cmd_queue[pos].array;
-		if (*p++ != COMMAND_ID)
-			break;
-		_queue_end = pos;
-
-		doCommand(p[0], p[1], p[2], p[3], p[4], p[5], p[6], 0);
-
-		if (_queue_cleared)
-			return;
-		pos = _queue_end;
-	} while (1);
-
-	_queue_end = pos;
-}
-
-int IMuseInternal::get_channel_volume(uint a) {
-	if (a < 8)
-		return _channel_volume_eff[a];
-	return (_master_volume * _music_volume / 255) / 2;
-}
-
-Part *IMuseInternal::allocate_part(byte pri, MidiDriver *midi) {
-	Part *part, *best = NULL;
-	int i;
-
-	for (i = ARRAYSIZE(_parts), part = _parts; i != 0; i--, part++) {
-		if (!part->_player)
-			return part;
-		if (pri >= part->_pri_eff) {
-			pri = part->_pri_eff;
-			best = part;
-		}
-	}
-
-	if (best) {
-		best->uninit();
-		reallocateMidiChannels(midi);
-	} else {
-		debug(1, "Denying part request");
-	}
-	return best;
-}
-
-int IMuseInternal::getSoundStatus(int sound, bool ignoreFadeouts) const {
-	int i;
-	const Player *player = _players;
-
-	for (i = ARRAYSIZE(_players); i != 0; i--, player++) {
-		if (player->isActive() && (!ignoreFadeouts || !player->isFadingOut())) {
-			if (sound == -1)
-				return player->getID();
-			else if (player->getID() == (uint16)sound)
-				return 1;
-		}
-	}
-	return (sound == -1) ? 0 : get_queue_sound_status(sound);
-}
-
-int IMuseInternal::get_queue_sound_status(int sound) const {
-	const uint16 *a;
-	int i, j;
-
-	j = _queue_pos;
-	i = _queue_end;
-
-	while (i != j) {
-		a = _cmd_queue[i].array;
-		if (a[0] == COMMAND_ID && a[1] == 8 && a[2] == (uint16)sound)
-			return 2;
-		i = (i + 1) % ARRAYSIZE(_cmd_queue);
-	}
-
-	for (i = 0; i < ARRAYSIZE (_deferredCommands); ++i) {
-		if (_deferredCommands[i].time_left && _deferredCommands[i].a == 8 &&
-			_deferredCommands[i].b == sound) {
-			return 2;
-		}
-	}
-
-	return 0;
-}
-
-int IMuseInternal::set_volchan(int sound, int volchan) {
-	int r;
-	int i;
-	int num;
-	Player *player, *best, *sameid;
-
-	r = get_volchan_entry(volchan);
-	if (r == -1)
-		return -1;
-
-	if (r >= 8) {
-		player = findActivePlayer(sound);
-		if (player && player->_vol_chan != (uint16)volchan) {
-			player->_vol_chan = volchan;
-			player->setVolume(player->getVolume());
-			return 0;
-		}
-		return -1;
-	} else {
-		best = NULL;
-		num = 0;
-		sameid = NULL;
-		for (i = ARRAYSIZE(_players), player = _players; i != 0; i--, player++) {
-			if (player->isActive()) {
-				if (player->_vol_chan == (uint16)volchan) {
-					num++;
-					if (!best || player->getPriority() <= best->getPriority())
-						best = player;
-				} else if (player->getID() == (uint16)sound) {
-					sameid = player;
-				}
-			}
-		}
-		if (sameid == NULL)
-			return -1;
-		if (num >= r)
-			best->clear();
-		player->_vol_chan = volchan;
-		player->setVolume(player->getVolume());
-		return 0;
-	}
-}
-
-int IMuseInternal::clear_queue() {
-	_queue_adding = false;
-	_queue_cleared = true;
-	_queue_pos = 0;
-	_queue_end = 0;
-	_trigger_count = 0;
-	return 0;
-}
-
-int IMuseInternal::enqueue_command(int a, int b, int c, int d, int e, int f, int g) {
-	uint16 *p;
-	uint i;
-
-	i = _queue_pos;
-
-	if (i == _queue_end)
-		return -1;
-
-	if (a == -1) {
-		_queue_adding = false;
-		_trigger_count++;
-		return 0;
-	}
-
-	p = _cmd_queue[_queue_pos].array;
-	p[0] = COMMAND_ID;
-	p[1] = a;
-	p[2] = b;
-	p[3] = c;
-	p[4] = d;
-	p[5] = e;
-	p[6] = f;
-	p[7] = g;
-
-	i = (i + 1) % ARRAYSIZE(_cmd_queue);
-
-	if (_queue_end != i) {
-		_queue_pos = i;
-		return 0;
-	} else {
-		_queue_pos = (i - 1) % ARRAYSIZE(_cmd_queue);
-		return -1;
-	}
-}
-
-int IMuseInternal::query_queue(int param) {
-	switch (param) {
-	case 0: // Get trigger count
-		return _trigger_count;
-	case 1: // Get trigger type
-		if (_queue_end == _queue_pos)
-			return -1;
-		return _cmd_queue[_queue_end].array[1];
-	case 2: // Get trigger sound
-		if (_queue_end == _queue_pos)
-			return 0xFF;
-		return _cmd_queue[_queue_end].array[2];
-	default:
-		return -1;
-	}
-}
-
-int IMuseInternal::setMusicVolume(uint vol) {
-	if (vol > 255)
-		vol = 255;
-	if (_music_volume == vol)
-		return 0;
-	_music_volume = vol;
-	vol = _master_volume * _music_volume / 255;
-	for (uint i = 0; i < ARRAYSIZE(_channel_volume); i++) {
-		_channel_volume_eff[i] = _channel_volume[i] * vol / 255;
-	}
-	if (!_paused)
-		update_volumes();
-	return 0;
-}
-
-int IMuseInternal::setImuseMasterVolume(uint vol) {
-	if (vol > 255)
-		vol = 255;
-	if (_master_volume == vol)
-		return 0;
-	_master_volume = vol;
-	vol = _master_volume * _music_volume / 255;
-	for (uint i = 0; i < ARRAYSIZE(_channel_volume); i++) {
-		_channel_volume_eff[i] = _channel_volume[i] * vol / 255;
-	}
-	if (!_paused)
-		update_volumes();
-	return 0;
-}
-
-int IMuseInternal::terminate1() {
-	_initialized = false;
-	stopAllSounds();
-	return 0;
-}
-
-// This is the stuff that has to be done
-// outside the monitor's mutex, otherwise
-// a deadlock occurs.
-int IMuseInternal::terminate2() {
-	if (_midi_adlib) {
-		_midi_adlib->close();
-		delete _midi_adlib;
-		_midi_adlib = 0;
-	}
-
-	if (_midi_native) {
-		_midi_native->close();
-		delete _midi_native;
-		_midi_native = 0;
-	}
-
-	return 0;
-}
-
-int IMuseInternal::enqueue_trigger(int sound, int marker) {
-	uint16 *p;
-	uint pos;
-
-	pos = _queue_pos;
-
-	p = _cmd_queue[pos].array;
-	p[0] = TRIGGER_ID;
-	p[1] = sound;
-	p[2] = marker;
-
-	pos = (pos + 1) % ARRAYSIZE(_cmd_queue);
-	if (_queue_end == pos) {
-		_queue_pos = (pos - 1) % ARRAYSIZE(_cmd_queue);
-		return -1;
-	}
-
-	_queue_pos = pos;
-	_queue_adding = true;
-	_queue_sound = sound;
-	_queue_marker = marker;
-	return 0;
-}
-
-int32 IMuseInternal::doCommand(int a, int b, int c, int d, int e, int f, int g, int h) {
-	int args[8];
-	args[0] = a;
-	args[1] = b;
-	args[2] = c;
-	args[3] = d;
-	args[4] = e;
-	args[5] = f;
-	args[6] = g;
-	args[7] = h;
-	return doCommand(8, args);
-}
-
-int32 IMuseInternal::doCommand(int numargs, int a[]) {
-	int i;
-
-	if (numargs < 1)
-		return -1;
-	byte cmd = a[0] & 0xFF;
-	byte param = a[0] >> 8;
-	Player *player = NULL;
-
-	if (!_initialized && (cmd || param))
-		return -1;
-
-#ifdef IMUSE_DEBUG
-	{
-		char string[128];
-		sprintf(string, "doCommand - %d (%d/%d)", a[0], (int)param, (int)cmd);
-		for (i = 1; i < numargs; ++i)
-			sprintf(string + strlen(string), ", %d", a[i]);
-		debug(0, string);
-	}
-#endif
-
-	if (param == 0) {
-		switch (cmd) {
-		case 6:
-			if (a[1] > 127)
-				return -1;
-			else {
-				debug(0, "IMuse doCommand(6) - setImuseMasterVolume (%d)", a[1]);
-				return setImuseMasterVolume((a[1] << 1) | (a[1] ? 0 : 1)); // Convert from 0-127 to 0-255
-			}
-		case 7:
-			debug(0, "IMuse doCommand(7) - getMasterVolume (%d)", a[1]);
-			return _master_volume / 2; // Convert from 0-255 to 0-127
-		case 8:
-			return startSound(a[1]) ? 0 : -1;
-		case 9:
-			return stopSound(a[1]);
-		case 10: // FIXME: Sam and Max - Not sure if this is correct
-			return stopAllSounds();
-		case 11:
-			return stopAllSounds();
-		case 12:
-			// Sam & Max: Player-scope commands
-			player = findActivePlayer(a[1]);
-			if (!player)
-				return -1;
-
-			switch (a[3]) {
-			case 6:
-				// Set player volume.
-				return player->setVolume(a[4]);
-			default:
-				error("IMuseInternal::doCommand(12) unsupported sub-command %d", a[3]);
-			}
-			return -1;
-		case 13:
-			return getSoundStatus(a[1]);
-		case 14:
-			// Sam and Max: Parameter fade
-			player = findActivePlayer(a[1]);
-			if (player)
-				return player->addParameterFader(a[3], a[4], a[5]);
-			return -1;
-
-		case 15:
-			// Sam & Max: Set hook for a "maybe" jump
-			player = findActivePlayer(a[1]);
-			if (player) {
-				player->setHook(0, a[3], 0);
-				return 0;
-			}
-			return -1;
-		case 16:
-			debug(0, "IMuse doCommand(16) - set_volchan (%d, %d)", a[1], a[2]);
-			return set_volchan(a[1], a[2]);
-		case 17:
-			if (g_scumm->_game.id != GID_SAMNMAX) {
-				debug(0, "IMuse doCommand(17) - set_channel_volume (%d, %d)", a[1], a[2]);
-				return set_channel_volume(a[1], a[2]);
-			} else {
-				if (a[4]) {
-					int b[16];
-					memset(b, 0, sizeof(b));
-					for (i = 0; i < numargs; ++i)
-						b[i] = a[i];
-					return ImSetTrigger(b[1], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11]);
-				} else {
-					return ImClearTrigger(a[1], a[3]);
-				}
-			}
-		case 18:
-			if (g_scumm->_game.id != GID_SAMNMAX) {
-				return set_volchan_entry(a[1], a[2]);
-			} else {
-				// Sam & Max: ImCheckTrigger.
-				// According to Mike's notes to Ender,
-				// this function returns the number of triggers
-				// associated with a particular player ID and
-				// trigger ID.
-				a[0] = 0;
-				for (i = 0; i < ARRAYSIZE(_snm_triggers); ++i) {
-					if (_snm_triggers[i].sound == a[1] && _snm_triggers[i].id &&
-					   (a[3] == -1 || _snm_triggers[i].id == a[3]))
-					{
-						++a[0];
-					}
-				}
-				return a[0];
-			}
-		case 19:
-			// Sam & Max: ImClearTrigger
-			// This should clear a trigger that's been set up
-			// with ImSetTrigger(cmd == 17). Seems to work....
-			return ImClearTrigger(a[1], a[3]);
-		case 20:
-			// Sam & Max: Deferred Command
-			addDeferredCommand(a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
-			return 0;
-		case 2:
-		case 3:
-			return 0;
-		default:
-			error("doCommand(%d [%d/%d], %d, %d, %d, %d, %d, %d, %d) unsupported", a[0], param, cmd, a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
-		}
-	} else if (param == 1) {
-		if ((1 << cmd) & 0x783FFF) {
-			player = findActivePlayer(a[1]);
-			if (!player)
-				return -1;
-			if ((1 << cmd) & (1 << 11 | 1 << 22)) {
-				assert(a[2] >= 0 && a[2] <= 15);
-				player = (Player *)player->getPart(a[2]);
-				if (!player)
-					return -1;
-			}
-		}
-
-		switch (cmd) {
-		case 0:
-			if (g_scumm->_game.id == GID_SAMNMAX) {
-				if (a[3] == 1) // Measure number
-					return ((player->getBeatIndex() - 1) >> 2) + 1;
-				else if (a[3] == 2) // Beat number
-					return player->getBeatIndex();
-				return -1;
-			} else {
-				return player->getParam(a[2], a[3]);
-			}
-		case 1:
-			if (g_scumm->_game.id == GID_SAMNMAX) {
-				// FIXME: Could someone verify this?
-				//
-				// This jump instruction is known to be used in
-				// the following cases:
-				//
-				// 1) Going anywhere on the USA map
-				// 2) Winning the Wak-A-Rat game
-				// 3) Losing or quitting the Wak-A-Rat game
-				// 4) Conroy hitting Max with a golf club
-				//
-				// For all these cases the position parameters
-				// are always the same: 2, 1, 0, 0.
-				//
-				// 5) When leaving the bigfoot party. The
-				//    position parameters are: 3, 4, 300, 0
-				// 6) At Frog Rock, when the UFO appears. The
-				//    position parameters are: 10, 4, 400, 1
-				//
-				// The last two cases used to be buggy, so I
-				// have made a change to how the last two
-				// position parameters are handled. I still do
-				// not know if it's correct, but it sounds
-				// good to me at least.
-
-				debug(0, "doCommand(%d [%d/%d], %d, %d, %d, %d, %d, %d, %d)", a[0], param, cmd, a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
-				player->jump(a[3] - 1, (a[4] - 1) * 4 + a[5], a[6] + ((a[7] * player->getTicksPerBeat()) >> 2));
-			} else
-				player->setPriority(a[2]);
-			return 0;
-		case 2:
-			return player->setVolume(a[2]);
-		case 3:
-			player->setPan(a[2]);
-			return 0;
-		case 4:
-			return player->setTranspose(a[2], a[3]);
-		case 5:
-			player->setDetune(a[2]);
-			return 0;
-		case 6:
-			player->setSpeed(a[2]);
-			return 0;
-		case 7:
-			return player->jump(a[2], a[3], a[4]) ? 0 : -1;
-		case 8:
-			return player->scan(a[2], a[3], a[4]);
-		case 9:
-			return player->setLoop(a[2], a[3], a[4], a[5], a[6]) ? 0 : -1;
-		case 10:
-			player->clearLoop();
-			return 0;
-		case 11:
-			((Part *)player)->set_onoff(a[3] != 0);
-			return 0;
-		case 12:
-			return player->setHook(a[2], a[3], a[4]);
-		case 13:
-			return player->addParameterFader(ParameterFader::pfVolume, a[2], a[3]);
-		case 14:
-			return enqueue_trigger(a[1], a[2]);
-		case 15:
-			return enqueue_command(a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
-		case 16:
-			return clear_queue();
-		case 19:
-			return player->getParam(a[2], a[3]);
-		case 20:
-			return player->setHook(a[2], a[3], a[4]);
-		case 21:
-			return -1;
-		case 22:
-			((Part *)player)->volume(a[3]);
-			return 0;
-		case 23:
-			return query_queue(a[1]);
-		case 24:
-			return 0;
-		default:
-			error("doCommand(%d [%d/%d], %d, %d, %d, %d, %d, %d, %d) unsupported", a[0], param, cmd, a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
-			return -1;
-		}
-	}
-
-	return -1;
-}
-
-int32 IMuseInternal::ImSetTrigger(int sound, int id, int a, int b, int c, int d, int e, int f, int g, int h) {
-	// Sam & Max: ImSetTrigger.
-	// Sets a trigger for a particular player and
-	// marker ID, along with doCommand parameters
-	// to invoke at the marker. The marker is
-	// represented by MIDI SysEx block 00 xx(F7)
-	// where "xx" is the marker ID.
-	uint16 oldest_trigger = 0;
-	ImTrigger *oldest_ptr = NULL;
-
-	int i;
-	ImTrigger *trig = _snm_triggers;
-	for (i = ARRAYSIZE(_snm_triggers); i; --i, ++trig) {
-		if (!trig->id)
-			break;
-		// We used to only compare 'id' and 'sound' here, but at least
-		// at the Dino Bungie Memorial that causes the music to stop
-		// after getting the T-Rex tooth. See bug #888161.
-		if (trig->id == id && trig->sound == sound && trig->command[0] == a)
-			break;
-
-		uint16 diff;
-		if (trig->expire <= _snm_trigger_index)
-			diff = _snm_trigger_index - trig->expire;
-		else
-			diff = 0x10000 - trig->expire + _snm_trigger_index;
-
-		if (!oldest_ptr || oldest_trigger < diff) {
-			oldest_ptr = trig;
-			oldest_trigger = diff;
-		}
-	}
-
-	// If we didn't find a trigger, see if we can expire one.
-	if (!i) {
-		if (!oldest_ptr)
-			return -1;
-		trig = oldest_ptr;
-	}
-
-	trig->id = id;
-	trig->sound = sound;
-	trig->expire = (++_snm_trigger_index & 0xFFFF);
-	trig->command[0] = a;
-	trig->command[1] = b;
-	trig->command[2] = c;
-	trig->command[3] = d;
-	trig->command[4] = e;
-	trig->command[5] = f;
-	trig->command[6] = g;
-	trig->command[7] = h;
-
-	// If the command is to start a sound, stop that sound if it's already playing.
-	// This fixes some carnival music problems.
-	// NOTE: We ONLY do this if the sound that will trigger the command is actually
-	// playing. Otherwise, there's a problem when exiting and re-entering the
-	// Bumpusville mansion. Ref Bug #780918.
-	if (trig->command[0] == 8 && getSoundStatus(trig->command[1]) && getSoundStatus(sound))
-		stopSound(trig->command[1]);
-	return 0;
-}
-
-int32 IMuseInternal::ImClearTrigger(int sound, int id) {
-	int count = 0;
-	int i;
-	ImTrigger *trig = _snm_triggers;
-	for (i = ARRAYSIZE(_snm_triggers); i; --i, ++trig) {
-		if ((sound == -1 || trig->sound == sound) && trig->id && (id == -1 || trig->id == id)) {
-			trig->sound = trig->id = 0;
-			++count;
-		}
-	}
-	return (count > 0) ? 0 : -1;
-}
-
-int32 IMuseInternal::ImFireAllTriggers(int sound) {
-	if (!sound)
-		return 0;
-	int count = 0;
-	int i;
-	for (i = 0; i < ARRAYSIZE(_snm_triggers); ++i) {
-		if (_snm_triggers[i].sound == sound) {
-			_snm_triggers[i].sound = _snm_triggers[i].id = 0;
-			doCommand(8, _snm_triggers[i].command);
-			++count;
-		}
-	}
-	return (count > 0) ? 0 : -1;
-}
-
-int IMuseInternal::set_channel_volume(uint chan, uint vol)
-{
-	if (chan >= 8 || vol > 127)
-		return -1;
-
-	_channel_volume[chan] = vol;
-	_channel_volume_eff[chan] = _master_volume * _music_volume * vol / 255 / 255;
-	update_volumes();
-	return 0;
-}
-
-void IMuseInternal::update_volumes() {
-	Player *player;
-	int i;
-
-	for (i = ARRAYSIZE(_players), player = _players; i != 0; i--, player++) {
-		if (player->isActive())
-			player->setVolume(player->getVolume());
-	}
-}
-
-int IMuseInternal::set_volchan_entry(uint a, uint b) {
-	if (a >= 8)
-		return -1;
-	_volchan_table[a] = b;
-	return 0;
-}
-
-int HookDatas::query_param(int param, byte chan) {
-	switch (param) {
-	case 18:
-		return _jump[0];
-	case 19:
-		return _transpose;
-	case 20:
-		return _part_onoff[chan];
-	case 21:
-		return _part_volume[chan];
-	case 22:
-		return _part_program[chan];
-	case 23:
-		return _part_transpose[chan];
-	default:
-		return -1;
-	}
-}
-
-int HookDatas::set(byte cls, byte value, byte chan) {
-	switch (cls) {
-	case 0:
-		if (value != _jump[0]) {
-			_jump[1] = _jump[0];
-			_jump[0] = value;
-		}
-		break;
-	case 1:
-		_transpose = value;
-		break;
-	case 2:
-		if (chan < 16)
-			_part_onoff[chan] = value;
-		else if (chan == 16)
-			memset(_part_onoff, value, 16);
-		break;
-	case 3:
-		if (chan < 16)
-			_part_volume[chan] = value;
-		else if (chan == 16)
-			memset(_part_volume, value, 16);
-		break;
-	case 4:
-		if (chan < 16)
-			_part_program[chan] = value;
-		else if (chan == 16)
-			memset(_part_program, value, 16);
-		break;
-	case 5:
-		if (chan < 16)
-			_part_transpose[chan] = value;
-		else if (chan == 16)
-			memset(_part_transpose, value, 16);
-		break;
-	default:
-		return -1;
-	}
-	return 0;
-}
-
-Player *IMuseInternal::findActivePlayer(int id) {
-	int i;
-	Player *player = _players;
-
-	for (i = ARRAYSIZE(_players); i != 0; i--, player++) {
-		if (player->isActive() && player->getID() == (uint16)id)
-			return player;
-	}
-	return NULL;
-}
-
-int IMuseInternal::get_volchan_entry(uint a) {
-	if (a < 8)
-		return _volchan_table[a];
-	return -1;
-}
-
-uint32 IMuseInternal::property(int prop, uint32 value) {
-	switch (prop) {
-	case IMuse::PROP_TEMPO_BASE:
-		// This is a specified as a percentage of normal
-		// music speed. The number must be an integer
-		// ranging from 50 to 200(for 50% to 200% normal speed).
-		if (value >= 50 && value <= 200)
-			_tempoFactor = value;
-		break;
-
-	case IMuse::PROP_NATIVE_MT32:
-		_native_mt32 = (value > 0);
-		Instrument::nativeMT32(_native_mt32);
-		if (_midi_native && _native_mt32)
-			initMT32(_midi_native);
-		break;
-
-	case IMuse::PROP_GS:
-		_enable_gs = (value > 0);
-
-		// If True Roland MT-32 is not selected, run in GM or GS mode.
-		// If it is selected, change the Roland GS synth to MT-32 mode.
-		if (_midi_native && !_native_mt32)
-			initGM(_midi_native);
-		else if (_midi_native && _native_mt32 && _enable_gs) {
-			_sc55 = true;
-			initGM(_midi_native);
-		}
-		break;
-
-	case IMuse::PROP_LIMIT_PLAYERS:
-		if (value > 0 && value <= ARRAYSIZE(_players))
-			_player_limit = (int)value;
-		break;
-
-	case IMuse::PROP_RECYCLE_PLAYERS:
-		_recycle_players = (value != 0);
-		break;
-
-	case IMuse::PROP_DIRECT_PASSTHROUGH:
-		_direct_passthrough = (value != 0);
-		break;
-	}
-
-	return 0;
-}
-
-void IMuseInternal::setBase(byte **base) {
-	_base_sounds = base;
-}
-
-IMuseInternal *IMuseInternal::create(OSystem *syst, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver) {
-	IMuseInternal *i = new IMuseInternal;
-	i->initialize(syst, nativeMidiDriver, adlibMidiDriver);
-	return i;
-}
-
-int IMuseInternal::initialize(OSystem *syst, MidiDriver *native_midi, MidiDriver *adlib_midi) {
-	int i;
-
-	_midi_native = native_midi;
-	_midi_adlib = adlib_midi;
-	if (native_midi != NULL)
-		initMidiDriver(native_midi);
-	if (adlib_midi != NULL)
-		initMidiDriver(adlib_midi);
-
-	if (!_tempoFactor)
-		_tempoFactor = 100;
-	_master_volume = 255;
-
-	for (i = 0; i != 8; i++)
-		_channel_volume[i] = _channel_volume_eff[i] = _volchan_table[i] = 127;
-
-	init_players();
-	init_queue();
-	init_parts();
-
-	_initialized = true;
-
-	return 0;
-}
-
-void IMuseInternal::initMidiDriver(MidiDriver *midi) {
-	// Open MIDI driver
-	int result = midi->open();
-	if (result)
-		error("IMuse initialization - %s", MidiDriver::getErrorName(result));
-
-	// Connect to the driver's timer
-	midi->setTimerCallback(midi, &IMuseInternal::midiTimerCallback);
-}
-
-void IMuseInternal::initMT32(MidiDriver *midi) {
-	byte buffer[52];
-	char info[256] = "ScummVM ";
-	int len;
-
-	// Reset the MT-32
-	memcpy(&buffer[0], "\x41\x10\x16\x12\x7f\x00\x00\x01\x00", 9);
-	midi->sysEx(buffer, 9);
-	g_system->delayMillis(100);
-
-	// Compute version string (truncated to 20 chars max.)
-	strcat(info, gScummVMVersion);
-	len = strlen(info);
-	if (len > 20)
-		len = 20;
-
-	// Display a welcome message on MT-32 displays.
-	memcpy(&buffer[4], "\x20\x00\x00", 3);
-	memcpy(&buffer[7], "                    ", 20);
-	memcpy(buffer + 7 +(20 - len) / 2, info, len);
-	byte checksum = 0;
-	for (int i = 4; i < 27; ++i)
-		checksum -= buffer[i];
-	buffer[27] = checksum & 0x7F;
-	midi->sysEx(buffer, 28);
-	g_system->delayMillis(500);
-
-	// Setup master tune, reverb mode, reverb time, reverb level,
-	// channel mapping, partial reserve and master volume
-	memcpy(&buffer[4], "\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", 27);
-	midi->sysEx(buffer, 31);
-	g_system->delayMillis(250);
-
-	// Map percussion to notes 24 - 34 without reverb
-	memcpy(&buffer[4], "\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", 48);
-	midi->sysEx(buffer, 52);
-	g_system->delayMillis(250);
-}
-
-void IMuseInternal::initGM(MidiDriver *midi) {
-	byte buffer[11];
-	int i;
-
-	// General MIDI System On message
-	// Resets all GM devices to default settings
-	memcpy(&buffer[0], "\xF0\x7E\x7F\x09\x01\xF7", 6);
-	midi->sysEx(buffer, 6);
-	debug(2, "GM SysEx: GM System On");
-	g_system->delayMillis(200);
-
-	if (_enable_gs) {
-
-		// All GS devices recognize the GS Reset command,
-		// even with 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], "\xF0\x41\x10\x42\x12", 5);
-
-		// GS Reset
-		memcpy(&buffer[5], "\x40\x00\x7F\x00\x41\xF7", 6);
-		midi->sysEx(buffer, 11);
-		debug(2, "GS SysEx: GS Reset");
-		g_system->delayMillis(200);
-
-		if (_sc55) {
-			// This mode is for GS devices that support an MT-32-compatible
-			// Map, such as the Roland Sound Canvas line of modules. It
-			// will allow them to work with True MT-32 mode, but will
-			// obviously still ignore MT-32 SysEx (and thus custom
-			// instruments).
-
-			// 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[5], "\x40\x01\x3A\x00\x05\xF7", 6);
-		midi->sysEx(buffer, 11);
-		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->send((  0    << 16) | (100 << 8) | (0xB0 | i));
-			midi->send((  0    << 16) | (101 << 8) | (0xB0 | i));
-			midi->send((  12   << 16) | (6   << 8) | (0xB0 | i));
-			midi->send((  0    << 16) | (38  << 8) | (0xB0 | i));
-			midi->send((  127  << 16) | (100 << 8) | (0xB0 | i));
-			midi->send((  127  << 16) | (101 << 8) | (0xB0 | i));
-		}
-		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[5], "\x40\x20\x04\x04\x18\xF7", 6);
-		midi->sysEx(buffer, 11);
-		memcpy(&buffer[5], "\x40\x21\x04\x04\x17\xF7", 6);
-		midi->sysEx(buffer, 11);
-		memcpy(&buffer[5], "\x40\x22\x04\x04\x16\xF7", 6);
-		midi->sysEx(buffer, 11);
-		memcpy(&buffer[5], "\x40\x23\x04\x04\x15\xF7", 6);
-		midi->sysEx(buffer, 11);
-		memcpy(&buffer[5], "\x40\x24\x04\x04\x14\xF7", 6);
-		midi->sysEx(buffer, 11);
-		memcpy(&buffer[5], "\x40\x25\x04\x04\x13\xF7", 6);
-		midi->sysEx(buffer, 11);
-		memcpy(&buffer[5], "\x40\x26\x04\x04\x12\xF7", 6);
-		midi->sysEx(buffer, 11);
-		memcpy(&buffer[5], "\x40\x27\x04\x04\x11\xF7", 6);
-		midi->sysEx(buffer, 11);
-		memcpy(&buffer[5], "\x40\x28\x04\x04\x10\xF7", 6);
-		midi->sysEx(buffer, 11);
-		memcpy(&buffer[5], "\x40\x29\x04\x04\x0F\xF7", 6);
-		midi->sysEx(buffer, 11);
-		memcpy(&buffer[5], "\x40\x2A\x04\x04\x0E\xF7", 6);
-		midi->sysEx(buffer, 11);
-		memcpy(&buffer[5], "\x40\x2B\x04\x04\x0D\xF7", 6);
-		midi->sysEx(buffer, 11);
-		memcpy(&buffer[5], "\x40\x2C\x04\x04\x0C\xF7", 6);
-		midi->sysEx(buffer, 11);
-		memcpy(&buffer[5], "\x40\x2D\x04\x04\x0B\xF7", 6);
-		midi->sysEx(buffer, 11);
-		memcpy(&buffer[5], "\x40\x2E\x04\x04\x0A\xF7", 6);
-		midi->sysEx(buffer, 11);
-		memcpy(&buffer[5], "\x40\x2F\x04\x04\x09\xF7", 6);
-		midi->sysEx(buffer, 11);
-		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[5], "\x40\x10\x0E\x00\x22\xF7", 6);
-		midi->sysEx(buffer, 11);
-		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[5], "\x40\x01\x31\x00\x0E\xF7", 6);
-		midi->sysEx(buffer, 11);
-		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[5], "\x40\x01\x32\x04\x09\xF7", 6);
-		midi->sysEx(buffer, 11);
-		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[5], "\x40\x01\x34\x6A\x21\xF7", 6);
-		midi->sysEx(buffer, 11);
-		debug(2, "GS SysEx: Reverb Time is 106");
-	}
-}
-
-void IMuseInternal::init_queue() {
-	_queue_adding = false;
-	_queue_pos = 0;
-	_queue_end = 0;
-	_trigger_count = 0;
-}
-
-void IMuseInternal::pause(bool paused) {
-	if (_paused == paused)
-		return;
-	int vol = _music_volume;
-	if (paused)
-		_music_volume = 0;
-	update_volumes();
-	_music_volume = vol;
-
-	// Fix for Bug #817871. The MT-32 apparently fails
-	// sometimes to respond to a channel volume message
-	// (or only uses it for subsequent note events).
-	// The result is hanging notes on pause. Reportedly
-	// happens in the original distro, too. To fix that,
-	// just send AllNotesOff to the channels.
-	if (_midi_native && _native_mt32) {
-		for (int i = 0; i < 16; ++i)
-			_midi_native->send(123 << 8 | 0xB0 | i);
-	}
-
-	_paused = paused;
-}
-
-void IMuseInternal::handleDeferredCommands(MidiDriver *midi) {
-	uint32 advance = midi->getBaseTempo();
-
-	DeferredCommand *ptr = &_deferredCommands[0];
-	int i;
-	for (i = ARRAYSIZE(_deferredCommands); i; --i, ++ptr) {
-		if (!ptr->time_left)
-			continue;
-		if (ptr->time_left <= advance) {
-			doCommand(ptr->a, ptr->b, ptr->c, ptr->d, ptr->e, ptr->f, 0, 0);
-			ptr->time_left = advance;
-		}
-		ptr->time_left -= advance;
-	}
-}
-
-// "time" is interpreted as hundredths of a second.
-// FIXME: Is that correct?
-// We convert it to microseconds before prceeding
-void IMuseInternal::addDeferredCommand(int time, int a, int b, int c, int d, int e, int f) {
-	DeferredCommand *ptr = &_deferredCommands[0];
-	int i;
-	for (i = ARRAYSIZE(_deferredCommands); i; --i, ++ptr) {
-		if (!ptr->time_left)
-			break;
-	}
-
-	if (i) {
-		ptr->time_left = time * 10000;
-		ptr->a = a;
-		ptr->b = b;
-		ptr->c = c;
-		ptr->d = d;
-		ptr->e = e;
-		ptr->f = f;
-	}
-}
-
-////////////////////////////////////////////////////////////
-//
-// IMuseInternal load/save implementation
-//
-////////////////////////////////////////////////////////////
-
-int IMuseInternal::save_or_load(Serializer *ser, ScummEngine *scumm) {
-	const SaveLoadEntry mainEntries[] = {
-		MKLINE(IMuseInternal, _queue_end, sleUint8, VER(8)),
-		MKLINE(IMuseInternal, _queue_pos, sleUint8, VER(8)),
-		MKLINE(IMuseInternal, _queue_sound, sleUint16, VER(8)),
-		MKLINE(IMuseInternal, _queue_adding, sleByte, VER(8)),
-		MKLINE(IMuseInternal, _queue_marker, sleByte, VER(8)),
-		MKLINE(IMuseInternal, _queue_cleared, sleByte, VER(8)),
-		MKLINE(IMuseInternal, _master_volume, sleByte, VER(8)),
-		MKLINE(IMuseInternal, _trigger_count, sleUint16, VER(8)),
-		MKLINE(IMuseInternal, _snm_trigger_index, sleUint16, VER(54)),
-		MKARRAY(IMuseInternal, _channel_volume[0], sleUint16, 8, VER(8)),
-		MKARRAY(IMuseInternal, _volchan_table[0], sleUint16, 8, VER(8)),
-		MKEND()
-	};
-
-	const SaveLoadEntry cmdQueueEntries[] = {
-		MKARRAY(CommandQueue, array[0], sleUint16, 8, VER(23)),
-		MKEND()
-	};
-
-	// VolumeFader is obsolete.
-	const SaveLoadEntry volumeFaderEntries[] = {
-		MK_OBSOLETE(VolumeFader, player, sleUint16, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, active, sleUint8, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, curvol, sleUint8, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, speed_lo_max, sleUint16, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, num_steps, sleUint16, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, speed_hi, sleInt8, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, direction, sleInt8, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, speed_lo, sleInt8, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, speed_lo_counter, sleUint16, VER(8), VER(16)),
-		MKEND()
-	};
-
-	const SaveLoadEntry snmTriggerEntries[] = {
-		MKLINE(ImTrigger, sound, sleInt16, VER(54)),
-		MKLINE(ImTrigger, id, sleByte, VER(54)),
-		MKLINE(ImTrigger, expire, sleUint16, VER(54)),
-		MKARRAY(ImTrigger, command[0], sleUint16, 8, VER(54)),
-		MKEND()
-	};
-
-	int i;
-
-	ser->saveLoadEntries(this, mainEntries);
-	ser->saveLoadArrayOf(_cmd_queue, ARRAYSIZE(_cmd_queue), sizeof(_cmd_queue[0]), cmdQueueEntries);
-	ser->saveLoadArrayOf(_snm_triggers, ARRAYSIZE(_snm_triggers), sizeof(_snm_triggers[0]), snmTriggerEntries);
-
-	// The players
-	for (i = 0; i < ARRAYSIZE(_players); ++i)
-		_players[i].saveLoadWithSerializer(ser);
-	
-	// The parts
-	for (i = 0; i < ARRAYSIZE(_parts); ++i)
-		_parts[i].saveLoadWithSerializer(ser);
-
-	{ // Load/save the instrument definitions, which were revamped with V11.
-		Part *part = &_parts[0];
-		if (ser->getVersion() >= VER(11)) {
-			for (i = ARRAYSIZE(_parts); i; --i, ++part) {
-				part->_instrument.saveOrLoad(ser);
-			}
-		} else {
-			for (i = ARRAYSIZE(_parts); i; --i, ++part)
-				part->_instrument.clear();
-		}
-	}
-
-	// VolumeFader has been replaced with the more generic ParameterFader.
-	// FIXME: replace this loop by something like
-	// if (loading && version <= 16)  ser->skip(XXX bytes);
-	for (i = 0; i < 8; ++i)
-		ser->saveLoadEntries(0, volumeFaderEntries);
-
-	if (ser->isLoading()) {
-		// Load all sounds that we need
-		fix_players_after_load(scumm);
-		fix_parts_after_load();
-		setImuseMasterVolume(_master_volume);
-
-		if (_midi_native)
-			reallocateMidiChannels(_midi_native);
-		if (_midi_adlib)
-			reallocateMidiChannels(_midi_adlib);
-	}
-
-	return 0;
-}
-
-void IMuseInternal::fix_parts_after_load() {
-	Part *part;
-	int i;
-
-	for (i = ARRAYSIZE(_parts), part = _parts; i != 0; i--, part++) {
-		if (part->_player)
-			part->fix_after_load();
-	}
-}
-
-// Only call this routine from the main thread,
-// since it uses getResourceAddress
-void IMuseInternal::fix_players_after_load(ScummEngine *scumm) {
-	Player *player = _players;
-	int i;
-
-	for (i = ARRAYSIZE(_players); i != 0; i--, player++) {
-		if (player->isActive()) {
-			scumm->getResourceAddress(rtSound, player->getID());
-			player->fixAfterLoad();
-		}
-	}
-}
-
-Part::Part() {
-	_slot = 0;
-	_next = 0;
-	_prev = 0;
-	_mc = 0;
-	_player = 0;
-	_pitchbend = 0;
-	_pitchbend_factor = 0;
-	_transpose = 0;
-	_transpose_eff = 0;
-	_vol = 0;
-	_vol_eff = 0;
-	_detune = 0;
-	_detune_eff = 0;
-	_pan = 0;
-	_pan_eff = 0;
-	_on = false;
-	_modwheel = 0;
-	_pedal = false;
-	_pri = 0;
-	_pri_eff = 0;
-	_chan = 0;
-	_effect_level = 0;
-	_chorus = 0;
-	_percussion = 0;
-	_bank = 0;
-	_unassigned_instrument = false;
-}
-
-void Part::saveLoadWithSerializer(Serializer *ser) {
-	const SaveLoadEntry partEntries[] = {
-		MKLINE(Part, _pitchbend, sleInt16, VER(8)),
-		MKLINE(Part, _pitchbend_factor, sleUint8, VER(8)),
-		MKLINE(Part, _transpose, sleInt8, VER(8)),
-		MKLINE(Part, _vol, sleUint8, VER(8)),
-		MKLINE(Part, _detune, sleInt8, VER(8)),
-		MKLINE(Part, _pan, sleInt8, VER(8)),
-		MKLINE(Part, _on, sleUint8, VER(8)),
-		MKLINE(Part, _modwheel, sleUint8, VER(8)),
-		MKLINE(Part, _pedal, sleUint8, VER(8)),
-		MK_OBSOLETE(Part, _program, sleUint8, VER(8), VER(16)),
-		MKLINE(Part, _pri, sleUint8, VER(8)),
-		MKLINE(Part, _chan, sleUint8, VER(8)),
-		MKLINE(Part, _effect_level, sleUint8, VER(8)),
-		MKLINE(Part, _chorus, sleUint8, VER(8)),
-		MKLINE(Part, _percussion, sleUint8, VER(8)),
-		MKLINE(Part, _bank, sleUint8, VER(8)),
-		MKEND()
-	};
-
-	int num;
-	if (ser->isSaving()) {
-		num = (_next ? (_next - _se->_parts + 1) : 0);
-		ser->saveUint16(num);
-
-		num = (_prev ? (_prev - _se->_parts + 1) : 0);
-		ser->saveUint16(num);
-
-		num = (_player ? (_player - _se->_players + 1) : 0);
-		ser->saveUint16(num);
-	} else {
-		num = ser->loadUint16();
-		_next = (num ? &_se->_parts[num - 1] : 0);
-
-		num = ser->loadUint16();
-		_prev = (num ? &_se->_parts[num - 1] : 0);
-
-		num = ser->loadUint16();
-		_player = (num ? &_se->_players[num - 1] : 0);
-	}
-	ser->saveLoadEntries(this, partEntries);
-}
-
-void Part::set_detune(int8 detune) {
-	_detune_eff = clamp((_detune = detune) + _player->getDetune(), -128, 127);
-	if (_mc)
-		sendPitchBend();
-}
-
-void Part::pitchBend(int16 value) {
-	_pitchbend = value;
-	if (_mc)
-		sendPitchBend();
-}
-
-void Part::volume(byte value) {
-	_vol_eff = ((_vol = value) + 1) * _player->getEffectiveVolume() >> 7;
-	if (_mc)
-		_mc->volume(_vol_eff);
-}
-
-void Part::set_pri(int8 pri) {
-	_pri_eff = clamp((_pri = pri) + _player->getPriority(), 0, 255);
-	if (_mc)
-		_mc->priority(_pri_eff);
-}
-
-void Part::set_pan(int8 pan) {
-	_pan_eff = clamp((_pan = pan) + _player->getPan(), -64, 63);
-	if (_mc)
-		_mc->panPosition(_pan_eff + 0x40);
-}
-
-void Part::set_transpose(int8 transpose) {
-	_transpose_eff = transpose_clamp((_transpose = transpose) + _player->getTranspose(), -24, 24);
-	if (_mc)
-		sendPitchBend();
-}
-
-void Part::sustain(bool value) {
-	_pedal = value;
-	if (_mc)
-		_mc->sustain(value);
-}
-
-void Part::modulationWheel(byte value) {
-	_modwheel = value;
-	if (_mc)
-		_mc->modulationWheel(value);
-}
-
-void Part::chorusLevel(byte value) {
-	_chorus = value;
-	if (_mc)
-		_mc->chorusLevel(value);
-}
-
-void Part::effectLevel(byte value)
-{
-	_effect_level = value;
-	if (_mc)
-		_mc->effectLevel(value);
-}
-
-void Part::fix_after_load() {
-	set_transpose(_transpose);
-	volume(_vol);
-	set_detune(_detune);
-	set_pri(_pri);
-	set_pan(_pan);
-	sendAll();
-}
-
-void Part::pitchBendFactor(byte value) {
-	if (value > 12)
-		return;
-	pitchBend(0);
-	_pitchbend_factor = value;
-	if (_mc)
-		_mc->pitchBendFactor(value);
-}
-
-void Part::set_onoff(bool on) {
-	if (_on != on) {
-		_on = on;
-		if (!on)
-			off();
-		if (!_percussion)
-			_player->_se->reallocateMidiChannels(_player->getMidiDriver());
-	}
-}
-
-void Part::set_instrument(byte * data) {
-	_instrument.adlib(data);
-	if (clearToTransmit())
-		_instrument.send(_mc);
-}
-
-void Part::load_global_instrument(byte slot) {
-	_player->_se->copyGlobalAdlibInstrument(slot, &_instrument);
-	if (clearToTransmit())
-		_instrument.send(_mc);
-}
-
-void Part::noteOn(byte note, byte velocity) {
-	if (!_on)
-		return;
-
-	MidiChannel *mc = _mc;
-
-	// DEBUG
-	if (_unassigned_instrument && !_percussion) {
-		_unassigned_instrument = false;
-		if (!_instrument.isValid()) {
-			debug(0, "[%02d] No instrument specified", (int)_chan);
-			return;
-		}
-	}
-
-	if (mc && _instrument.isValid()) {
-		mc->noteOn(note, velocity);
-	} else if (_percussion) {
-		mc = _player->getMidiDriver()->getPercussionChannel();
-		if (!mc)
-			return;
-		static byte prev_vol_eff = 128;
-		if (_vol_eff != prev_vol_eff){
-			mc->volume(_vol_eff);
-			prev_vol_eff = _vol_eff;
-		}
-		if ((note < 35) && (!_player->_se->isNativeMT32()))
-			note = Instrument::_gmRhythmMap[note];
-
-		mc->noteOn(note, velocity);
-	}
-}
-
-void Part::noteOff(byte note) {
-	if (!_on)
-		return;
-
-	MidiChannel *mc = _mc;
-	if (mc) {
-		mc->noteOff(note);
-	} else if (_percussion) {
-		mc = _player->getMidiDriver()->getPercussionChannel();
-		if (mc)
-			mc->noteOff(note);
-	}
-}
-
-void Part::init() {
-	_player = NULL;
-	_next = NULL;
-	_prev = NULL;
-	_mc = NULL;
-}
-
-void Part::setup(Player *player) {
-	_player = player;
-
-	_percussion = (player->isMIDI() && _chan == 9); // true;
-	_on = true;
-	_pri_eff = player->getPriority();
-	_pri = 0;
-	_vol = 127;
-	_vol_eff = player->getEffectiveVolume();
-	_pan = clamp(player->getPan(), -64, 63);
-	_transpose_eff = player->getTranspose();
-	_transpose = 0;
-	_detune = 0;
-	_detune_eff = player->getDetune();
-	_pitchbend_factor = 2;
-	_pitchbend = 0;
-	_effect_level = 64;
-	_instrument.clear();
-	_unassigned_instrument = true;
-	_chorus = 0;
-	_modwheel = 0;
-	_bank = 0;
-	_pedal = false;
-	_mc = NULL;
-}
-
-void Part::uninit() {
-	if (!_player)
-		return;
-	off();
-	_player->removePart(this);
-	_player = NULL;
-}
-
-void Part::off() {
-	if (_mc) {
-		_mc->allNotesOff();
-		_mc->release();
-		_mc = NULL;
-	}
-}
-
-bool Part::clearToTransmit() {
-	if (_mc)
-		return true;
-	if (_instrument.isValid())
-		_player->_se->reallocateMidiChannels(_player->getMidiDriver());
-	return false;
-}
-
-void Part::sendAll() {
-	if (!clearToTransmit())
-		return;
-	_mc->pitchBendFactor(_pitchbend_factor);
-	sendPitchBend();
-	_mc->volume(_vol_eff);
-	_mc->sustain(_pedal);
-	_mc->modulationWheel(_modwheel);
-	_mc->panPosition(_pan_eff + 0x40);
-	_mc->effectLevel(_effect_level);
-	if (_instrument.isValid())
-		_instrument.send(_mc);
-	_mc->chorusLevel(_chorus);
-	_mc->priority(_pri_eff);
-}
-
-void Part::sendPitchBend() {
-	int16 bend = _pitchbend;
-	// RPN-based pitchbend range doesn't work for the MT32,
-	// so we'll do the scaling ourselves.
-	if (_player->_se->isNativeMT32())
-		bend = bend * _pitchbend_factor / 12;
-	_mc->pitchBend(clamp(bend + (_detune_eff * 64 / 12) + (_transpose_eff * 8192 / 12), -8192, 8191));
-}
-
-void Part::programChange(byte value) {
-	_bank = 0;
-	_instrument.program(value, _player->isMT32());
-	if (clearToTransmit())
-		_instrument.send(_mc);
-}
-
-void Part::set_instrument(uint b) {
-	_bank = (byte)(b >> 8);
-	if (_bank)
-		error("Non-zero instrument bank selection. Please report this");
-	_instrument.program((byte)b, _player->isMT32());
-	if (clearToTransmit())
-		_instrument.send(_mc);
-}
-
-void Part::allNotesOff() {
-	if (!_mc)
-		return;
-	_mc->allNotesOff();
-}
-
-////////////////////////////////////////
-//
-// Some more IMuseInternal stuff
-//
-////////////////////////////////////////
-
-void IMuseInternal::midiTimerCallback(void *data) {
-	MidiDriver *driver = (MidiDriver *)data;
-	if (g_scumm->_imuse)
-		g_scumm->_imuse->on_timer(driver);
-}
-
-void IMuseInternal::reallocateMidiChannels(MidiDriver *midi) {
-	Part *part, *hipart;
-	int i;
-	byte hipri, lopri;
-	Part *lopart;
-
-	while (true) {
-		hipri = 0;
-		hipart = NULL;
-		for (i = 32, part = _parts; i; i--, part++) {
-			if (part->_player && part->_player->getMidiDriver() == midi &&
-						!part->_percussion && part->_on &&
-						!part->_mc && part->_pri_eff >= hipri) {
-				hipri = part->_pri_eff;
-				hipart = part;
-			}
-		}
-
-		if (!hipart)
-			return;
-
-		if ((hipart->_mc = midi->allocateChannel()) == NULL) {
-			lopri = 255;
-			lopart = NULL;
-			for (i = 32, part = _parts; i; i--, part++) {
-				if (part->_mc && part->_mc->device() == midi && part->_pri_eff <= lopri) {
-					lopri = part->_pri_eff;
-					lopart = part;
-				}
-			}
-
-			if (lopart == NULL || lopri >= hipri)
-				return;
-			lopart->off();
-
-			if ((hipart->_mc = midi->allocateChannel()) == NULL)
-				return;
-		}
-		hipart->sendAll();
-	}
-}
-
-void IMuseInternal::setGlobalAdlibInstrument(byte slot, byte *data) {
-	if (slot < 32) {
-		_global_adlib_instruments[slot].adlib(data);
-	}
-}
-
-void IMuseInternal::copyGlobalAdlibInstrument(byte slot, Instrument *dest) {
-	if (slot >= 32)
-		return;
-	_global_adlib_instruments[slot].copy_to(dest);
-}
-
-////////////////////////////////////////////////////////////
-//
-// IMuse implementation
-//
-// IMuse actually serves as a concurency monitor front-end
-// to IMuseInternal and ensures that only one thread
-// accesses the object at a time. This is necessary to
-// prevent scripts and the MIDI parser from yanking objects
-// out from underneath each other.
-//
-////////////////////////////////////////////////////////////
-
-IMuse::IMuse(OSystem *system, IMuseInternal *target)
-	: _system(system), _target(target) {
-	_mutex = system->createMutex();
-}
-
-IMuse::~IMuse() {
-	if (_mutex)
-		_system->deleteMutex(_mutex);
-	if (_target)
-		delete _target;
-}
-
-inline void IMuse::in() const {
-	_system->lockMutex(_mutex);
-}
-inline void IMuse::out() const {
-	_system->unlockMutex(_mutex);
-}
-
-void IMuse::on_timer(MidiDriver *midi) { in(); _target->on_timer(midi); out(); }
-void IMuse::pause(bool paused) { in(); _target->pause(paused); out(); }
-int IMuse::save_or_load(Serializer *ser, ScummEngine *scumm) { in(); int ret = _target->save_or_load(ser, scumm); out(); return ret; }
-void IMuse::setMusicVolume(int vol) { in(); _target->setMusicVolume(vol); out(); }
-void IMuse::startSound(int sound) { in(); _target->startSound(sound); out(); }
-void IMuse::stopSound(int sound) { in(); _target->stopSound(sound); out(); }
-void IMuse::stopAllSounds() { in(); _target->stopAllSounds(); out(); }
-int IMuse::getSoundStatus(int sound) const { in(); int ret = _target->getSoundStatus(sound, true); out(); return ret; }
-bool IMuse::get_sound_active(int sound) const { in(); bool ret = _target->getSoundStatus(sound, false) ? 1 : 0; out(); return ret; }
-int IMuse::getMusicTimer() const { in(); int ret = _target->getMusicTimer(); out(); return ret; }
-int32 IMuse::doCommand(int a, int b, int c, int d, int e, int f, int g, int h) { in(); int32 ret = _target->doCommand(a,b,c,d,e,f,g,h); out(); return ret; }
-int32 IMuse::doCommand(int numargs, int args[]) { in(); int32 ret = _target->doCommand(numargs, args); out(); return ret; }
-int IMuse::clear_queue() { in(); int ret = _target->clear_queue(); out(); return ret; }
-void IMuse::setBase(byte **base) { in(); _target->setBase(base); out(); }
-uint32 IMuse::property(int prop, uint32 value) { in(); uint32 ret = _target->property(prop, value); out(); return ret; }
-void IMuse::terminate() { in(); _target->terminate1(); out(); _target->terminate2(); }
-
-// The IMuse::create method provides a front-end factory
-// for creating IMuseInternal without exposing that class
-// to the client.
-IMuse *IMuse::create(OSystem *syst, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver) {
-	IMuseInternal *engine = IMuseInternal::create(syst, nativeMidiDriver, adlibMidiDriver);
-	return new IMuse(syst, engine);
-}
-
-} // End of namespace Scumm

Deleted: scummvm/trunk/engines/scumm/imuse.h
===================================================================
--- scummvm/trunk/engines/scumm/imuse.h	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/imuse.h	2006-02-20 20:57:26 UTC (rev 20801)
@@ -1,85 +0,0 @@
-/* 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 IMUSE_H
-#define IMUSE_H
-
-#include "common/scummsys.h"
-#include "common/mutex.h"
-#include "scumm/music.h"
-
-class MidiDriver;
-class OSystem;
-
-namespace Scumm {
-
-class IMuseInternal;
-class ScummEngine;
-class Serializer;
-
-class IMuse : public MusicEngine {
-private:
-	OSystem *_system;
-	IMuseInternal *_target;
-	mutable Common::MutexRef _mutex;
-
-	IMuse(OSystem *system, IMuseInternal *target);
-	void in() const;
-	void out() const;
-
-public:
-	~IMuse();
-
-	enum {
-		PROP_TEMPO_BASE,
-		PROP_NATIVE_MT32,
-		PROP_GS,
-		PROP_LIMIT_PLAYERS,
-		PROP_RECYCLE_PLAYERS,
-		PROP_DIRECT_PASSTHROUGH
-	};
-
-	void on_timer(MidiDriver *midi);
-	void pause(bool paused);
-	int save_or_load(Serializer *ser, ScummEngine *scumm);
-	void setMusicVolume(int vol);
-	void startSound(int sound);
-	void stopSound(int sound);
-	void stopAllSounds();
-	int getSoundStatus(int sound) const;
-	bool get_sound_active(int sound) const;
-	int getMusicTimer() const;
-	int32 doCommand(int a, int b, int c, int d, int e, int f, int g, int h);
-	int32 doCommand(int numargs, int args[]);
-	int clear_queue();
-	void setBase(byte **base);
-	uint32 property(int prop, uint32 value);
-	void terminate();
-
-	// Factory methods
-	static IMuse *create(OSystem *syst, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver);
-};
-
-} // End of namespace Scumm
-
-#endif

Deleted: scummvm/trunk/engines/scumm/imuse_internal.h
===================================================================
--- scummvm/trunk/engines/scumm/imuse_internal.h	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/imuse_internal.h	2006-02-20 20:57:26 UTC (rev 20801)
@@ -1,472 +0,0 @@
-/* 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_IMUSE_INTERNAL
-#define DEFINED_IMUSE_INTERNAL
-
-#include "common/scummsys.h"
-#include "scumm/instrument.h"
-#include "scumm/saveload.h"
-#include "sound/mididrv.h"
-
-class MidiParser;
-class OSystem;
-
-namespace Scumm {
-
-// Unremark this statement to activate some of
-// the most common iMuse diagnostic messages.
-// #define IMUSE_DEBUG
-
-struct ParameterFader;
-struct DeferredCommand;
-struct ImTrigger;
-struct SustainingNotes;
-struct CommandQueue;
-struct IsNoteCmdData;
-class  Player;
-struct Part;
-class  IMuseInternal;
-
-// Some entities also referenced
-class ScummEngine;
-
-
-
-//////////////////////////////////////////////////
-//
-// Some constants
-//
-//////////////////////////////////////////////////
-
-#define TICKS_PER_BEAT 480
-
-#define TRIGGER_ID 0
-#define COMMAND_ID 1
-
-#define MDPG_TAG "MDpg"
-
-
-////////////////////////////////////////
-//
-//  Helper functions
-//
-////////////////////////////////////////
-
-inline int clamp(int val, int min, int max) {
-	if (val < min)
-		return min;
-	if (val > max)
-		return max;
-	return val;
-}
-
-inline int transpose_clamp(int a, int b, int c) {
-	if (b > a)
-		a += (b - a + 11) / 12 * 12;
-	if (c < a)
-		a -= (a - c + 11) / 12 * 12;
-	return a;
-}
-
-
-
-//////////////////////////////////////////////////
-//
-// Entity declarations
-//
-//////////////////////////////////////////////////
-
-struct HookDatas {
-	byte _jump[2];
-	byte _transpose;
-	byte _part_onoff[16];
-	byte _part_volume[16];
-	byte _part_program[16];
-	byte _part_transpose[16];
-
-	int query_param(int param, byte chan);
-	int set(byte cls, byte value, byte chan);
-	HookDatas() { memset(this, 0, sizeof(HookDatas)); }
-};
-
-struct ParameterFader {
-	enum {
-		pfVolume = 1,
-		pfTranspose = 3,
-		pfSpeed = 4
-	};
-
-	int param;
-	int start;
-	int end;
-	uint32 total_time;
-	uint32 current_time;
-
-	ParameterFader() { param = 0; }
-	void init() { param = 0; }
-};
-
-struct DeferredCommand {
-	uint32 time_left;
-	int a, b, c, d, e, f;
-	DeferredCommand() { memset(this, 0, sizeof(DeferredCommand)); }
-};
-
-struct ImTrigger {
-	int sound;
-	byte id;
-	uint16 expire;
-	int command [8];
-	ImTrigger() { memset(this, 0, sizeof(ImTrigger)); }
-};
-
-struct CommandQueue {
-	uint16 array[8];
-	CommandQueue() { memset(this, 0, sizeof(CommandQueue)); }
-};
-
-class Player : public MidiDriver {
-protected:
-	// Moved from IMuseInternal.
-	// This is only used by one player at a time.
-	static uint16 _active_notes[128];
-
-protected:
-	MidiDriver *_midi;
-	MidiParser *_parser;
-	bool _passThrough; // Only respond to EOT, all else direct to MidiDriver
-
-	Part *_parts;
-	bool _active;
-	bool _scanning;
-	int _id;
-	byte _priority;
-	byte _volume;
-	int8 _pan;
-	int8 _transpose;
-	int8 _detune;
-	byte _vol_eff;
-
-	uint _track_index;
-	uint _loop_to_beat;
-	uint _loop_from_beat;
-	uint _loop_counter;
-	uint _loop_to_tick;
-	uint _loop_from_tick;
-	byte _speed;
-	bool _abort;
-
-	// This does not get used by us! It is only
-	// here for save/load purposes, and gets
-	// passed on to the MidiParser during
-	// fixAfterLoad().
-	uint32 _music_tick;
-
-	HookDatas _hook;
-	ParameterFader _parameterFaders[4];
-
-	bool _isMT32;
-	bool _isMIDI;
-
-protected:
-	// Player part
-	void hook_clear();
-	void uninit_parts();
-	byte *parse_midi(byte *s);
-	void part_set_transpose(uint8 chan, byte relative, int8 b);
-	void parse_sysex(byte *p, uint len);
-	void maybe_jump(byte cmd, uint track, uint beat, uint tick);
-	void maybe_set_transpose(byte *data);
-	void maybe_part_onoff(byte *data);
-	void maybe_set_volume(byte *data);
-	void maybe_set_program(byte *data);
-	void maybe_set_transpose_part(byte *data);
-	void turn_off_pedals();
-	int  query_part_param(int param, byte chan);
-	void turn_off_parts();
-	void play_active_notes();
-
-	void transitionParameters();
-
-	static void decode_sysex_bytes(const byte *src, byte *dst, int len);
-
-	// Sequencer part
-	int start_seq_sound(int sound, bool reset_vars = true);
-	int query_param(int param);
-
-public:
-	IMuseInternal *_se;
-	uint _vol_chan;
-
-public:
-	Player();
-	virtual ~Player();
-
-	int	 addParameterFader(int param, int target, int time);
-	void clear();
-	void clearLoop();
-	void fixAfterLoad();
-	Part * getActivePart(uint8 part);
-	uint getBeatIndex();
-	int8 getDetune() const { return _detune; }
-	byte getEffectiveVolume() const { return _vol_eff; }
-	int getID() const { return _id; }
-	MidiDriver *getMidiDriver() const { return _midi; }
-	int getParam(int param, byte chan);
-	int8 getPan() const { return _pan; }
-	Part * getPart(uint8 part);
-	byte getPriority() const { return _priority; }
-	uint getTicksPerBeat() const { return TICKS_PER_BEAT; }
-	int8 getTranspose() const { return _transpose; }
-	byte getVolume() const { return _volume; }
-	bool isActive() const { return _active; }
-	bool isFadingOut() const;
-	bool isMIDI() const { return _isMIDI; }
-	bool isMT32() const { return _isMT32; }
-	bool jump(uint track, uint beat, uint tick);
-	void onTimer();
-	void removePart(Part *part);
-	int scan(uint totrack, uint tobeat, uint totick);
-	void saveLoadWithSerializer(Serializer *ser);
-	int setHook(byte cls, byte value, byte chan) { return _hook.set(cls, value, chan); }
-	void setDetune(int detune);
-	bool setLoop(uint count, uint tobeat, uint totick, uint frombeat, uint fromtick);
-	void setPan(int pan);
-	void setPriority(int pri);
-	void setSpeed(byte speed);
-	int setTranspose(byte relative, int b);
-	int setVolume(byte vol);
-	bool startSound(int sound, MidiDriver *midi, bool passThrough);
-	int getMusicTimer() const;
-
-public:
-	// MidiDriver interface
-	int open() { return 0; }
-	void close() { }
-	void send(uint32 b);
-	const char *getErrorName(int error_code) { return "Unknown"; }
-	void sysEx(byte *msg, uint16 length);
-	void metaEvent(byte type, byte *data, uint16 length);
-	void setTimerCallback(void *timer_param, void(*timer_proc)(void *)) { }
-	uint32 getBaseTempo();
-	MidiChannel *allocateChannel() { return 0; }
-	MidiChannel *getPercussionChannel() { return 0; }
-};
-
-struct Part : public Serializable {
-	IMuseInternal *_se;
-	int _slot;
-	Part *_next, *_prev;
-	MidiChannel *_mc;
-	Player *_player;
-	int16 _pitchbend;
-	byte _pitchbend_factor;
-	int8 _transpose, _transpose_eff;
-	byte _vol, _vol_eff;
-	int8 _detune, _detune_eff;
-	int8 _pan, _pan_eff;
-	bool _on;
-	byte _modwheel;
-	bool _pedal;
-	int8 _pri;
-	byte _pri_eff;
-	byte _chan;
-	byte _effect_level;
-	byte _chorus;
-	byte _percussion;
-	byte _bank;
-
-	// New abstract instrument definition
-	Instrument _instrument;
-	bool _unassigned_instrument; // For diagnostic reporting purposes only
-
-	// MidiChannel interface
-	// (We don't currently derive from MidiChannel,
-	//  but if we ever do, this will make it easy.)
-	void noteOff(byte note);
-	void noteOn(byte note, byte velocity);
-	void programChange(byte value);
-	void pitchBend(int16 value);
-	void modulationWheel(byte value);
-	void volume(byte value);
-	void pitchBendFactor(byte value);
-	void sustain(bool value);
-	void effectLevel(byte value);
-	void chorusLevel(byte value);
-	void allNotesOff();
-
-	void set_param(byte param, int value) { }
-	void init();
-	void setup(Player *player);
-	void uninit();
-	void off();
-	void set_instrument(uint b);
-	void set_instrument(byte *data);
-	void load_global_instrument(byte b);
-
-	void set_transpose(int8 transpose);
-	void set_detune(int8 detune);
-	void set_pri(int8 pri);
-	void set_pan(int8 pan);
-
-	void set_onoff(bool on);
-	void fix_after_load();
-
-	void sendAll();
-	void sendPitchBend();
-	bool clearToTransmit();
-
-	Part();
-
-	void saveLoadWithSerializer(Serializer *ser);
-};
-
-// WARNING: This is the internal variant of the IMUSE class.
-// imuse.h contains a public version of the same class.
-// the public version, only contains a set of methods.
-class IMuseInternal {
-	friend class Player;
-	friend struct Part;
-
-protected:
-	bool _native_mt32;
-	bool _enable_gs;
-	bool _sc55;
-	MidiDriver *_midi_adlib;
-	MidiDriver *_midi_native;
-
-	byte **_base_sounds;
-
-protected:
-	bool _paused;
-	bool _initialized;
-
-	int _tempoFactor;
-
-	int  _player_limit;       // Limits how many simultaneous music tracks are played
-	bool _recycle_players;    // Can we stop a player in order to start another one?
-	bool _direct_passthrough; // Pass data direct to MidiDriver (no interactivity)
-
-	uint _queue_end, _queue_pos, _queue_sound;
-	byte _queue_adding;
-
-	byte _queue_marker;
-	byte _queue_cleared;
-	byte _master_volume; // Master volume. 0-255
-	byte _music_volume; // Global music volume. 0-255
-
-	uint16 _trigger_count;
-	ImTrigger _snm_triggers[16]; // Sam & Max triggers
-	uint16 _snm_trigger_index;
-
-	uint16 _channel_volume[8];
-	uint16 _channel_volume_eff[8]; // No Save
-	uint16 _volchan_table[8];
-
-	Player _players[8];
-	Part _parts[32];
-
-	Instrument _global_adlib_instruments[32];
-	CommandQueue _cmd_queue[64];
-	DeferredCommand _deferredCommands[4];
-
-protected:
-	byte *findStartOfSound(int sound);
-	bool isMT32(int sound);
-	bool isMIDI(int sound);
-	int get_queue_sound_status(int sound) const;
-	void handle_marker(uint id, byte data);
-	int get_channel_volume(uint a);
-	void initMidiDriver(MidiDriver *midi);
-	void initGM(MidiDriver *midi);
-	void initMT32(MidiDriver *midi);
-	void init_players();
-	void init_parts();
-	void init_queue();
-
-	void sequencer_timers(MidiDriver *midi);
-
-	MidiDriver *getBestMidiDriver(int sound);
-	Player *allocate_player(byte priority);
-	Part *allocate_part(byte pri, MidiDriver *midi);
-
-	int32 ImSetTrigger(int sound, int id, int a, int b, int c, int d, int e, int f, int g, int h);
-	int32 ImClearTrigger(int sound, int id);
-	int32 ImFireAllTriggers(int sound);
-
-	void addDeferredCommand(int time, int a, int b, int c, int d, int e, int f);
-	void handleDeferredCommands(MidiDriver *midi);
-
-	int enqueue_command(int a, int b, int c, int d, int e, int f, int g);
-	int enqueue_trigger(int sound, int marker);
-	int query_queue(int param);
-	Player *findActivePlayer(int id);
-
-	int get_volchan_entry(uint a);
-	int set_volchan_entry(uint a, uint b);
-	int set_channel_volume(uint chan, uint vol);
-	void update_volumes();
-	void reset_tick();
-
-	int set_volchan(int sound, int volchan);
-
-	void fix_parts_after_load();
-	void fix_players_after_load(ScummEngine *scumm);
-
-	static void midiTimerCallback(void *data);
-
-public:
-	IMuseInternal();
-
-	int initialize(OSystem *syst, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver);
-	void reallocateMidiChannels(MidiDriver *midi);
-	void setGlobalAdlibInstrument(byte slot, byte *data);
-	void copyGlobalAdlibInstrument(byte slot, Instrument *dest);
-	bool isNativeMT32() { return _native_mt32; }
-
-	// IMuse interface
-
-	void on_timer(MidiDriver *midi);
-	void pause(bool paused);
-	int terminate1();
-	int terminate2();
-	int save_or_load(Serializer *ser, ScummEngine *scumm);
-	int setMusicVolume(uint vol);
-	int setImuseMasterVolume(uint vol);
-	bool startSound(int sound);
-	int stopSound(int sound);
-	int stopAllSounds();
-	int getSoundStatus(int sound, bool ignoreFadeouts = true) const;
-	int getMusicTimer() const;
-	int32 doCommand (int a, int b, int c, int d, int e, int f, int g, int h);
-	int32 doCommand (int numargs, int args[]);
-	int clear_queue();
-	void setBase(byte **base);
-	uint32 property(int prop, uint32 value);
-
-	static IMuseInternal *create(OSystem *syst, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver);
-};
-
-} // End of namespace Scumm
-
-#endif

Deleted: scummvm/trunk/engines/scumm/imuse_player.cpp
===================================================================
--- scummvm/trunk/engines/scumm/imuse_player.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/imuse_player.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -1,1241 +0,0 @@
-/* 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"
-#include "base/engine.h"
-
-#include "scumm/imuse_internal.h"
-#include "scumm/saveload.h"
-#include "scumm/scumm.h"
-
-#include "sound/midiparser.h"
-
-namespace Scumm {
-
-////////////////////////////////////////
-//
-//  Miscellaneous
-//
-////////////////////////////////////////
-
-#define IMUSE_SYSEX_ID 0x7D
-#define YM2612_SYSEX_ID 0x7C
-#define ROLAND_SYSEX_ID 0x41
-#define PERCUSSION_CHANNEL 9
-
-extern MidiParser *MidiParser_createRO();
-extern MidiParser *MidiParser_createEUP();
-
-uint16 Player::_active_notes[128];
-
-
-
-//////////////////////////////////////////////////
-//
-// IMuse Player implementation
-//
-//////////////////////////////////////////////////
-
-Player::Player() :
-	_midi(0),
-	_parser(0),
-	_passThrough(0),
-	_parts(0),
-	_active(false),
-	_scanning(false),
-	_id(0),
-	_priority(0),
-	_volume(0),
-	_pan(0),
-	_transpose(0),
-	_detune(0),
-	_vol_eff(0),
-	_track_index(0),
-	_loop_to_beat(0),
-	_loop_from_beat(0),
-	_loop_counter(0),
-	_loop_to_tick(0),
-	_loop_from_tick(0),
-	_speed(128),
-	_isMT32(false),
-	_isMIDI(false),
-	_se(0),
-	_vol_chan(0){
-}
-
-Player::~Player() {
-	if (_parser) {
-		delete _parser;
-		_parser = 0;
-	}
-}
-
-bool Player::startSound(int sound, MidiDriver *midi, bool passThrough) {
-	void *ptr;
-	int i;
-
-	// Not sure what the old code was doing,
-	// but we'll go ahead and do a similar check.
-	ptr = _se->findStartOfSound(sound);
-	if (!ptr) {
-		error("Player::startSound(): Couldn't find start of sound %d!", sound);
-		return false;
-	}
-
-	_isMT32 = _se->isMT32(sound);
-	_isMIDI = _se->isMIDI(sound);
-
-	_parts = NULL;
-	_active = true;
-	_midi = midi;
-	_id = sound;
-	_priority = 0x80;
-	_volume = 0x7F;
-	_vol_chan = 0xFFFF;
-	_vol_eff = (_se->get_channel_volume(0xFFFF) << 7) >> 7;
-	_pan = 0;
-	_transpose = 0;
-	_detune = 0;
-	_passThrough = passThrough;
-
-	for (i = 0; i < ARRAYSIZE(_parameterFaders); ++i)
-		_parameterFaders[i].init();
-	hook_clear();
-
-	if (start_seq_sound(sound) != 0) {
-		_active = false;
-		_midi = NULL;
-		return false;
-	}
-
-#ifdef IMUSE_DEBUG
-	debug(0, "Starting music %d", sound);
-#endif
-	return true;
-}
-
-int Player::getMusicTimer() const {
-	return _parser ? (_parser->getTick() * 2 / _parser->getPPQN()) : 0;
-}
-
-bool Player::isFadingOut() const {
-	int i;
-	for (i = 0; i < ARRAYSIZE(_parameterFaders); ++i) {
-		if (_parameterFaders[i].param == ParameterFader::pfVolume &&
-						_parameterFaders[i].end == 0) {
-			return true;
-		}
-	}
-	return false;
-}
-
-void Player::clear() {
-	if (!_active)
-		return;
-
-#ifdef IMUSE_DEBUG
-	debug(0, "Stopping music %d", _id);
-#endif
-
-	if (_parser) {
-		_parser->unloadMusic();
-		delete _parser;
-		_parser = 0;
-	}
-	uninit_parts();
-	_se->ImFireAllTriggers(_id);
-	_active = false;
-	_midi = NULL;
-	_id = 0;
-}
-
-void Player::hook_clear() {
-	memset(&_hook, 0, sizeof(_hook));
-}
-
-int Player::start_seq_sound(int sound, bool reset_vars) {
-	byte *ptr;
-
-	if (reset_vars) {
-		_loop_to_beat = 1;
-		_loop_from_beat = 1;
-		_track_index = 0;
-		_loop_counter = 0;
-		_loop_to_tick = 0;
-		_loop_from_tick = 0;
-	}
-
-	ptr = _se->findStartOfSound(sound);
-	if (ptr == NULL)
-		return -1;
-	if (_parser)
-		delete _parser;
-
-	if (!memcmp(ptr, "RO", 2)) {
-		// Old style 'RO' resource
-		_parser = MidiParser_createRO();
-	} else if (!memcmp(ptr, "SO", 2)) {
-		// Euphony (FM-TOWNS) resource
-		_parser = MidiParser_createEUP();
-	} else if (!memcmp(ptr, "FORM", 4)) {
-		// Humongous Games XMIDI resource
-		_parser = MidiParser::createParser_XMIDI();
-	} else {
-		// SCUMM SMF resource
-		_parser = MidiParser::createParser_SMF();
-	}
-
-	_parser->setMidiDriver(this);
-	_parser->property(MidiParser::mpSmartJump, 1);
-	_parser->loadMusic(ptr, 0);
-	_parser->setTrack(_track_index);
-	setSpeed(reset_vars ? 128 : _speed);
-
-	return 0;
-}
-
-void Player::uninit_parts() {
-	if (_parts && _parts->_player != this)
-		error("asd");
-	while (_parts)
-		_parts->uninit();
-
-	// In case another player is waiting to allocate parts
-	if (_midi)
-		_se->reallocateMidiChannels(_midi);
-}
-
-void Player::setSpeed(byte speed) {
-	_speed = speed;
-	if (_parser)
-		_parser->setTimerRate(((_midi->getBaseTempo() * speed) >> 7) * _se->_tempoFactor / 100);
-}
-
-void Player::send(uint32 b) {
-	if (_passThrough) {
-		_midi->send(b);
-		return;
-	}
-
-	byte cmd = (byte)(b & 0xF0);
-	byte chan = (byte)(b & 0x0F);
-	byte param1 = (byte)((b >> 8) & 0xFF);
-	byte param2 = (byte)((b >> 16) & 0xFF);
-	Part *part;
-
-	switch (cmd >> 4) {
-	case 0x8: // Key Off
-		if (!_scanning) {
-			if ((part = getPart(chan)) != 0)
-				part->noteOff(param1);
-		} else {
-			_active_notes[param1] &= ~(1 << chan);
-		}
-		break;
-
-	case 0x9: // Key On
-		if (!_scanning) {
-			if (_isMT32 && !_se->isNativeMT32())
-				param2 = (((param2 * 3) >> 2) + 32) & 0x7F;
-			if ((part = getPart(chan)) != 0)
-				part->noteOn(param1, param2);
-		} else {
-			_active_notes[param1] |= (1 << chan);
-		}
-		break;
-
-	case 0xB: // Control Change
-		part = (param1 == 123 ? getActivePart(chan) : getPart(chan));
-		if (!part)
-			break;
-
-		switch (param1) {
-		case 0: // Bank select. Not supported
-			break;
-		case 1: // Modulation Wheel
-			part->modulationWheel(param2);
-			break;
-		case 7: // Volume
-			part->volume(param2);
-			break;
-		case 10: // Pan Position
-			part->set_pan(param2 - 0x40);
-			break;
-		case 16: // Pitchbend Factor(non-standard)
-			part->pitchBendFactor(param2);
-			break;
-		case 17: // GP Slider 2
-			part->set_detune(param2 - 0x40);
-			break;
-		case 18: // GP Slider 3
-			part->set_pri(param2 - 0x40);
-			_se->reallocateMidiChannels(_midi);
-			break;
-		case 64: // Sustain Pedal
-			part->sustain(param2 != 0);
-			break;
-		case 91: // Effects Level
-			part->effectLevel(param2);
-			break;
-		case 93: // Chorus Level
-			part->chorusLevel(param2);
-			break;
-		case 116: // XMIDI For Loop. Not supported
-			// Used in the ending sequence of puttputt
-			break;
-		case 117: // XMIDI Next/Break. Not supported
-			// Used in the ending sequence of puttputt
-			break;
-		case 123: // All Notes Off
-			part->allNotesOff();
-			break;
-		default:
-			error("Player::send(): Invalid control change %d", param1);
-		}
-		break;
-
-	case 0xC: // Program Change
-		part = getPart(chan);
-		if (part) {
-			if (_isMIDI) {
-				if (param1 < 128)
-					part->programChange(param1);
-			} else {
-				if (param1 < 32)
-					part->load_global_instrument(param1);
-			}
-		}
-		break;
-
-	case 0xE: // Pitch Bend
-		part = getPart(chan);
-		if (part)
-			part->pitchBend(((param2 << 7) | param1) - 0x2000);
-		break;
-
-	case 0xA: // Aftertouch
-	case 0xD: // Channel Pressure
-	case 0xF: // Sequence Controls
-		break;
-
-	default:
-		if (!_scanning) {
-			error("Player::send(): Invalid command %d", cmd);
-			clear();
-		}
-	}
-	return;
-}
-
-void Player::sysEx(byte *p, uint16 len) {
-	byte code;
-	byte a;
-	uint b;
-	byte buf[128];
-	Part *part;
-
-	if (_passThrough) {
-		_midi->sysEx(p, len);
-		return;
-	}
-
-	// Check SysEx manufacturer.
-	a = *p++;
-	--len;
-	if (a != IMUSE_SYSEX_ID) {
-		if (a == ROLAND_SYSEX_ID) {
-			// Roland custom instrument definition.
-			part = getPart(p[0] & 0x0F);
-			if (part) {
-				part->_instrument.roland(p - 1);
-				if (part->clearToTransmit())
-					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 {
-			error("Unknown SysEx manufacturer 0x%02X", (int)a);
-		}
-		return;
-	}
-	--len;
-
-	// Too big?
-	if (len >= sizeof(buf) * 2)
-		return;
-
-#ifdef IMUSE_DEBUG
-	if (!_scanning) {
-		for (a = 0; a < len + 1 && a < 19; ++a) {
-			sprintf((char *)&buf[a*3], " %02X", p[a]);
-		} // next for
-		if (a < len + 1) {
-			buf[a*3] = buf[a*3+1] = buf[a*3+2] = '.';
-			++a;
-		} // end if
-		buf[a*3] = '\0';
-		debug(0, "[%02d] SysEx:%s", _id, buf);
-	}
-#endif
-
-	switch (code = *p++) {
-	case 0:
-		if (g_scumm->_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)
-			//   BYTE 04: Priority adjustment [guessing]
-			//   BYTE 05: Volume(upper 4 bits) [guessing]
-			//   BYTE 06: Volume(lower 4 bits) [guessing]
-			//   BYTE 09: BIT 04(0x08): Percussion?(1 = yes)
-			//   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->set_pri(p[4]);
-				part->volume((p[5] & 0x0F) << 4 |(p[6] & 0x0F));
-				part->_percussion = _isMIDI ? ((p[9] & 0x08) > 0) : false;
-				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:
-		// This SysEx is used in Sam & Max for 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);
-	}
-}
-
-void Player::decode_sysex_bytes(const byte *src, byte *dst, int len) {
-	while (len >= 0) {
-		*dst++ = ((src[0] << 4)&0xFF) | (src[1] & 0xF);
-		src += 2;
-		len -= 2;
-	}
-}
-
-void Player::maybe_jump(byte cmd, uint track, uint beat, uint tick) {
-	// Is this the hook I'm waiting for?
-	if (cmd && _hook._jump[0] != cmd)
-		return;
-
-	// Reset hook?
-	if (cmd != 0 && cmd < 0x80) {
-		_hook._jump[0] = _hook._jump[1];
-		_hook._jump[1] = 0;
-	}
-
-	jump(track, beat, tick);
-}
-
-void Player::maybe_set_transpose(byte *data) {
-	byte cmd;
-
-	cmd = data[0];
-
-	// Is this the hook I'm waiting for?
-	if (cmd && _hook._transpose != cmd)
-		return;
-
-	// Reset hook?
-	if (cmd != 0 && cmd < 0x80)
-		_hook._transpose = 0;
-
-	setTranspose(data[1], (int8)data[2]);
-}
-
-void Player::maybe_part_onoff(byte *data) {
-	byte cmd, *p;
-	uint chan;
-	Part *part;
-
-	cmd = data[1];
-	chan = data[0];
-
-	p = &_hook._part_onoff[chan];
-
-	// Is this the hook I'm waiting for?
-	if (cmd && *p != cmd)
-		return;
-
-	if (cmd != 0 && cmd < 0x80)
-		*p = 0;
-
-	part = getPart(chan);
-	if (part)
-		part->set_onoff(data[2] != 0);
-}
-
-void Player::maybe_set_volume(byte *data) {
-	byte cmd;
-	byte *p;
-	uint chan;
-	Part *part;
-
-	cmd = data[1];
-	chan = data[0];
-
-	p = &_hook._part_volume[chan];
-
-	// Is this the hook I'm waiting for?
-	if (cmd && *p != cmd)
-		return;
-
-	// Reset hook?
-	if (cmd != 0 && cmd < 0x80)
-		*p = 0;
-
-	part = getPart(chan);
-	if (part)
-		part->volume(data[2]);
-}
-
-void Player::maybe_set_program(byte *data) {
-	byte cmd;
-	byte *p;
-	uint chan;
-	Part *part;
-
-	cmd = data[1];
-	chan = data[0];
-
-	// Is this the hook I'm waiting for?
-	p = &_hook._part_program[chan];
-
-	if (cmd && *p != cmd)
-		return;
-
-	if (cmd != 0 && cmd < 0x80)
-		*p = 0;
-
-	part = getPart(chan);
-	if (part)
-		part->programChange(data[2]);
-}
-
-void Player::maybe_set_transpose_part(byte *data) {
-	byte cmd;
-	byte *p;
-	uint chan;
-
-	cmd = data[1];
-	chan = data[0];
-
-	// Is this the hook I'm waiting for?
-	p = &_hook._part_transpose[chan];
-
-	if (cmd && *p != cmd)
-		return;
-
-	// Reset hook?
-	if (cmd != 0 && cmd < 0x80)
-		*p = 0;
-
-	part_set_transpose(chan, data[2], (int8)data[3]);
-}
-
-int Player::setTranspose(byte relative, int b) {
-	Part *part;
-
-	if (b > 24 || b < -24 || relative > 1)
-		return -1;
-	if (relative)
-		b = transpose_clamp(_transpose + b, -24, 24);
-
-	_transpose = b;
-
-	for (part = _parts; part; part = part->_next) {
-		part->set_transpose(part->_transpose);
-	}
-
-	return 0;
-}
-
-void Player::part_set_transpose(uint8 chan, byte relative, int8 b) {
-	Part *part;
-
-	if (b > 24 || b < -24)
-		return;
-
-	part = getPart(chan);
-	if (!part)
-		return;
-	if (relative)
-		b = transpose_clamp(b + part->_transpose, -7, 7);
-	part->set_transpose(b);
-}
-
-bool Player::jump(uint track, uint beat, uint tick) {
-	if (!_parser)
-		return false;
-	if (_parser->setTrack(track))
-		_track_index = track;
-	if (!_parser->jumpToTick((beat - 1) * TICKS_PER_BEAT + tick))
-		return false;
-	turn_off_pedals();
-	return true;
-}
-
-bool Player::setLoop(uint count, uint tobeat, uint totick, uint frombeat, uint fromtick) {
-	if (tobeat + 1 >= frombeat)
-		return false;
-
-	if (tobeat == 0)
-		tobeat = 1;
-
-	_loop_counter = 0; // Because of possible interrupts
-	_loop_to_beat = tobeat;
-	_loop_to_tick = totick;
-	_loop_from_beat = frombeat;
-	_loop_from_tick = fromtick;
-	_loop_counter = count;
-
-	return true;
-}
-
-void Player::clearLoop() {
-	_loop_counter = 0;
-}
-
-void Player::turn_off_pedals() {
-	Part *part;
-
-	for (part = _parts; part; part = part->_next) {
-		if (part->_pedal)
-			part->sustain(false);
-	}
-}
-
-Part *Player::getActivePart(uint8 chan) {
-	Part *part = _parts;
-	while (part) {
-		if (part->_chan == chan)
-			return part;
-		part = part->_next;
-	}
-	return 0;
-}
-
-Part *Player::getPart(uint8 chan) {
-	Part *part = getActivePart(chan);
-	if (part)
-		return part;
-
-	part = _se->allocate_part(_priority, _midi);
-	if (!part) {
-		debug(1, "No parts available");
-		return NULL;
-	}
-
-	// Insert part into front of parts list
-	part->_prev = NULL;
-	part->_next = _parts;
-	if (_parts)
-		_parts->_prev = part;
-	_parts = part;
-
-
-	part->_chan = chan;
-	part->setup(this);
-
-	return part;
-}
-
-void Player::setPriority(int pri) {
-	Part *part;
-
-	_priority = pri;
-	for (part = _parts; part; part = part->_next) {
-		part->set_pri(part->_pri);
-	}
-	_se->reallocateMidiChannels(_midi);
-}
-
-void Player::setPan(int pan) {
-	Part *part;
-
-	_pan = pan;
-	for (part = _parts; part; part = part->_next) {
-		part->set_pan(part->_pan);
-	}
-}
-
-void Player::setDetune(int detune) {
-	Part *part;
-
-	_detune = detune;
-	for (part = _parts; part; part = part->_next) {
-		part->set_detune(part->_detune);
-	}
-}
-
-int Player::scan(uint totrack, uint tobeat, uint totick) {
-	if (!_active || !_parser)
-		return -1;
-
-	if (tobeat == 0)
-		tobeat++;
-
-	turn_off_parts();
-	memset(_active_notes, 0, sizeof(_active_notes));
-	_scanning = true;
-
-	// If the scan involves a track switch, scan to the end of
-	// the current track so that our state when starting the
-	// new track is fully up to date.
-	if (totrack != _track_index)
-		_parser->jumpToTick((uint32)-1, true);
-	_parser->setTrack(totrack);
-	if (!_parser->jumpToTick((tobeat - 1) * TICKS_PER_BEAT + totick, true)) {
-		_scanning = false;
-		return -1;
-	}
-
-	_scanning = false;
-	_se->reallocateMidiChannels(_midi);
-	play_active_notes();
-
-	if (_track_index != totrack) {
-		_track_index = totrack;
-		_loop_counter = 0;
-	}
-	return 0;
-}
-
-void Player::turn_off_parts() {
-	Part *part;
-
-	for (part = _parts; part; part = part->_next)
-		part->off();
-	_se->reallocateMidiChannels(_midi);
-}
-
-void Player::play_active_notes() {
-	int i, j;
-	uint mask;
-	Part *part;
-
-	for (i = 0; i < 16; ++i) {
-		part = getPart(i);
-		if (part) {
-			mask = 1 << i;
-			for (j = 0; j < 128; ++j) {
-				if (_active_notes[j] & mask)
-					part->noteOn(j, 80);
-			}
-		}
-	}
-}
-
-int Player::setVolume(byte vol) {
-	Part *part;
-
-	if (vol > 127)
-		return -1;
-
-	_volume = vol;
-	_vol_eff = _se->get_channel_volume(_vol_chan) * (vol + 1) >> 7;
-
-	for (part = _parts; part; part = part->_next) {
-		part->volume(part->_vol);
-	}
-
-	return 0;
-}
-
-int Player::getParam(int param, byte chan) {
-	switch (param) {
-	case 0:
-		return (byte)_priority;
-	case 1:
-		return (byte)_volume;
-	case 2:
-		return (byte)_pan;
-	case 3:
-		return (byte)_transpose;
-	case 4:
-		return (byte)_detune;
-	case 5:
-		return _speed;
-	case 6:
-		return _track_index;
-	case 7:
-		return getBeatIndex();
-	case 8:
-		return (_parser ? _parser->getTick() % TICKS_PER_BEAT : 0); // _tick_index;
-	case 9:
-		return _loop_counter;
-	case 10:
-		return _loop_to_beat;
-	case 11:
-		return _loop_to_tick;
-	case 12:
-		return _loop_from_beat;
-	case 13:
-		return _loop_from_tick;
-	case 14:
-	case 15:
-	case 16:
-	case 17:
-		return query_part_param(param, chan);
-	case 18:
-	case 19:
-	case 20:
-	case 21:
-	case 22:
-	case 23:
-		return _hook.query_param(param, chan);
-	default:
-		return -1;
-	}
-}
-
-int Player::query_part_param(int param, byte chan) {
-	Part *part;
-
-	part = _parts;
-	while (part) {
-		if (part->_chan == chan) {
-			switch (param) {
-			case 14:
-				return part->_on;
-			case 15:
-				return part->_vol;
-			case 16:
-// FIXME: Need to know where this occurs...
-error("Trying to cast instrument (%d, %d) -- please tell Fingolfin\n", param, chan);
-// In old versions of the code, this used to return part->_program.
-// This was changed in revision 2.29 of imuse.cpp (where this code used
-// to reside).
-//				return (int)part->_instrument;
-			case 17:
-				return part->_transpose;
-			default:
-				return -1;
-			}
-		}
-		part = part->_next;
-	}
-	return 129;
-}
-
-void Player::onTimer() {
-	// First handle any parameter transitions
-	// that are occuring.
-	transitionParameters();
-
-	// Since the volume parameter can cause
-	// the player to be deactivated, check
-	// to make sure we're still active.
-	if (!_active || !_parser)
-		return;
-
-	uint32 target_tick = _parser->getTick();
-	uint beat_index = target_tick / TICKS_PER_BEAT + 1;
-	uint tick_index = target_tick % TICKS_PER_BEAT;
-
-	if (_loop_counter &&(beat_index > _loop_from_beat ||
-	   (beat_index == _loop_from_beat && tick_index >= _loop_from_tick)))
-	{
-		_loop_counter--;
-		jump(_track_index, _loop_to_beat, _loop_to_tick);
-	}
-	_parser->onTimer();
-}
-
-// "time" is referenced as hundredths of a second.
-// IS THAT CORRECT??
-// We convert it to microseconds before proceeding
-int Player::addParameterFader(int param, int target, int time) {
-	int start;
-
-	switch (param) {
-	case ParameterFader::pfVolume:
-		// HACK: If volume is set to 0 with 0 time,
-		// set it so immediately but DON'T clear
-		// the player. This fixes a problem with
-		// music being cleared inappropriately
-		// in S&M when playing with the Dinosaur.
-		if (!target && !time) {
-			setVolume(0);
-			return 0;
-		}
-
-		// Volume fades are handled differently.
-		start = _volume;
-		break;
-
-	case ParameterFader::pfTranspose:
-		// FIXME: Is this transpose? And what's the scale?
-		// It's set to fade to -2400 in the tunnel of love.
-//		debug(0, "parameterTransition(3) outside Tunnel of Love?");
-		start = _transpose;
-//		target /= 200;
-		break;
-
-	case ParameterFader::pfSpeed: // impSpeed
-		// FIXME: Is the speed from 0-100?
-		// Right now I convert it to 0-128.
-		start = _speed;
-//		target = target * 128 / 100;
-		break;
-
-	case 127:
-		{ // FIXME? I *think* this clears all parameter faders.
-			ParameterFader *ptr = &_parameterFaders[0];
-			int i;
-			for (i = ARRAYSIZE(_parameterFaders); i; --i, ++ptr)
-				ptr->param = 0;
-			return 0;
-		}
-		break;
-
-	default:
-		debug(0, "Player::addParameterFader (%d, %d, %d): Unknown parameter", param, target, time);
-		return 0; // Should be -1, but we'll let the script think it worked.
-	}
-
-	ParameterFader *ptr = &_parameterFaders[0];
-	ParameterFader *best = 0;
-	int i;
-	for (i = ARRAYSIZE(_parameterFaders); i; --i, ++ptr) {
-		if (ptr->param == param) {
-			best = ptr;
-			start = ptr->end;
-			break;
-		} else if (!ptr->param) {
-			best = ptr;
-		}
-	}
-
-	if (best) {
-		best->param = param;
-		best->start = start;
-		best->end = target;
-		if (!time)
-			best->total_time = 1;
-		else
-			best->total_time = (uint32)time * 10000;
-		best->current_time = 0;
-	} else {
-		debug(0, "IMuse Player %d: Out of parameter faders", _id);
-		return -1;
-	}
-
-	return 0;
-}
-
-void Player::transitionParameters() {
-	uint32 advance = _midi->getBaseTempo();
-	int value;
-
-	ParameterFader *ptr = &_parameterFaders[0];
-	int i;
-	for (i = ARRAYSIZE(_parameterFaders); i; --i, ++ptr) {
-		if (!ptr->param)
-			continue;
-
-		ptr->current_time += advance;
-		if (ptr->current_time > ptr->total_time)
-			ptr->current_time = ptr->total_time;
-		value = (int32)ptr->start + (int32)(ptr->end - ptr->start) * (int32)ptr->current_time / (int32)ptr->total_time;
-
-		switch (ptr->param) {
-		case ParameterFader::pfVolume:
-			// Volume.
-			if (!value && !ptr->end) {
-				clear();
-				return;
-			}
-			setVolume((byte)value);
-			break;
-
-		case ParameterFader::pfTranspose:
-			// FIXME: Is this really transpose?
-			setTranspose(0, value / 100);
-			setDetune(value % 100);
-			break;
-
-		case ParameterFader::pfSpeed: // impSpeed:
-			// Speed.
-			setSpeed((byte)value);
-			break;
-
-		default:
-			ptr->param = 0;
-		}
-
-		if (ptr->current_time >= ptr->total_time)
-			ptr->param = 0;
-	}
-}
-
-uint Player::getBeatIndex() {
-	return (_parser ? (_parser->getTick() / TICKS_PER_BEAT + 1) : 0);
-}
-
-void Player::removePart(Part *part) {
-	// Unlink
-	if (part->_next)
-		part->_next->_prev = part->_prev;
-	if (part->_prev)
-		part->_prev->_next = part->_next;
-	else
-		_parts = part->_next;
-	part->_next = part->_prev = 0;
-}
-
-void Player::fixAfterLoad() {
-	_midi = _se->getBestMidiDriver(_id);
-	if (!_midi) {
-		clear();
-	} else {
-		start_seq_sound(_id, false);
-		setSpeed(_speed);
-		if (_parser)
-			_parser->jumpToTick(_music_tick); // start_seq_sound already switched tracks
-		_isMT32 = _se->isMT32(_id);
-		_isMIDI = _se->isMIDI(_id);
-	}
-}
-
-uint32 Player::getBaseTempo() {
-	return (_midi ? _midi->getBaseTempo() : 0);
-}
-
-void Player::metaEvent(byte type, byte *msg, uint16 len) {
-	if (type == 0x2F)
-		clear();
-}
-
-
-
-////////////////////////////////////////
-//
-//  Player save/load functions
-//
-////////////////////////////////////////
-
-void Player::saveLoadWithSerializer(Serializer *ser) {
-	static const SaveLoadEntry playerEntries[] = {
-		MKLINE(Player, _active, sleByte, VER(8)),
-		MKLINE(Player, _id, sleUint16, VER(8)),
-		MKLINE(Player, _priority, sleByte, VER(8)),
-		MKLINE(Player, _volume, sleByte, VER(8)),
-		MKLINE(Player, _pan, sleInt8, VER(8)),
-		MKLINE(Player, _transpose, sleByte, VER(8)),
-		MKLINE(Player, _detune, sleInt8, VER(8)),
-		MKLINE(Player, _vol_chan, sleUint16, VER(8)),
-		MKLINE(Player, _vol_eff, sleByte, VER(8)),
-		MKLINE(Player, _speed, sleByte, VER(8)),
-		MK_OBSOLETE(Player, _song_index, sleUint16, VER(8), VER(19)),
-		MKLINE(Player, _track_index, sleUint16, VER(8)),
-		MK_OBSOLETE(Player, _timer_counter, sleUint16, VER(8), VER(17)),
-		MKLINE(Player, _loop_to_beat, sleUint16, VER(8)),
-		MKLINE(Player, _loop_from_beat, sleUint16, VER(8)),
-		MKLINE(Player, _loop_counter, sleUint16, VER(8)),
-		MKLINE(Player, _loop_to_tick, sleUint16, VER(8)),
-		MKLINE(Player, _loop_from_tick, sleUint16, VER(8)),
-		MK_OBSOLETE(Player, _tempo, sleUint32, VER(8), VER(19)),
-		MK_OBSOLETE(Player, _cur_pos, sleUint32, VER(8), VER(17)),
-		MK_OBSOLETE(Player, _next_pos, sleUint32, VER(8), VER(17)),
-		MK_OBSOLETE(Player, _song_offset, sleUint32, VER(8), VER(17)),
-		MK_OBSOLETE(Player, _tick_index, sleUint16, VER(8), VER(17)),
-		MK_OBSOLETE(Player, _beat_index, sleUint16, VER(8), VER(17)),
-		MK_OBSOLETE(Player, _ticks_per_beat, sleUint16, VER(8), VER(17)),
-		MKLINE(Player, _music_tick, sleUint32, VER(19)),
-		MKLINE(Player, _hook._jump[0], sleByte, VER(8)),
-		MKLINE(Player, _hook._transpose, sleByte, VER(8)),
-		MKARRAY(Player, _hook._part_onoff[0], sleByte, 16, VER(8)),
-		MKARRAY(Player, _hook._part_volume[0], sleByte, 16, VER(8)),
-		MKARRAY(Player, _hook._part_program[0], sleByte, 16, VER(8)),
-		MKARRAY(Player, _hook._part_transpose[0], sleByte, 16, VER(8)),
-		MKEND()
-	};
-
-	const SaveLoadEntry parameterFaderEntries[] = {
-		MKLINE(ParameterFader, param,        sleInt16,  VER(17)),
-		MKLINE(ParameterFader, start,        sleInt16,  VER(17)),
-		MKLINE(ParameterFader, end,          sleInt16,  VER(17)),
-		MKLINE(ParameterFader, total_time,   sleUint32, VER(17)),
-		MKLINE(ParameterFader, current_time, sleUint32, VER(17)),
-		MKEND()
-	};
-
-	if (!ser->isSaving() && _parser) {
-		delete _parser;
-		_parser = 0;
-	}
-	_music_tick = _parser ? _parser->getTick() : 0;
-
-	int num;
-	if (ser->isSaving()) {
-		num = (_parts ? (_parts - _se->_parts + 1) : 0);
-		ser->saveUint16(num);
-	} else {
-		num = ser->loadUint16();
-		_parts = (num ? &_se->_parts[num - 1] : 0);
-	}
-	ser->saveLoadEntries(this, playerEntries);
-	ser->saveLoadArrayOf(_parameterFaders, ARRAYSIZE(_parameterFaders),
-						sizeof(ParameterFader), parameterFaderEntries);
-	return;
-}
-
-} // End of namespace Scumm

Modified: scummvm/trunk/engines/scumm/input.cpp
===================================================================
--- scummvm/trunk/engines/scumm/input.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/input.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -32,7 +32,7 @@
 #include "scumm/debugger.h"
 #include "scumm/dialogs.h"
 #include "scumm/insane/insane.h"
-#include "scumm/imuse.h"
+#include "scumm/imuse/imuse.h"
 #ifndef DISABLE_HE
 #include "scumm/he/intern_he.h"
 #include "scumm/he/logic_he.h"

Modified: scummvm/trunk/engines/scumm/insane/insane.cpp
===================================================================
--- scummvm/trunk/engines/scumm/insane/insane.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/insane/insane.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -31,7 +31,7 @@
 #include "scumm/actor.h"
 #include "scumm/sound.h"
 
-#include "scumm/imuse.h"
+#include "scumm/imuse/imuse.h"
 #include "scumm/imuse_digi/dimuse.h"
 
 #include "scumm/smush/smush_player.h"

Deleted: scummvm/trunk/engines/scumm/instrument.cpp
===================================================================
--- scummvm/trunk/engines/scumm/instrument.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/instrument.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -1,462 +0,0 @@
-/* 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 "scumm/scumm.h"
-#include "scumm/saveload.h"
-#include "scumm/instrument.h"
-#include "sound/mididrv.h"
-
-namespace Scumm {
-
-static bool _native_mt32 = false;
-
-static struct {
-	const char *name;
-	byte program;
-}
-
-roland_to_gm_map [] = {
-	// Monkey Island 2 instruments
-	// TODO: Complete
-	{ "badspit   ",  62 },
-	{ "Big Drum  ", 116 },
-	{ "burp      ",  58 },
-//	{ "dinkfall  ", ??? },
-//	{ "Fire Pit  ", ??? },
-	{ "foghorn   ",  60 },
-	{ "glop      ",  39 },
-//	{ "jacob's la", ??? },
-	{ "LeshBass  ",  33 },
-//	{ "lowsnort  ", ??? },
-	{ "ML explosn", 127 },
-	{ "ReggaeBass",  32 },
-//	{ "rope fall ", ??? },
-	{ "rumble    ",  89 },
-	{ "SdTrk Bend",  97 },
-//	{ "snort     ", ??? },
-	{ "spitting  ",  62 },
-	{ "Swell 1   ",  95 },
-	{ "Swell 2   ",  95 },
-	{ "thnderclap", 127 }
-
-	// Fate of Atlantis instruments
-	// TODO: Build
-//	{ "*aah!     ", ??? },
-//	{ "*ooh!     ", ??? },
-//	{ "*ShotFar4 ", ??? },
-//	{ "*splash3  ", ??? },
-//	{ "*torpedo5 ", ??? },
-//	{ "*whip3    ", ??? },
-//	{ "*woodknock", ??? },
-//	{ "35 lavabub", ??? },
-//	{ "49 bzzt!  ", ??? },
-//	{ "applause  ", ??? },
-//	{ "Arabongo  ", ??? },
-//	{ "Big Drum  ", ??? }, // DUPLICATE (todo: confirm)
-//	{ "bodythud1 ", ??? },
-//	{ "boneKLOK2 ", ??? },
-//	{ "boom10    ", ??? },
-//	{ "boom11    ", ??? },
-//	{ "boom15    ", ??? },
-//	{ "boxclik1a ", ??? },
-//	{ "brassbonk3", ??? },
-//	{ "carstart  ", ??? },
-//	{ "cb tpt 2  ", ??? },
-//	{ "cell door ", ??? },
-//	{ "chains    ", ??? },
-//	{ "crash     ", ??? },
-//	{ "crsrt/idl3", ??? },
-//	{ "Fire Pit  ", ??? }, // DUPLICATE (todo: confirm)
-//	{ "Fzooom    ", ??? },
-//	{ "Fzooom 2  ", ??? },
-//	{ "ghostwhosh", ??? },
-//	{ "glasssmash", ??? },
-//	{ "gloop2    ", ??? },
-//	{ "gunShotNea", ??? },
-//	{ "idoorclse ", ??? },
-//	{ "knife     ", ??? },
-//	{ "lavacmbl4 ", ??? },
-//	{ "Mellow Str", ??? },
-//	{ "mtlheater1", ??? },
-//	{ "pachinko5 ", ??? },
-//	{ "Ping1     ", ??? },
-//	{ "rockcrunch", ??? },
-//	{ "rumble    ", ??? }, // DUPLICATE (todo: confirm)
-//	{ "runngwatr ", ??? },
-//	{ "scrape2   ", ??? },
-//	{ "snakeHiss ", ??? },
-//	{ "snort     ", ??? }, // DUPLICATE (todo: confirm)
-//	{ "spindle4  ", ??? },
-//	{ "splash2   ", ??? },
-//	{ "squirel   ", ??? },
-//	{ "steam3    ", ??? },
-//	{ "stonwheel6", ??? },
-//	{ "street    ", ??? },
-//	{ "trickle4  ", ??? }
-};
-
-const byte Instrument::_gmRhythmMap[35] = {
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0, 36, 37, 38, 39, 40, 41, 66, 47,
-	 65, 48, 56};
-       // This emulates the percussion bank setup LEC used with the MT-32,
-       // where notes 24 - 34 were assigned instruments without reverb.
-       // It also fixes problems on GS devices that map sounds to these
-       // notes by default.
-
-class Instrument_Program : public InstrumentInternal {
-private:
-	byte _program;
-	bool _mt32;
-
-public:
-	Instrument_Program (byte program, bool mt32);
-	Instrument_Program (Serializer *s);
-	void saveOrLoad (Serializer *s);
-	void send (MidiChannel *mc);
-	void copy_to (Instrument *dest) { dest->program (_program, _mt32); }
-	bool is_valid() {
-		return (_program < 128) &&
-			((_native_mt32 == _mt32) || _native_mt32
-				? (MidiDriver::_gmToMt32[_program] < 128)
-				: (MidiDriver::_mt32ToGm[_program] < 128)); }
-};
-
-class Instrument_Adlib : public InstrumentInternal {
-private:
-	struct {
-		byte flags_1;
-		byte oplvl_1;
-		byte atdec_1;
-		byte sustrel_1;
-		byte waveform_1;
-		byte flags_2;
-		byte oplvl_2;
-		byte atdec_2;
-		byte sustrel_2;
-		byte waveform_2;
-		byte feedback;
-		byte flags_a;
-		struct { byte a,b,c,d,e,f,g,h; } extra_a;
-		byte flags_b;
-		struct { byte a,b,c,d,e,f,g,h; } extra_b;
-		byte duration;
-	} _instrument;
-
-public:
-	Instrument_Adlib (byte *data);
-	Instrument_Adlib (Serializer *s);
-	void saveOrLoad (Serializer *s);
-	void send (MidiChannel *mc);
-	void copy_to (Instrument *dest) { dest->adlib ((byte *) &_instrument); }
-	bool is_valid() { return true; }
-};
-
-class Instrument_Roland : public InstrumentInternal {
-private:
-	struct RolandInstrument {
-		byte roland_id;
-		byte device_id;
-		byte model_id;
-		byte command;
-		byte address[3];
-		struct {
-			byte name[10];
-			byte partial_struct12;
-			byte partial_struct34;
-			byte partial_mute;
-			byte env_mode;
-		} common;
-		struct {
-			byte wg_pitch_coarse;
-			byte wg_pitch_fine;
-			byte wg_pitch_keyfollow;
-			byte wg_pitch_bender_sw;
-			byte wg_waveform_pcm_bank;
-			byte wg_pcm_wave_num;
-			byte wg_pulse_width;
-			byte wg_pw_velo_sens;
-			byte p_env_depth;
-			byte p_evn_velo_sens;
-			byte p_env_time_keyf;
-			byte p_env_time[4];
-			byte p_env_level[3];
-			byte p_env_sustain_level;
-			byte end_level;
-			byte p_lfo_rate;
-			byte p_lfo_depth;
-			byte p_lfo_mod_sens;
-			byte tvf_cutoff_freq;
-			byte tvf_resonance;
-			byte tvf_keyfollow;
-			byte tvf_bias_point_dir;
-			byte tvf_bias_level;
-			byte tvf_env_depth;
-			byte tvf_env_velo_sens;
-			byte tvf_env_depth_keyf;
-			byte tvf_env_time_keyf;
-			byte tvf_env_time[5];
-			byte tvf_env_level[3];
-			byte tvf_env_sustain_level;
-			byte tva_level;
-			byte tva_velo_sens;
-			byte tva_bias_point_1;
-			byte tva_bias_level_1;
-			byte tva_bias_point_2;
-			byte tva_bias_level_2;
-			byte tva_env_time_keyf;
-			byte tva_env_time_v_follow;
-			byte tva_env_time[5];
-			byte tva_env_level[3];
-			byte tva_env_sustain_level;
-		} partial[4];
-		byte checksum;
-	} GNUPACK;
-	RolandInstrument _instrument;
-
-	char _instrument_name [11];
-
-	uint8 getEquivalentGM();
-
-public:
-	Instrument_Roland (byte *data);
-	Instrument_Roland (Serializer *s);
-	void saveOrLoad (Serializer *s);
-	void send (MidiChannel *mc);
-	void copy_to (Instrument *dest) { dest->roland ((byte *) &_instrument); }
-	bool is_valid() { return (_native_mt32 ? true : (_instrument_name[0] != '\0')); }
-};
-
-////////////////////////////////////////
-//
-// Instrument class members
-//
-////////////////////////////////////////
-
-void Instrument::nativeMT32 (bool native) {
-	_native_mt32 = native;
-}
-
-void Instrument::clear() {
-	if (_instrument)
-		delete _instrument;
-	_instrument = NULL;
-	_type = itNone;
-}
-
-void Instrument::program (byte prog, bool mt32) {
-	clear();
-	if (prog > 127)
-		return;
-	_type = itProgram;
-	_instrument = new Instrument_Program (prog, mt32);
-}
-
-void Instrument::adlib (byte *instrument) {
-	clear();
-	if (!instrument)
-		return;
-	_type = itAdlib;
-	_instrument = new Instrument_Adlib (instrument);
-}
-
-void Instrument::roland (byte *instrument) {
-	clear();
-	if (!instrument)
-		return;
-	_type = itRoland;
-	_instrument = new Instrument_Roland (instrument);
-}
-
-void Instrument::saveOrLoad (Serializer *s) {
-	if (s->isSaving()) {
-		s->saveByte (_type);
-		if (_instrument)
-			_instrument->saveOrLoad (s);
-	} else {
-		clear();
-		_type = s->loadByte();
-		switch (_type) {
-		case itNone:
-			break;
-		case itProgram:
-			_instrument = new Instrument_Program (s);
-			break;
-		case itAdlib:
-			_instrument = new Instrument_Adlib (s);
-			break;
-		case itRoland:
-			_instrument = new Instrument_Roland (s);
-			break;
-		default:
-			warning ("No known instrument classification #%d", (int) _type);
-			_type = itNone;
-		}
-	}
-}
-
-////////////////////////////////////////
-//
-// Instrument_Program class members
-//
-////////////////////////////////////////
-
-Instrument_Program::Instrument_Program (byte program, bool mt32) :
-_program (program),
-_mt32 (mt32) {
-	if (program > 127)
-		_program = 255;
-}
-
-Instrument_Program::Instrument_Program (Serializer *s) {
-	_program = 255;
-	if (!s->isSaving())
-		saveOrLoad (s);
-}
-
-void Instrument_Program::saveOrLoad (Serializer *s) {
-	if (s->isSaving()) {
-		s->saveByte (_program);
-		s->saveByte (_mt32 ? 1 : 0);
-	} else {
-		_program = s->loadByte();
-		_mt32 = (s->loadByte() > 0);
-	}
-}
-
-void Instrument_Program::send (MidiChannel *mc) {
-	if (_program > 127)
-		return;
-
-	byte program = _program;
-	if (_native_mt32 != _mt32)
-		program = _native_mt32 ? MidiDriver::_gmToMt32 [program] : MidiDriver::_mt32ToGm [program];
-	if (program < 128)
-		mc->programChange (program);
-}
-
-////////////////////////////////////////
-//
-// Instrument_Adlib class members
-//
-////////////////////////////////////////
-
-Instrument_Adlib::Instrument_Adlib (byte *data) {
-	memcpy (&_instrument, data, sizeof (_instrument));
-}
-
-Instrument_Adlib::Instrument_Adlib (Serializer *s) {
-	if (!s->isSaving())
-		saveOrLoad (s);
-	else
-		memset (&_instrument, 0, sizeof (_instrument));
-}
-
-void Instrument_Adlib::saveOrLoad (Serializer *s) {
-	if (s->isSaving())
-		s->saveBytes (&_instrument, sizeof (_instrument));
-	else
-		s->loadBytes (&_instrument, sizeof (_instrument));
-}
-
-void Instrument_Adlib::send (MidiChannel *mc) {
-	mc->sysEx_customInstrument ('ADL ', (byte *) &_instrument);
-}
-
-////////////////////////////////////////
-//
-// Instrument_Roland class members
-//
-////////////////////////////////////////
-
-Instrument_Roland::Instrument_Roland (byte *data) {
-	memcpy (&_instrument, data, sizeof (_instrument));
-	memcpy (&_instrument_name, &_instrument.common.name, sizeof (_instrument.common.name));
-	_instrument_name[10] = '\0';
-	if (!_native_mt32 && getEquivalentGM() >= 128) {
-		debug (0, "MT-32 instrument \"%s\" not supported yet", _instrument_name);
-		_instrument_name[0] = '\0';
-	}
-}
-
-Instrument_Roland::Instrument_Roland (Serializer *s) {
-	_instrument_name[0] = '\0';
-	if (!s->isSaving())
-		saveOrLoad (s);
-	else
-		memset (&_instrument, 0, sizeof (_instrument));
-}
-
-void Instrument_Roland::saveOrLoad (Serializer *s) {
-	if (s->isSaving()) {
-		s->saveBytes (&_instrument, sizeof (_instrument));
-	} else {
-		s->loadBytes (&_instrument, sizeof (_instrument));
-		memcpy (&_instrument_name, &_instrument.common.name, sizeof (_instrument.common.name));
-		_instrument_name[10] = '\0';
-		if (!_native_mt32 && getEquivalentGM() >= 128) {
-			debug (2, "MT-32 custom instrument \"%s\" not supported", _instrument_name);
-			_instrument_name[0] = '\0';
-		}
-	} // end if
-}
-
-void Instrument_Roland::send (MidiChannel *mc) {
-	if (_native_mt32) {
-		if (mc->getNumber() > 8)
-			return;
-		_instrument.device_id = mc->getNumber();
-
-		// Remap instrument to appropriate address space.
-		int address = 0x008000;
-		_instrument.address[0] = (address >> 14) & 0x7F;
-		_instrument.address[1] = (address >>  7) & 0x7F;
-		_instrument.address[2] = (address      ) & 0x7F;
-
-		// Recompute the checksum.
-		byte checksum = 0;
-		byte *ptr = (byte *) &_instrument + 4;
-		int i;
-		for (i = 4; i < (int)sizeof (_instrument) - 1; ++i)
-			checksum -= *ptr++;
-		_instrument.checksum = checksum & 0x7F;
-
-		mc->device()->sysEx ((byte *) &_instrument, sizeof (_instrument));
-	} else {
-		// Convert to a GM program change.
-		byte program = getEquivalentGM();
-		if (program < 128)
-			mc->programChange (program);
-	}
-}
-
-uint8 Instrument_Roland::getEquivalentGM() {
-	byte i;
-	for (i = 0; i != ARRAYSIZE(roland_to_gm_map); ++i) {
-		if (!memcmp (roland_to_gm_map[i].name, _instrument.common.name, 10))
-			return roland_to_gm_map[i].program;
-	}
-	return 255;
-}
-
-} // End of namespace Scumm

Deleted: scummvm/trunk/engines/scumm/instrument.h
===================================================================
--- scummvm/trunk/engines/scumm/instrument.h	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/instrument.h	2006-02-20 20:57:26 UTC (rev 20801)
@@ -1,79 +0,0 @@
-/* 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 INSTRUMENT_H
-#define INSTRUMENT_H
-
-#include "common/stdafx.h"
-#include "common/scummsys.h"
-
-class MidiChannel;
-
-namespace Scumm {
-
-class Serializer;
-class Instrument;
-
-class InstrumentInternal {
-public:
-	virtual ~InstrumentInternal() {}
-	virtual void saveOrLoad (Serializer *s) = 0;
-	virtual void send (MidiChannel *mc) = 0;
-	virtual void copy_to (Instrument *dest) = 0;
-	virtual bool is_valid() = 0;
-	virtual operator int() { return 255; }
-};
-
-class Instrument {
-private:
-	byte _type;
-	InstrumentInternal *_instrument;
-
-public:
-	enum {
-		itNone = 0,
-		itProgram = 1,
-		itAdlib = 2,
-		itRoland = 3
-	};
-
-	Instrument() : _type (0), _instrument (0) { }
-	~Instrument() { delete _instrument; }
-	static void nativeMT32 (bool native);
-	static const byte _gmRhythmMap[35];
-
-	void clear();
-	void copy_to (Instrument *dest) { if (_instrument) _instrument->copy_to (dest); else dest->clear(); }
-
-	void program (byte program, bool mt32);
-	void adlib (byte *instrument);
-	void roland (byte *instrument);
-
-	byte getType() { return _type; }
-	bool isValid() { return (_instrument ? _instrument->is_valid() : false); }
-	void saveOrLoad (Serializer *s);
-	void send (MidiChannel *mc) { if (_instrument) _instrument->send (mc); }
-};
-
-} // End of namespace Scumm
-
-#endif

Modified: scummvm/trunk/engines/scumm/module.mk
===================================================================
--- scummvm/trunk/engines/scumm/module.mk	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/module.mk	2006-02-20 20:57:26 UTC (rev 20801)
@@ -13,42 +13,42 @@
 	debugger.o \
 	dialogs.o \
 	gfx.o \
-	imuse.o \
-	imuse_player.o \
+	he/script_v60he.o \
+	he/sound_he.o \
+	help.o \
+	imuse/imuse_player.o \
+	imuse/imuse.o \
+	imuse/instrument.o \
 	input.o \
-	instrument.o \
-	help.o \
+	midiparser_eup.o \
 	midiparser_ro.o \
-	midiparser_eup.o \
 	object.o \
 	palette.o \
 	player_mod.o \
+	player_nes.o \
 	player_v1.o \
-	player_nes.o \
 	player_v2.o \
 	player_v2a.o \
 	player_v3a.o \
-	resource.o \
 	resource_v2.o \
 	resource_v3.o \
 	resource_v4.o \
+	resource.o \
 	room.o \
 	saveload.o \
-	script.o \
 	script_c64.o \
 	script_v2.o \
 	script_v5.o \
 	script_v6.o \
-	he/script_v60he.o \
+	script.o \
 	scumm.o \
 	sound.o \
-	he/sound_he.o \
 	string.o \
+	thumbnail.o \
 	usage_bits.o \
 	util.o \
 	vars.o \
-	verbs.o \
-	thumbnail.o
+	verbs.o
 
 ifndef DISABLE_SCUMM_7_8
 MODULE_OBJS += \
@@ -95,6 +95,8 @@
 
 MODULE_DIRS += \
 	engines/scumm \
+	engines/scumm/he \
+	engines/scumm/imuse \
 	engines/scumm/imuse_digi \
 	engines/scumm/insane \
 	engines/scumm/smush

Modified: scummvm/trunk/engines/scumm/resource.cpp
===================================================================
--- scummvm/trunk/engines/scumm/resource.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/resource.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -26,7 +26,7 @@
 
 #include "scumm/charset.h"
 #include "scumm/dialogs.h"
-#include "scumm/imuse.h"
+#include "scumm/imuse/imuse.h"
 #include "scumm/imuse_digi/dimuse.h"
 #include "scumm/intern.h"
 #ifndef DISABLE_HE

Modified: scummvm/trunk/engines/scumm/saveload.cpp
===================================================================
--- scummvm/trunk/engines/scumm/saveload.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/saveload.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -30,7 +30,7 @@
 #include "scumm/actor.h"
 #include "scumm/charset.h"
 #include "scumm/imuse_digi/dimuse.h"
-#include "scumm/imuse.h"
+#include "scumm/imuse/imuse.h"
 #include "scumm/intern.h"
 #include "scumm/he/intern_he.h"
 #include "scumm/object.h"

Modified: scummvm/trunk/engines/scumm/script_v6.cpp
===================================================================
--- scummvm/trunk/engines/scumm/script_v6.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/script_v6.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -27,7 +27,7 @@
 
 #include "scumm/actor.h"
 #include "scumm/charset.h"
-#include "scumm/imuse.h"
+#include "scumm/imuse/imuse.h"
 #include "scumm/imuse_digi/dimuse.h"
 #include "scumm/insane/insane.h"
 #include "scumm/intern.h"

Modified: scummvm/trunk/engines/scumm/scumm.cpp
===================================================================
--- scummvm/trunk/engines/scumm/scumm.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/scumm.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -40,7 +40,7 @@
 #include "scumm/costume.h"
 #include "scumm/debugger.h"
 #include "scumm/dialogs.h"
-#include "scumm/imuse.h"
+#include "scumm/imuse/imuse.h"
 #include "scumm/imuse_digi/dimuse.h"
 #include "scumm/insane/insane.h"
 #include "scumm/intern.h"

Modified: scummvm/trunk/engines/scumm/smush/smush_mixer.cpp
===================================================================
--- scummvm/trunk/engines/scumm/smush/smush_mixer.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/smush/smush_mixer.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -27,7 +27,7 @@
 #include "scumm/smush/channel.h"
 #include "scumm/scumm.h"
 #include "scumm/sound.h"
-#include "scumm/imuse.h"
+#include "scumm/imuse/imuse.h"
 
 #include "sound/mixer.h"
 

Modified: scummvm/trunk/engines/scumm/smush/smush_player.cpp
===================================================================
--- scummvm/trunk/engines/scumm/smush/smush_player.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/smush/smush_player.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -32,7 +32,7 @@
 
 #include "scumm/bomp.h"
 #include "scumm/imuse_digi/dimuse.h"
-#include "scumm/imuse.h"
+#include "scumm/imuse/imuse.h"
 #include "scumm/scumm.h"
 #include "scumm/sound.h"
 #include "scumm/smush/channel.h"

Modified: scummvm/trunk/engines/scumm/sound.cpp
===================================================================
--- scummvm/trunk/engines/scumm/sound.cpp	2006-02-20 20:42:03 UTC (rev 20800)
+++ scummvm/trunk/engines/scumm/sound.cpp	2006-02-20 20:57:26 UTC (rev 20801)
@@ -23,7 +23,7 @@
 
 #include "common/stdafx.h"
 #include "scumm/actor.h"
-#include "scumm/imuse.h"
+#include "scumm/imuse/imuse.h"
 #include "scumm/imuse_digi/dimuse.h"
 #include "scumm/scumm.h"
 #include "scumm/sound.h"







More information about the Scummvm-git-logs mailing list