[Scummvm-git-logs] scummvm master -> e815605b1bab62779765f6de4006bd2b3291fb93

NMIError noreply at scummvm.org
Sun Aug 16 15:11:45 UTC 2026


This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
ab9ac1f19a MADS: Move MT-32 driver to sound manager and improve Channel naming
e815605b1b MADS: Fixes for Rex MT-32 sound driver


Commit: ab9ac1f19abc54b59c86b42df04b1436e571103f
    https://github.com/scummvm/scummvm/commit/ab9ac1f19abc54b59c86b42df04b1436e571103f
Author: Coen Rampen (crampen at gmail.com)
Date: 2026-08-16T16:49:59+02:00

Commit Message:
MADS: Move MT-32 driver to sound manager and improve Channel naming

Changed paths:
    engines/mads/core/sound_manager.cpp
    engines/mads/core/sound_manager.h
    engines/mads/nebular/sound/rsound.cpp
    engines/mads/nebular/sound/rsound.h
    engines/mads/nebular/sound/rsound_nebular.cpp
    engines/mads/nebular/sound/rsound_nebular.h
    engines/mads/nebular/sound/sound.cpp


diff --git a/engines/mads/core/sound_manager.cpp b/engines/mads/core/sound_manager.cpp
index cc3525c1eff..0155a3d52a6 100644
--- a/engines/mads/core/sound_manager.cpp
+++ b/engines/mads/core/sound_manager.cpp
@@ -33,8 +33,14 @@ class Mixer;
 
 namespace MADS {
 
-SoundManager::SoundManager(Audio::Mixer *mixer, bool &soundFlag,
+	const uint32 SoundManager::UPDATE_DELTA = 1000000 / 60;
+
+	SoundManager::SoundManager(Audio::Mixer *mixer, bool &soundFlag,
 		bool supportsGeneralMidi) : _mixer(mixer), _soundFlag(soundFlag) {
+	_updateDeltaRemainder = 0;
+	_driverCallbackDelta = 0;
+	_midiDriver = nullptr;
+
 	MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32);
 	MusicType musicType = MidiDriver::getMusicType(dev);
 	if ((musicType == MT_GM || musicType == MT_GS) && ConfMan.getBool("native_mt32"))
@@ -42,6 +48,15 @@ SoundManager::SoundManager(Audio::Mixer *mixer, bool &soundFlag,
 	switch (musicType) {
 	case MT_MT32:
 		_driverType = SOUND_MT32;
+		_midiDriver = new MidiDriver_MT32GM(MusicType::MT_MT32);
+		int returnCode;
+		returnCode = _midiDriver->open();
+		if (returnCode != 0)
+			error("RSound - Failed to open MIDI music driver - error code %d.", returnCode);
+
+		_driverCallbackDelta = _midiDriver->getBaseTempo();
+		_midiDriver->setTimerCallback(this, &timerCallback);
+
 		break;
 	case MT_GM:
 	case MT_GS:
@@ -57,9 +72,21 @@ SoundManager::SoundManager(Audio::Mixer *mixer, bool &soundFlag,
 }
 
 SoundManager::~SoundManager() {
-	if (_driver) {
+	if (_driver != nullptr) {
 		_driver->stop();
+	}
+	if (_midiDriver != nullptr) {
+		_midiDriver->setTimerCallback(nullptr, nullptr);
+		_midiDriver->close();
+	}
+
+	if (_driver != nullptr) {
 		delete _driver;
+		_driver = nullptr;
+	}
+	if (_midiDriver != nullptr) {
+		delete _midiDriver;
+		_midiDriver = nullptr;
 	}
 }
 
@@ -144,6 +171,23 @@ void SoundManager::noise() {
 		_driver->noise();
 }
 
+void SoundManager::onTimer() {
+	// The frequency of the callbacks is dependent on the underlying driver
+	// implementation and might not be 60Hz. Adjust to make sure poll() is called
+	// with the correct frequency.
+	_updateDeltaRemainder += _driverCallbackDelta;
+	while (_updateDeltaRemainder >= UPDATE_DELTA) {
+		if (_driver)
+			_driver->poll();
+		_updateDeltaRemainder -= UPDATE_DELTA;
+	}
+}
+
+void SoundManager::timerCallback(void *data) {
+	SoundManager *soundManager = (SoundManager *)data;
+	soundManager->onTimer();
+}
+
 //====================================================================
 
 SoundDriver::SoundDriver(Audio::Mixer *mixer, const Common::Path &filename,
diff --git a/engines/mads/core/sound_manager.h b/engines/mads/core/sound_manager.h
index c48aaea47ce..22d47028219 100644
--- a/engines/mads/core/sound_manager.h
+++ b/engines/mads/core/sound_manager.h
@@ -22,6 +22,7 @@
 #ifndef MADS_CORE_SOUND_MANAGER_H
 #define MADS_CORE_SOUND_MANAGER_H
 
+#include "audio/mt32gm.h"
 #include "common/array.h"
 #include "common/memstream.h"
 #include "common/mutex.h"
@@ -98,9 +99,16 @@ protected:
 		int _param;
 	};
 
+	// Number of microseconds between driver updates (60 Hz frequency)
+	static const uint32 UPDATE_DELTA;
+
 	enum DriverType { SOUND_ADLIB, SOUND_MT32, SOUND_GM, SOUND_PCSPEAKER, SOUND_PAS };
 	Audio::Mixer *_mixer;
 	DriverType _driverType;
+	MidiDriver_MT32GM *_midiDriver;
+	uint32 _driverCallbackDelta;
+	uint32 _updateDeltaRemainder;
+
 	bool &_soundFlag;
 	SoundDriver *_driver = nullptr;
 	bool _newSoundsPaused = false;
@@ -193,6 +201,9 @@ public:
 	void noise();
 
 	//@}
+
+	void onTimer();
+	static void timerCallback(void *data);
 };
 
 } // namespace MADS
diff --git a/engines/mads/nebular/sound/rsound.cpp b/engines/mads/nebular/sound/rsound.cpp
index 2c2ef48c2d8..1df08cb7bc2 100644
--- a/engines/mads/nebular/sound/rsound.cpp
+++ b/engines/mads/nebular/sound/rsound.cpp
@@ -29,46 +29,45 @@ namespace MADS {
 namespace RexNebular {
 namespace Sound {
 
-void Channel::reset(byte *startPtr) {
-	_pitchBendFadeStep = 0;
-	_panFadeStep = 0;
-	_innerLoopCount = 0;
-	_outerLoopCount = 0;
-	_noteOffset = 0;
-	_pendingStop = 0;
-	_volumeFadeReload = 0xFF;
+void Channel::loadData(byte *soundData) {
+	_pitchSlideStepSize = 0;
+	_panningSweepStepSize = 0;
+	_innerLoopCounter = 0;
+	_outerLoopCounter = 0;
+	_noteDurationOffset = 0;
+	_fadeOutActive = 0;
+	_volumeFadeSpeed = 0xFF;
 	_pitchBend = 64;
-	_pan = 64;
-	_loopStartPtr = startPtr;
-	_pSrc = startPtr;
-	_innerLoopPtr = startPtr;
-	_outerLoopPtr = startPtr;
-	_soundData = startPtr;
+	_panning = 64;
+	_soundDataStart = soundData;
+	_pSrc = soundData;
+	_innerLoopStart = soundData;
+	_outerLoopStart = soundData;
+	_soundData = soundData;
 }
 
-void Channel::enable(int flag) {
-	if (_activeCount) {
-		_pendingStop = flag;
+void Channel::setFadeOut(bool fadeOut) {
+	if (_deltaCounter) {
+		_fadeOutActive = fadeOut;
 
 		// WORKAROUND: matches the same apparent original-code quirk
-		// documented in AdlibChannel::enable() - the original set
+		// documented in AdlibChannel::setFadeOut() - the original set
 		// _soundData to the flag value here, which we replace with
 		// a simple null pointer.
 		_soundData = nullptr;
 	}
 }
 
-void Channel::load(byte *pData) {
-	reset(pData);
-	_activeCount = 1;
+void Channel::playData(byte *soundData) {
+	loadData(soundData);
+	_deltaCounter = 1;
 	_owner->sendPitchBend(_midiChannel, 0x40);
 }
 
 /*-----------------------------------------------------------------------*/
 
-RSound::RSound(Audio::Mixer *mixer, const Common::Path &filename,
-		int dataOffset, int dataSize, int sysExOffset,
-		RSoundFadeCheckMode fadeCheckMode) :
+RSound::RSound(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver, const Common::Path &filename,
+		int dataOffset, int dataSize, int sysExOffset, RSoundFadeCheckMode fadeCheckMode) : 
 		SoundDriver(mixer, filename, dataOffset, dataSize) {
 	_commandParam = 0;
 	_frameCounter = 0;
@@ -80,6 +79,7 @@ RSound::RSound(Audio::Mixer *mixer, const Common::Path &filename,
 	_pollResult = 0;
 	_resultFlag = 0;
 	_sysExOffset = sysExOffset;
+	_midiDriver = midiDriver;
 	_fadeCheckMode = fadeCheckMode;
 	_fadeCheckAlternate = false;
 	_fadeCheckCounter = 0;
@@ -90,13 +90,6 @@ RSound::RSound(Audio::Mixer *mixer, const Common::Path &filename,
 		_channels[i]._midiChannel = i + 1;
 	}
 
-	_midiDriver = new MidiDriver_MT32GM(MusicType::MT_MT32);
-	int returnCode = _midiDriver->open();
-	if (returnCode != 0)
-		error("RSound - Failed to open MIDI music driver - error code %d.", returnCode);
-
-	_driverCallbackDelta = _midiDriver->getBaseTempo();
-
 	// rsound_init calls resetAllChannels directly, then later
 	// (via initDeviceOnce, on successful hardware detection) calls
 	// rsound_command0, which resets the channels again and sends the
@@ -109,21 +102,9 @@ RSound::RSound(Audio::Mixer *mixer, const Common::Path &filename,
 	// nothing to guard against.
 	command0();
 	sendSysExSequence();
-
-	_midiDriver->setTimerCallback(this, &timerCallback);
 }
 
 RSound::~RSound() {
-	_isDisabled = true;
-	if (_midiDriver != nullptr) {
-		_midiDriver->setTimerCallback(nullptr, nullptr);
-		_midiDriver->close();
-
-		Common::StackLock lock(_driverMutex);
-
-		delete _midiDriver;
-		_midiDriver = nullptr;
-	}
 }
 
 void RSound::validate(bool isDemo) {
@@ -169,6 +150,8 @@ int RSound::stop() {
 }
 
 int RSound::poll() {
+	Common::StackLock slock(_driverMutex);
+
 	update();
 
 	int result = _pollResult;
@@ -195,16 +178,16 @@ Channel *RSound::playSoundData(byte *pData, int startingChannel) {
 
 	// Scan for a free channel
 	for (int i = startingChannel; i < endChannel; ++i) {
-		if (!_channels[i]._activeCount) {
-			_channels[i].load(pData);
+		if (!_channels[i]._deltaCounter) {
+			_channels[i].playData(pData);
 			return &_channels[i];
 		}
 	}
 
 	// None found; fall back to an interruptable (pending-stop) channel
 	for (int i = endChannel - 1; i >= startingChannel; --i) {
-		if (_channels[i]._pendingStop == 0xFF) {
-			_channels[i].load(pData);
+		if (_channels[i]._fadeOutActive) {
+			_channels[i].playData(pData);
 			return &_channels[i];
 		}
 	}
@@ -216,7 +199,7 @@ bool RSound::isSoundActive(byte *pData) {
 	// Deliberately excludes channel 9 (index 8), matching the disassembly -
 	// same as playSoundData()'s scan never reaching channel 9 either.
 	for (int i = 0; i < RSOUND_CHANNEL_COUNT - 1; ++i) {
-		if (_channels[i]._activeCount && _channels[i]._soundData == pData)
+		if (_channels[i]._deltaCounter && _channels[i]._soundData == pData)
 			return true;
 	}
 
@@ -229,22 +212,6 @@ int RSound::getRandomNumber() {
 	return _randomSeed;
 }
 
-void RSound::onTimer() {
-	Common::StackLock slock(_driverMutex);
-
-	uint32 serviceTicks = _hostTimer.advance(_driverCallbackDelta, 1000000);
-	while (serviceTicks--) {
-		// RSOUND export 4 is a return stub in every audited overlay.
-		if (_hostTimer.pollDue())
-			poll();
-	}
-}
-
-void RSound::timerCallback(void* data) {
-	RSound *rsound = (RSound *)data;
-	rsound->onTimer();
-}
-
 void RSound::setVolume(int volume) {
 	_masterVolume = CLIP(volume, 0, 255);
 	for (int i = 0; i < RSOUND_CHANNEL_COUNT; ++i)
@@ -355,9 +322,9 @@ void RSound::Channel_flushHeldNotes(Channel *channel) {
 }
 
 void RSound::Channel_checkFade(Channel *channel) {
-	if (!channel->_activeCount)
+	if (!channel->_deltaCounter)
 		return;
-	if (!channel->_pendingStop)
+	if (!channel->_fadeOutActive)
 		return;
 
 	if (channel->_volume != 0) {
@@ -366,13 +333,13 @@ void RSound::Channel_checkFade(Channel *channel) {
 	} else {
 		// Fully silent - recycle the channel to a fixed 2-byte (0,0)
 		// silence stream. pollActiveChannel() processing a (note=0,
-		// duration=0) pair sets _activeCount to 0, and its own
+		// duration=0) pair sets _deltaCounter to 0, and its own
 		// top-of-function guard (checked before any decrement) then
 		// short-circuits every later call before _pSrc is ever read
 		// again - so only these first 2 bytes are ever consumed.
 		static byte silenceStream[2] = { 0, 0 };
 		channel->_pSrc = silenceStream;
-		channel->_pendingStop = 0;
+		channel->_fadeOutActive = false;
 	}
 }
 
@@ -395,15 +362,15 @@ void RSound::checkFadingChannels() {
 }
 
 void RSound::Channel_pollActive(Channel *channel) {
-	if (!channel->_activeCount)
+	if (!channel->_deltaCounter)
 		return;
 
 	int midiChannel = channel->_midiChannel;
 
-	if (channel->_keyOnDelay > 0 && --channel->_keyOnDelay == 0)
+	if (channel->_noteDurationCounter > 0 && --channel->_noteDurationCounter == 0)
 		Channel_flushHeldNotes(channel);
 
-	if (--channel->_activeCount <= 0) {
+	if (--channel->_deltaCounter <= 0) {
 		for (;;) {
 			byte *pSrc = channel->_pSrc;
 
@@ -418,16 +385,16 @@ void RSound::Channel_pollActive(Channel *channel) {
 				byte note = pSrc[0];
 				byte duration = pSrc[1];
 				channel->_note = note;
-				channel->_activeCount = duration;
+				channel->_deltaCounter = duration;
 				channel->_pSrc = pSrc + 2;
 
 				if (!note || !duration) {
 					Channel_flushHeldNotes(channel);
 				} else {
-					channel->_keyOnDelay = channel->_activeCount - channel->_noteOffset;
+					channel->_noteDurationCounter = channel->_deltaCounter - channel->_noteDurationOffset;
 
 					bool skipRetrigger = false;
-					if ((int8)channel->_noteOffset < 0 && _heldNotes[midiChannel][0] == note)
+					if ((int8)channel->_noteDurationOffset < 0 && _heldNotes[midiChannel][0] == note)
 						skipRetrigger = true;
 
 					if (!skipRetrigger) {
@@ -459,15 +426,15 @@ void RSound::Channel_pollActive(Channel *channel) {
 			}
 
 			case 2: // 0xF3: setup pan fade
-				channel->_panFadeReload = pSrc[1];
-				channel->_panFadeStep = pSrc[2];
-				channel->_panFadeCounter = 1;
+				channel->_panningSweepSpeed = pSrc[1];
+				channel->_panningSweepStepSize = pSrc[2];
+				channel->_panningSweepCounter = 1;
 				channel->_pSrc = pSrc + 3;
 				break;
 
 			case 3: // 0xF4: set pan directly and send
-				channel->_pan = pSrc[1];
-				sendPan(midiChannel, channel->_pan);
+				channel->_panning = pSrc[1];
+				sendPan(midiChannel, channel->_panning);
 				channel->_pSrc = pSrc + 2;
 				break;
 
@@ -488,12 +455,12 @@ void RSound::Channel_pollActive(Channel *channel) {
 					slots[i] = 0xFF;
 
 				byte duration = notes[noteCount];
-				channel->_activeCount = duration;
-				if (channel->_noteOffset != 0xFF) {
-					channel->_keyOnDelay = (duration < channel->_noteOffset) ?
-						duration : duration - channel->_noteOffset;
+				channel->_deltaCounter = duration;
+				if (channel->_noteDurationOffset != 0xFF) {
+					channel->_noteDurationCounter = (duration < channel->_noteDurationOffset) ?
+						duration : duration - channel->_noteDurationOffset;
 				} else {
-					channel->_keyOnDelay = duration + 1;
+					channel->_noteDurationCounter = duration + 1;
 				}
 
 				channel->_pSrc = pSrc + noteCount + 3;
@@ -502,7 +469,7 @@ void RSound::Channel_pollActive(Channel *channel) {
 			}
 
 			case 5: // 0xF6: set volume directly and send (priority-gated while pending-stop)
-				if (!channel->_pendingStop || channel->_volume >= pSrc[1]) {
+				if (!channel->_fadeOutActive || channel->_volume >= pSrc[1]) {
 					channel->_volume = pSrc[1];
 					sendVolume(midiChannel, channel->_volume);
 				}
@@ -516,10 +483,10 @@ void RSound::Channel_pollActive(Channel *channel) {
 				break;
 
 			case 7: // 0xF8: setup volume fade (gated by pending-stop)
-				if (!channel->_pendingStop) {
-					channel->_volumeFadeReload = pSrc[1];
+				if (!channel->_fadeOutActive) {
+					channel->_volumeFadeSpeed = pSrc[1];
 					channel->_volumeFadeCounter = pSrc[1];
-					channel->_volumeFadeStep = pSrc[2];
+					channel->_volumeFadeStepSize = pSrc[2];
 				}
 				channel->_pSrc = pSrc + 3;
 				break;
@@ -530,15 +497,15 @@ void RSound::Channel_pollActive(Channel *channel) {
 				break;
 
 			case 9: // 0xFA: setup pitch-bend ramp
-				channel->_pitchBendFadeReload = pSrc[1];
-				channel->_pitchBendFadeStep = pSrc[2];
-				channel->_pitchBendFadeCount = pSrc[3];
-				channel->_pitchBendFadeCounter = 1;
+				channel->_pitchSlideSpeed = pSrc[1];
+				channel->_pitchSlideStepSize = pSrc[2];
+				channel->_pitchSlideDurationCounter = pSrc[3];
+				channel->_pitchSlideCounter = 1;
 				channel->_pSrc = pSrc + 4;
 				break;
 
 			case 10: // 0xFB: set note offset
-				channel->_noteOffset = pSrc[1];
+				channel->_noteDurationOffset = pSrc[1];
 				channel->_pSrc = pSrc + 2;
 				break;
 
@@ -549,52 +516,52 @@ void RSound::Channel_pollActive(Channel *channel) {
 				break;
 
 			case 12: { // 0xFD: full reset / loop restart, preserving pending-stop
-				int pendingStop = channel->_pendingStop;
-				channel->reset(channel->_loopStartPtr);
-				channel->_pendingStop = pendingStop;
+				bool fadeOutActive = channel->_fadeOutActive;
+				channel->loadData(channel->_soundDataStart);
+				channel->_fadeOutActive = fadeOutActive;
 				break;
 			}
 
 			case 13: // 0xFE: outer loop
-				if (!channel->_outerLoopCount) {
+				if (!channel->_outerLoopCounter) {
 					if (*++pSrc == 0) {
 						channel->_pSrc += 2;
-						channel->_outerLoopPtr = channel->_pSrc;
-						channel->_innerLoopPtr = channel->_pSrc;
-						channel->_innerLoopCount = 0;
-						channel->_outerLoopCount = 0;
+						channel->_outerLoopStart = channel->_pSrc;
+						channel->_innerLoopStart = channel->_pSrc;
+						channel->_innerLoopCounter = 0;
+						channel->_outerLoopCounter = 0;
 					} else {
-						channel->_outerLoopCount =
-								(uint16)(int16)(int8)*pSrc;
-						channel->_pSrc = channel->_outerLoopPtr;
-						channel->_innerLoopPtr = channel->_outerLoopPtr;
+						channel->_outerLoopCounter =
+							(uint16)(int16)(int8)*pSrc;
+						channel->_pSrc = channel->_outerLoopStart;
+						channel->_innerLoopStart = channel->_outerLoopStart;
 					}
-				} else if (--channel->_outerLoopCount) {
-					channel->_pSrc = channel->_outerLoopPtr;
-					channel->_innerLoopPtr = channel->_outerLoopPtr;
+				} else if (--channel->_outerLoopCounter) {
+					channel->_pSrc = channel->_outerLoopStart;
+					channel->_innerLoopStart = channel->_outerLoopStart;
 				} else {
 					channel->_pSrc += 2;
-					channel->_outerLoopPtr = channel->_pSrc;
-					channel->_innerLoopPtr = channel->_pSrc;
+					channel->_outerLoopStart = channel->_pSrc;
+					channel->_innerLoopStart = channel->_pSrc;
 				}
 				break;
 
 			case 14: // 0xFF: inner loop
-				if (!channel->_innerLoopCount) {
+				if (!channel->_innerLoopCounter) {
 					if (*++pSrc == 0) {
 						channel->_pSrc += 2;
-						channel->_innerLoopPtr = channel->_pSrc;
-						channel->_innerLoopCount = 0;
+						channel->_innerLoopStart = channel->_pSrc;
+						channel->_innerLoopCounter = 0;
 					} else {
-						channel->_innerLoopCount =
-								(uint16)(int16)(int8)*pSrc;
-						channel->_pSrc = channel->_innerLoopPtr;
+						channel->_innerLoopCounter =
+							(uint16)(int16)(int8)*pSrc;
+						channel->_pSrc = channel->_innerLoopStart;
 					}
-				} else if (--channel->_innerLoopCount) {
-					channel->_pSrc = channel->_innerLoopPtr;
+				} else if (--channel->_innerLoopCounter) {
+					channel->_pSrc = channel->_innerLoopStart;
 				} else {
 					channel->_pSrc += 2;
-					channel->_innerLoopPtr = channel->_pSrc;
+					channel->_innerLoopStart = channel->_pSrc;
 				}
 				break;
 
@@ -605,25 +572,25 @@ void RSound::Channel_pollActive(Channel *channel) {
 	}
 
 	// Fade tail: pitch bend, volume, pan
-	if (channel->_pitchBendFadeStep) {
-		if (!--channel->_pitchBendFadeCounter) {
-			channel->_pitchBendFadeCounter = channel->_pitchBendFadeReload;
-			channel->_pitchBend += channel->_pitchBendFadeStep;
+	if (channel->_pitchSlideStepSize) {
+		if (!--channel->_pitchSlideCounter) {
+			channel->_pitchSlideCounter = channel->_pitchSlideSpeed;
+			channel->_pitchBend += channel->_pitchSlideStepSize;
 			sendPitchBend(midiChannel, channel->_pitchBend);
 		}
-		if (!--channel->_pitchBendFadeCount)
-			channel->_pitchBendFadeStep = 0;
+		if (!--channel->_pitchSlideDurationCounter)
+			channel->_pitchSlideStepSize = 0;
 	}
 
-	if (channel->_volumeFadeStep) {
+	if (channel->_volumeFadeStepSize) {
 		if (!--channel->_volumeFadeCounter) {
-			channel->_volumeFadeCounter = channel->_volumeFadeReload;
-			int8 newVolume = (int8)channel->_volume + (int8)channel->_volumeFadeStep;
+			channel->_volumeFadeCounter = channel->_volumeFadeSpeed;
+			int8 newVolume = (int8)channel->_volume + (int8)channel->_volumeFadeStepSize;
 			if (newVolume < 0) {
-				channel->_volumeFadeStep = 0;
+				channel->_volumeFadeStepSize = 0;
 				newVolume = 0;
 			} else if (newVolume >= 0x7F) {
-				channel->_volumeFadeStep = 0;
+				channel->_volumeFadeStepSize = 0;
 				newVolume = 0x7F;
 			}
 			channel->_volume = newVolume;
@@ -631,15 +598,15 @@ void RSound::Channel_pollActive(Channel *channel) {
 		}
 	}
 
-	if (channel->_panFadeStep) {
-		if (!--channel->_panFadeCounter) {
-			channel->_panFadeCounter = channel->_panFadeReload;
-			byte newPan = channel->_pan + channel->_panFadeStep;
+	if (channel->_panningSweepStepSize) {
+		if (!--channel->_panningSweepCounter) {
+			channel->_panningSweepCounter = channel->_panningSweepSpeed;
+			byte newPan = channel->_panning + channel->_panningSweepStepSize;
 			if (newPan > 0x7F) {
 				newPan = (newPan ^ 0x7F) & 0x7F;
-				channel->_panFadeCounter = 0;
+				channel->_panningSweepCounter = 0;
 			}
-			channel->_pan = newPan;
+			channel->_panning = newPan;
 			sendPan(midiChannel, newPan);
 		}
 	}
@@ -665,7 +632,7 @@ void RSound::update() {
 /*-----------------------------------------------------------------------*/
 
 /**
- * Zeroes _activeCount and the three fade-step fields for channels in
+ * Zeroes _deltaCounter and the three fade-step fields for channels in
  * [first, last).
  * Deliberately does NOT touch the loop pointers, volume, program, pan etc,
  * matching the original.
@@ -675,10 +642,10 @@ void RSound::resetChannelRange(int first, int last) {
 	_isDisabled = true;
 
 	for (int i = first; i < last; ++i) {
-		_channels[i]._activeCount = 0;
-		_channels[i]._pitchBendFadeStep = 0;
-		_channels[i]._volumeFadeStep = 0;
-		_channels[i]._panFadeStep = 0;
+		_channels[i]._deltaCounter = 0;
+		_channels[i]._pitchSlideStepSize = 0;
+		_channels[i]._volumeFadeStepSize = 0;
+		_channels[i]._panningSweepStepSize = 0;
 	}
 
 	_isDisabled = wasDisabled;
@@ -744,7 +711,7 @@ int RSound::command0() {
 int RSound::command1() {
 	setFadeCheckPeriod(1);
 	for (int i = 0; i < RSOUND_CHANNEL_COUNT; ++i)
-		_channels[i].enable(0xFF);
+		_channels[i].setFadeOut(true);
 	return 0;
 }
 
@@ -761,7 +728,7 @@ int RSound::command2() {
 int RSound::command3() {
 	setFadeCheckPeriod(1);
 	for (int i = 0; i < 5; ++i)
-		_channels[i].enable(0xFF);
+		_channels[i].setFadeOut(true);
 	return 0;
 }
 
@@ -777,7 +744,7 @@ int RSound::command4() {
 int RSound::command5() {
 	setFadeCheckPeriod(1);
 	for (int i = 5; i < RSOUND_CHANNEL_COUNT; ++i)
-		_channels[i].enable(0xFF);
+		_channels[i].setFadeOut(true);
 	return 0;
 }
 
@@ -796,7 +763,7 @@ int RSound::command7() {
 int RSound::command8() {
 	int result = 0;
 	for (int i = 0; i < RSOUND_CHANNEL_COUNT; ++i)
-		result |= _channels[i]._activeCount;
+		result |= _channels[i]._deltaCounter;
 
 	return result;
 }
diff --git a/engines/mads/nebular/sound/rsound.h b/engines/mads/nebular/sound/rsound.h
index c62a1a4dfca..fb3c0e3fe59 100644
--- a/engines/mads/nebular/sound/rsound.h
+++ b/engines/mads/nebular/sound/rsound.h
@@ -48,20 +48,20 @@ enum RSoundFadeCheckMode {
  * equivalent AdlibChannel fields in asound.h.
  *
  * Confirmed against the real DOS struct layout (IDA struct dump,
- * sizeof=0x22): every field below from _activeCount through _soundData
+ * sizeof=0x22): every field below from _deltaCounter through _soundData
  * matches the original both in name and in byte offset/order exactly:
- *   0x00 _activeCount    0x0C _volume          0x18 _innerLoopPtr
- *   0x01 _pitchBendFadeStep 0x0D _pitchBend     0x1A _outerLoopPtr
- *   0x02 _volumeFadeStep  0x0E _pan             0x1C _innerLoopCount
- *   0x03 _panFadeStep     0x0F _volumeFadeReload 0x1E _outerLoopCount
- *   0x04 _note            0x10 _pitchBendFadeReload 0x20 _soundData
- *   0x05 _program         0x11 _panFadeReload
- *   0x06 _velocity        0x12 _pitchBendFadeCount
- *   0x07 _noteOffset      0x13 _pendingStop
- *   0x08 _keyOnDelay      0x14 _loopStartPtr
- *   0x09 _volumeFadeCounter 0x16 _pSrc
- *   0x0A _pitchBendFadeCounter
- *   0x0B _panFadeCounter
+ *   0x00 _deltaCounter			0x0C _volume					0x18 _innerLoopStart
+ *   0x01 _pitchSlideStepSize	0x0D _pitchBend					0x1A _outerLoopStart
+ *   0x02 _volumeFadeStepSize	0x0E _panning					0x1C _innerLoopCounter
+ *   0x03 _panningSweepStepSize	0x0F _volumeFadeSpeed			0x1E _outerLoopCounter
+ *   0x04 _note					0x10 _pitchSlideSpeed			0x20 _soundData
+ *   0x05 _program				0x11 _panningSweepSpeed
+ *   0x06 _velocity				0x12 _pitchSlideDurationCounter
+ *   0x07 _noteDurationOffset	0x13 _fadeOutActive
+ *   0x08 _noteDurationCounter	0x14 _soundDataStart
+ *   0x09 _volumeFadeCounter	0x16 _pSrc
+ *   0x0A _pitchSlideCounter
+ *   0x0B _panningSweepCounter
  * _owner and _midiChannel below are NOT part of the original struct (it
  * has no equivalent fields) - they're C++-side conveniences so Channel
  * methods and callers don't need the MIDI channel number (array index+1)
@@ -71,57 +71,61 @@ enum RSoundFadeCheckMode {
 class Channel {
 public:
 	RSound *_owner = nullptr;
-	int _midiChannel = 0;        // 1-9: the MIDI channel this struct drives
-
-	int _activeCount = 0;        // gate/duration countdown; also freshly loaded from the duration byte of a note event
-	int _pitchBendFadeStep = 0;  // per-step delta added to _pitchBend each ramp tick
-	int _volumeFadeStep = 0;     // per-step delta added to _volume each ramp tick
-	int _panFadeStep = 0;        // per-step delta added to _pan each ramp tick
-	int _note = 0;               // MIDI note number, read from the note/duration stream
-	int _program = 0;            // patch/instrument number, sent as a Program Change
-	int _velocity = 0;           // note velocity, used by RSound::sendNoteOn()
-	int _noteOffset = 0;         // subtracted from _activeCount to derive _keyOnDelay; 0xFF = sustain full duration +1 (no early cutoff)
-	int _keyOnDelay = 0;         // countdown to RSound::Channel_flushHeldNotes()
-	int _volumeFadeCounter = 0;  // counts down to 0 before applying _volumeFadeStep
-	int _pitchBendFadeCounter = 0; // counts down to 0 before applying _pitchBendFadeStep
-	int _panFadeCounter = 0;     // counts down to 0 before applying _panFadeStep
-	int _volume = 0;             // current channel volume (MIDI CC#7)
-	int _pitchBend = 0;          // current pitch bend value (status 0xEn, coarse/MSB only)
-	int _pan = 0;                // current pan value (MIDI CC#10); 64 = center
-	int _volumeFadeReload = 0;   // reload value for _volumeFadeCounter
-	int _pitchBendFadeReload = 0; // reload value for _pitchBendFadeCounter
-	int _panFadeReload = 0;      // reload value for _panFadeCounter
-	int _pitchBendFadeCount = 0; // total ramp steps remaining before the pitch-bend ramp halts
-	int _pendingStop = 0;        // non-zero while the channel is fading out to silence
-	byte *_loopStartPtr = nullptr; // fixed restart anchor used by the full-reset/loop-restart opcode
-	byte *_pSrc = nullptr;         // current read pointer into the sound-data stream
-	byte *_innerLoopPtr = nullptr; // inner-loop restart address
-	byte *_outerLoopPtr = nullptr; // outer-loop restart address
-	uint16 _innerLoopCount = 0; // signed byte stored as a 16-bit loop count
-	uint16 _outerLoopCount = 0; // signed byte stored as a 16-bit loop count
-	byte *_soundData = nullptr;    // identity pointer used by RSound::isSoundActive()
+	int _midiChannel = 0;				// 1-9: the MIDI channel to which the data in this struct pertains
+
+	int _deltaCounter = 0;				// number of ticks until the next event occurs; loaded from the delta byte of a note or chord event
+										// 0: channel is not active
+	int _pitchSlideStepSize = 0;		// delta added to _pitchBend each pitch-slide step; 0: pitch slide is not active
+	int _volumeFadeStepSize = 0;		// delta added to _volume each volume fade step; 0: volume fade is not active
+	int _panningSweepStepSize = 0;		// delta added to _panning each panning sweep step; 0: panning sweep is not active
+	int _note = 0;						// MIDI note number, read from the note or chord event
+	int _program = 0;					// patch/instrument number, sent as a Program Change
+	int _velocity = 0;					// note velocity, used by RSound::sendNoteOn()
+	int _noteDurationOffset = 0;		// subtracted from the event delta to derive the note duration; positive offset: note is turned off
+										// before the next event is processed. Data might only use up to -1 in the negative direction.
+	int _noteDurationCounter = 0;		// number of ticks until the currently active note(s) is/are turned off
+	int _volumeFadeCounter = 0;			// number of ticks until the next volume fade step is processed
+	int _pitchSlideCounter = 0;			// number of ticks until the next pitch slide step is processed
+	int _panningSweepCounter = 0;		// number of ticks until the next panning sweep step is processed
+	int _volume = 0;					// current channel volume (MIDI CC#7)
+	int _pitchBend = 0;					// current pitch bend value (status 0xEn, coarse/MSB only); 0x40 = center
+	int _panning = 0;					// current pan value (MIDI CC#10); 0x40 = center
+	int _volumeFadeSpeed = 0;			// number of ticks between volume fade steps
+	int _pitchSlideSpeed = 0;			// number of ticks between pitch slide steps
+	int _panningSweepSpeed = 0;			// number of ticks between panning sweep steps
+	int _pitchSlideDurationCounter = 0;	// number of ticks until the pitch slide ends
+	bool _fadeOutActive = false;		// true while the channel is fading out to silence (not to be confused with a volume fade)
+	byte *_soundDataStart = nullptr;	// start of the sound data stream playing on this channel
+	byte *_pSrc = nullptr;				// current read pointer into the sound data stream
+	byte *_innerLoopStart = nullptr;	// inner loop restart address
+	byte *_outerLoopStart = nullptr;	// outer loop restart address
+	int _innerLoopCounter = 0;			// number of repeats of the inner loop remaining
+	int _outerLoopCounter = 0;			// number of repeats of the outer loop remaining
+	byte *_soundData = nullptr;			// identifies the sound data played by this channel; effectively the same as _soundDataStart
 
 public:
 	Channel() {}
 
 	/**
-	 * Partial reset used both when loading a new sound and when the
-	 * loop-restart opcode fires. Deliberately does NOT touch volume,
-	 * program, velocity, key-on state or active/duration - matches
-	 * Channel_reset() in the original disassembly.
+	 * Resets most of the channel data to its default values and loads
+	 * the specified sound data into the channel. Deliberately does NOT
+	 * touch volume, program, velocity, key-on state or delta/duration -
+	 * matches the original disassembly.
 	 */
-	void reset(byte *startPtr);
+	void loadData(byte *soundData);
 
 	/**
-	 * Marks the channel as pending-stop (fading toward silence).
+	 * Marks the channel as fading out (fading toward silence) and stopping
+	 * playback when the fade-out is complete. Not to be confused with a
+	 * volume fade triggered by event 0xF8.
 	 */
-	void enable(int flag);
+	void setFadeOut(bool fadeOut);
 
 	/**
-	 * Loads a brand new sound into the channel: resets it, marks it
-	 * active, and resets pitch bend to center on the real device.
+	 * Loads new sound data into the channel, starts playback by setting
+	 * _deltaCounter to 1 and resets pitch bend to center on the MT-32.
 	 */
-	void load(byte *pData);
+	void playData(byte *soundData);
 };
 
 /**
@@ -163,10 +167,6 @@ private:
 	void pollAllChannels();
 	void Channel_pollActive(Channel *channel);
 
-	/**
-	 * Zeroes _activeCount and the three fade-step fields for channels in
-	 * [first, last).
-	 */
 	/**
 	 * Resets all 9 channels and the held-notes table.
 	 */
@@ -323,9 +323,8 @@ public:
 	 * @param sysExOffset	Offset of this driver's own command0_array
 	 * @param fadeCheckMode Native pending-stop fade scheduler
 	 */
-	RSound(Audio::Mixer *mixer, const Common::Path &filename,
-		int dataOffset, int dataSize, int sysExOffset,
-		RSoundFadeCheckMode fadeCheckMode);
+	RSound(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver, const Common::Path &filename,
+		int dataOffset, int dataSize, int sysExOffset, RSoundFadeCheckMode fadeCheckMode);
 
 	~RSound() override;
 
@@ -339,9 +338,6 @@ public:
 	int getFrameCounter() {
 		return _frameCounter;
 	}
-
-	void onTimer();
-	static void timerCallback(void *data);
 };
 
 } // namespace Sound
diff --git a/engines/mads/nebular/sound/rsound_nebular.cpp b/engines/mads/nebular/sound/rsound_nebular.cpp
index dd93a28af30..cb31b8234f3 100644
--- a/engines/mads/nebular/sound/rsound_nebular.cpp
+++ b/engines/mads/nebular/sound/rsound_nebular.cpp
@@ -25,17 +25,17 @@ namespace MADS {
 namespace RexNebular {
 namespace Sound {
 
-RSoundDemo::RSoundDemo(Audio::Mixer *mixer, const Common::Path &filename,
+RSoundDemo::RSoundDemo(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver, const Common::Path &filename,
 		int dataOffset, int dataSize, int sysExOffset,
 		int firstEffectChannel) :
-		RSound(mixer, filename, dataOffset, dataSize, sysExOffset,
+		RSound(mixer, midiDriver, filename, dataOffset, dataSize, sysExOffset,
 				kRSoundFadeCheckAlternating),
 		_firstEffectChannel(firstEffectChannel) {
 }
 
 void RSoundDemo::startVoice(int channelIndex, int sequenceOffset) {
 	assert(channelIndex >= 0 && channelIndex < RSOUND_CHANNEL_COUNT);
-	_channels[channelIndex].load(loadData(sequenceOffset));
+	_channels[channelIndex].playData(loadData(sequenceOffset));
 }
 
 int RSoundDemo::startVoiceInRange(int sequenceOffset, int firstChannel,
@@ -43,14 +43,14 @@ int RSoundDemo::startVoiceInRange(int sequenceOffset, int firstChannel,
 	assert(firstChannel >= 0 && firstChannel <= lastChannel && lastChannel < 8);
 
 	for (int channel = firstChannel; channel <= lastChannel; ++channel) {
-		if (!_channels[channel]._activeCount) {
+		if (!_channels[channel]._deltaCounter) {
 			startVoice(channel, sequenceOffset);
 			return channel;
 		}
 	}
 
 	for (int channel = lastChannel; channel >= firstChannel; --channel) {
-		if (_channels[channel]._pendingStop == 0xFF) {
+		if (_channels[channel]._fadeOutActive) {
 			startVoice(channel, sequenceOffset);
 			return channel;
 		}
@@ -73,7 +73,7 @@ void RSoundDemo::requestStopRange(int firstChannel, int channelCount) {
 			firstChannel + channelCount <= RSOUND_CHANNEL_COUNT);
 	for (int channel = firstChannel;
 			channel < firstChannel + channelCount; ++channel)
-		_channels[channel].enable(0xFF);
+		_channels[channel].setFadeOut(true);
 }
 
 void RSoundDemo::requestStopAll() {
@@ -112,8 +112,8 @@ const RSound1::CommandPtr RSound1::_commandList[42] = {
 	&RSound1::command40, &RSound1::command41
 };
 
-RSound1::RSound1(Audio::Mixer *mixer) : RSound(mixer, "rsound.001",
-		0x1350, 0x1A90, 0x67, kRSoundFadeCheckAlternating) {
+RSound1::RSound1(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver) : 
+	RSound(mixer, midiDriver, "rsound.001", 0x1350, 0x1A90, 0x67, kRSoundFadeCheckAlternating) {
 }
 
 int RSound1::command(int commandId, int param) {
@@ -133,10 +133,10 @@ void RSound1::method1() {
 	byte *pData = loadData(0x1166);
 	if (!isSoundActive(pData)) {
 		command1();
-		_channels[0].load(pData);
-		_channels[1].load(loadData(0x13BC));
-		_channels[2].load(loadData(0x155C));
-		_channels[3].load(loadData(0x15D8));
+		_channels[0].playData(pData);
+		_channels[1].playData(loadData(0x13BC));
+		_channels[2].playData(loadData(0x155C));
+		_channels[3].playData(loadData(0x15D8));
 	}
 }
 
@@ -148,10 +148,10 @@ int RSound1::command9() {
 int RSound1::command10() {
 	byte *pData = loadData(0xCE4);
 	if (!isSoundActive(pData)) {
-		_channels[0].load(pData);
-		_channels[1].load(loadData(0xD18));
-		_channels[2].load(loadData(0xE9C));
-		_channels[3].load(loadData(0xEE8));
+		_channels[0].playData(pData);
+		_channels[1].playData(loadData(0xD18));
+		_channels[2].playData(loadData(0xE9C));
+		_channels[3].playData(loadData(0xEE8));
 	}
 	return 0;
 }
@@ -192,9 +192,9 @@ int RSound1::command15() {
 	byte *pData = loadData(0xF3A);
 	if (!isSoundActive(pData)) {
 		command1();
-		_channels[4].load(pData);
-		_channels[5].load(loadData(0x102A));
-		_channels[6].load(loadData(0x110E));
+		_channels[4].playData(pData);
+		_channels[5].playData(loadData(0x102A));
+		_channels[6].playData(loadData(0x110E));
 	}
 	return 0;
 }
@@ -258,7 +258,7 @@ int RSound1::command26() {
 	pData[8] = v1;
 	int v2 = clampParam() + 64;
 	pData[5] = v2;
-	_channels[7].load(pData);
+	_channels[7].playData(pData);
 	return 0;
 }
 
@@ -268,7 +268,7 @@ int RSound1::command27() {
 	pData[8] = v1;
 	int v2 = clampParam() + 64;
 	pData[5] = v2;
-	_channels[7].load(pData);
+	_channels[7].playData(pData);
 	return 0;
 }
 
@@ -355,11 +355,11 @@ int RSound1::command38() {
 int RSound1::command39() {
 	byte *pData = loadData(0x1818);
 	if (!isSoundActive(pData)) {
-		_channels[4].load(pData);
-		_channels[5].load(loadData(0x1848));
-		_channels[6].load(loadData(0x1874));
-		_channels[7].load(loadData(0x18B4));
-		_channels[8].load(loadData(0x18CE));
+		_channels[4].playData(pData);
+		_channels[5].playData(loadData(0x1848));
+		_channels[6].playData(loadData(0x1874));
+		_channels[7].playData(loadData(0x18B4));
+		_channels[8].playData(loadData(0x18CE));
 	}
 	return 0;
 }
@@ -376,8 +376,8 @@ int RSound1::command41() {
 
 /*-----------------------------------------------------------------------*/
 
-RSoundDemo1::RSoundDemo1(Audio::Mixer *mixer) :
-		RSoundDemo(mixer, "rsound.001", 0x12E0, 0x1D28, 0x67, 0),
+RSoundDemo1::RSoundDemo1(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver) :
+		RSoundDemo(mixer, midiDriver, "rsound.001", 0x12E0, 0x1D28, 0x67, 0),
 		_command23Toggle(false) {
 }
 
@@ -609,8 +609,8 @@ const RSound2::CommandPtr RSound2::_commandList[44] = {
 	&RSound2::command40, &RSound2::command41, &RSound2::command42, &RSound2::command43
 };
 
-RSound2::RSound2(Audio::Mixer *mixer) : RSound(mixer, "rsound.002",
-		0x1390, 0x42F0, 0x87, kRSoundFadeCheckAlternating) {
+RSound2::RSound2(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver) : 
+	RSound(mixer, midiDriver, "rsound.002", 0x1390, 0x42F0, 0x87, kRSoundFadeCheckAlternating) {
 }
 
 int RSound2::command(int commandId, int param) {
@@ -624,11 +624,11 @@ int RSound2::command(int commandId, int param) {
 
 int RSound2::command5() {
 	_pitchCycleCounter = 47;
-	_channels[3].enable(0xFF);
-	_channels[4].enable(0xFF);
-	_channels[5].enable(0xFF);
-	_channels[6].enable(0xFF);
-	_channels[7].enable(0xFF);
+	_channels[3].setFadeOut(true);
+	_channels[4].setFadeOut(true);
+	_channels[5].setFadeOut(true);
+	_channels[6].setFadeOut(true);
+	_channels[7].setFadeOut(true);
 	return 0;
 }
 
@@ -636,9 +636,9 @@ int RSound2::command9() {
 	byte *pData = loadData(0x103C);
 	if (!isSoundActive(pData)) {
 		command1();
-		_channels[0].load(pData);
-		_channels[1].load(loadData(0x11B2));
-		_channels[8].load(loadData(0x127E));
+		_channels[0].playData(pData);
+		_channels[1].playData(loadData(0x11B2));
+		_channels[8].playData(loadData(0x127E));
 	}
 	return 0;
 }
@@ -647,8 +647,8 @@ int RSound2::command10() {
 	byte *pData = loadData(0x132E);
 	if (!isSoundActive(pData)) {
 		command1();
-		_channels[2].load(pData);
-		_channels[8].load(loadData(0x1384));
+		_channels[2].playData(pData);
+		_channels[8].playData(loadData(0x1384));
 	}
 	return 0;
 }
@@ -657,8 +657,8 @@ int RSound2::command11() {
 	byte *pData = loadData(0x1548);
 	if (!isSoundActive(pData)) {
 		command1();
-		_channels[2].load(pData);
-		_channels[8].load(loadData(0x1648));
+		_channels[2].playData(pData);
+		_channels[8].playData(loadData(0x1648));
 	}
 	return 0;
 }
@@ -690,7 +690,7 @@ int RSound2::command15() {
 		playSoundAny(0x1DFC);
 		playSoundAny(0x222E);
 		playSoundAny(0x2648);
-		_channels[8].load(loadData(0x26A2));
+		_channels[8].playData(loadData(0x26A2));
 	}
 	return 0;
 }
@@ -721,11 +721,11 @@ int RSound2::command17() {
 }
 
 int RSound2::command18() {
-	if (_channels[7]._activeCount)
+	if (_channels[7]._deltaCounter)
 		return 0;
 
 	int idx = (getRandomNumber() & 30) >> 1;
-	_channels[7].load(loadData(_table1[idx]));
+	_channels[7].playData(loadData(_table1[idx]));
 	return 0;
 }
 
@@ -784,11 +784,11 @@ int RSound2::command26() {
 int RSound2::command27() {
 	Channel *ch = playSound(0xFAC);
 	if (ch)
-		ch->_innerLoopPtr = loadData(0xFB8);
+		ch->_innerLoopStart = loadData(0xFB8);
 
 	ch = playSound(0xFB2);
 	if (ch)
-		ch->_innerLoopPtr = loadData(0xFB8);
+		ch->_innerLoopStart = loadData(0xFB8);
 
 	playSound(0xFB8);
 	return 0;
@@ -919,8 +919,8 @@ const RSound3::CommandPtr RSound3::_commandList[61] = {
 	&RSound3::command60
 };
 
-RSound3::RSound3(Audio::Mixer *mixer) : RSound(mixer, "rsound.003",
-		0x14E0, 0x4C60, 0x67, kRSoundFadeCheckProgrammable) {
+RSound3::RSound3(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver) : 
+	RSound(mixer, midiDriver, "rsound.003", 0x14E0, 0x4C60, 0x67, kRSoundFadeCheckProgrammable) {
 }
 
 int RSound3::command(int commandId, int param) {
@@ -940,10 +940,10 @@ Channel *RSound3::method1(int offset, byte value) {
 
 void RSound3::resetUpperChannelsTail() {
 	setFadeCheckPeriod(1);
-	_channels[4].enable(0xFF);
-	_channels[5].enable(0xFF);
-	_channels[6].enable(0xFF);
-	_channels[7].enable(0xFF);
+	_channels[4].setFadeOut(true);
+	_channels[5].setFadeOut(true);
+	_channels[6].setFadeOut(true);
+	_channels[7].setFadeOut(true);
 }
 
 int RSound3::command1() {
@@ -973,11 +973,11 @@ int RSound3::command10() {
 	byte *pData = loadData(0x14FE);
 	if (!isSoundActive(pData)) {
 		command1();
-		_channels[0].load(pData);
-		_channels[1].load(loadData(0x1630));
-		_channels[2].load(loadData(0x186E));
-		_channels[3].load(loadData(0x1A68));
-		_channels[8].load(loadData(0x1AA6));
+		_channels[0].playData(pData);
+		_channels[1].playData(loadData(0x1630));
+		_channels[2].playData(loadData(0x186E));
+		_channels[3].playData(loadData(0x1A68));
+		_channels[8].playData(loadData(0x1AA6));
 	}
 	return 0;
 }
@@ -992,13 +992,13 @@ void RSound3::setVariantByte(byte value) {
 int RSound3::command11() {
 	if (!isSoundActive(loadData(0x1AE6))) {
 		setVariantByte(0x64);
-		_channels[0].load(loadData(0x1AE6));
-		_channels[1].load(loadData(0x1E00));
-		_channels[2].load(loadData(0x1E66));
-		_channels[3].load(loadData(0x204A));
-		_channels[4].load(loadData(0x229C));
-		_channels[5].load(loadData(0x2748));
-		_channels[6].load(loadData(0x2C56));
+		_channels[0].playData(loadData(0x1AE6));
+		_channels[1].playData(loadData(0x1E00));
+		_channels[2].playData(loadData(0x1E66));
+		_channels[3].playData(loadData(0x204A));
+		_channels[4].playData(loadData(0x229C));
+		_channels[5].playData(loadData(0x2748));
+		_channels[6].playData(loadData(0x2C56));
 	}
 	return 0;
 }
@@ -1014,14 +1014,14 @@ int RSound3::command13() {
 }
 
 int RSound3::command14() {
-	_channels[0].load(loadData(0x32DC));
-	_channels[1].load(loadData(0x32FC));
-	_channels[2].load(loadData(0x331C));
-	_channels[3].load(loadData(0x333E));
-	_channels[4].load(loadData(0x335C));
-	_channels[5].load(loadData(0x339E));
-	_channels[6].load(loadData(0x33DE));
-	_channels[7].load(loadData(0x341E));
+	_channels[0].playData(loadData(0x32DC));
+	_channels[1].playData(loadData(0x32FC));
+	_channels[2].playData(loadData(0x331C));
+	_channels[3].playData(loadData(0x333E));
+	_channels[4].playData(loadData(0x335C));
+	_channels[5].playData(loadData(0x339E));
+	_channels[6].playData(loadData(0x33DE));
+	_channels[7].playData(loadData(0x341E));
 	return 0;
 }
 
@@ -1036,20 +1036,20 @@ int RSound3::command15() {
 	setVariantByte(0x60);
 	sendDualVolume(0x60);
 
-	if (_channels[3]._activeCount && _channels[3]._soundData == loadData(0x204A)) {
-		_channels[2]._pendingStop = 0xFF;
-		_channels[3]._pendingStop = 0xFF;
-		_channels[4]._pendingStop = 0xFF;
-		_channels[5]._pendingStop = 0xFF;
-		_channels[6]._pendingStop = 0xFF;
-		_channels[7]._pendingStop = 0xFF;
+	if (_channels[3]._deltaCounter && _channels[3]._soundData == loadData(0x204A)) {
+		_channels[2]._fadeOutActive = true;
+		_channels[3]._fadeOutActive = true;
+		_channels[4]._fadeOutActive = true;
+		_channels[5]._fadeOutActive = true;
+		_channels[6]._fadeOutActive = true;
+		_channels[7]._fadeOutActive = true;
 		setFadeCheckPeriod(1);
 		return 0;
 	}
 
 	command1();
-	_channels[0].load(loadData(0x1AE6));
-	_channels[1].load(loadData(0x1E00));
+	_channels[0].playData(loadData(0x1AE6));
+	_channels[1].playData(loadData(0x1E00));
 	return 0;
 }
 
@@ -1059,19 +1059,19 @@ int RSound3::command16() {
 	if (_command16AltFlag) {
 		byte *pData = loadData(0x345E);
 		if (!isSoundActive(pData)) {
-			_channels[0].load(pData);
-			_channels[1].load(loadData(0x364C));
-			_channels[2].load(loadData(0x3806));
-			_channels[3].load(loadData(0x399E));
+			_channels[0].playData(pData);
+			_channels[1].playData(loadData(0x364C));
+			_channels[2].playData(loadData(0x3806));
+			_channels[3].playData(loadData(0x399E));
 		}
 	} else {
 		byte *pData = loadData(0x3B26);
 		if (!isSoundActive(pData)) {
 			command1();
-			_channels[0].load(pData);
-			_channels[1].load(loadData(0x3BD8));
-			_channels[2].load(loadData(0x3CF8));
-			_channels[3].load(loadData(0x3E46));
+			_channels[0].playData(pData);
+			_channels[1].playData(loadData(0x3BD8));
+			_channels[2].playData(loadData(0x3CF8));
+			_channels[3].playData(loadData(0x3E46));
 		}
 	}
 	return 0;
@@ -1081,22 +1081,22 @@ int RSound3::command17() {
 	byte *pData = loadData(0x3F5C);
 	if (!isSoundActive(pData)) {
 		command1();
-		_channels[0].load(pData);
-		_channels[1].load(loadData(0x4022));
-		_channels[2].load(loadData(0x41F0));
-		_channels[3].load(loadData(0x42F8));
+		_channels[0].playData(pData);
+		_channels[1].playData(loadData(0x4022));
+		_channels[2].playData(loadData(0x41F0));
+		_channels[3].playData(loadData(0x42F8));
 	}
 	return 0;
 }
 
 int RSound3::command18() {
 	command1();
-	_channels[0].load(loadData(0x4492));
-	_channels[1].load(loadData(0x45A4));
-	_channels[2].load(loadData(0x46A2));
-	_channels[3].load(loadData(0x47DC));
-	_channels[4].load(loadData(0x49C0));
-	_channels[5].load(loadData(0x4A4E));
+	_channels[0].playData(loadData(0x4492));
+	_channels[1].playData(loadData(0x45A4));
+	_channels[2].playData(loadData(0x46A2));
+	_channels[3].playData(loadData(0x47DC));
+	_channels[4].playData(loadData(0x49C0));
+	_channels[5].playData(loadData(0x4A4E));
 	return 0;
 }
 
@@ -1323,8 +1323,8 @@ const RSound4::CommandPtr RSound4::_commandList[60] = {
 	&RSound4::command56, &RSound4::command57, &RSound4::command58, &RSound4::command59
 };
 
-RSound4::RSound4(Audio::Mixer *mixer) : RSound(mixer, "rsound.004",
-		0x1340, 0x2E20, 0x67, kRSoundFadeCheckProgrammable) {
+RSound4::RSound4(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver) : 
+	RSound(mixer, midiDriver, "rsound.004", 0x1340, 0x2E20, 0x67, kRSoundFadeCheckProgrammable) {
 }
 
 int RSound4::command(int commandId, int param) {
@@ -1367,31 +1367,31 @@ void RSound4::setCommand12Variant() {
 }
 
 int RSound4::command12() {
-	if (_channels[4]._soundData == loadData(0x1966) && _channels[4]._activeCount) {
+	if (_channels[4]._soundData == loadData(0x1966) && _channels[4]._deltaCounter) {
 		setCommand12Variant();
 		return 0;
 	}
 
 	setCommand12Variant();
 	command1();
-	_channels[4].load(loadData(0x1966));
-	_channels[5].load(loadData(0x1DC8));
-	_channels[6].load(loadData(0x1FBA));
-	_channels[7].load(loadData(0x211E));
-	_channels[8].load(loadData(0x24A8));
+	_channels[4].playData(loadData(0x1966));
+	_channels[5].playData(loadData(0x1DC8));
+	_channels[6].playData(loadData(0x1FBA));
+	_channels[7].playData(loadData(0x211E));
+	_channels[8].playData(loadData(0x24A8));
 	return 0;
 }
 
 void RSound4::loadIntroChannels() {
-	_channels[0].load(loadData(0x1274));
-	_channels[1].load(loadData(0x13A6));
-	_channels[2].load(loadData(0x15E4));
+	_channels[0].playData(loadData(0x1274));
+	_channels[1].playData(loadData(0x13A6));
+	_channels[2].playData(loadData(0x15E4));
 }
 
 int RSound4::command10() {
 	command1();
-	_channels[3].load(loadData(0x17DE));
-	_channels[8].load(loadData(0x181C));
+	_channels[3].playData(loadData(0x17DE));
+	_channels[8].playData(loadData(0x181C));
 	loadIntroChannels();
 	return 0;
 }
@@ -1458,7 +1458,7 @@ int RSound4::command52() {
 	_channels[0]._pSrc = loadData(0x1188);
 	_channels[1]._pSrc = loadData(0x1188);
 	_channels[2]._pSrc = loadData(0x1188);
-	_channels[4].load(loadData(0x2A0C));
+	_channels[4].playData(loadData(0x2A0C));
 	return 0;
 }
 
@@ -1534,8 +1534,8 @@ const RSound5::CommandPtr RSound5::_commandList[42] = {
 	&RSound5::command40, &RSound5::command41
 };
 
-RSound5::RSound5(Audio::Mixer *mixer) : RSound(mixer, "rsound.005",
-		0x12A0, 0x1FD0, 0x67, kRSoundFadeCheckProgrammable) {
+RSound5::RSound5(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver) : 
+	RSound(mixer, midiDriver, "rsound.005", 0x12A0, 0x1FD0, 0x67, kRSoundFadeCheckProgrammable) {
 }
 
 int RSound5::command(int commandId, int param) {
@@ -1574,16 +1574,16 @@ int RSound5::command13() {
 }
 
 int RSound5::command14() {
-	_channels[7].load(loadData(0x1272));
+	_channels[7].playData(loadData(0x1272));
 	return 0;
 }
 
 int RSound5::command15() {
 	if (_channels[7]._soundData == loadData(0x1272)) {
 		byte *pData = loadData(0x1288);
-		_channels[7]._innerLoopPtr = pData;
-		_channels[7]._outerLoopPtr = pData;
-		_channels[7]._activeCount = 1;
+		_channels[7]._innerLoopStart = pData;
+		_channels[7]._outerLoopStart = pData;
+		_channels[7]._deltaCounter = 1;
 	}
 	return 0;
 }
@@ -1653,17 +1653,17 @@ int RSound5::command28() {
 }
 
 void RSound5::loadTailChannels() {
-	_channels[3].load(loadData(0x1688));
-	_channels[8].load(loadData(0x1882));
+	_channels[3].playData(loadData(0x1688));
+	_channels[8].playData(loadData(0x1882));
 }
 
 int RSound5::command29() {
 	byte *pData = loadData(0x1488);
 	if (!isSoundActive(pData)) {
 		command1();
-		_channels[0].load(pData);
-		_channels[1].load(loadData(0x1534));
-		_channels[2].load(loadData(0x15EA));
+		_channels[0].playData(pData);
+		_channels[1].playData(loadData(0x1534));
+		_channels[2].playData(loadData(0x15EA));
 		loadTailChannels();
 	}
 	return 0;
@@ -1730,7 +1730,7 @@ int RSound5::command40() {
 
 int RSound5::command41() {
 	_channels[8]._pSrc = loadData(0x1182);
-	_channels[3].load(loadData(0x1BB6));
+	_channels[3].playData(loadData(0x1BB6));
 	return 0;
 }
 
@@ -1747,8 +1747,8 @@ const RSound6::CommandPtr RSound6::_commandList[30] = {
 	&RSound6::nullCommand, &RSound6::command28
 };
 
-RSound6::RSound6(Audio::Mixer *mixer) : RSound(mixer, "rsound.006",
-		0x12D0, 0x1EF0, 0x67, kRSoundFadeCheckProgrammable) {
+RSound6::RSound6(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver) : 
+	RSound(mixer, midiDriver, "rsound.006", 0x12D0, 0x1EF0, 0x67, kRSoundFadeCheckProgrammable) {
 }
 
 int RSound6::command(int commandId, int param) {
@@ -1776,9 +1776,9 @@ void RSound6::reloadCommand24() {
 	command1();
 	_callbackCounter = 84;
 	_callbackPeriod = 84;
-	_channels[0].load(loadData(0x1A38));
-	_channels[1].load(loadData(0x1BBE));
-	_channels[8].load(loadData(0x1B90));
+	_channels[0].playData(loadData(0x1A38));
+	_channels[1].playData(loadData(0x1BBE));
+	_channels[8].playData(loadData(0x1B90));
 }
 
 void RSound6::reloadCommand28() {
@@ -1786,11 +1786,11 @@ void RSound6::reloadCommand28() {
 	command1();
 	_callbackCounter = 84;
 	_callbackPeriod = 84;
-	_channels[0].load(loadData(0x130A));
-	_channels[1].load(loadData(0x13B6));
-	_channels[2].load(loadData(0x146C));
-	_channels[3].load(loadData(0x150A));
-	_channels[8].load(loadData(0x1704));
+	_channels[0].playData(loadData(0x130A));
+	_channels[1].playData(loadData(0x13B6));
+	_channels[2].playData(loadData(0x146C));
+	_channels[3].playData(loadData(0x150A));
+	_channels[8].playData(loadData(0x1704));
 }
 
 int RSound6::command9() {
@@ -1858,7 +1858,7 @@ int RSound6::command20() {
 }
 
 int RSound6::command21() {
-	_channels[4].load(loadData(0x1282));
+	_channels[4].playData(loadData(0x1282));
 	playSound(0x1282);
 	playSound(0x1282);
 	playSound(0x12AA);
@@ -1866,10 +1866,10 @@ int RSound6::command21() {
 }
 
 int RSound6::command22() {
-	_channels[4].load(loadData(0x12CE));
-	_channels[5].load(loadData(0x12CE));
-	_channels[6].load(loadData(0x12CE));
-	_channels[7].load(loadData(0x12CE));
+	_channels[4].playData(loadData(0x12CE));
+	_channels[5].playData(loadData(0x12CE));
+	_channels[6].playData(loadData(0x12CE));
+	_channels[7].playData(loadData(0x12CE));
 	return 0;
 }
 
@@ -1879,7 +1879,7 @@ int RSound6::command23() {
 }
 
 int RSound6::command24() {
-	if (_channels[0]._activeCount && _channels[0]._soundData == loadData(0x130A)) {
+	if (_channels[0]._deltaCounter && _channels[0]._soundData == loadData(0x130A)) {
 		_callbackFnPtr = &RSound6::reloadCommand24;
 		return 0;
 	}
@@ -1889,7 +1889,7 @@ int RSound6::command24() {
 }
 
 int RSound6::command25() {
-	_channels[4].load(loadData(0x12FE));
+	_channels[4].playData(loadData(0x12FE));
 	return 0;
 }
 
@@ -1897,7 +1897,7 @@ int RSound6::command28() {
 	if (isSoundActive(loadData(0x130A)))
 		return 0;
 
-	if (_channels[0]._activeCount && _channels[0]._soundData == loadData(0x1A38)) {
+	if (_channels[0]._deltaCounter && _channels[0]._soundData == loadData(0x1A38)) {
 		_callbackFnPtr = &RSound6::reloadCommand28;
 		return 0;
 	}
@@ -1921,8 +1921,8 @@ const RSound7::CommandPtr RSound7::_commandList[38] = {
 	&RSound7::command36, &RSound7::command37
 };
 
-RSound7::RSound7(Audio::Mixer *mixer) : RSound(mixer, "rsound.007",
-		0x1240, 0x1EF0, 0x67, kRSoundFadeCheckProgrammable) {
+RSound7::RSound7(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver) : 
+	RSound(mixer, midiDriver, "rsound.007", 0x1240, 0x1EF0, 0x67, kRSoundFadeCheckProgrammable) {
 }
 
 int RSound7::command(int commandId, int param) {
@@ -1936,10 +1936,10 @@ int RSound7::command(int commandId, int param) {
 
 int RSound7::command9() {
 	command1();
-	_channels[0].load(loadData(0x1C0E));
-	_channels[1].load(loadData(0x1C88));
-	_channels[2].load(loadData(0x1CD4));
-	_channels[3].load(loadData(0x1D4E));
+	_channels[0].playData(loadData(0x1C0E));
+	_channels[1].playData(loadData(0x1C88));
+	_channels[2].playData(loadData(0x1CD4));
+	_channels[3].playData(loadData(0x1D4E));
 	return 0;
 }
 
@@ -1959,16 +1959,16 @@ int RSound7::command17() {
 }
 
 int RSound7::command18() {
-	_channels[7].load(loadData(0x12FC));
+	_channels[7].playData(loadData(0x12FC));
 	return 0;
 }
 
 int RSound7::command19() {
 	if (_channels[7]._soundData == loadData(0x12FC)) {
 		byte *pData = loadData(0x1312);
-		_channels[7]._innerLoopPtr = pData;
-		_channels[7]._outerLoopPtr = pData;
-		_channels[7]._activeCount = 1;
+		_channels[7]._innerLoopStart = pData;
+		_channels[7]._outerLoopStart = pData;
+		_channels[7]._deltaCounter = 1;
 	}
 	return 0;
 }
@@ -1995,29 +1995,29 @@ int RSound7::command23() {
 }
 
 int RSound7::command24() {
-	_channels[0].load(loadData(0x137C));
-	_channels[1].load(loadData(0x1406));
-	_channels[2].load(loadData(0x1492));
-	_channels[3].load(loadData(0x1516));
-	_channels[4].load(loadData(0x1588));
+	_channels[0].playData(loadData(0x137C));
+	_channels[1].playData(loadData(0x1406));
+	_channels[2].playData(loadData(0x1492));
+	_channels[3].playData(loadData(0x1516));
+	_channels[4].playData(loadData(0x1588));
 	return 0;
 }
 
 int RSound7::command25() {
 	command1();
-	_channels[0].load(loadData(0x1612));
-	_channels[1].load(loadData(0x16C8));
-	_channels[2].load(loadData(0x177E));
-	_channels[3].load(loadData(0x1838));
+	_channels[0].playData(loadData(0x1612));
+	_channels[1].playData(loadData(0x16C8));
+	_channels[2].playData(loadData(0x177E));
+	_channels[3].playData(loadData(0x1838));
 	return 0;
 }
 
 int RSound7::command27() {
-	_channels[0].load(loadData(0x1932));
-	_channels[1].load(loadData(0x1986));
-	_channels[2].load(loadData(0x19EC));
-	_channels[3].load(loadData(0x1A66));
-	_channels[4].load(loadData(0x1B3C));
+	_channels[0].playData(loadData(0x1932));
+	_channels[1].playData(loadData(0x1986));
+	_channels[2].playData(loadData(0x19EC));
+	_channels[3].playData(loadData(0x1A66));
+	_channels[4].playData(loadData(0x1B3C));
 	return 0;
 }
 
@@ -2073,8 +2073,8 @@ const RSound8::CommandPtr RSound8::_commandList[38] = {
 	&RSound8::command36, &RSound8::command37
 };
 
-RSound8::RSound8(Audio::Mixer *mixer) : RSound(mixer, "rsound.008",
-		0x1290, 0x19A0, 0x67, kRSoundFadeCheckProgrammable) {
+RSound8::RSound8(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver) : 
+	RSound(mixer, midiDriver, "rsound.008", 0x1290, 0x19A0, 0x67, kRSoundFadeCheckProgrammable) {
 }
 
 int RSound8::command(int commandId, int param) {
@@ -2092,10 +2092,10 @@ int RSound8::command9() {
 }
 
 int RSound8::command10() {
-	_channels[0].load(loadData(0x115A));
-	_channels[1].load(loadData(0x115A));
-	_channels[2].load(loadData(0x115A));
-	_channels[3].load(loadData(0x1150));
+	_channels[0].playData(loadData(0x115A));
+	_channels[1].playData(loadData(0x115A));
+	_channels[2].playData(loadData(0x115A));
+	_channels[3].playData(loadData(0x1150));
 	return 0;
 }
 
@@ -2175,10 +2175,10 @@ int RSound8::command22() {
 }
 
 int RSound8::command23() {
-	_channels[0].load(loadData(0x128E));
-	_channels[1].load(loadData(0x128E));
-	_channels[2].load(loadData(0x128E));
-	_channels[3].load(loadData(0x128E));
+	_channels[0].playData(loadData(0x128E));
+	_channels[1].playData(loadData(0x128E));
+	_channels[2].playData(loadData(0x128E));
+	_channels[3].playData(loadData(0x128E));
 	return 0;
 }
 
@@ -2206,9 +2206,9 @@ int RSound8::command28() {
 	byte *pData = loadData(0x130A);
 	if (!isSoundActive(pData)) {
 		command1();
-		_channels[0].load(pData);
-		_channels[1].load(loadData(0x1480));
-		_channels[8].load(loadData(0x154C));
+		_channels[0].playData(pData);
+		_channels[1].playData(loadData(0x1480));
+		_channels[8].playData(loadData(0x154C));
 	}
 	return 0;
 }
@@ -2217,8 +2217,8 @@ int RSound8::command29() {
 	byte *pData = loadData(0x15FC);
 	if (!isSoundActive(pData)) {
 		command1();
-		_channels[2].load(pData);
-		_channels[8].load(loadData(0x1652));
+		_channels[2].playData(pData);
+		_channels[8].playData(loadData(0x1652));
 	}
 	return 0;
 }
@@ -2283,8 +2283,8 @@ const RSound9::CommandPtr RSound9::_commandList[52] = {
 	&RSound9::command48, &RSound9::command49, &RSound9::command50, &RSound9::command51
 };
 
-RSound9::RSound9(Audio::Mixer *mixer) : RSound(mixer, "rsound.009",
-		0x1520, 0x8920, 0x6F, kRSoundFadeCheckAlternating) {
+RSound9::RSound9(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver) : 
+	RSound(mixer, midiDriver, "rsound.009", 0x1520, 0x8920, 0x6F, kRSoundFadeCheckAlternating) {
 	_callbackCounter = 0;
 	_callbackPeriod = 0;
 	_callbackFnPtr = nullptr;
@@ -2320,56 +2320,56 @@ int RSound9::command0() {
 int RSound9::command9() {
 	_callbackCounter = 1848;
 	_callbackPeriod = 84;
-	_channels[0].load(loadData(0x16E4));
-	_channels[1].load(loadData(0x1E9E));
-	_channels[2].load(loadData(0x2F9C));
-	_channels[3].load(loadData(0x2644));
-	_channels[4].load(loadData(0x1FF4));
-	_channels[5].load(loadData(0x2382));
-	_channels[6].load(loadData(0x1AAE));
+	_channels[0].playData(loadData(0x16E4));
+	_channels[1].playData(loadData(0x1E9E));
+	_channels[2].playData(loadData(0x2F9C));
+	_channels[3].playData(loadData(0x2644));
+	_channels[4].playData(loadData(0x1FF4));
+	_channels[5].playData(loadData(0x2382));
+	_channels[6].playData(loadData(0x1AAE));
 	return 0;
 }
 
 int RSound9::command10() {
-	_channels[0].load(loadData(0x31E2));
-	_channels[1].load(loadData(0x31FA));
-	_channels[2].load(loadData(0x3212));
-	_channels[3].load(loadData(0x322C));
+	_channels[0].playData(loadData(0x31E2));
+	_channels[1].playData(loadData(0x31FA));
+	_channels[2].playData(loadData(0x3212));
+	_channels[3].playData(loadData(0x322C));
 	return 0;
 }
 
 int RSound9::command11() {
-	_channels[7].load(loadData(0x33E2));
+	_channels[7].playData(loadData(0x33E2));
 	return 0;
 }
 
 int RSound9::command12() {
-	_channels[7].load(loadData(0x342E));
+	_channels[7].playData(loadData(0x342E));
 	return 0;
 }
 
 int RSound9::command13() {
-	_channels[7].load(loadData(0x343A));
+	_channels[7].playData(loadData(0x343A));
 	return 0;
 }
 
 int RSound9::command14() {
-	_channels[7].load(loadData(0x3442));
+	_channels[7].playData(loadData(0x3442));
 	return 0;
 }
 
 int RSound9::command15() {
-	_channels[7].load(loadData(0x3462));
+	_channels[7].playData(loadData(0x3462));
 	return 0;
 }
 
 int RSound9::command16() {
-	_channels[7].load(loadData(0x347A));
+	_channels[7].playData(loadData(0x347A));
 	return 0;
 }
 
 int RSound9::command17() {
-	_channels[7].load(loadData(0x3470));
+	_channels[7].playData(loadData(0x3470));
 	return 0;
 }
 
@@ -2410,15 +2410,15 @@ int RSound9::command22() {
 int RSound9::command23() {
 	Channel *chan = playSound(0x32B0);
 	if (chan)
-		chan->_innerLoopPtr = loadData(0x32CE);
+		chan->_innerLoopStart = loadData(0x32CE);
 
 	chan = playSound(0x32B6);
 	if (chan)
-		chan->_innerLoopPtr = loadData(0x32CE);
+		chan->_innerLoopStart = loadData(0x32CE);
 
 	chan = playSound(0x32C8);
 	if (chan)
-		chan->_innerLoopPtr = loadData(0x32CE);
+		chan->_innerLoopStart = loadData(0x32CE);
 	return 0;
 }
 
@@ -2446,7 +2446,7 @@ int RSound9::command28() {
 	int v = (getRandomNumber() & 28) + 15;
 	byte *pData = loadData(0x334A);
 	pData[6] = v & 0x7F;
-	_channels[7].load(pData);
+	_channels[7].playData(pData);
 	return 0;
 }
 
@@ -2489,11 +2489,11 @@ int RSound9::command34() {
 	*loadData(0x7DCD) = 2;
 	*loadData(0x8791) = 2;
 
-	_channels[0].load(loadData(0x4D2A));
-	_channels[1].load(loadData(0x51AA));
-	_channels[2].load(loadData(0x5634));
-	_channels[3].load(loadData(0x6844));
-	_channels[4].load(loadData(0x7DD0));
+	_channels[0].playData(loadData(0x4D2A));
+	_channels[1].playData(loadData(0x51AA));
+	_channels[2].playData(loadData(0x5634));
+	_channels[3].playData(loadData(0x6844));
+	_channels[4].playData(loadData(0x7DD0));
 	return 0;
 }
 
@@ -2507,11 +2507,11 @@ int RSound9::command36() {
 
 	Channel *chan = playSound(0x32C2);
 	if (chan)
-		chan->_innerLoopPtr = loadData(0x3378);
+		chan->_innerLoopStart = loadData(0x3378);
 
 	chan = playSound(0x32BC);
 	if (chan)
-		chan->_innerLoopPtr = loadData(0x3368);
+		chan->_innerLoopStart = loadData(0x3368);
 	return 0;
 }
 
@@ -2530,13 +2530,13 @@ int RSound9::command38() {
 
 void RSound9::loadCommand38() {
 	_callbackFnPtr = nullptr;
-	_channels[0].load(loadData(0x1878));
-	_channels[1].load(loadData(0x1F64));
-	_channels[2].load(loadData(0x308E));
-	_channels[3].load(loadData(0x2A10));
-	_channels[4].load(loadData(0x21C8));
-	_channels[5].load(loadData(0x2558));
-	_channels[6].load(loadData(0x1E9A));
+	_channels[0].playData(loadData(0x1878));
+	_channels[1].playData(loadData(0x1F64));
+	_channels[2].playData(loadData(0x308E));
+	_channels[3].playData(loadData(0x2A10));
+	_channels[4].playData(loadData(0x21C8));
+	_channels[5].playData(loadData(0x2558));
+	_channels[6].playData(loadData(0x1E9A));
 }
 
 int RSound9::command39() {
@@ -2546,13 +2546,13 @@ int RSound9::command39() {
 
 void RSound9::loadCommand39() {
 	_callbackFnPtr = nullptr;
-	_channels[0].load(loadData(0x1A24));
-	_channels[1].load(loadData(0x1FD0));
-	_channels[2].load(loadData(0x318A));
-	_channels[3].load(loadData(0x2E4A));
-	_channels[4].load(loadData(0x2380));
-	_channels[5].load(loadData(0x2642));
-	_channels[6].load(loadData(0x1E9C));
+	_channels[0].playData(loadData(0x1A24));
+	_channels[1].playData(loadData(0x1FD0));
+	_channels[2].playData(loadData(0x318A));
+	_channels[3].playData(loadData(0x2E4A));
+	_channels[4].playData(loadData(0x2380));
+	_channels[5].playData(loadData(0x2642));
+	_channels[6].playData(loadData(0x1E9C));
 }
 
 int RSound9::command40() {
@@ -2562,11 +2562,11 @@ int RSound9::command40() {
 
 void RSound9::loadCommand40() {
 	_callbackFnPtr = nullptr;
-	_channels[0].load(loadData(0x4F00));
-	_channels[1].load(loadData(0x534A));
-	_channels[2].load(loadData(0x5CDE));
-	_channels[3].load(loadData(0x6F8E));
-	_channels[4].load(loadData(0x8110));
+	_channels[0].playData(loadData(0x4F00));
+	_channels[1].playData(loadData(0x534A));
+	_channels[2].playData(loadData(0x5CDE));
+	_channels[3].playData(loadData(0x6F8E));
+	_channels[4].playData(loadData(0x8110));
 }
 
 int RSound9::command41() {
@@ -2576,11 +2576,11 @@ int RSound9::command41() {
 
 void RSound9::loadCommand41() {
 	_callbackFnPtr = nullptr;
-	_channels[0].load(loadData(0x4F26));
-	_channels[1].load(loadData(0x53BC));
-	_channels[2].load(loadData(0x5DFE));
-	_channels[3].load(loadData(0x747E));
-	_channels[4].load(loadData(0x8340));
+	_channels[0].playData(loadData(0x4F26));
+	_channels[1].playData(loadData(0x53BC));
+	_channels[2].playData(loadData(0x5DFE));
+	_channels[3].playData(loadData(0x747E));
+	_channels[4].playData(loadData(0x8340));
 }
 
 int RSound9::command42() {
@@ -2590,20 +2590,20 @@ int RSound9::command42() {
 
 void RSound9::loadCommand42() {
 	_callbackFnPtr = nullptr;
-	_channels[0].load(loadData(0x4F30));
-	_channels[1].load(loadData(0x555C));
-	_channels[2].load(loadData(0x6582));
-	_channels[3].load(loadData(0x7A2E));
-	_channels[4].load(loadData(0x8480));
+	_channels[0].playData(loadData(0x4F30));
+	_channels[1].playData(loadData(0x555C));
+	_channels[2].playData(loadData(0x6582));
+	_channels[3].playData(loadData(0x7A2E));
+	_channels[4].playData(loadData(0x8480));
 }
 
 int RSound9::command43() {
 	_callbackCounter = 80;
 	_callbackPeriod = 80;
-	_channels[0].load(loadData(0x34BE));
-	_channels[1].load(loadData(0x3A46));
-	_channels[2].load(loadData(0x3F52));
-	_channels[3].load(loadData(0x439A));
+	_channels[0].playData(loadData(0x34BE));
+	_channels[1].playData(loadData(0x3A46));
+	_channels[2].playData(loadData(0x3F52));
+	_channels[3].playData(loadData(0x439A));
 	return 0;
 }
 
@@ -2614,10 +2614,10 @@ int RSound9::command44_46() {
 
 void RSound9::loadCommand44_46() {
 	_callbackFnPtr = nullptr;
-	_channels[0].load(loadData(0x3518));
-	_channels[1].load(loadData(0x3AA2));
-	_channels[2].load(loadData(0x403A));
-	_channels[3].load(loadData(0x4486));
+	_channels[0].playData(loadData(0x3518));
+	_channels[1].playData(loadData(0x3AA2));
+	_channels[2].playData(loadData(0x403A));
+	_channels[3].playData(loadData(0x4486));
 }
 
 int RSound9::command45() {
@@ -2627,10 +2627,10 @@ int RSound9::command45() {
 
 void RSound9::loadCommand45() {
 	_callbackFnPtr = nullptr;
-	_channels[0].load(loadData(0x37AC));
-	_channels[1].load(loadData(0x3CF8));
-	_channels[2].load(loadData(0x41E6));
-	_channels[3].load(loadData(0x4630));
+	_channels[0].playData(loadData(0x37AC));
+	_channels[1].playData(loadData(0x3CF8));
+	_channels[2].playData(loadData(0x41E6));
+	_channels[3].playData(loadData(0x4630));
 }
 
 int RSound9::command47() {
@@ -2640,10 +2640,10 @@ int RSound9::command47() {
 
 void RSound9::loadCommand47() {
 	_callbackFnPtr = nullptr;
-	_channels[0].load(loadData(0x47D6));
-	_channels[1].load(loadData(0x48FA));
-	_channels[2].load(loadData(0x4A20));
-	_channels[3].load(loadData(0x4BAE));
+	_channels[0].playData(loadData(0x47D6));
+	_channels[1].playData(loadData(0x48FA));
+	_channels[2].playData(loadData(0x4A20));
+	_channels[3].playData(loadData(0x4BAE));
 }
 
 int RSound9::command48() {
@@ -2655,13 +2655,13 @@ int RSound9::command48() {
 }
 
 int RSound9::command49() {
-	_channels[0].load(loadData(0x12CA));
-	_channels[1].load(loadData(0x132A));
-	_channels[2].load(loadData(0x1384));
-	_channels[3].load(loadData(0x1666));
-	_channels[4].load(loadData(0x1682));
-	_channels[5].load(loadData(0x16A0));
-	_channels[6].load(loadData(0x16BE));
+	_channels[0].playData(loadData(0x12CA));
+	_channels[1].playData(loadData(0x132A));
+	_channels[2].playData(loadData(0x1384));
+	_channels[3].playData(loadData(0x1666));
+	_channels[4].playData(loadData(0x1682));
+	_channels[5].playData(loadData(0x16A0));
+	_channels[6].playData(loadData(0x16BE));
 	return 0;
 }
 
@@ -2677,11 +2677,11 @@ void RSound9::loadCommand50() {
 	*loadData(0x7DCD) = 0;
 	*loadData(0x8791) = 0;
 
-	_channels[0].load(loadData(0x50B8));
-	_channels[1].load(loadData(0x7DCE));
-	_channels[2].load(loadData(0x676A));
-	_channels[3].load(loadData(0x7D08));
-	_channels[4].load(loadData(0x85C4));
+	_channels[0].playData(loadData(0x50B8));
+	_channels[1].playData(loadData(0x7DCE));
+	_channels[2].playData(loadData(0x676A));
+	_channels[3].playData(loadData(0x7D08));
+	_channels[4].playData(loadData(0x85C4));
 }
 
 int RSound9::command51() {
@@ -2693,18 +2693,18 @@ int RSound9::command51() {
 	*loadData(0x7DCD) = 2;
 	*loadData(0x8791) = 2;
 
-	_channels[0].load(loadData(0x4D3C));
-	_channels[1].load(loadData(0x51EE));
-	_channels[2].load(loadData(0x5A62));
-	_channels[3].load(loadData(0x6986));
-	_channels[4].load(loadData(0x7E5C));
+	_channels[0].playData(loadData(0x4D3C));
+	_channels[1].playData(loadData(0x51EE));
+	_channels[2].playData(loadData(0x5A62));
+	_channels[3].playData(loadData(0x6986));
+	_channels[4].playData(loadData(0x7E5C));
 	return 0;
 }
 
 /*-----------------------------------------------------------------------*/
 
-RSoundDemo9::RSoundDemo9(Audio::Mixer *mixer) :
-		RSoundDemo(mixer, "rsound.009", 0x11D0, 0x3664, 0x69, 5) {
+RSoundDemo9::RSoundDemo9(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver) :
+		RSoundDemo(mixer, midiDriver, "rsound.009", 0x11D0, 0x3664, 0x69, 5) {
 }
 
 int RSoundDemo9::executeDemoCommonCommand(int commandId) {
@@ -2798,7 +2798,7 @@ int RSoundDemo9::command(int commandId, int param) {
 		for (uint index = 0; index < 3; ++index) {
 			const int channel = startEffectVoice(sequences[index]);
 			if (channel >= 0)
-				voice(channel)._innerLoopPtr = loadData(0x1340);
+				voice(channel)._innerLoopStart = loadData(0x1340);
 		}
 		break;
 	}
@@ -2856,11 +2856,11 @@ int RSoundDemo9::command(int commandId, int param) {
 
 		int channel = startEffectVoice(0x1334);
 		if (channel >= 0)
-			voice(channel)._innerLoopPtr = loadData(0x13EA);
+			voice(channel)._innerLoopStart = loadData(0x13EA);
 
 		channel = startEffectVoice(0x132E);
 		if (channel >= 0)
-			voice(channel)._innerLoopPtr = loadData(0x13DA);
+			voice(channel)._innerLoopStart = loadData(0x13DA);
 		break;
 	}
 	case 37: {
diff --git a/engines/mads/nebular/sound/rsound_nebular.h b/engines/mads/nebular/sound/rsound_nebular.h
index a7e71d0abf6..e0cd91de427 100644
--- a/engines/mads/nebular/sound/rsound_nebular.h
+++ b/engines/mads/nebular/sound/rsound_nebular.h
@@ -34,7 +34,7 @@ private:
 	int _firstEffectChannel;
 
 protected:
-	RSoundDemo(Audio::Mixer *mixer, const Common::Path &filename,
+	RSoundDemo(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver, const Common::Path &filename,
 			int dataOffset, int dataSize, int sysExOffset,
 			int firstEffectChannel);
 
@@ -104,7 +104,7 @@ private:
 	int command40();
 	int command41();
 public:
-	RSound1(Audio::Mixer *mixer);
+	RSound1(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver);
 
 	int command(int commandId, int param) override;
 };
@@ -119,7 +119,7 @@ private:
 	int executeDemoCommonCommand(int commandId);
 
 public:
-	explicit RSoundDemo1(Audio::Mixer *mixer);
+	explicit RSoundDemo1(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver);
 	int command(int commandId, int param) override;
 };
 
@@ -186,7 +186,7 @@ private:
 	int command42();
 	int command43();
 public:
-	RSound2(Audio::Mixer *mixer);
+	RSound2(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver);
 
 	int command(int commandId, int param) override;
 };
@@ -296,7 +296,7 @@ private:
 	int command59();
 	int command60();
 public:
-	RSound3(Audio::Mixer *mixer);
+	RSound3(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver);
 
 	int command(int commandId, int param) override;
 };
@@ -366,7 +366,7 @@ private:
 	int command58();
 	int command59();
 public:
-	RSound4(Audio::Mixer *mixer);
+	RSound4(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver);
 
 	int command(int commandId, int param) override;
 };
@@ -414,7 +414,7 @@ private:
 	int command40();
 	int command41();
 public:
-	RSound5(Audio::Mixer *mixer);
+	RSound5(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver);
 
 	int command(int commandId, int param) override;
 };
@@ -467,7 +467,7 @@ private:
 	int command25();
 	int command28();
 public:
-	RSound6(Audio::Mixer *mixer);
+	RSound6(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver);
 
 	int command(int commandId, int param) override;
 };
@@ -498,7 +498,7 @@ private:
 	int command36();
 	int command37();
 public:
-	RSound7(Audio::Mixer *mixer);
+	RSound7(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver);
 
 	int command(int commandId, int param) override;
 };
@@ -544,7 +544,7 @@ private:
 	int command36();
 	int command37();
 public:
-	RSound8(Audio::Mixer *mixer);
+	RSound8(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver);
 
 	int command(int commandId, int param) override;
 };
@@ -624,7 +624,7 @@ private:
 	void loadCommand47();
 	void loadCommand50();
 public:
-	RSound9(Audio::Mixer *mixer);
+	RSound9(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver);
 
 	int command(int commandId, int param) override;
 };
@@ -635,7 +635,7 @@ private:
 	int executeDemoCommonCommand(int commandId);
 
 public:
-	explicit RSoundDemo9(Audio::Mixer *mixer);
+	explicit RSoundDemo9(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver);
 	int command(int commandId, int param) override;
 };
 
diff --git a/engines/mads/nebular/sound/sound.cpp b/engines/mads/nebular/sound/sound.cpp
index e42073cd865..5b4375c1acf 100644
--- a/engines/mads/nebular/sound/sound.cpp
+++ b/engines/mads/nebular/sound/sound.cpp
@@ -70,7 +70,7 @@ void RexSoundManager::validate() {
 }
 
 void RexSoundManager::loadDriver(int sectionNumber) {
-	removeDriver();
+	closeDriver();
 
 	if (_isDemo && _driverType == SOUND_ADLIB) {
 		switch (sectionNumber) {
@@ -93,39 +93,39 @@ void RexSoundManager::loadDriver(int sectionNumber) {
 			// The demo shares RSOUND.001 across numbered gameplay sections
 			// and uses RSOUND.009 only for its opening presentation.
 			if (sectionNumber == 9)
-				_driver = new RSoundDemo9(_mixer);
+				_driver = new RSoundDemo9(_mixer, _midiDriver);
 			else
-				_driver = new RSoundDemo1(_mixer);
+				_driver = new RSoundDemo1(_mixer, _midiDriver);
 			break;
 		}
 
 		switch (sectionNumber) {
 		case 1:
-			_driver = new RSound1(_mixer);
+			_driver = new RSound1(_mixer, _midiDriver);
 			break;
 		case 2:
-			_driver = new RSound2(_mixer);
+			_driver = new RSound2(_mixer, _midiDriver);
 			break;
 		case 3:
-			_driver = new RSound3(_mixer);
+			_driver = new RSound3(_mixer, _midiDriver);
 			break;
 		case 4:
-			_driver = new RSound4(_mixer);
+			_driver = new RSound4(_mixer, _midiDriver);
 			break;
 		case 5:
-			_driver = new RSound5(_mixer);
+			_driver = new RSound5(_mixer, _midiDriver);
 			break;
 		case 6:
-			_driver = new RSound6(_mixer);
+			_driver = new RSound6(_mixer, _midiDriver);
 			break;
 		case 7:
-			_driver = new RSound7(_mixer);
+			_driver = new RSound7(_mixer, _midiDriver);
 			break;
 		case 8:
-			_driver = new RSound8(_mixer);
+			_driver = new RSound8(_mixer, _midiDriver);
 			break;
 		case 9:
-			_driver = new RSound9(_mixer);
+			_driver = new RSound9(_mixer, _midiDriver);
 			break;
 		default:
 			return;


Commit: e815605b1bab62779765f6de4006bd2b3291fb93
    https://github.com/scummvm/scummvm/commit/e815605b1bab62779765f6de4006bd2b3291fb93
Author: Coen Rampen (crampen at gmail.com)
Date: 2026-08-16T17:11:24+02:00

Commit Message:
MADS: Fixes for Rex MT-32 sound driver

Changed paths:
    engines/mads/core/sound_manager.cpp
    engines/mads/core/sound_manager.h
    engines/mads/nebular/sound/rsound.cpp
    engines/mads/nebular/sound/rsound.h
    engines/mads/nebular/sound/rsound_nebular.cpp
    engines/mads/nebular/sound/rsound_nebular.h
    engines/mads/nebular/sound/sound.cpp


diff --git a/engines/mads/core/sound_manager.cpp b/engines/mads/core/sound_manager.cpp
index 0155a3d52a6..1517a4f2281 100644
--- a/engines/mads/core/sound_manager.cpp
+++ b/engines/mads/core/sound_manager.cpp
@@ -33,9 +33,9 @@ class Mixer;
 
 namespace MADS {
 
-	const uint32 SoundManager::UPDATE_DELTA = 1000000 / 60;
+const uint32 SoundManager::UPDATE_DELTA = 1000000 / 60;
 
-	SoundManager::SoundManager(Audio::Mixer *mixer, bool &soundFlag,
+SoundManager::SoundManager(Audio::Mixer *mixer, bool &soundFlag,
 		bool supportsGeneralMidi) : _mixer(mixer), _soundFlag(soundFlag) {
 	_updateDeltaRemainder = 0;
 	_driverCallbackDelta = 0;
@@ -48,15 +48,6 @@ namespace MADS {
 	switch (musicType) {
 	case MT_MT32:
 		_driverType = SOUND_MT32;
-		_midiDriver = new MidiDriver_MT32GM(MusicType::MT_MT32);
-		int returnCode;
-		returnCode = _midiDriver->open();
-		if (returnCode != 0)
-			error("RSound - Failed to open MIDI music driver - error code %d.", returnCode);
-
-		_driverCallbackDelta = _midiDriver->getBaseTempo();
-		_midiDriver->setTimerCallback(this, &timerCallback);
-
 		break;
 	case MT_GM:
 	case MT_GS:
@@ -175,12 +166,21 @@ void SoundManager::onTimer() {
 	// The frequency of the callbacks is dependent on the underlying driver
 	// implementation and might not be 60Hz. Adjust to make sure poll() is called
 	// with the correct frequency.
+	/*
 	_updateDeltaRemainder += _driverCallbackDelta;
 	while (_updateDeltaRemainder >= UPDATE_DELTA) {
 		if (_driver)
 			_driver->poll();
 		_updateDeltaRemainder -= UPDATE_DELTA;
 	}
+	*/
+
+	uint32 serviceTicks = _hostTimer.advance(_driverCallbackDelta, 1000000);
+	while (serviceTicks--) {
+		// RSOUND export 4 is a return stub in every audited overlay.
+		if (_driver && _hostTimer.pollDue())
+			_driver->poll();
+	}
 }
 
 void SoundManager::timerCallback(void *data) {
diff --git a/engines/mads/core/sound_manager.h b/engines/mads/core/sound_manager.h
index 22d47028219..f03c36546bb 100644
--- a/engines/mads/core/sound_manager.h
+++ b/engines/mads/core/sound_manager.h
@@ -27,6 +27,7 @@
 #include "common/memstream.h"
 #include "common/mutex.h"
 #include "common/queue.h"
+#include "native_sound_timer.h"
 
 namespace Audio {
 class Mixer;
@@ -115,6 +116,8 @@ protected:
 	Common::Queue<QueuedCommand> _queuedCommands;
 	int _masterVolume = 255;
 
+	NativeSoundTimer _hostTimer;
+
 protected:
 	/**
 	 * Load the particular section sound handler
diff --git a/engines/mads/nebular/sound/rsound.cpp b/engines/mads/nebular/sound/rsound.cpp
index 1df08cb7bc2..97bb3726bac 100644
--- a/engines/mads/nebular/sound/rsound.cpp
+++ b/engines/mads/nebular/sound/rsound.cpp
@@ -59,9 +59,14 @@ void Channel::setFadeOut(bool fadeOut) {
 }
 
 void Channel::playData(byte *soundData) {
+	bool ticksProcessingDisabled = _owner->_ticksProcessingDisabled;
+	_owner->_ticksProcessingDisabled = true;
+
 	loadData(soundData);
 	_deltaCounter = 1;
 	_owner->sendPitchBend(_midiChannel, 0x40);
+
+	_owner->_ticksProcessingDisabled = ticksProcessingDisabled;
 }
 
 /*-----------------------------------------------------------------------*/
@@ -70,12 +75,13 @@ RSound::RSound(Audio::Mixer *mixer, MidiDriver_MT32GM *midiDriver, const Common:
 		int dataOffset, int dataSize, int sysExOffset, RSoundFadeCheckMode fadeCheckMode) : 
 		SoundDriver(mixer, filename, dataOffset, dataSize) {
 	_commandParam = 0;
-	_frameCounter = 0;
-	_isDisabled = false;
+	_ticksSinceLastCommand = 0;
+	_ticksProcessingDisabled = false;
+	_mute = false;
 	_masterVolume = 255;
+	// FIXME RSOUND.008 initializes this to 0x005C; is the initial value different per driver?
 	_randomSeed = 1234;
-	_lastMidiStatus = 0;
-	_noteTriggeredThisPoll = false;
+	_runningStatus = 0;
 	_pollResult = 0;
 	_resultFlag = 0;
 	_sysExOffset = sysExOffset;
@@ -152,7 +158,7 @@ int RSound::stop() {
 int RSound::poll() {
 	Common::StackLock slock(_driverMutex);
 
-	update();
+	processTick();
 
 	int result = _pollResult;
 	_pollResult = 0;
@@ -166,25 +172,26 @@ void RSound::resultCheck() {
 	}
 }
 
-Channel *RSound::playSound(int offset) {
-	return playSoundData(loadData(offset));
+Channel *RSound::playSoundCh5To8(int offset) {
+	return allocateAndPlay(loadData(offset));
+}
+
+Channel *RSound::playSoundCh1To8(int offset) {
+	return allocateAndPlay(loadData(offset), 0);
 }
 
-Channel *RSound::playSoundData(byte *pData, int startingChannel) {
-	// playSound() (startingChannel=5) deliberately excludes channel 9
-	// (index 8), matching rsound.009's disassembly. playSoundAny()
-	// (startingChannel=0) reaches all 9 channels.
-	int endChannel = (startingChannel == 0) ? RSOUND_CHANNEL_COUNT : RSOUND_CHANNEL_COUNT - 1;
+Channel *RSound::allocateAndPlay(byte *pData, int startingChannel) {
+	int endChannel = RSOUND_CHANNEL_COUNT - 1;
 
 	// Scan for a free channel
 	for (int i = startingChannel; i < endChannel; ++i) {
-		if (!_channels[i]._deltaCounter) {
+		if (_channels[i]._deltaCounter == 0) {
 			_channels[i].playData(pData);
 			return &_channels[i];
 		}
 	}
 
-	// None found; fall back to an interruptable (pending-stop) channel
+	// None found; fall back to a channel that is fading out to stop
 	for (int i = endChannel - 1; i >= startingChannel; --i) {
 		if (_channels[i]._fadeOutActive) {
 			_channels[i].playData(pData);
@@ -192,21 +199,22 @@ Channel *RSound::playSoundData(byte *pData, int startingChannel) {
 		}
 	}
 
+	// No available channel
 	return nullptr;
 }
 
-bool RSound::isSoundActive(byte *pData) {
+bool RSound::isSoundPlaying(byte *pData) {
 	// Deliberately excludes channel 9 (index 8), matching the disassembly -
-	// same as playSoundData()'s scan never reaching channel 9 either.
+	// same as allocateAndPlay()'s scan never reaching channel 9 either.
 	for (int i = 0; i < RSOUND_CHANNEL_COUNT - 1; ++i) {
-		if (_channels[i]._deltaCounter && _channels[i]._soundData == pData)
+		if (_channels[i]._deltaCounter > 0 && _channels[i]._soundData == pData)
 			return true;
 	}
 
 	return false;
 }
 
-int RSound::getRandomNumber() {
+int RSound::generateRandomNumber() {
 	int v = 0x9249 + (int)_randomSeed;
 	_randomSeed = ((v >> 3) | (v << 13)) & 0xFFFF;
 	return _randomSeed;
@@ -215,7 +223,7 @@ int RSound::getRandomNumber() {
 void RSound::setVolume(int volume) {
 	_masterVolume = CLIP(volume, 0, 255);
 	for (int i = 0; i < RSOUND_CHANNEL_COUNT; ++i)
-		sendVolume(i + 1, _isDisabled ? 0 : _channels[i]._volume);
+		sendVolume(i + 1, _mute ? 0 : _channels[i]._volume);
 }
 
 /*-----------------------------------------------------------------------*/
@@ -239,7 +247,7 @@ void RSound::sendPitchBend(int midiChannel, int value) {
 	_midiDriver->send(MidiDriver::MIDI_COMMAND_PITCH_BEND | midiChannel, 0, value);
 }
 
-void RSound::sendPan(int midiChannel, int value) {
+void RSound::sendPanning(int midiChannel, int value) {
 	_midiDriver->send(MidiDriver::MIDI_COMMAND_CONTROL_CHANGE | midiChannel, MidiDriver::MIDI_CONTROLLER_PANNING, value);
 }
 
@@ -247,7 +255,7 @@ void RSound::muteChannel(int midiChannel) {
 	sendVolume(midiChannel, 0);
 }
 
-void RSound::restoreChannelVolume(int midiChannel, int volume) {
+void RSound::unmuteChannel(int midiChannel, int volume) {
 	sendVolume(midiChannel, volume);
 }
 
@@ -309,19 +317,19 @@ void RSound::sendSysExSequence() {
 
 /*-----------------------------------------------------------------------*/
 
-void RSound::Channel_flushHeldNotes(Channel *channel) {
-	byte *slots = _heldNotes[channel->_midiChannel];
+void RSound::Channel_turnOffActiveNotes(Channel *channel) {
+	byte *channelActiveNotes = _activeNotes[channel->_midiChannel];
 
 	for (int i = 0; i < 4; ++i) {
-		if (slots[i] == 0xFF)
+		if (channelActiveNotes[i] == 0xFF)
 			break;
 
-		sendNoteOn(channel->_midiChannel, slots[i], 0); // velocity 0 = note off
-		slots[i] = 0xFF;
+		sendNoteOn(channel->_midiChannel, channelActiveNotes[i], 0); // velocity 0 = note off
+		channelActiveNotes[i] = 0xFF;
 	}
 }
 
-void RSound::Channel_checkFade(Channel *channel) {
+void RSound::Channel_processFadeOut(Channel *channel) {
 	if (!channel->_deltaCounter)
 		return;
 	if (!channel->_fadeOutActive)
@@ -343,7 +351,7 @@ void RSound::Channel_checkFade(Channel *channel) {
 	}
 }
 
-void RSound::checkFadingChannels() {
+void RSound::processChannelFadeOuts() {
 	if (_fadeCheckMode == kRSoundFadeCheckAlternating) {
 		_fadeCheckAlternate = !_fadeCheckAlternate;
 		if (_fadeCheckAlternate)
@@ -358,30 +366,25 @@ void RSound::checkFadingChannels() {
 	}
 
 	for (int i = 0; i < RSOUND_CHANNEL_COUNT; ++i)
-		Channel_checkFade(&_channels[i]);
+		Channel_processFadeOut(&_channels[i]);
 }
 
-void RSound::Channel_pollActive(Channel *channel) {
-	if (!channel->_deltaCounter)
+void RSound::Channel_processTick(Channel *channel) {
+	if (channel->_deltaCounter == 0)
 		return;
 
 	int midiChannel = channel->_midiChannel;
 
 	if (channel->_noteDurationCounter > 0 && --channel->_noteDurationCounter == 0)
-		Channel_flushHeldNotes(channel);
+		Channel_turnOffActiveNotes(channel);
 
 	if (--channel->_deltaCounter <= 0) {
-		for (;;) {
+		bool chordEventProcessed = false;
+		while (!chordEventProcessed) {
 			byte *pSrc = channel->_pSrc;
 
 			if (*pSrc < 0x80) {
 				// Plain (note, duration) pair
-				if (_noteTriggeredThisPoll) {
-					// Already fired a note-on this poll tick - defer to next tick
-					_noteTriggeredThisPoll = false;
-					break;
-				}
-
 				byte note = pSrc[0];
 				byte duration = pSrc[1];
 				channel->_note = note;
@@ -389,19 +392,19 @@ void RSound::Channel_pollActive(Channel *channel) {
 				channel->_pSrc = pSrc + 2;
 
 				if (!note || !duration) {
-					Channel_flushHeldNotes(channel);
+					Channel_turnOffActiveNotes(channel);
 				} else {
 					channel->_noteDurationCounter = channel->_deltaCounter - channel->_noteDurationOffset;
 
 					bool skipRetrigger = false;
-					if ((int8)channel->_noteDurationOffset < 0 && _heldNotes[midiChannel][0] == note)
+					if ((int8)channel->_noteDurationOffset < 0 && _activeNotes[midiChannel][0] == note)
 						skipRetrigger = true;
 
 					if (!skipRetrigger) {
-						Channel_flushHeldNotes(channel);
+						Channel_turnOffActiveNotes(channel);
 						sendNoteOn(midiChannel, note, channel->_velocity);
 					}
-					_heldNotes[midiChannel][0] = note;
+					_activeNotes[midiChannel][0] = note;
 				}
 
 				break;
@@ -417,7 +420,7 @@ void RSound::Channel_pollActive(Channel *channel) {
 			case 1: { // 0xF2: self-modifying randomize (byte swap in the data stream)
 				int v1 = *++pSrc;
 				++pSrc;
-				int v2 = (v1 - 1) & getRandomNumber();
+				int v2 = (v1 - 1) & generateRandomNumber();
 				int v3 = pSrc[v2];
 				int v4 = pSrc[v1];
 				pSrc[v4 + v1 + 1] = v3;
@@ -434,14 +437,14 @@ void RSound::Channel_pollActive(Channel *channel) {
 
 			case 3: // 0xF4: set pan directly and send
 				channel->_panning = pSrc[1];
-				sendPan(midiChannel, channel->_panning);
+				sendPanning(midiChannel, channel->_panning);
 				channel->_pSrc = pSrc + 2;
 				break;
 
 			case 4: { // 0xF5: chord note-on trigger (up to 4 simultaneous notes)
 				byte noteCount = pSrc[1];
 				byte *notes = pSrc + 2;
-				byte *slots = _heldNotes[midiChannel];
+				byte *slots = _activeNotes[midiChannel];
 
 				int i;
 				for (i = 0; i < noteCount; ++i) {
@@ -464,7 +467,7 @@ void RSound::Channel_pollActive(Channel *channel) {
 				}
 
 				channel->_pSrc = pSrc + noteCount + 3;
-				_noteTriggeredThisPoll = true;
+				chordEventProcessed = true;
 				break;
 			}
 
@@ -498,7 +501,7 @@ void RSound::Channel_pollActive(Channel *channel) {
 
 			case 9: // 0xFA: setup pitch-bend ramp
 				channel->_pitchSlideSpeed = pSrc[1];
-				channel->_pitchSlideStepSize = pSrc[2];
+				channel->_pitchSlideStepSize = (int8) pSrc[2];
 				channel->_pitchSlideDurationCounter = pSrc[3];
 				channel->_pitchSlideCounter = 1;
 				channel->_pSrc = pSrc + 4;
@@ -572,13 +575,22 @@ void RSound::Channel_pollActive(Channel *channel) {
 	}
 
 	// Fade tail: pitch bend, volume, pan
-	if (channel->_pitchSlideStepSize) {
-		if (!--channel->_pitchSlideCounter) {
+	if (channel->_pitchSlideStepSize != 0) {
+		if (--channel->_pitchSlideCounter == 0) {
 			channel->_pitchSlideCounter = channel->_pitchSlideSpeed;
-			channel->_pitchBend += channel->_pitchSlideStepSize;
+			int newPitchBend = channel->_pitchBend + channel->_pitchSlideStepSize;
+			if (newPitchBend < 0 || newPitchBend > 0x7F) {
+				// Overflow will cause the driver to output invalid MIDI events.
+				// This actually happens in the original code, in the intro,
+				// when Rex lands his ship.
+				warning("Pitch bend overflow; terminating pitch slide");
+				channel->_pitchSlideStepSize = 0;
+				newPitchBend = CLIP(newPitchBend, 0, 0x7F);
+			}
+			channel->_pitchBend = newPitchBend;
 			sendPitchBend(midiChannel, channel->_pitchBend);
 		}
-		if (!--channel->_pitchSlideDurationCounter)
+		if (--channel->_pitchSlideDurationCounter == 0)
 			channel->_pitchSlideStepSize = 0;
 	}
 
@@ -607,72 +619,78 @@ void RSound::Channel_pollActive(Channel *channel) {
 				channel->_panningSweepCounter = 0;
 			}
 			channel->_panning = newPan;
-			sendPan(midiChannel, newPan);
+			sendPanning(midiChannel, newPan);
 		}
 	}
 }
 
-void RSound::pollAllChannels() {
+void RSound::processTickAllChannels() {
 	for (int i = 0; i < RSOUND_CHANNEL_COUNT; ++i)
-		Channel_pollActive(&_channels[i]);
+		Channel_processTick(&_channels[i]);
 }
 
-void RSound::update() {
-	getRandomNumber();
-	if (_isDisabled)
+void RSound::processTick() {
+	generateRandomNumber();
+	if (_ticksProcessingDisabled)
 		return;
 
 	tickCallback();
 
-	++_frameCounter;
-	pollAllChannels();
-	checkFadingChannels();
+	++_ticksSinceLastCommand;
+	processTickAllChannels();
+	processChannelFadeOuts();
 }
 
 /*-----------------------------------------------------------------------*/
 
 /**
  * Zeroes _deltaCounter and the three fade-step fields for channels in
- * [first, last).
+ * [first, last].
  * Deliberately does NOT touch the loop pointers, volume, program, pan etc,
  * matching the original.
  */
-void RSound::resetChannelRange(int first, int last) {
-	bool wasDisabled = _isDisabled;
-	_isDisabled = true;
+void RSound::resetChannelRange(int firstChannel, int lastChannel, bool includeChannel9) {
+	_ticksProcessingDisabled = true;
 
-	for (int i = first; i < last; ++i) {
+	for (int i = firstChannel - 1; i < lastChannel; ++i) {
 		_channels[i]._deltaCounter = 0;
 		_channels[i]._pitchSlideStepSize = 0;
 		_channels[i]._volumeFadeStepSize = 0;
 		_channels[i]._panningSweepStepSize = 0;
 	}
 
-	_isDisabled = wasDisabled;
+	if (lastChannel <= 8 && includeChannel9) {
+		_channels[8]._deltaCounter = 0;
+		_channels[8]._pitchSlideStepSize = 0;
+		_channels[8]._volumeFadeStepSize = 0;
+		_channels[8]._panningSweepStepSize = 0;
+	}
+
+	_ticksProcessingDisabled = false;
 }
 
-void RSound::resetHeldNotes() {
+void RSound::clearActiveNotes() {
 	for (int i = 0; i < RSOUND_CHANNEL_COUNT + 1; ++i)
 		for (int j = 0; j < 4; ++j)
-			_heldNotes[i][j] = 0xFF;
+			_activeNotes[i][j] = 0xFF;
 }
 
-void RSound::resetHeldNotesRange(int firstChannel, int lastChannel) {
+void RSound::clearActiveNotesRange(int firstChannel, int lastChannel) {
 	assert(firstChannel >= 1 && lastChannel <= RSOUND_CHANNEL_COUNT &&
 			firstChannel <= lastChannel);
 	for (int channel = firstChannel; channel <= lastChannel; ++channel)
 		for (int slot = 0; slot < 4; ++slot)
-			_heldNotes[channel][slot] = 0xFF;
+			_activeNotes[channel][slot] = 0xFF;
 }
 
 /**
- * Resets all 9 channels and the held-notes table.
+ * Resets all 9 channels and the active notes table.
  * Called both from the constructor (mirroring rsound_init) and from
  * command0.
  */
 void RSound::resetAllChannels() {
-	resetChannelRange(0, RSOUND_CHANNEL_COUNT);
-	resetHeldNotes();
+	resetChannelRange(1, RSOUND_CHANNEL_COUNT);
+	clearActiveNotes();
 }
 
 /**
@@ -690,9 +708,6 @@ void RSound::sendMidiChannelReset(int first, int last) {
 }
 
 int RSound::command0() {
-	bool isDisabled = _isDisabled;
-	_isDisabled = true;
-
 	resetAllChannels();
 	setFadeCheckPeriod(0);
 	sendMidiChannelReset(1, RSOUND_CHANNEL_COUNT);
@@ -704,7 +719,6 @@ int RSound::command0() {
 	// copy of this table, so no per-driver command0() override is needed.
 	sendSysEx(_sysExOffset);
 
-	_isDisabled = isDisabled;
 	return 0;
 }
 
@@ -716,39 +730,49 @@ int RSound::command1() {
 }
 
 int RSound::command2() {
-	// Channels 1-5 (also reinitializes the held-notes
+	// Channels 1-4 and 9 (also reinitializes the held-notes
 	// table) plus the MIDI channel reset for those same channels.
-	resetChannelRange(0, 5);
-	resetHeldNotes();
+	resetChannelRange(1, 4, true);
+	clearActiveNotes();
 	setFadeCheckPeriod(0);
-	sendMidiChannelReset(1, 5);
+	// The original code does not reset MIDI channel 9, which is
+	// probably an oversight.
+	sendMidiChannelReset(1, 4);
+	sendMidiChannelReset(9, 9);
 	return 0;
 }
 
 int RSound::command3() {
+	// Start fade-out to stop for channels 1-4 and 9.
 	setFadeCheckPeriod(1);
-	for (int i = 0; i < 5; ++i)
+	for (int i = 0; i < 4; ++i)
 		_channels[i].setFadeOut(true);
+	_channels[8].setFadeOut(true);
 	return 0;
 }
 
 int RSound::command4() {
-	// Channels 6-9 (does NOT touch the held-notes
+	// Channels 5-8 (does NOT touch the held-notes
 	// table) plus the MIDI channel reset for those same channels.
-	resetChannelRange(5, RSOUND_CHANNEL_COUNT);
+	resetChannelRange(5, 8);
 	setFadeCheckPeriod(0);
-	sendMidiChannelReset(6, RSOUND_CHANNEL_COUNT);
+	// The original code also resets MIDI channel 9, which is
+	// probably incorrect.
+	sendMidiChannelReset(5, 8);
 	return 0;
 }
 
 int RSound::command5() {
+	// Start fade-out to stop for channels 5-8.
 	setFadeCheckPeriod(1);
-	for (int i = 5; i < RSOUND_CHANNEL_COUNT; ++i)
+	for (int i = 4; i < 8; ++i)
 		_channels[i].setFadeOut(true);
 	return 0;
 }
 
 int RSound::command6() {
+	_ticksProcessingDisabled = true;
+	_mute = true;
 	for (int ch = 1; ch <= RSOUND_CHANNEL_COUNT; ++ch)
 		muteChannel(ch);
 	return 0;
@@ -756,7 +780,9 @@ int RSound::command6() {
 
 int RSound::command7() {
 	for (int i = 0; i < RSOUND_CHANNEL_COUNT; ++i)
-		restoreChannelVolume(_channels[i]._midiChannel, _channels[i]._volume);
+		unmuteChannel(_channels[i]._midiChannel, _channels[i]._volume);
+	_mute = false;
+	_ticksProcessingDisabled = false;
 	return 0;
 }
 
diff --git a/engines/mads/nebular/sound/rsound.h b/engines/mads/nebular/sound/rsound.h
index fb3c0e3fe59..b427785e8cc 100644
--- a/engines/mads/nebular/sound/rsound.h
+++ b/engines/mads/nebular/sound/rsound.h
@@ -43,9 +43,10 @@ enum RSoundFadeCheckMode {
 /**
  * Represents the data for a channel on the Roland MT-32 / MPU-401 driver.
  * Ported from the Channel struct identified in rsound.009's disassembly;
- * field names/roles were derived by tracing Channel_pollActive() (the
+ * field names/roles were derived by tracing Channel_processTick() (the
  * per-channel opcode interpreter) and cross-referencing against the
  * equivalent AdlibChannel fields in asound.h.
+ * Note: fields have been renamed here; this will be done in asound.* too.
  *
  * Confirmed against the real DOS struct layout (IDA struct dump,
  * sizeof=0x22): every field below from _deltaCounter through _soundData
@@ -139,9 +140,9 @@ class RSound : public SoundDriver {
 private:
 	uint16 _randomSeed;
 	int _masterVolume;
-	byte _lastMidiStatus;             // running-status cache, avoids resending an unchanged status byte
-	bool _noteTriggeredThisPoll;      // throttles note-on dispatch to at most one per update() tick, across all channels
-	byte _heldNotes[RSOUND_CHANNEL_COUNT + 1][4]; // per-MIDI-channel held-note slots (index 0 unused; channels are 1-9)
+	byte _runningStatus;							// running-status cache, avoids resending an unchanged status byte
+													// Note that the ScummVM MIDI drivers do not use this; they always send the status byte
+	byte _activeNotes[RSOUND_CHANNEL_COUNT + 1][4];	// The note(s) currently playing on each MIDI channel (index 0 unused; channels are 1-9)
 	RSoundFadeCheckMode _fadeCheckMode;
 	bool _fadeCheckAlternate;
 	int _fadeCheckCounter;
@@ -151,8 +152,7 @@ private:
 	 * Data-segment offset of this driver's own "command0_array" (the
 	 * MT-32 title-display + patch-init SysEx table sent by command0()).
 	 * Each driver has its own copy of this table at its own offset
-	 * within its own resource file - unlike the fixed 5-byte SysEx
-	 * header (_sysExHeader below), the table's content differs per
+	 * within its own resource file. The table's contents differs per
 	 * driver beyond a shared prefix, so it can't be hardcoded once;
 	 * parameterizing the offset via the constructor avoids needing a
 	 * command0() override in every derived class.
@@ -161,11 +161,10 @@ private:
 
 	MidiDriver_MT32GM *_midiDriver;
 	uint32 _driverCallbackDelta;
-	NativeSoundTimer _hostTimer;
 
-	void update();
-	void pollAllChannels();
-	void Channel_pollActive(Channel *channel);
+	void processTick();
+	void processTickAllChannels();
+	void Channel_processTick(Channel *channel);
 
 	/**
 	 * Resets all 9 channels and the held-notes table.
@@ -173,19 +172,20 @@ private:
 	void resetAllChannels();
 
 	/**
-	 * Run pending-stop volume decay using the scheduler embedded in the
-	 * loaded overlay. Sections 1, 2, and 9 and both demo overlays use a
-	 * fixed every-other-poll toggle. Sections 3-8 use a programmable
+	 * Process channels fading out to stop. Not to be confused with the
+	 * volume fade event 0xF8.
+	 * Sections 1, 2, and 9 and both demo overlays use a fixed
+	 * every-other-poll toggle. Sections 3-8 use a programmable
 	 * countdown; zero disables it and the counter reloads after each pass.
 	 */
-	void checkFadingChannels();
-	void Channel_checkFade(Channel *channel);
+	void processChannelFadeOuts();
+	void Channel_processFadeOut(Channel *channel);
 
 	/**
-	 * Sends Note-Off (velocity 0) for all currently-held notes on the
-	 * given channel's MIDI channel, then clears the held-note table for it.
+	 * Sends Note-Off (velocity 0) for all active notes on the
+	 * given channel's MIDI channel, then clears the active note table for it.
 	 */
-	void Channel_flushHeldNotes(Channel *channel);
+	void Channel_turnOffActiveNotes(Channel *channel);
 
 protected:
 	int _commandParam;
@@ -195,21 +195,24 @@ protected:
 			_fadeCheckPeriod = period;
 	}
 
-	/** Clear the active and fade state for channel indices in [first, last). */
-	void resetChannelRange(int first, int last);
+	/**
+	 * Clear the active and fade state for MIDI channels in [first, last].
+	 * Specify includeChannel9 to also reset MIDI channel 9.
+	 */
+	void resetChannelRange(int firstChannel, int lastChannel, bool includeChannel9 = false);
 
-	/** Reset the per-MIDI-channel held-note tracking table to empty. */
-	void resetHeldNotes();
+	/** Reset the per-MIDI-channel active note tracking table to empty. */
+	void clearActiveNotes();
 
-	/** Reset held-note slots for the inclusive MIDI-channel range. */
-	void resetHeldNotesRange(int firstChannel, int lastChannel);
+	/** Reset active note slots for the inclusive MIDI-channel range. */
+	void clearActiveNotesRange(int firstChannel, int lastChannel);
 
 	byte *loadData(int offset) {
 		return &_soundData[offset];
 	}
 
 	/**
-	 * Hook called once per update() frame, immediately after the disabled
+	 * Hook called once per processTick() frame, immediately after the disabled
 	 * check and before channel polling. Only RSound9's driver data makes
 	 * use of a recurring deferred-callback timer (g_callbackCounter/
 	 * g_callbackPeriod/_soundPtr in the original disassembly, mirroring
@@ -222,42 +225,43 @@ protected:
 	void resultCheck();
 
 	/**
-	 * Play the specified sound, using any free channel from 6 to 8.
-	 * Channel 9 is deliberately never touched here - matches the
-	 * disassembly, which never includes it in this scan. Returns the
-	 * channel that was used (or nullptr if none was free), since some
-	 * commands poke the just-loaded channel's loop pointer directly
-	 * afterward.
+	 * Play the specified sound using any free channel from 5 to 8.
+	 * Returns the channel that was used (or nullptr if none was free),
+	 * since some commands poke the just-loaded channel's loop pointer
+	 * directly afterward.
 	 */
-	Channel *playSound(int offset);
+	Channel *playSoundCh5To8(int offset);
 
 	/**
-	 * Play the specified sound using any channel from 0 to 8, including
-	 * channel 9 - confirmed distinct from playSound() by rsound.001's
-	 * disassembly (rsound_command30/32/38).
+	 * Play the specified sound using any free channel from 1 to 8.
 	 */
-	Channel *playSoundAny(int offset) {
-		return playSoundData(loadData(offset), 0);
-	}
+	Channel *playSoundCh1To8(int offset);
 
-	Channel *playSoundData(byte *pData, int startingChannel = 5);
+	/**
+	 * Allocates a MIDI channel, loads the specified sound data into it
+	 * and starts playback. Allocation will look for a free channel in
+	 * the range starting with the specified channel (default 5) and
+	 * ending with channel 8. If no suitable channel could be found,
+	 * nullptr is returned and the sound data is not played.
+	 */
+	Channel *allocateAndPlay(byte *pData, int startingChannel = 5);
 
 	/**
 	 * Checks to see whether the given block of data is already loaded into a channel.
 	 */
-	bool isSoundActive(byte *pData);
+	bool isSoundPlaying(byte *pData);
 
-	int getRandomNumber();
+	int generateRandomNumber();
 
 	// ---- Low-level MIDI send helpers -------------------------------
-	// All send through the ScummVM MT-32/MIDI driver.
+	// All send through the ScummVM MT-32 / General MIDI driver.
 	void sendNoteOn(int midiChannel, int note, int velocity);
 	void sendProgramChange(int midiChannel, int program);
 	void sendVolume(int midiChannel, int volume);
 	void sendPitchBend(int midiChannel, int value);
-	void sendPan(int midiChannel, int value);
+	void sendPanning(int midiChannel, int value);
 	void muteChannel(int midiChannel);
-	void restoreChannelVolume(int midiChannel, int volume);
+	void unmuteChannel(int midiChannel, int volume);
 
 	/**
 	 * Resets the MIDI channel state (all notes off, reset all
@@ -305,8 +309,9 @@ protected:
 
 public:
 	Channel _channels[RSOUND_CHANNEL_COUNT];
-	int _frameCounter;
-	bool _isDisabled;
+	int _ticksSinceLastCommand;
+	bool _ticksProcessingDisabled;
+	bool _mute;
 	int _pollResult;
 	int _resultFlag;
 
@@ -317,6 +322,7 @@ public:
 	/**
 	 * Constructor
 	 * @param mixer			Mixer
+	 * @param midiDriver	MIDI driver instance used for MIDI message output
 	 * @param filename		Specifies the Roland sound player file to use
 	 * @param dataOffset	Offset in the file of the data segment
 	 * @param dataSize		Size of the data segment
@@ -335,8 +341,8 @@ public:
 	}
 	void setVolume(int volume) override;
 
-	int getFrameCounter() {
-		return _frameCounter;
+	int getTicksSinceLastCommand() {
+		return _ticksSinceLastCommand;
 	}
 };
 
diff --git a/engines/mads/nebular/sound/rsound_nebular.cpp b/engines/mads/nebular/sound/rsound_nebular.cpp
index cb31b8234f3..ce7152af906 100644
--- a/engines/mads/nebular/sound/rsound_nebular.cpp
+++ b/engines/mads/nebular/sound/rsound_nebular.cpp
@@ -83,8 +83,8 @@ void RSoundDemo::requestStopAll() {
 void RSoundDemo::stopAndResetRange(int firstChannel, int channelCount) {
 	assert(firstChannel >= 0 && channelCount > 0 &&
 			firstChannel + channelCount <= RSOUND_CHANNEL_COUNT);
-	resetChannelRange(firstChannel, firstChannel + channelCount);
-	resetHeldNotesRange(firstChannel + 1, firstChannel + channelCount);
+	resetChannelRange(firstChannel + 1, firstChannel + channelCount);
+	clearActiveNotesRange(firstChannel + 1, firstChannel + channelCount);
 	sendMidiChannelReset(firstChannel + 1, firstChannel + channelCount);
 }
 
@@ -95,7 +95,7 @@ void RSoundDemo::setVoiceVolume(int channelIndex, byte volume) {
 }
 
 bool RSoundDemo::isSequenceActive(int sequenceOffset) {
-	return isSoundActive(loadData(sequenceOffset));
+	return isSoundPlaying(loadData(sequenceOffset));
 }
 
 const RSound1::CommandPtr RSound1::_commandList[42] = {
@@ -121,7 +121,7 @@ int RSound1::command(int commandId, int param) {
 		return 0;
 
 	_commandParam = param;
-	_frameCounter = 0;
+	_ticksSinceLastCommand = 0;
 	return (this->*_commandList[commandId])();
 }
 
@@ -131,7 +131,7 @@ int RSound1::clampParam() {
 
 void RSound1::method1() {
 	byte *pData = loadData(0x1166);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		command1();
 		_channels[0].playData(pData);
 		_channels[1].playData(loadData(0x13BC));
@@ -141,13 +141,13 @@ void RSound1::method1() {
 }
 
 int RSound1::command9() {
-	playSound(0xAD4);
+	playSoundCh5To8(0xAD4);
 	return 0;
 }
 
 int RSound1::command10() {
 	byte *pData = loadData(0xCE4);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		_channels[0].playData(pData);
 		_channels[1].playData(loadData(0xD18));
 		_channels[2].playData(loadData(0xE9C));
@@ -184,13 +184,13 @@ int RSound1::command13() {
 }
 
 int RSound1::command14() {
-	playSound(0x16C2);
+	playSoundCh5To8(0x16C2);
 	return 0;
 }
 
 int RSound1::command15() {
 	byte *pData = loadData(0xF3A);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		command1();
 		_channels[4].playData(pData);
 		_channels[5].playData(loadData(0x102A));
@@ -200,61 +200,61 @@ int RSound1::command15() {
 }
 
 int RSound1::command16() {
-	playSound(0xADE);
+	playSoundCh5To8(0xADE);
 	return 0;
 }
 
 int RSound1::command17() {
-	playSound(0xAE8);
+	playSoundCh5To8(0xAE8);
 	return 0;
 }
 
 int RSound1::command18() {
-	playSound(0xAF2);
+	playSoundCh5To8(0xAF2);
 	return 0;
 }
 
 int RSound1::command19() {
 	command1();
-	playSound(0xB04);
+	playSoundCh5To8(0xB04);
 	return 0;
 }
 
 int RSound1::command20() {
-	playSound(0xB5E);
+	playSoundCh5To8(0xB5E);
 	return 0;
 }
 
 int RSound1::command21() {
-	playSound(0xB4C);
+	playSoundCh5To8(0xB4C);
 	return 0;
 }
 
 int RSound1::command22() {
-	playSound(0xB6E);
+	playSoundCh5To8(0xB6E);
 	return 0;
 }
 
 int RSound1::command23() {
 	byte *pData = loadData(0xB7A);
 	pData[6] ^= 0x1F;
-	playSound(0xB7A);
+	playSoundCh5To8(0xB7A);
 	return 0;
 }
 
 int RSound1::command24() {
-	playSound(0xB84);
+	playSoundCh5To8(0xB84);
 	return 0;
 }
 
 int RSound1::command25() {
-	playSound(0xB8E);
+	playSoundCh5To8(0xB8E);
 	return 0;
 }
 
 int RSound1::command26() {
 	byte *pData = loadData(0xCCA);
-	int v1 = (getRandomNumber() & 24) + 45;
+	int v1 = (generateRandomNumber() & 24) + 45;
 	pData[8] = v1;
 	int v2 = clampParam() + 64;
 	pData[5] = v2;
@@ -264,7 +264,7 @@ int RSound1::command26() {
 
 int RSound1::command27() {
 	byte *pData = loadData(0xCBE);
-	int v1 = (getRandomNumber() & 24) + 45;
+	int v1 = (generateRandomNumber() & 24) + 45;
 	pData[8] = v1;
 	int v2 = clampParam() + 64;
 	pData[5] = v2;
@@ -273,7 +273,7 @@ int RSound1::command27() {
 }
 
 int RSound1::command28() {
-	playSound(0xB9E);
+	playSoundCh5To8(0xB9E);
 	return 0;
 }
 
@@ -281,8 +281,8 @@ int RSound1::command29() {
 	byte *pData = loadData(0xC6C);
 	int v = (clampParam() >> 1) + 32;
 	pData[0xB] = v;
-	if (!isSoundActive(pData))
-		playSound(0xC6C);
+	if (!isSoundPlaying(pData))
+		playSoundCh5To8(0xC6C);
 	return 0;
 }
 
@@ -290,13 +290,13 @@ int RSound1::command30() {
 	byte *pData = loadData(0xC80);
 	int v = clampParam() + 63;
 	pData[0xB] = v;
-	if (!isSoundActive(pData))
-		playSoundAny(0xC80);
+	if (!isSoundPlaying(pData))
+		playSoundCh1To8(0xC80);
 	return 0;
 }
 
 int RSound1::command31() {
-	playSound(0xBBE);
+	playSoundCh5To8(0xBBE);
 	return 0;
 }
 
@@ -305,56 +305,56 @@ int RSound1::command32() {
 	int half = clampParam() >> 1;
 	pData[0xB] = pData[0x17] = half + 68;
 	pData[0x11] = pData[0x1D] = half + 20;
-	if (!isSoundActive(pData))
-		playSoundAny(0xC96);
+	if (!isSoundPlaying(pData))
+		playSoundCh1To8(0xC96);
 	return 0;
 }
 
 int RSound1::command33() {
-	playSound(0xBD0);
-	playSound(0xBDA);
+	playSoundCh5To8(0xBD0);
+	playSoundCh5To8(0xBDA);
 	return 0;
 }
 
 int RSound1::command34() {
 	byte *pData = loadData(0xBE8);
-	int v = (getRandomNumber() & 12) + 45;
+	int v = (generateRandomNumber() & 12) + 45;
 	pData[9] = v;
 	pData[0x10] = v + 36;
-	playSound(0xBE8);
+	playSoundCh5To8(0xBE8);
 	return 0;
 }
 
 int RSound1::command35() {
-	playSound(0xBFC);
-	playSound(0xC0E);
-	playSound(0xC20);
+	playSoundCh5To8(0xBFC);
+	playSoundCh5To8(0xC0E);
+	playSoundCh5To8(0xC20);
 	return 0;
 }
 
 int RSound1::command36() {
-	playSound(0xC3E);
+	playSoundCh5To8(0xC3E);
 	return 0;
 }
 
 int RSound1::command37() {
 	byte *pData = loadData(0xC4C);
-	int r = getRandomNumber() & 15;
+	int r = generateRandomNumber() & 15;
 	pData[6] = r + 42;
 	pData[3] = 62 - (r << 1);
-	playSound(0xC4C);
+	playSoundCh5To8(0xC4C);
 	return 0;
 }
 
 int RSound1::command38() {
-	playSoundAny(0xC56);
-	playSound(0xC60);
+	playSoundCh1To8(0xC56);
+	playSoundCh5To8(0xC60);
 	return 0;
 }
 
 int RSound1::command39() {
 	byte *pData = loadData(0x1818);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		_channels[4].playData(pData);
 		_channels[5].playData(loadData(0x1848));
 		_channels[6].playData(loadData(0x1874));
@@ -365,12 +365,12 @@ int RSound1::command39() {
 }
 
 int RSound1::command40() {
-	playSound(0xC34);
+	playSoundCh5To8(0xC34);
 	return 0;
 }
 
 int RSound1::command41() {
-	playSound(0xCD6);
+	playSoundCh5To8(0xCD6);
 	return 0;
 }
 
@@ -432,7 +432,7 @@ int RSoundDemo1::command(int commandId, int param) {
 		return 0;
 
 	_commandParam = param;
-	_frameCounter = 0;
+	_ticksSinceLastCommand = 0;
 	if (commandId <= 8)
 		return executeDemoCommonCommand(commandId);
 
@@ -496,7 +496,7 @@ int RSoundDemo1::command(int commandId, int param) {
 		break;
 	case 22: {
 		byte *data = sequenceData(0x0FCE);
-		data[6] = (getRandomNumber() & 0x07) + 0x73;
+		data[6] = (generateRandomNumber() & 0x07) + 0x73;
 		startAnyVoice(0x0FCE);
 		break;
 	}
@@ -514,7 +514,7 @@ int RSoundDemo1::command(int commandId, int param) {
 	case 27: {
 		const int sequenceOffset = commandId == 26 ? 0x10F8 : 0x10EC;
 		byte *data = sequenceData(sequenceOffset);
-		data[8] = (getRandomNumber() & 0x18) + 0x2D;
+		data[8] = (generateRandomNumber() & 0x18) + 0x2D;
 		data[5] = adjustedCommandParam() + 0x40;
 		startVoice(7, sequenceOffset);
 		break;
@@ -554,7 +554,7 @@ int RSoundDemo1::command(int commandId, int param) {
 		break;
 	case 34: {
 		byte *data = sequenceData(0x104C);
-		data[9] = (getRandomNumber() & 0x0C) + 0x2D;
+		data[9] = (generateRandomNumber() & 0x0C) + 0x2D;
 		data[16] = data[9] + 0x24;
 		startAnyVoice(0x104C);
 		break;
@@ -618,7 +618,7 @@ int RSound2::command(int commandId, int param) {
 		return 0;
 
 	_commandParam = param;
-	_frameCounter = 0;
+	_ticksSinceLastCommand = 0;
 	return (this->*_commandList[commandId])();
 }
 
@@ -634,7 +634,7 @@ int RSound2::command5() {
 
 int RSound2::command9() {
 	byte *pData = loadData(0x103C);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		command1();
 		_channels[0].playData(pData);
 		_channels[1].playData(loadData(0x11B2));
@@ -645,7 +645,7 @@ int RSound2::command9() {
 
 int RSound2::command10() {
 	byte *pData = loadData(0x132E);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		command1();
 		_channels[2].playData(pData);
 		_channels[8].playData(loadData(0x1384));
@@ -655,7 +655,7 @@ int RSound2::command10() {
 
 int RSound2::command11() {
 	byte *pData = loadData(0x1548);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		command1();
 		_channels[2].playData(pData);
 		_channels[8].playData(loadData(0x1648));
@@ -667,29 +667,29 @@ int RSound2::command12() {
 	byte *pData = loadData(0xE52);
 	_pitchCycleCounter += 16;
 	pData[3] = _pitchCycleCounter & 0x7F;
-	playSound(0xE52);
+	playSoundCh5To8(0xE52);
 	return 0;
 }
 
 int RSound2::command13() {
-	playSound(0xE5C);
-	playSound(0xE66);
+	playSoundCh5To8(0xE5C);
+	playSoundCh5To8(0xE66);
 	return 0;
 }
 
 int RSound2::command14() {
-	playSound(0xE70);
-	playSound(0xE8A);
+	playSoundCh5To8(0xE70);
+	playSoundCh5To8(0xE8A);
 	return 0;
 }
 
 int RSound2::command15() {
 	byte *pData = loadData(0x1DFC);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		command1();
-		playSoundAny(0x1DFC);
-		playSoundAny(0x222E);
-		playSoundAny(0x2648);
+		playSoundCh1To8(0x1DFC);
+		playSoundCh1To8(0x222E);
+		playSoundCh1To8(0x2648);
 		_channels[8].playData(loadData(0x26A2));
 	}
 	return 0;
@@ -697,25 +697,25 @@ int RSound2::command15() {
 
 int RSound2::command16() {
 	byte *pData = loadData(0x3456);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		command1();
-		playSoundAny(0x3456);
-		playSoundAny(0x3572);
-		playSoundAny(0x367E);
-		playSoundAny(0x37C6);
-		playSoundAny(0x39AE);
-		playSoundAny(0x3A3A);
+		playSoundCh1To8(0x3456);
+		playSoundCh1To8(0x3572);
+		playSoundCh1To8(0x367E);
+		playSoundCh1To8(0x37C6);
+		playSoundCh1To8(0x39AE);
+		playSoundCh1To8(0x3A3A);
 	}
 	return 0;
 }
 
 int RSound2::command17() {
 	byte *pData = loadData(0x3AC0);
-	if (!isSoundActive(pData)) {
-		playSound(0x3AC0);
-		playSound(0x3C70);
-		playSound(0x3E16);
-		playSound(0x3FBE);
+	if (!isSoundPlaying(pData)) {
+		playSoundCh5To8(0x3AC0);
+		playSoundCh5To8(0x3C70);
+		playSoundCh5To8(0x3E16);
+		playSoundCh5To8(0x3FBE);
 	}
 	return 0;
 }
@@ -724,177 +724,177 @@ int RSound2::command18() {
 	if (_channels[7]._deltaCounter)
 		return 0;
 
-	int idx = (getRandomNumber() & 30) >> 1;
+	int idx = (generateRandomNumber() & 30) >> 1;
 	_channels[7].playData(loadData(_table1[idx]));
 	return 0;
 }
 
 int RSound2::command19() {
 	byte *pData = loadData(0x2A64);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		command1();
-		playSoundAny(0x2A64);
-		playSoundAny(0x2BE2);
-		playSoundAny(0x2DAC);
-		playSoundAny(0x2ECE);
-		playSoundAny(0x3026);
-		playSoundAny(0x30C2);
+		playSoundCh1To8(0x2A64);
+		playSoundCh1To8(0x2BE2);
+		playSoundCh1To8(0x2DAC);
+		playSoundCh1To8(0x2ECE);
+		playSoundCh1To8(0x3026);
+		playSoundCh1To8(0x30C2);
 	}
 	return 0;
 }
 
 int RSound2::command20() {
-	playSound(0xF1E);
-	playSound(0xF1E);
-	playSound(0xF1E);
-	playSound(0xF1E);
+	playSoundCh5To8(0xF1E);
+	playSoundCh5To8(0xF1E);
+	playSoundCh5To8(0xF1E);
+	playSoundCh5To8(0xF1E);
 	return 0;
 }
 
 int RSound2::command21() {
-	playSound(0xF58);
+	playSoundCh5To8(0xF58);
 	return 0;
 }
 
 int RSound2::command22() {
-	playSound(0xF44);
+	playSoundCh5To8(0xF44);
 	return 0;
 }
 
 int RSound2::command23() {
-	playSound(0xEBA);
+	playSoundCh5To8(0xEBA);
 	return 0;
 }
 
 int RSound2::command24() {
-	playSound(0xEB0);
+	playSoundCh5To8(0xEB0);
 	return 0;
 }
 
 int RSound2::command25() {
-	playSound(0xEA6);
+	playSoundCh5To8(0xEA6);
 	return 0;
 }
 
 int RSound2::command26() {
-	playSound(0xF4E);
+	playSoundCh5To8(0xF4E);
 	return 0;
 }
 
 int RSound2::command27() {
-	Channel *ch = playSound(0xFAC);
+	Channel *ch = playSoundCh5To8(0xFAC);
 	if (ch)
 		ch->_innerLoopStart = loadData(0xFB8);
 
-	ch = playSound(0xFB2);
+	ch = playSoundCh5To8(0xFB2);
 	if (ch)
 		ch->_innerLoopStart = loadData(0xFB8);
 
-	playSound(0xFB8);
+	playSoundCh5To8(0xFB8);
 	return 0;
 }
 
 int RSound2::command28() {
 	byte *pData = loadData(0xEDA);
-	int r = getRandomNumber();
+	int r = generateRandomNumber();
 	int v1 = r & 0x7F;
 	pData[7] = v1;
 	int v2 = (v1 & 0x0F) + 0x43;
 	pData[8] = v2;
 	int v3 = v2 + 0x0C;
 	pData[0xA] = v3;
-	playSound(0xEDA);
+	playSoundCh5To8(0xEDA);
 	return 0;
 }
 
 int RSound2::command29() {
-	playSoundAny(0xF80);
+	playSoundCh1To8(0xF80);
 	return 0;
 }
 
 int RSound2::command30() {
-	playSound(0xF14);
+	playSoundCh5To8(0xF14);
 	byte *pData = loadData(0xF0A);
 	pData[3] = 40;
-	playSound(0xF0A);
+	playSoundCh5To8(0xF0A);
 	return 0;
 }
 
 int RSound2::command31() {
 	byte *pData = loadData(0xF0A);
 	pData[3] = 0x18;
-	playSound(0xF0A);
+	playSoundCh5To8(0xF0A);
 	return 0;
 }
 
 int RSound2::command32() {
-	playSound(0xEC4);
+	playSoundCh5To8(0xEC4);
 	return 0;
 }
 
 int RSound2::command33() {
-	playSound(0xED0);
+	playSoundCh5To8(0xED0);
 	return 0;
 }
 
 int RSound2::command34() {
-	playSound(0xEE8);
+	playSoundCh5To8(0xEE8);
 	return 0;
 }
 
 int RSound2::command35() {
-	playSound(0xEF8);
+	playSoundCh5To8(0xEF8);
 	return 0;
 }
 
 int RSound2::command36() {
-	playSound(0xFF4);
-	playSound(0x1008);
+	playSoundCh5To8(0xFF4);
+	playSoundCh5To8(0x1008);
 	return 0;
 }
 
 int RSound2::command37() {
-	playSound(0xFCC);
+	playSoundCh5To8(0xFCC);
 	return 0;
 }
 
 int RSound2::command38() {
 	byte *pData = loadData(0x2B0E);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		command1();
-		playSoundAny(0x2B0E);
-		playSoundAny(0x2CD0);
-		playSoundAny(0x2E46);
-		playSoundAny(0x2F7C);
-		playSoundAny(0x3074);
-		playSoundAny(0x317E);
+		playSoundCh1To8(0x2B0E);
+		playSoundCh1To8(0x2CD0);
+		playSoundCh1To8(0x2E46);
+		playSoundCh1To8(0x2F7C);
+		playSoundCh1To8(0x3074);
+		playSoundCh1To8(0x317E);
 	}
 	return 0;
 }
 
 int RSound2::command39() {
-	playSound(0xFDA);
+	playSoundCh5To8(0xFDA);
 	return 0;
 }
 
 int RSound2::command40() {
-	playSound(0xFE6);
+	playSoundCh5To8(0xFE6);
 	return 0;
 }
 
 int RSound2::command41() {
-	playSoundAny(0xF62);
+	playSoundCh1To8(0xF62);
 	return 0;
 }
 
 int RSound2::command42() {
-	playSound(0xF92);
+	playSoundCh5To8(0xF92);
 	return 0;
 }
 
 int RSound2::command43() {
-	playSound(0x1018);
-	playSound(0x102A);
+	playSoundCh5To8(0x1018);
+	playSoundCh5To8(0x102A);
 	return 0;
 }
 
@@ -928,14 +928,14 @@ int RSound3::command(int commandId, int param) {
 		return 0;
 
 	_commandParam = param;
-	_frameCounter = 0;
+	_ticksSinceLastCommand = 0;
 	return (this->*_commandList[commandId])();
 }
 
 Channel *RSound3::method1(int offset, byte value) {
 	byte *pData = loadData(offset);
 	pData[5] = value;
-	return playSound(offset);
+	return playSoundCh5To8(offset);
 }
 
 void RSound3::resetUpperChannelsTail() {
@@ -971,7 +971,7 @@ int RSound3::command9() {
 
 int RSound3::command10() {
 	byte *pData = loadData(0x14FE);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		command1();
 		_channels[0].playData(pData);
 		_channels[1].playData(loadData(0x1630));
@@ -990,7 +990,7 @@ void RSound3::setVariantByte(byte value) {
 }
 
 int RSound3::command11() {
-	if (!isSoundActive(loadData(0x1AE6))) {
+	if (!isSoundPlaying(loadData(0x1AE6))) {
 		setVariantByte(0x64);
 		_channels[0].playData(loadData(0x1AE6));
 		_channels[1].playData(loadData(0x1E00));
@@ -1005,11 +1005,11 @@ int RSound3::command11() {
 
 int RSound3::command13() {
 	command1();
-	playSoundAny(0x1364);
-	playSoundAny(0x1364);
-	playSoundAny(0x1364);
-	playSoundAny(0x1364);
-	playSoundAny(0x1364);
+	playSoundCh1To8(0x1364);
+	playSoundCh1To8(0x1364);
+	playSoundCh1To8(0x1364);
+	playSoundCh1To8(0x1364);
+	playSoundCh1To8(0x1364);
 	return 0;
 }
 
@@ -1058,7 +1058,7 @@ int RSound3::command16() {
 
 	if (_command16AltFlag) {
 		byte *pData = loadData(0x345E);
-		if (!isSoundActive(pData)) {
+		if (!isSoundPlaying(pData)) {
 			_channels[0].playData(pData);
 			_channels[1].playData(loadData(0x364C));
 			_channels[2].playData(loadData(0x3806));
@@ -1066,7 +1066,7 @@ int RSound3::command16() {
 		}
 	} else {
 		byte *pData = loadData(0x3B26);
-		if (!isSoundActive(pData)) {
+		if (!isSoundPlaying(pData)) {
 			command1();
 			_channels[0].playData(pData);
 			_channels[1].playData(loadData(0x3BD8));
@@ -1079,7 +1079,7 @@ int RSound3::command16() {
 
 int RSound3::command17() {
 	byte *pData = loadData(0x3F5C);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		command1();
 		_channels[0].playData(pData);
 		_channels[1].playData(loadData(0x4022));
@@ -1101,42 +1101,42 @@ int RSound3::command18() {
 }
 
 int RSound3::command19() {
-	if (!isSoundActive(loadData(0x1AE6)))
-		playSound(0x12B4);
+	if (!isSoundPlaying(loadData(0x1AE6)))
+		playSoundCh5To8(0x12B4);
 	return 0;
 }
 
 int RSound3::command20() {
-	if (!isSoundActive(loadData(0x1AE6)))
-		playSound(0x1246);
+	if (!isSoundPlaying(loadData(0x1AE6)))
+		playSoundCh5To8(0x1246);
 	return 0;
 }
 
 int RSound3::command21() {
-	if (!isSoundActive(loadData(0x1AE6))) {
-		playSound(0x1232);
-		playSound(0x123C);
+	if (!isSoundPlaying(loadData(0x1AE6))) {
+		playSoundCh5To8(0x1232);
+		playSoundCh5To8(0x123C);
 	}
 	return 0;
 }
 
 int RSound3::command22() {
-	playSound(0x126E);
+	playSoundCh5To8(0x126E);
 	return 0;
 }
 
 int RSound3::command23() {
-	if (!isSoundActive(loadData(0x1AE6))) {
-		playSound(0x12D2);
-		playSound(0x12E0);
+	if (!isSoundPlaying(loadData(0x1AE6))) {
+		playSoundCh5To8(0x12D2);
+		playSoundCh5To8(0x12E0);
 	}
 	return 0;
 }
 
 int RSound3::command24() {
-	if (!isSoundActive(loadData(0x1AE6))) {
-		playSound(0x11E2);
-		playSound(0x120A);
+	if (!isSoundPlaying(loadData(0x1AE6))) {
+		playSoundCh5To8(0x11E2);
+		playSoundCh5To8(0x120A);
 	}
 	return 0;
 }
@@ -1150,74 +1150,74 @@ int RSound3::command25() {
 }
 
 int RSound3::command26() {
-	playSound(0x1252);
+	playSoundCh5To8(0x1252);
 	return 0;
 }
 
 int RSound3::command27x42() {
-	playSound(0x14BE);
+	playSoundCh5To8(0x14BE);
 	return 0;
 }
 
 int RSound3::command28() {
 	byte *pData = loadData(0x12EE);
 	pData[3] = 0x4D;
-	playSound(0x12EE);
+	playSoundCh5To8(0x12EE);
 	return 0;
 }
 
 int RSound3::command29() {
 	byte *pData = loadData(0x12EE);
 	pData[3] = 0x7F;
-	playSound(0x12EE);
+	playSoundCh5To8(0x12EE);
 	return 0;
 }
 
 int RSound3::command30() {
-	playSound(0x14B4);
-	playSound(0x14AA);
+	playSoundCh5To8(0x14B4);
+	playSoundCh5To8(0x14AA);
 	return 0;
 }
 
 int RSound3::command31() {
-	playSound(0x12F8);
-	playSound(0x130E);
+	playSoundCh5To8(0x12F8);
+	playSoundCh5To8(0x130E);
 	return 0;
 }
 
 int RSound3::command32() {
-	playSound(0x1472);
+	playSoundCh5To8(0x1472);
 	return 0;
 }
 
 int RSound3::command33() {
-	playSound(0x147E);
+	playSoundCh5To8(0x147E);
 	return 0;
 }
 
 int RSound3::command34() {
-	playSound(0x1488);
+	playSoundCh5To8(0x1488);
 	return 0;
 }
 
 int RSound3::command35() {
-	playSound(0x1498);
+	playSoundCh5To8(0x1498);
 	return 0;
 }
 
 int RSound3::command36() {
-	playSound(0x14DA);
-	playSound(0x14EE);
+	playSoundCh5To8(0x14DA);
+	playSoundCh5To8(0x14EE);
 	return 0;
 }
 
 int RSound3::command37() {
-	playSound(0x14CC);
+	playSoundCh5To8(0x14CC);
 	return 0;
 }
 
 int RSound3::command38() {
-	playSound(0x133A);
+	playSoundCh5To8(0x133A);
 	return 0;
 }
 
@@ -1226,7 +1226,7 @@ int RSound3::command39() {
 	pData[3] = 77;
 	_command3940Toggle ^= 4;
 	pData[6] = _command3940Toggle + 0x28;
-	playSound(0x1346);
+	playSoundCh5To8(0x1346);
 	return 0;
 }
 
@@ -1235,71 +1235,71 @@ int RSound3::command40() {
 	pData[3] = 47;
 	_command3940Toggle ^= 4;
 	pData[6] = _command3940Toggle + 0x28;
-	playSound(0x1346);
+	playSoundCh5To8(0x1346);
 	return 0;
 }
 
 int RSound3::command41() {
-	playSound(0x1184);
+	playSoundCh5To8(0x1184);
 	return 0;
 }
 
 int RSound3::command43() {
-	playSound(0x1350);
-	playSound(0x135A);
+	playSoundCh5To8(0x1350);
+	playSoundCh5To8(0x135A);
 	return 0;
 }
 
 int RSound3::command44() {
-	playSound(0x12A0);
+	playSoundCh5To8(0x12A0);
 	return 0;
 }
 
 int RSound3::command45() {
-	playSound(0x12AA);
+	playSoundCh5To8(0x12AA);
 	return 0;
 }
 
 int RSound3::command46() {
-	playSound(0x13AA);
-	playSound(0x13C6);
+	playSoundCh5To8(0x13AA);
+	playSoundCh5To8(0x13C6);
 	return 0;
 }
 
 int RSound3::command47x49() {
-	playSound(0x13E6);
-	playSound(0x13FE);
+	playSoundCh5To8(0x13E6);
+	playSoundCh5To8(0x13FE);
 	return 0;
 }
 
 int RSound3::command48() {
-	playSound(0x141E);
+	playSoundCh5To8(0x141E);
 	return 0;
 }
 
 int RSound3::command50() {
-	playSound(0x1436);
-	playSound(0x144C);
+	playSoundCh5To8(0x1436);
+	playSoundCh5To8(0x144C);
 	return 0;
 }
 
 int RSound3::command51() {
-	playSound(0x125C);
+	playSoundCh5To8(0x125C);
 	return 0;
 }
 
 int RSound3::command57() {
-	playSound(0x1466);
+	playSoundCh5To8(0x1466);
 	return 0;
 }
 
 int RSound3::command59() {
-	playSound(0x1324);
+	playSoundCh5To8(0x1324);
 	return 0;
 }
 
 int RSound3::command60() {
-	playSound(0x132E);
+	playSoundCh5To8(0x132E);
 	return 0;
 }
 
@@ -1332,7 +1332,7 @@ int RSound4::command(int commandId, int param) {
 		return 0;
 
 	_commandParam = param;
-	_frameCounter = 0;
+	_ticksSinceLastCommand = 0;
 	return (this->*_commandList[commandId])();
 }
 
@@ -1397,60 +1397,60 @@ int RSound4::command10() {
 }
 
 int RSound4::command19() {
-	playSound(0x1196);
+	playSoundCh5To8(0x1196);
 	return 0;
 }
 
 int RSound4::command20() {
-	playSound(0x118A);
+	playSoundCh5To8(0x118A);
 	return 0;
 }
 
 int RSound4::command21() {
-	playSound(0x1260);
-	playSound(0x126A);
+	playSoundCh5To8(0x1260);
+	playSoundCh5To8(0x126A);
 	return 0;
 }
 
 int RSound4::command27() {
-	playSound(0x1220);
+	playSoundCh5To8(0x1220);
 	return 0;
 }
 
 int RSound4::command30() {
-	playSound(0x1216);
-	playSound(0x120C);
+	playSoundCh5To8(0x1216);
+	playSoundCh5To8(0x120C);
 	return 0;
 }
 
 int RSound4::command32() {
-	playSound(0x11D4);
+	playSoundCh5To8(0x11D4);
 	return 0;
 }
 
 int RSound4::command33() {
-	playSound(0x11E0);
+	playSoundCh5To8(0x11E0);
 	return 0;
 }
 
 int RSound4::command34() {
-	playSound(0x11EA);
+	playSoundCh5To8(0x11EA);
 	return 0;
 }
 
 int RSound4::command35() {
-	playSound(0x11FA);
+	playSoundCh5To8(0x11FA);
 	return 0;
 }
 
 int RSound4::command36() {
-	playSound(0x123C);
-	playSound(0x1250);
+	playSoundCh5To8(0x123C);
+	playSoundCh5To8(0x1250);
 	return 0;
 }
 
 int RSound4::command37() {
-	playSound(0x122E);
+	playSoundCh5To8(0x122E);
 	return 0;
 }
 
@@ -1466,15 +1466,15 @@ int RSound4::command53() {
 	command1();
 	_callbackCounter = 56;
 	_callbackPeriod = 56;
-	playSoundAny(0x1888);
-	playSoundAny(0x18DE);
+	playSoundCh1To8(0x1888);
+	playSoundCh1To8(0x18DE);
 	return 0;
 }
 
 void RSound4::loadCommand54() {
 	_callbackFnPtr = nullptr;
-	playSoundAny(0x18B2);
-	playSoundAny(0x1904);
+	playSoundCh1To8(0x18B2);
+	playSoundCh1To8(0x1904);
 }
 
 int RSound4::command54() {
@@ -1484,7 +1484,7 @@ int RSound4::command54() {
 
 void RSound4::loadCommand55() {
 	_callbackFnPtr = nullptr;
-	playSoundAny(0x191E);
+	playSoundCh1To8(0x191E);
 }
 
 int RSound4::command55() {
@@ -1494,7 +1494,7 @@ int RSound4::command55() {
 
 void RSound4::loadCommand56() {
 	_callbackFnPtr = nullptr;
-	playSoundAny(0x185C);
+	playSoundCh1To8(0x185C);
 }
 
 int RSound4::command56() {
@@ -1503,7 +1503,7 @@ int RSound4::command56() {
 }
 
 int RSound4::command57() {
-	playSound(0x11C8);
+	playSoundCh5To8(0x11C8);
 	return 0;
 }
 
@@ -1514,7 +1514,7 @@ int RSound4::command58() {
 }
 
 int RSound4::command59() {
-	playSound(0x11BE);
+	playSoundCh5To8(0x11BE);
 	return 0;
 }
 
@@ -1543,33 +1543,33 @@ int RSound5::command(int commandId, int param) {
 		return 0;
 
 	_commandParam = param;
-	_frameCounter = 0;
+	_ticksSinceLastCommand = 0;
 	return (this->*_commandList[commandId])();
 }
 
 int RSound5::command9() {
-	playSound(0x11C4);
+	playSoundCh5To8(0x11C4);
 	return 0;
 }
 
 int RSound5::command10() {
-	playSound(0x1238);
+	playSoundCh5To8(0x1238);
 	return 0;
 }
 
 int RSound5::command11x24() {
-	playSound(0x1196);
+	playSoundCh5To8(0x1196);
 	return 0;
 }
 
 int RSound5::command12x25() {
-	playSound(0x1242);
+	playSoundCh5To8(0x1242);
 	return 0;
 }
 
 int RSound5::command13() {
-	playSound(0x125E);
-	playSound(0x1268);
+	playSoundCh5To8(0x125E);
+	playSoundCh5To8(0x1268);
 	return 0;
 }
 
@@ -1589,66 +1589,66 @@ int RSound5::command15() {
 }
 
 int RSound5::command16() {
-	playSound(0x129A);
-	playSound(0x129A);
-	playSound(0x129A);
-	playSound(0x129A);
+	playSoundCh5To8(0x129A);
+	playSoundCh5To8(0x129A);
+	playSoundCh5To8(0x129A);
+	playSoundCh5To8(0x129A);
 	return 0;
 }
 
 int RSound5::command17() {
-	playSound(0x11B4);
+	playSoundCh5To8(0x11B4);
 	return 0;
 }
 
 int RSound5::command18() {
-	playSound(0x12E4);
-	playSound(0x12F6);
-	playSound(0x1308);
-	playSound(0x131A);
+	playSoundCh5To8(0x12E4);
+	playSoundCh5To8(0x12F6);
+	playSoundCh5To8(0x1308);
+	playSoundCh5To8(0x131A);
 	return 0;
 }
 
 int RSound5::command19() {
-	playSound(0x132C);
+	playSoundCh5To8(0x132C);
 	return 0;
 }
 
 int RSound5::command20() {
-	playSound(0x1368);
+	playSoundCh5To8(0x1368);
 	return 0;
 }
 
 int RSound5::command21() {
-	playSound(0x1388);
+	playSoundCh5To8(0x1388);
 	return 0;
 }
 
 int RSound5::command22() {
-	playSound(0x139A);
+	playSoundCh5To8(0x139A);
 	return 0;
 }
 
 int RSound5::command23() {
-	playSound(0x13AA);
-	playSound(0x13AA);
-	playSound(0x13AA);
-	playSound(0x13AA);
+	playSoundCh5To8(0x13AA);
+	playSoundCh5To8(0x13AA);
+	playSoundCh5To8(0x13AA);
+	playSoundCh5To8(0x13AA);
 	return 0;
 }
 
 int RSound5::command26() {
-	playSound(0x13D6);
+	playSoundCh5To8(0x13D6);
 	return 0;
 }
 
 int RSound5::command27() {
-	playSound(0x13F0);
+	playSoundCh5To8(0x13F0);
 	return 0;
 }
 
 int RSound5::command28() {
-	playSound(0x121C);
+	playSoundCh5To8(0x121C);
 	return 0;
 }
 
@@ -1659,7 +1659,7 @@ void RSound5::loadTailChannels() {
 
 int RSound5::command29() {
 	byte *pData = loadData(0x1488);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		command1();
 		_channels[0].playData(pData);
 		_channels[1].playData(loadData(0x1534));
@@ -1670,44 +1670,44 @@ int RSound5::command29() {
 }
 
 int RSound5::command30() {
-	playSound(0x1212);
-	playSound(0x1208);
+	playSoundCh5To8(0x1212);
+	playSoundCh5To8(0x1208);
 	return 0;
 }
 
 int RSound5::command31() {
-	playSound(0x140A);
+	playSoundCh5To8(0x140A);
 	return 0;
 }
 
 int RSound5::command32() {
-	playSound(0x11D0);
+	playSoundCh5To8(0x11D0);
 	return 0;
 }
 
 int RSound5::command33() {
-	playSound(0x11DC);
+	playSoundCh5To8(0x11DC);
 	return 0;
 }
 
 int RSound5::command34() {
-	playSound(0x11E6);
+	playSoundCh5To8(0x11E6);
 	return 0;
 }
 
 int RSound5::command35() {
-	playSound(0x11F6);
+	playSoundCh5To8(0x11F6);
 	return 0;
 }
 
 int RSound5::command36() {
-	playSound(0x1464);
-	playSound(0x1478);
+	playSoundCh5To8(0x1464);
+	playSoundCh5To8(0x1478);
 	return 0;
 }
 
 int RSound5::command37() {
-	playSound(0x122A);
+	playSoundCh5To8(0x122A);
 	return 0;
 }
 
@@ -1718,13 +1718,13 @@ int RSound5::command38() {
 }
 
 int RSound5::command39() {
-	playSound(0x141E);
-	playSound(0x1428);
+	playSoundCh5To8(0x141E);
+	playSoundCh5To8(0x1428);
 	return 0;
 }
 
 int RSound5::command40() {
-	playSound(0x1432);
+	playSoundCh5To8(0x1432);
 	return 0;
 }
 
@@ -1756,7 +1756,7 @@ int RSound6::command(int commandId, int param) {
 		return 0;
 
 	_commandParam = param;
-	_frameCounter = 0;
+	_ticksSinceLastCommand = 0;
 	return (this->*_commandList[commandId])();
 }
 
@@ -1794,74 +1794,74 @@ void RSound6::reloadCommand28() {
 }
 
 int RSound6::command9() {
-	playSound(0x111C);
+	playSoundCh5To8(0x111C);
 	return 0;
 }
 
 int RSound6::command10() {
-	playSound(0x1190);
+	playSoundCh5To8(0x1190);
 	return 0;
 }
 
 int RSound6::command11() {
-	playSound(0x11A4);
-	playSound(0x11A4);
-	playSound(0x11A4);
-	playSound(0x11A4);
+	playSoundCh5To8(0x11A4);
+	playSoundCh5To8(0x11A4);
+	playSoundCh5To8(0x11A4);
+	playSoundCh5To8(0x11A4);
 	return 0;
 }
 
 int RSound6::command12() {
-	playSound(0x11C8);
+	playSoundCh5To8(0x11C8);
 	return 0;
 }
 
 int RSound6::command13x14() {
-	playSound(0x11E8);
+	playSoundCh5To8(0x11E8);
 	return 0;
 }
 
 int RSound6::command15() {
-	playSound(0x11F2);
-	playSound(0x11F2);
-	playSound(0x11F2);
-	playSound(0x11F2);
+	playSoundCh5To8(0x11F2);
+	playSoundCh5To8(0x11F2);
+	playSoundCh5To8(0x11F2);
+	playSoundCh5To8(0x11F2);
 	return 0;
 }
 
 int RSound6::command16() {
-	playSound(0x121E);
+	playSoundCh5To8(0x121E);
 	return 0;
 }
 
 int RSound6::command17() {
-	playSound(0x1228);
-	playSound(0x1228);
-	playSound(0x1228);
-	playSound(0x1228);
+	playSoundCh5To8(0x1228);
+	playSoundCh5To8(0x1228);
+	playSoundCh5To8(0x1228);
+	playSoundCh5To8(0x1228);
 	return 0;
 }
 
 int RSound6::command18() {
-	playSound(0x1254);
+	playSoundCh5To8(0x1254);
 	return 0;
 }
 
 int RSound6::command19() {
-	playSound(0x1266);
+	playSoundCh5To8(0x1266);
 	return 0;
 }
 
 int RSound6::command20() {
-	playSound(0x1278);
+	playSoundCh5To8(0x1278);
 	return 0;
 }
 
 int RSound6::command21() {
 	_channels[4].playData(loadData(0x1282));
-	playSound(0x1282);
-	playSound(0x1282);
-	playSound(0x12AA);
+	playSoundCh5To8(0x1282);
+	playSoundCh5To8(0x1282);
+	playSoundCh5To8(0x12AA);
 	return 0;
 }
 
@@ -1874,7 +1874,7 @@ int RSound6::command22() {
 }
 
 int RSound6::command23() {
-	playSound(0x1174);
+	playSoundCh5To8(0x1174);
 	return 0;
 }
 
@@ -1894,7 +1894,7 @@ int RSound6::command25() {
 }
 
 int RSound6::command28() {
-	if (isSoundActive(loadData(0x130A)))
+	if (isSoundPlaying(loadData(0x130A)))
 		return 0;
 
 	if (_channels[0]._deltaCounter && _channels[0]._soundData == loadData(0x1A38)) {
@@ -1930,7 +1930,7 @@ int RSound7::command(int commandId, int param) {
 		return 0;
 
 	_commandParam = param;
-	_frameCounter = 0;
+	_ticksSinceLastCommand = 0;
 	return (this->*_commandList[commandId])();
 }
 
@@ -1944,17 +1944,17 @@ int RSound7::command9() {
 }
 
 int RSound7::command15() {
-	playSound(0x125C);
+	playSoundCh5To8(0x125C);
 	return 0;
 }
 
 int RSound7::command16() {
-	playSound(0x12DE);
+	playSoundCh5To8(0x12DE);
 	return 0;
 }
 
 int RSound7::command17() {
-	playSound(0x12C2);
+	playSoundCh5To8(0x12C2);
 	return 0;
 }
 
@@ -1974,23 +1974,23 @@ int RSound7::command19() {
 }
 
 int RSound7::command20() {
-	playSound(0x1324);
-	playSound(0x1324);
+	playSoundCh5To8(0x1324);
+	playSoundCh5To8(0x1324);
 	return 0;
 }
 
 int RSound7::command21() {
-	playSound(0x1336);
+	playSoundCh5To8(0x1336);
 	return 0;
 }
 
 int RSound7::command22() {
-	playSound(0x1340);
+	playSoundCh5To8(0x1340);
 	return 0;
 }
 
 int RSound7::command23() {
-	playSound(0x12B4);
+	playSoundCh5To8(0x12B4);
 	return 0;
 }
 
@@ -2022,39 +2022,39 @@ int RSound7::command27() {
 }
 
 int RSound7::command30() {
-	playSound(0x12AA);
-	playSound(0x12A0);
+	playSoundCh5To8(0x12AA);
+	playSoundCh5To8(0x12A0);
 	return 0;
 }
 
 int RSound7::command32() {
-	playSound(0x1268);
+	playSoundCh5To8(0x1268);
 	return 0;
 }
 
 int RSound7::command33() {
-	playSound(0x1274);
+	playSoundCh5To8(0x1274);
 	return 0;
 }
 
 int RSound7::command34() {
-	playSound(0x127E);
+	playSoundCh5To8(0x127E);
 	return 0;
 }
 
 int RSound7::command35() {
-	playSound(0x128E);
+	playSoundCh5To8(0x128E);
 	return 0;
 }
 
 int RSound7::command36() {
-	playSound(0x1358);
-	playSound(0x136C);
+	playSoundCh5To8(0x1358);
+	playSoundCh5To8(0x136C);
 	return 0;
 }
 
 int RSound7::command37() {
-	playSound(0x134A);
+	playSoundCh5To8(0x134A);
 	return 0;
 }
 
@@ -2082,12 +2082,12 @@ int RSound8::command(int commandId, int param) {
 		return 0;
 
 	_commandParam = param;
-	_frameCounter = 0;
+	_ticksSinceLastCommand = 0;
 	return (this->*_commandList[commandId])();
 }
 
 int RSound8::command9() {
-	playSound(0x10BA);
+	playSoundCh5To8(0x10BA);
 	return 0;
 }
 
@@ -2100,20 +2100,20 @@ int RSound8::command10() {
 }
 
 int RSound8::command11() {
-	playSound(0x1194);
+	playSoundCh5To8(0x1194);
 	return 0;
 }
 
 int RSound8::command12() {
-	playSound(0x11B2);
+	playSoundCh5To8(0x11B2);
 	return 0;
 }
 
 int RSound8::command13() {
-	playSound(0x11D0);
-	playSound(0x11D0);
-	playSound(0x11D0);
-	playSound(0x11D0);
+	playSoundCh5To8(0x11D0);
+	playSoundCh5To8(0x11D0);
+	playSoundCh5To8(0x11D0);
+	playSoundCh5To8(0x11D0);
 	return 0;
 }
 
@@ -2122,10 +2122,10 @@ void RSound8::setCommand1415Variant(byte v1, byte v2) {
 	pData[3] = v1;
 	pData[6] = v2;
 	pData[9] = v2;
-	playSound(0x1204);
-	playSound(0x1204);
-	playSound(0x1204);
-	playSound(0x1204);
+	playSoundCh5To8(0x1204);
+	playSoundCh5To8(0x1204);
+	playSoundCh5To8(0x1204);
+	playSoundCh5To8(0x1204);
 }
 
 int RSound8::command14() {
@@ -2139,38 +2139,38 @@ int RSound8::command15() {
 }
 
 int RSound8::command16() {
-	playSound(0x112E);
-	playSound(0x112E);
+	playSoundCh5To8(0x112E);
+	playSoundCh5To8(0x112E);
 	return 0;
 }
 
 int RSound8::command17() {
-	playSound(0x1234);
+	playSoundCh5To8(0x1234);
 	return 0;
 }
 
 int RSound8::command18() {
-	playSound(0x1244);
+	playSoundCh5To8(0x1244);
 	return 0;
 }
 
 int RSound8::command19() {
-	playSound(0x1254);
+	playSoundCh5To8(0x1254);
 	return 0;
 }
 
 int RSound8::command20() {
-	playSound(0x125E);
+	playSoundCh5To8(0x125E);
 	return 0;
 }
 
 int RSound8::command21() {
-	playSound(0x126E);
+	playSoundCh5To8(0x126E);
 	return 0;
 }
 
 int RSound8::command22() {
-	playSound(0x1278);
+	playSoundCh5To8(0x1278);
 	return 0;
 }
 
@@ -2183,28 +2183,28 @@ int RSound8::command23() {
 }
 
 int RSound8::command24() {
-	playSound(0x12B4);
+	playSoundCh5To8(0x12B4);
 	return 0;
 }
 
 int RSound8::command25() {
-	playSound(0x12CA);
+	playSoundCh5To8(0x12CA);
 	return 0;
 }
 
 int RSound8::command26() {
-	playSound(0x12DC);
+	playSoundCh5To8(0x12DC);
 	return 0;
 }
 
 int RSound8::command27() {
-	playSound(0x1112);
+	playSoundCh5To8(0x1112);
 	return 0;
 }
 
 int RSound8::command28() {
 	byte *pData = loadData(0x130A);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		command1();
 		_channels[0].playData(pData);
 		_channels[1].playData(loadData(0x1480));
@@ -2215,7 +2215,7 @@ int RSound8::command28() {
 
 int RSound8::command29() {
 	byte *pData = loadData(0x15FC);
-	if (!isSoundActive(pData)) {
+	if (!isSoundPlaying(pData)) {
 		command1();
 		_channels[2].playData(pData);
 		_channels[8].playData(loadData(0x1652));
@@ -2224,44 +2224,44 @@ int RSound8::command29() {
 }
 
 int RSound8::command30() {
-	playSound(0x1108);
-	playSound(0x10FE);
+	playSoundCh5To8(0x1108);
+	playSoundCh5To8(0x10FE);
 	return 0;
 }
 
 int RSound8::command31() {
-	playSound(0x1140);
+	playSoundCh5To8(0x1140);
 	return 0;
 }
 
 int RSound8::command32() {
-	playSound(0x10C6);
+	playSoundCh5To8(0x10C6);
 	return 0;
 }
 
 int RSound8::command33() {
-	playSound(0x10D2);
+	playSoundCh5To8(0x10D2);
 	return 0;
 }
 
 int RSound8::command34() {
-	playSound(0x10DC);
+	playSoundCh5To8(0x10DC);
 	return 0;
 }
 
 int RSound8::command35() {
-	playSound(0x10EC);
+	playSoundCh5To8(0x10EC);
 	return 0;
 }
 
 int RSound8::command36() {
-	playSound(0x12E6);
-	playSound(0x12FA);
+	playSoundCh5To8(0x12E6);
+	playSoundCh5To8(0x12FA);
 	return 0;
 }
 
 int RSound8::command37() {
-	playSound(0x1120);
+	playSoundCh5To8(0x1120);
 	return 0;
 }
 
@@ -2295,7 +2295,7 @@ int RSound9::command(int commandId, int param) {
 		return 0;
 
 	_commandParam = param;
-	_frameCounter = 0;
+	_ticksSinceLastCommand = 0;
 	return (this->*_commandList[commandId])();
 }
 
@@ -2374,76 +2374,76 @@ int RSound9::command17() {
 }
 
 int RSound9::command18() {
-	playSound(0x3248);
+	playSoundCh5To8(0x3248);
 	return 0;
 }
 
 int RSound9::command19() {
-	playSound(0x3262);
+	playSoundCh5To8(0x3262);
 	return 0;
 }
 
 int RSound9::command20() {
-	int v = (getRandomNumber() & 24) + 77;
+	int v = (generateRandomNumber() & 24) + 77;
 	byte *pData = loadData(0x3284);
 	pData[6] = v & 0x7F;
-	playSound(0x3284);
+	playSoundCh5To8(0x3284);
 	return 0;
 }
 
 int RSound9::command21() {
 	byte *pData = loadData(0x3298);
 	pData[9] = 70;
-	if (!isSoundActive(pData))
-		playSound(0x3298);
+	if (!isSoundPlaying(pData))
+		playSoundCh5To8(0x3298);
 	return 0;
 }
 
 int RSound9::command22() {
 	byte *pData = loadData(0x3298);
 	pData[9] = 45;
-	if (!isSoundActive(pData))
-		playSound(0x3298);
+	if (!isSoundPlaying(pData))
+		playSoundCh5To8(0x3298);
 	return 0;
 }
 
 int RSound9::command23() {
-	Channel *chan = playSound(0x32B0);
+	Channel *chan = playSoundCh5To8(0x32B0);
 	if (chan)
 		chan->_innerLoopStart = loadData(0x32CE);
 
-	chan = playSound(0x32B6);
+	chan = playSoundCh5To8(0x32B6);
 	if (chan)
 		chan->_innerLoopStart = loadData(0x32CE);
 
-	chan = playSound(0x32C8);
+	chan = playSoundCh5To8(0x32C8);
 	if (chan)
 		chan->_innerLoopStart = loadData(0x32CE);
 	return 0;
 }
 
 int RSound9::command24() {
-	playSound(0x32E0);
+	playSoundCh5To8(0x32E0);
 	return 0;
 }
 
 int RSound9::command25() {
-	playSound(0x32F6);
+	playSoundCh5To8(0x32F6);
 	return 0;
 }
 
 int RSound9::command26() {
-	playSound(0x331A);
+	playSoundCh5To8(0x331A);
 	return 0;
 }
 
 int RSound9::command27() {
-	playSound(0x3332);
+	playSoundCh5To8(0x3332);
 	return 0;
 }
 
 int RSound9::command28() {
-	int v = (getRandomNumber() & 28) + 15;
+	int v = (generateRandomNumber() & 28) + 15;
 	byte *pData = loadData(0x334A);
 	pData[6] = v & 0x7F;
 	_channels[7].playData(pData);
@@ -2451,32 +2451,32 @@ int RSound9::command28() {
 }
 
 int RSound9::command29() {
-	int v = (getRandomNumber() & 12) + 33;
+	int v = (generateRandomNumber() & 12) + 33;
 	byte *pData = loadData(0x335E);
 	pData[6] = v & 0x7F;
-	playSound(0x335E);
+	playSoundCh5To8(0x335E);
 	return 0;
 }
 
 int RSound9::command30() {
-	playSound(0x3386);
+	playSoundCh5To8(0x3386);
 	return 0;
 }
 
 int RSound9::command31() {
-	playSound(0x3396);
-	playSound(0x33A4);
-	playSound(0x33B2);
+	playSoundCh5To8(0x3396);
+	playSoundCh5To8(0x33A4);
+	playSoundCh5To8(0x33B2);
 	return 0;
 }
 
 int RSound9::command32() {
-	playSound(0x33C0);
+	playSoundCh5To8(0x33C0);
 	return 0;
 }
 
 int RSound9::command33() {
-	playSound(0x33CA);
+	playSoundCh5To8(0x33CA);
 	return 0;
 }
 
@@ -2498,28 +2498,28 @@ int RSound9::command34() {
 }
 
 int RSound9::command35() {
-	playSound(0x344C);
+	playSoundCh5To8(0x344C);
 	return 0;
 }
 
 int RSound9::command36() {
-	playSound(0x334A);
+	playSoundCh5To8(0x334A);
 
-	Channel *chan = playSound(0x32C2);
+	Channel *chan = playSoundCh5To8(0x32C2);
 	if (chan)
 		chan->_innerLoopStart = loadData(0x3378);
 
-	chan = playSound(0x32BC);
+	chan = playSoundCh5To8(0x32BC);
 	if (chan)
 		chan->_innerLoopStart = loadData(0x3368);
 	return 0;
 }
 
 int RSound9::command37() {
-	int v = (getRandomNumber() & 2) + 72;
+	int v = (generateRandomNumber() & 2) + 72;
 	byte *pData = loadData(0x349C);
 	pData[6] = v & 0x7F;
-	playSound(0x349C);
+	playSoundCh5To8(0x349C);
 	return 0;
 }
 
@@ -2650,7 +2650,7 @@ int RSound9::command48() {
 	byte *pData = loadData(0x34B0);
 	pData[6] ^= 0x1F;
 	pData[0xA] ^= 0x1F;
-	playSound(0x34B0);
+	playSoundCh5To8(0x34B0);
 	return 0;
 }
 
@@ -2744,7 +2744,7 @@ int RSoundDemo9::command(int commandId, int param) {
 		return 0;
 
 	_commandParam = param;
-	_frameCounter = 0;
+	_ticksSinceLastCommand = 0;
 	if (commandId <= 8)
 		return executeDemoCommonCommand(commandId);
 
@@ -2781,7 +2781,7 @@ int RSoundDemo9::command(int commandId, int param) {
 		break;
 	case 20: {
 		byte *data = sequenceData(0x12F6);
-		data[6] = (byte)(((getRandomNumber() & 0x38) + 0x4D) & 0x7F);
+		data[6] = (byte)(((generateRandomNumber() & 0x38) + 0x4D) & 0x7F);
 		startEffectVoice(0x12F6);
 		break;
 	}
@@ -2816,13 +2816,13 @@ int RSoundDemo9::command(int commandId, int param) {
 		break;
 	case 28: {
 		byte *data = sequenceData(0x13BC);
-		data[6] = (byte)(((getRandomNumber() & 0x1C) + 0x0F) & 0x7F);
+		data[6] = (byte)(((generateRandomNumber() & 0x1C) + 0x0F) & 0x7F);
 		startEffectVoice(0x13BC);
 		break;
 	}
 	case 29: {
 		byte *data = sequenceData(0x13D0);
-		data[6] = (byte)(((getRandomNumber() & 0x0C) + 0x21) & 0x7F);
+		data[6] = (byte)(((generateRandomNumber() & 0x0C) + 0x21) & 0x7F);
 		startEffectVoice(0x13D0);
 		break;
 	}
@@ -2865,7 +2865,7 @@ int RSoundDemo9::command(int commandId, int param) {
 	}
 	case 37: {
 		byte *data = sequenceData(0x150E);
-		data[6] = (byte)(((getRandomNumber() & 0x02) + 0x48) & 0x7F);
+		data[6] = (byte)(((generateRandomNumber() & 0x02) + 0x48) & 0x7F);
 		startEffectVoice(0x150E);
 		break;
 	}
diff --git a/engines/mads/nebular/sound/rsound_nebular.h b/engines/mads/nebular/sound/rsound_nebular.h
index e0cd91de427..c6ea4b15f20 100644
--- a/engines/mads/nebular/sound/rsound_nebular.h
+++ b/engines/mads/nebular/sound/rsound_nebular.h
@@ -59,7 +59,7 @@ private:
 
 	/**
 	 * Shared loader for command11/12/13 - matches method1 in the
-	 * disassembly (isSoundActive-gated command1() + 4-channel load).
+	 * disassembly (isSoundPlaying-gated command1() + 4-channel load).
 	 */
 	void method1();
 
@@ -243,7 +243,7 @@ private:
 	/**
 	 * Shared tail used by both command1
 	 * (falls through into it after calling command3()) and command5
-	 * (jumps straight into it after its isSoundActive gate). Enables
+	 * (jumps straight into it after its isSoundPlaying gate). Enables
 	 * channels 5-8 (1-based; indices 4-7) - notably never reaches
 	 * channel 9.
 	 */
diff --git a/engines/mads/nebular/sound/sound.cpp b/engines/mads/nebular/sound/sound.cpp
index 5b4375c1acf..3ec45274e88 100644
--- a/engines/mads/nebular/sound/sound.cpp
+++ b/engines/mads/nebular/sound/sound.cpp
@@ -43,6 +43,17 @@ RexSoundManager::RexSoundManager(Audio::Mixer *mixer, bool &soundFlag,
 					"falling back to AdLib");
 		}
 	}
+	if (_driverType == SOUND_MT32) {
+		// TODO Move to SoundManager superclass when other sound drivers have been reworked
+		_midiDriver = new MidiDriver_MT32GM(MusicType::MT_MT32);
+		int returnCode;
+		returnCode = _midiDriver->open();
+		if (returnCode != 0)
+			error("SoundManager - Failed to open MIDI music driver - error code %d.", returnCode);
+
+		_driverCallbackDelta = _midiDriver->getBaseTempo();
+		_midiDriver->setTimerCallback(this, &timerCallback);
+	}
 }
 
 void RexSoundManager::validate() {




More information about the Scummvm-git-logs mailing list