[Scummvm-git-logs] scummvm master -> 78433d5085d14a307848cccdc3a5ca917fe09fd7

athrxx noreply at scummvm.org
Thu Mar 7 21:31:05 UTC 2024


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

Summary:
78433d5085 SCUMM: (MI1/Mac) - extend new sound player to support MI1


Commit: 78433d5085d14a307848cccdc3a5ca917fe09fd7
    https://github.com/scummvm/scummvm/commit/78433d5085d14a307848cccdc3a5ca917fe09fd7
Author: athrxx (athrxx at scummvm.org)
Date: 2024-03-07T22:30:18+01:00

Commit Message:
SCUMM: (MI1/Mac) - extend new sound player to support MI1

Changed paths:
  A engines/scumm/players/player_mac_loom_monkey.cpp
  R engines/scumm/players/player_mac_loom.cpp
    engines/scumm/module.mk
    engines/scumm/players/player_mac_intern.h
    engines/scumm/players/player_mac_new.cpp
    engines/scumm/players/player_mac_new.h
    engines/scumm/players/player_v5m.cpp
    engines/scumm/saveload.cpp
    engines/scumm/scumm.cpp
    engines/scumm/sound.cpp
    engines/scumm/vars.cpp


diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 4ce393f1ac1..ba7673d6177 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -54,7 +54,7 @@ MODULE_OBJS := \
 	players/player_he.o \
 	players/player_mac.o \
 	players/player_mac_indy3.o \
-	players/player_mac_loom.o \
+	players/player_mac_loom_monkey.o \
 	players/player_mac_new.o \
 	players/player_mod.o \
 	players/player_nes.o \
diff --git a/engines/scumm/players/player_mac_intern.h b/engines/scumm/players/player_mac_intern.h
index 3b48d57d23c..28c1d2eaa17 100644
--- a/engines/scumm/players/player_mac_intern.h
+++ b/engines/scumm/players/player_mac_intern.h
@@ -367,12 +367,13 @@ public:
 	MusicChannel *getMusicChannel(uint8 id) const;
 };
 
-class LoomMacSnd final : public VblTaskClientDriver, public MacLowLevelPCMDriver::CallbackClient {
+class MacSndLoader;
+class LoomMonkeyMacSnd final : public VblTaskClientDriver, public MacLowLevelPCMDriver::CallbackClient {
 private:
-	LoomMacSnd(ScummEngine *vm, Audio::Mixer *mixer);
+	LoomMonkeyMacSnd(ScummEngine *vm, Audio::Mixer *mixer);
 public:
-	~LoomMacSnd();
-	static Common::SharedPtr<LoomMacSnd> open(ScummEngine *scumm, Audio::Mixer *mixer);
+	~LoomMonkeyMacSnd();
+	static Common::SharedPtr<LoomMonkeyMacSnd> open(ScummEngine *scumm, Audio::Mixer *mixer);
 	bool startDevice(uint32 outputRate, uint32 pcmDeviceRate, uint32 feedBufferSize, bool enableInterpolation, bool stereo, bool internal16Bit);
 
 	void setMusicVolume(int vol);
@@ -393,7 +394,7 @@ public:
 	void sndChannelCallback(uint16 arg1, const void *arg2) override;
 
 private:
-	void sendSoundCommands(const byte *data, int timeStamp);
+	void sendSoundCommands(int timeStamp);
 	void stopActiveSound();
 	void setupChannels();
 	void disposeAllChannels();
@@ -401,33 +402,17 @@ private:
 	void detectQuality();
 	bool isSoundCardType10() const;
 
-	struct Instrument {
-	public:
-		Instrument(uint16 id, Common::SeekableReadStream *&in, Common::String &&name);
-		~Instrument() { _res.reset(); }
-		const MacLowLevelPCMDriver::PCMSound *data() const { return &_snd; }
-		uint16 id() const { return _id; }
-	private:
-		uint16 _id;
-		Common::SharedPtr<const byte> _res;
-		Common::String _name;
-		MacLowLevelPCMDriver::PCMSound _snd;
-	};
-
-	bool loadInstruments();
-	const Common::SharedPtr<Instrument> *findInstrument(uint16 id) const;
-	Common::Array<Common::SharedPtr<Instrument> > _instruments;
-
 	int _curSound;
+	int _restartSound;
+	int _curSoundSaveVar;
 	int _songTimer;
 	byte _songTimerInternal;
-	byte *_soundUsage;
 	byte *_chanConfigTable;
 	const int _idRangeMax;
+	const byte _saveVersionChange;
+	const byte _legacySaveUnits;
 	bool _mixerThread;
 
-	MacLowLevelPCMDriver *_sdrv;
-
 	int _machineRating;
 	int _selectedQuality;
 	int _effectiveChanConfig;
@@ -438,13 +423,15 @@ private:
 	MacLowLevelPCMDriver::ChanHandle _musChannels[4];
 
 	MacPlayerAudioStream *_macstr;
+	MacSndLoader *_loader;
+	MacLowLevelPCMDriver *_sdrv;
 	Audio::SoundHandle _soundHandle;
-	MacPlayerAudioStream::CallbackProc _songTimerUpdt;
+	MacPlayerAudioStream::CallbackProc _vblTskProc;
 	MacLowLevelPCMDriver::ChanCallback _chanCbProc;
 
 	ScummEngine *_vm;
 	Audio::Mixer *_mixer;
-	static Common::WeakPtr<LoomMacSnd> *_inst;
+	static Common::WeakPtr<LoomMonkeyMacSnd> *_inst;
 
 	byte _curChanConfig;
 	byte _chanUse;
@@ -452,21 +439,6 @@ private:
 	Audio::Mixer::SoundType _curSndType;
 	Audio::Mixer::SoundType _lastSndType;
 	byte _chanPlaying;
-
-	struct SoundConfig {
-		SoundConfig(LoomMacSnd *pl) : player(pl), sndRes6(0), switchable(0), sndRes10(0), chanSetup(0), timbre(0) {
-			assert(player);
-			memset(instruments, 0, sizeof(instruments));
-		}
-		void load(const byte *data);
-		byte sndRes6;
-		byte switchable;
-		byte sndRes10;
-		uint16 chanSetup;
-		uint16 timbre;
-		const Common::SharedPtr<Instrument> *instruments[5];
-		LoomMacSnd *player;
-	} _soundConfig;
 };
 
 extern const uint8 _fourToneSynthWaveForm[256];
diff --git a/engines/scumm/players/player_mac_loom.cpp b/engines/scumm/players/player_mac_loom.cpp
deleted file mode 100644
index 318e1f04447..00000000000
--- a/engines/scumm/players/player_mac_loom.cpp
+++ /dev/null
@@ -1,590 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-
-#include "scumm/players/player_mac_new.h"
-#include "scumm/players/player_mac_intern.h"
-#include "scumm/resource.h"
-
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
-#include "common/punycode.h"
-#include "common/macresman.h"
-
-namespace Scumm {
-
-#define ASC_DEVICE_RATE		0x56EE8BA3
-#define PCM_BUFFER_SIZE		1024
-
-Common::WeakPtr<LoomMacSnd> *LoomMacSnd::_inst = nullptr;
-
-LoomMacSnd::LoomMacSnd(ScummEngine *vm, Audio::Mixer *mixer) : VblTaskClientDriver(),
-	_vm(vm), _mixer(mixer), _curSound(0), _macstr(nullptr), _soundUsage(0), _sdrv(nullptr), _songTimerUpdt(this, &VblTaskClientDriver::vblCallback), _soundConfig(this),
-	_songTimer(0), _songTimerInternal(0), _machineRating(0), _selectedQuality(2), _effectiveChanConfig(0), _16bit(false), _idRangeMax(200), _sndChannel(0), _chanUse(0),
-	_defaultChanConfig(0), _chanConfigTable(nullptr), _chanPlaying(0), _curChanConfig(0), _curSynthType(0), _curSndType(Audio::Mixer::kPlainSoundType),
-	_mixerThread(false), _lastSndType(Audio::Mixer::kPlainSoundType), _chanCbProc(this, &MacLowLevelPCMDriver::CallbackClient::sndChannelCallback) {
-	assert(_vm);
-	assert(_mixer);
-
-	static const byte cfgtable[] = { 0, 0, 0, 1, 4, 5, 1, 5, 6, 6, 8, 9 };
-	_chanConfigTable = new byte[sizeof(cfgtable)]();
-	memcpy(_chanConfigTable, cfgtable, sizeof(cfgtable));
-	_soundUsage = new byte[_idRangeMax]();
-	memset(_musChannels, 0, sizeof(_musChannels));
-}
-
-LoomMacSnd::~LoomMacSnd() {
-	_mixer->stopHandle(_soundHandle);
-	delete _macstr;
-	delete[] _soundUsage;
-	delete[] _chanConfigTable;
-
-	disposeAllChannels();
-	delete _sdrv;
-
-	delete _inst;
-	_inst = nullptr;
-}
-
-Common::SharedPtr<LoomMacSnd> LoomMacSnd::open(ScummEngine *vm, Audio::Mixer *mixer) {
-	Common::SharedPtr<LoomMacSnd> scp = nullptr;
-
-	if (_inst == nullptr) {
-		scp = Common::SharedPtr<LoomMacSnd>(new LoomMacSnd(vm, mixer));
-		_inst = new Common::WeakPtr<LoomMacSnd>(scp);
-		// We can start this with the ScummVM mixer output rate instead of the ASC rate. The Mac sample rate converter can handle it (at
-		// least for up to 48 KHz, I haven't tried higher settings) and we don't have to do another rate conversion in the ScummVM mixer.
-		if ((_inst == nullptr) || (mixer == nullptr) || !(scp->startDevice(mixer->getOutputRate(), mixer->getOutputRate() << 16/*ASC_DEVICE_RATE*/, PCM_BUFFER_SIZE, true, false, true)))
-			error("LoomMacSnd::open(): Failed to start player");
-	}
-
-	return _inst->lock();
-}
-
-bool LoomMacSnd::startDevice(uint32 outputRate, uint32 pcmDeviceRate, uint32 feedBufferSize, bool enableInterpolation, bool stereo, bool internal16Bit) {
-	_macstr = new MacPlayerAudioStream(this, outputRate, stereo, enableInterpolation, internal16Bit);
-	if (!_macstr || !_mixer)
-		return false;
-
-	if (!loadInstruments())
-		return false;
-
-	_sdrv = new MacLowLevelPCMDriver(_mixer->mutex(), pcmDeviceRate, internal16Bit);
-	if (!_sdrv)
-		return false;
-
-	_effectiveChanConfig = 9;
-	_16bit = internal16Bit;
-
-	_macstr->initDrivers();
-	_macstr->initBuffers(feedBufferSize);
-	_macstr->setVblCallback(&_songTimerUpdt);
-
-	_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, _macstr, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-
-	return true;
-}
-
-void LoomMacSnd::setMusicVolume(int vol) {
-	Common::StackLock lock(_mixer->mutex());
-	if (_macstr)
-		_macstr->setMasterVolume(Audio::Mixer::kMusicSoundType, vol);
-}
-
-void LoomMacSnd::setSfxVolume(int vol) {
-	Common::StackLock lock(_mixer->mutex());
-	if (_macstr)
-		_macstr->setMasterVolume(Audio::Mixer::kSFXSoundType, vol);
-}
-
-void LoomMacSnd::startSound(int id, int jumpToTick) {
-	if (_sdrv == nullptr || id < 0 || id >= _idRangeMax) {
-		warning("LoomMacSnd::startSound(): sound id '%d' out of range (0 - %d)", id, _idRangeMax - 1);
-		return;
-	}
-
-	Common::StackLock lock(_mixer->mutex());
-
-	const byte *ptr = _vm->getResourceAddress(rtSound, id);
-	assert(ptr);
-
-	if (READ_BE_UINT16(ptr + 4) != 'so' || READ_BE_UINT32(ptr + 10)) {
-		warning("LoomMacSnd::startSound(): Sound resource '%d' cannot be played", id);
-		return;
-	}
-
-	stopActiveSound();
-	if (_chanUse <= 1)
-		disposeAllChannels();
-
-	if (!_defaultChanConfig)
-		detectQuality();
-
-	_soundConfig.load(ptr);
-	//if (_sndDisableFlags && _soundConfig.switchable)
-	//	return;
-
-	if (_soundConfig.chanSetup) {
-		_effectiveChanConfig = _soundConfig.chanSetup;
-		_curSndType = Audio::Mixer::kSFXSoundType;
-	} else {
-		_effectiveChanConfig = _defaultChanConfig;
-		_curSndType = Audio::Mixer::kMusicSoundType;
-	}
-
-	if (_lastSndType != _curSndType)
-		_curChanConfig = 0;
-
-	_curSound = id;
-	_soundUsage[id] = 1;
-
-	setupChannels();
-	sendSoundCommands(ptr, jumpToTick);
-
-	if (!jumpToTick) {
-		_songTimer = 0;
-		_songTimerInternal = 0;
-	}
-}
-
-void LoomMacSnd::stopSound(int id) {
-	if (id < 0 || id >= _idRangeMax) {
-		warning("LoomMacSnd::stopSound(): sound id '%d' out of range (0 - %d)", id, _idRangeMax - 1);
-		return;
-	}
-
-	Common::StackLock lock(_mixer->mutex());
-	_soundUsage[id] = 0;
-
-	if (id == _curSound)
-		stopActiveSound();
-}
-
-void LoomMacSnd::stopAllSounds() {
-	Common::StackLock lock(_mixer->mutex());
-	memset(_soundUsage, 0, _idRangeMax);
-	stopActiveSound();
-}
-
-int LoomMacSnd::getMusicTimer() {
-	Common::StackLock lock(_mixer->mutex());
-	return _songTimer;
-}
-
-int LoomMacSnd::getSoundStatus(int id) const {
-	if (id < 0 || id >= _idRangeMax) {
-		warning("LoomMacSnd::getSoundStatus(): sound id '%d' out of range (0 - %d)", id, _idRangeMax - 1);
-		return 0;
-	}
-	Common::StackLock lock(_mixer->mutex());
-	return _soundUsage[id];
-}
-
-void LoomMacSnd::setQuality(int qual) {
-	assert(qual >= MacSound::kQualityAuto && qual <= MacSound::kQualityHighest);
-	Common::StackLock lock(_mixer->mutex());
-
-	if (qual > MacSound::kQualityAuto) {
-		qual--;
-		_machineRating = (qual / 3) + 1;
-		_selectedQuality = qual % 3;
-		qual = _chanConfigTable[_machineRating * 3 + _selectedQuality];
-		if (qual && qual == _defaultChanConfig)
-			return;
-	}
-
-	int csnd = _curSound;
-	int32 timeStamp = csnd ? _songTimer * 1000 + ((_songTimerInternal * 1000) / 30) : 0;
-	stopActiveSound();
-	
-	detectQuality();
-	if (csnd)
-		startSound(csnd, timeStamp);
-}
-
-void LoomMacSnd::saveLoadWithSerializer(Common::Serializer &ser) {
-	if (ser.isLoading() && ser.getVersion() < VER(94)) {
-		memset(_soundUsage, 0, _idRangeMax);
-		_curSound = 0;
-		return;
-	}
-
-	if (ser.isLoading() && ser.getVersion() < VER(114)) {
-		memset(_soundUsage, 0, _idRangeMax);
-		// Skip over old driver savedata, since it is not needed here.
-		ser.skip(4);
-		// We need only this
-		ser.syncAsSint16LE(_curSound);
-		_curSound = CLIP<int>(_curSound, 0, _idRangeMax - 1);
-		if (_curSound > 0)
-			_soundUsage[_curSound] = 1;
-		// Skip the rest
-		ser.skip(ser.getVersion() >= VER(94) && ser.getVersion() <= VER(103) ? 120 : 100);
-	} else {
-		ser.syncBytes(_soundUsage, _idRangeMax, VER(114));
-	}
-}
-
-void LoomMacSnd::restoreAfterLoad() {
-	for (int i = 1; i < _idRangeMax; ++i) {
-		if (_soundUsage[i]) {
-			_soundUsage[i] = 0;
-			startSound(i);
-		}
-	}
-}
-
-void LoomMacSnd::vblCallback() {
-	if (_songTimerInternal++ == 29) {
-		_songTimerInternal = 0;
-		++_songTimer;
-	}
-}
-
-void LoomMacSnd::generateData(int8 *dst, uint32 len, Audio::Mixer::SoundType type, bool expectStereo) const {
-	assert(dst);
-	memset(dst, 0, len);
-	_sdrv->feed(dst, len, type, expectStereo);
-}
-
-const MacSoundDriver::Status &LoomMacSnd::getDriverStatus(uint8, Audio::Mixer::SoundType sndType) const {
-	return _sdrv->getStatus(sndType);
-}
-
-void LoomMacSnd::sndChannelCallback(uint16 arg1, const void*) {
-	// We do this a little smarter than the original player which would stop the track immediately when
-	// the first channel invoked its end-of-track callback. This would cut of the playback early, in an
-	// unpleasant way. Instead, we stop the playback not before all channels have finished.
-	_chanPlaying &= ~arg1;
-	if (_chanPlaying)
-		return;
-	stopActiveSound();
-}
-
-void LoomMacSnd::sendSoundCommands(const byte *data, int timeStamp) {
-	if (!_defaultChanConfig || !_curSound)
-		return;
-
-	if (_chanUse == 1 && _sndChannel) {
-		const byte *s = data + READ_BE_UINT16(data + 30) + 6;
-		uint16 len = READ_BE_UINT16(s - 2);
-		while (len--) {
-			uint16 p1 = READ_BE_UINT16(s);
-			s += 2;
-			uint8 note = *s++;
-
-			if (timeStamp > 0) {
-				int ts = timeStamp;
-				timeStamp = MAX<int>(0, timeStamp - p1);
-				p1 -= ts;
-			}
-			if (timeStamp)
-				continue;
-
-			_sdrv->playNote(_sndChannel, MacLowLevelPCMDriver::kEnqueue, note & 0x7f, p1);
-			if (note == 0) // Workaround for tempo glitch in original driver
-				_sdrv->wait(_sndChannel, MacLowLevelPCMDriver::kEnqueue, p1);
-		}
-		_sdrv->quiet(_sndChannel, MacLowLevelPCMDriver::kEnqueue);
-		_sdrv->callback(_sndChannel, MacLowLevelPCMDriver::kEnqueue, 1, nullptr);
-		_chanPlaying |= 1;
-
-	} else if (_chanUse == 4) {
-		const byte *src[4];
-		uint16 len[4];
-		int tmstmp[4];
-
-		for (int i = 0; i < 4; ++i) {
-			src[i] = nullptr;
-			len[i] = 0;
-			tmstmp[i] = timeStamp;
-			if (!_musChannels[i])
-				continue;
-			src[i] = data + READ_BE_UINT16(data + 32 + 2 * i) + 6;
-			len[i] = READ_BE_UINT16(src[i] - 2);
-		}
-
-		for (bool loop = true; loop; ) {
-			loop = false;
-			for (int i = 0; i < 4; ++i) {
-				if (!src[i] || !len[i])
-					continue;
-				uint16 p1 = READ_BE_UINT16(src[i]);
-				src[i] += 2;
-				byte note = *src[i]++;
-				if (tmstmp[i] > 0) {
-					int ts = tmstmp[i];
-					tmstmp[i] = MAX<int>(0, tmstmp[i] - p1);
-					p1 -= ts;
-				}
-				loop |= static_cast<bool>(--len[i]);
-
-				if (tmstmp[i])
-					continue;
-
-				_sdrv->playNote(_musChannels[i], MacLowLevelPCMDriver::kEnqueue, (_curSynthType == 4 && note == 0) ? 1 : note & 0x7f, p1);
-				// Workaround for tempo glitch in original driver. For the sampled synth in 4 channel mode, there is
-				// some sort of fix in the original (see above), but that really does not work well for the other cases.
-				if (note == 0 && _curSynthType != 4)
-					_sdrv->wait(_musChannels[i], MacLowLevelPCMDriver::kEnqueue, p1);
-			}
-		}
-
-		_chanPlaying = 0;
-		for (int i = 0; i < 4; ++i) {
-			if (src[i]) {
-				_sdrv->quiet(_musChannels[i], MacLowLevelPCMDriver::kEnqueue);
-				_sdrv->callback(_musChannels[i], MacLowLevelPCMDriver::kEnqueue, 1 << i, nullptr);
-				_chanPlaying |= (1 << i);
-			}
-		}
-	}
-}
-
-void LoomMacSnd::stopActiveSound() {
-	if (_sndChannel) {
-		_sdrv->quiet(_sndChannel, MacLowLevelPCMDriver::kImmediate);
-		_sdrv->flush(_sndChannel, MacLowLevelPCMDriver::kImmediate);
-	}
-
-	for (int i = 0; i < ARRAYSIZE(_musChannels); ++i) {
-		if (_musChannels[i]) {
-			_sdrv->quiet(_musChannels[i], MacLowLevelPCMDriver::kImmediate);
-			_sdrv->flush(_musChannels[i], MacLowLevelPCMDriver::kImmediate);
-		}
-	}
-
-	if (_curSound) {
-		_soundUsage[_curSound] = 0;
-		_curSound = 0;
-	}
-	_chanPlaying = 0;
-}
-
-void LoomMacSnd::setupChannels() {
-	static const byte synthType[] =	{ 0x00,	0x01, 0x02, 0x04, 0x04, 0x04, 0x02, 0x04, 0x04, 0x04 };
-	static const byte numChan[] =	{ 0x00,	0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x04, 0x04 };
-	static const byte attrib[] =	{ 0x00, 0x00, 0x04, 0xAC, 0xA4, 0xA0, 0x04, 0xAC, 0xA4, 0xA0 };
-
-	if (!_defaultChanConfig)
-		return;
-
-	if (_curChanConfig != _effectiveChanConfig) {
-		disposeAllChannels();
-		_curChanConfig = _effectiveChanConfig;
-		_curSynthType = synthType[_curChanConfig];
-		_chanUse = numChan[_curChanConfig];
-		_lastSndType = _curSndType;
-
-		switch (_curSynthType) {
-		case 1:
-			if (_chanUse == 1 && !_sndChannel) {
-				_sndChannel = _sdrv->createChannel(_curSndType, MacLowLevelPCMDriver::kSquareWaveSynth, attrib[_curChanConfig], &_chanCbProc);
-			}
-			break;
-		case 2:
-			if (_chanUse == 1 && !_sndChannel) {
-				_sndChannel = _sdrv->createChannel(_curSndType, MacLowLevelPCMDriver::kWaveTableSynth, attrib[_curChanConfig], &_chanCbProc);
-			} else if (_chanUse == 4) {
-				for (int i = 0; i < ARRAYSIZE(_musChannels); ++i) {
-					if ((_soundConfig.instruments[i + 1] && _soundConfig.instruments[i + 1]->get()->id() == 0x2D1C) || _musChannels[i])
-						continue;
-					_musChannels[i] = _sdrv->createChannel(_curSndType, MacLowLevelPCMDriver::kWaveTableSynth, attrib[_curChanConfig] + i, &_chanCbProc);
-				}
-			}
-			break;
-		case 4:
-			if (_chanUse == 1 && !_sndChannel) {
-				_sndChannel = _sdrv->createChannel(_curSndType, MacLowLevelPCMDriver::kSampledSynth, attrib[_curChanConfig], &_chanCbProc);
-			} else if (_chanUse == 4) {
-				for (int i = 0; i < ARRAYSIZE(_musChannels); ++i) {
-					if ((_soundConfig.instruments[i + 1] && _soundConfig.instruments[i + 1]->get()->id() == 0x2D1C) || _musChannels[i])
-						continue;
-					_musChannels[i] = _sdrv->createChannel(_curSndType, MacLowLevelPCMDriver::kSampledSynth, attrib[_curChanConfig], &_chanCbProc);
-				}
-			}
-			break;
-		default:
-			break;
-		}
-	}
-
-	switch (_curSynthType) {
-	case 1:
-		if (_sndChannel)
-			_sdrv->setTimbre(_sndChannel, MacLowLevelPCMDriver::kImmediate, _soundConfig.timbre);
-		break;
-	case 2:
-		if (_chanUse == 1) {
-			if (_sndChannel)
-				_sdrv->loadWaveTable(_sndChannel, MacLowLevelPCMDriver::kImmediate, _fourToneSynthWaveForm, _fourToneSynthWaveFormSize);
-		} else {
-			for (int i = 0; i < ARRAYSIZE(_musChannels); ++i) {
-				if (_musChannels[i])
-					_sdrv->loadWaveTable(_musChannels[i], MacLowLevelPCMDriver::kImmediate, _fourToneSynthWaveForm, _fourToneSynthWaveFormSize);
-			}
-		}
-		break;
-	case 4:
-		if (_chanUse == 1) {
-			if (_sndChannel && _soundConfig.instruments[0])
-				_sdrv->loadInstrument(_sndChannel, MacLowLevelPCMDriver::kImmediate, _soundConfig.instruments[0]->get()->data());
-		} else {
-			for (int i = 0; i < ARRAYSIZE(_musChannels); ++i) {
-				if (_musChannels[i] && _soundConfig.instruments[i + 1])
-					_sdrv->loadInstrument(_musChannels[i], MacLowLevelPCMDriver::kImmediate, _soundConfig.instruments[i + 1]->get()->data());
-			}
-		}
-		break;
-	default:
-		break;
-	}
-}
-
-void LoomMacSnd::disposeAllChannels() {
-	if (_sndChannel)
-		_sdrv->disposeChannel(_sndChannel);
-	_sndChannel = 0;
-
-	for (int i = 0; i < ARRAYSIZE(_musChannels); ++i) {
-		if (_musChannels[i])
-			_sdrv->disposeChannel(_musChannels[i]);
-		_musChannels[i] = 0;
-	}
-
-	_curChanConfig = 0;
-}
-
-void LoomMacSnd::detectQuality() {
-	if (_machineRating == 0) {
-		if (isSoundCardType10())
-			_machineRating = 1;
-		/*else if (0)
-			_machineRating = 2;*/
-		else
-			_machineRating = 3;
-	}
-
-	_defaultChanConfig = _effectiveChanConfig = _chanConfigTable[_machineRating * 3 + _selectedQuality];
-	_curChanConfig = 0;
-	disposeAllChannels();
-	setupChannels();
-	_chanConfigTable[_machineRating * 3 + _selectedQuality] = _defaultChanConfig;
-}
-
-bool LoomMacSnd::isSoundCardType10() const {
-	return _mixerThread ? (_machineRating == 1) : (_vm->VAR_SOUNDCARD != 0xff && _vm->VAR(_vm->VAR_SOUNDCARD) == 10);
-}
-
-LoomMacSnd::Instrument::Instrument(uint16 id, Common::SeekableReadStream *&in, Common::String &&name) : _id(id), _name(name) {
-	in->seek(2);
-	uint16 numTypes = in->readUint16BE();
-	in->seek(numTypes * 6 + 4);
-	in->seek(in->readUint16BE() * 8 + numTypes * 6 + 10);
-
-	_snd.len = in->readUint32BE();
-	_snd.rate = in->readUint32BE();
-	_snd.loopst = in->readUint32BE();
-	_snd.loopend = in->readUint32BE();
-	_snd.enc = in->readByte();
-	_snd.baseFreq = in->readByte();
-
-	byte *buff = new byte[_snd.len];
-	in->read(buff, _snd.len);
-	_snd.data = Common::SharedPtr<const byte> (buff, Common::ArrayDeleter<const byte>());
-}
-
-bool LoomMacSnd::loadInstruments() {
-	static const char *tryNames[] = {
-		"Loom",
-		"Loom\xaa",
-		"Loom PPC",
-		"Loom\xaa PPC"
-	};
-
-	const Common::CodePage tryCodePages[] = {
-		Common::kMacRoman,
-		Common::kISO8859_1
-	};
-
-	Common::MacResManager resMan;
-	Common::Path resFile;
-	for (int i = 0; resFile.empty() && i < ARRAYSIZE(tryNames); ++i) {
-		for (int ii = 0; resFile.empty() && ii < ARRAYSIZE(tryCodePages); ++ii) {
-			Common::U32String fn(tryNames[i], tryCodePages[ii]);
-			resFile = Common::Path(fn.encode(Common::kUtf8));
-			if (!resMan.exists(resFile) || !resMan.open(resFile) || !resMan.hasResFork()) {
-				resMan.close();
-				resFile = Common::Path(Common::punycode_encodefilename(fn));
-				if (!resMan.exists(resFile) || !resMan.open(resFile) || !resMan.hasResFork()) {
-					resMan.close();
-					resFile.clear();
-				}
-			}
-		}
-	}
-
-	if (resFile.empty()) {
-		warning("LoomMacSnd::loadInstruments(): Loom resource fork not found");
-		return false;
-	}
-
-	Common::MacResIDArray ids = resMan.getResIDArray(MKTAG('s', 'n', 'd', ' '));
-	for (uint i = 0; i < ids.size(); ++i) {
-		Common::SeekableReadStream *str = resMan.getResource(MKTAG('s', 'n', 'd', ' '), ids[i]);
-		if (!str || str->readUint16BE() != 1) {
-			static const char *const errStr[2] = { "Failed to load", "Invalid sound resource format for" };
-			warning("LoomMacSnd::loadInstruments(): %s instrument with id 0x%04x", errStr[str ? 1 : 0], ids[i]);
-			delete str;
-			return false;
-		}
-		_instruments.push_back(Common::SharedPtr<Instrument>(new Instrument(ids[i], str, resMan.getResName(MKTAG('s', 'n', 'd', ' '), ids[i]))));
-		delete str;
-	}
-
-	return true;
-}
-
-const Common::SharedPtr<LoomMacSnd::Instrument> *LoomMacSnd::findInstrument(uint16 id) const {
-	Common::Array<Common::SharedPtr<Instrument> >::const_iterator replacement = _instruments.end();
-	for (Common::Array<Common::SharedPtr<Instrument> >::const_iterator i = _instruments.begin(); i != _instruments.end(); ++i) {
-		if ((*i)->id() == id)
-			return i;
-		else if ((*i)->id() == 0x2D1C)
-			replacement = i;
-	}
-	return (replacement != _instruments.end()) ? replacement : nullptr;
-}
-
-void LoomMacSnd::SoundConfig::load(const byte *data) {
-	sndRes6 = READ_BE_UINT16(data + 6) & 0xff;
-	switchable = READ_BE_UINT16(data + 8) >> 8;
-	sndRes10 = READ_BE_UINT16(data + 10) >> 8;
-	chanSetup = READ_BE_UINT16(data + 16);
-	timbre = READ_BE_UINT16(data + 18);
-	for (int i = 0; i < 5; ++i)
-		instruments[i] = player->findInstrument(READ_BE_UINT16(data + 20 + 2 * i));
-}
-
-#undef ASC_DEVICE_RATE
-#undef PCM_BUFFER_SIZE
-
-} // End of namespace Scumm
diff --git a/engines/scumm/players/player_mac_loom_monkey.cpp b/engines/scumm/players/player_mac_loom_monkey.cpp
new file mode 100644
index 00000000000..6bbd6fe4c4d
--- /dev/null
+++ b/engines/scumm/players/player_mac_loom_monkey.cpp
@@ -0,0 +1,901 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "scumm/players/player_mac_new.h"
+#include "scumm/players/player_mac_intern.h"
+#include "scumm/resource.h"
+
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+#include "common/punycode.h"
+#include "common/macresman.h"
+#include "common/memstream.h"
+
+namespace Scumm {
+
+#define ASC_DEVICE_RATE		0x56EE8BA3
+#define PCM_BUFFER_SIZE		1024
+
+class MacSndLoader{
+protected:
+	MacSndLoader(bool useInstrTag);
+public:
+	virtual ~MacSndLoader() {}
+
+	virtual bool init() = 0;
+	virtual bool checkResource(const byte *data, uint32 dataSize) const = 0;
+	virtual bool blocked(const byte *data, uint32 dataSize) const = 0;
+	virtual bool loadSound(byte synthType, const byte *data, uint32 dataSize) = 0;
+	virtual void unblock() = 0;
+
+	const MacLowLevelPCMDriver::PCMSound *getInstrData(uint16 chan);
+	virtual bool isInstrUsable(uint16 chan) const = 0;
+	virtual bool parseNextEvent(uint16 chan, uint16 &duration, uint8 &note, bool &skip, bool &updateInstr) = 0;
+	virtual uint16 getChanSetup() const = 0;
+	uint16 getTimbre() const { return _timbre; }
+	virtual bool isMusic() const = 0;
+	bool isLooping() const { return _loop; }
+	virtual bool restartSoundAfterLoad() const = 0;
+
+	virtual bool ignoreMachineRating() const = 0;
+
+protected:
+	bool loadInstruments(const char *const *tryFileNames, uint16 numTryFileNames, uint16 numInstruments);
+
+	struct Instrument {
+	public:
+		Instrument(uint32 id, Common::SeekableReadStream *&in, Common::String &&name);
+		~Instrument() { _res.reset(); }
+		const MacLowLevelPCMDriver::PCMSound *data() const { return &_snd; }
+		uint32 id() const { return _id; }
+
+	private:
+		uint32 _id;
+		Common::SharedPtr<const byte> _res;
+		Common::String _name;
+		MacLowLevelPCMDriver::PCMSound _snd;
+	};
+
+	Common::Array<Common::SharedPtr<Instrument> > _instruments;
+
+	byte _sndRes6;
+	byte _isMusic;
+	byte _sndRes9;
+	byte _sndRes10;
+	byte _sndRes11;
+	byte _sndRes12;
+	uint16 _chanSetup;
+	uint16 _timbre;
+	bool _loop;
+	byte _synth;
+	const byte *_chanSndData[5];
+	uint32 _chanNumEvents[5];
+	uint32 _chanCurEvent[5];
+	const Common::SharedPtr<Instrument> *_chanInstr[5];
+	const Common::SharedPtr<Instrument> *_chanInstr2[5];
+
+	const bool _useInstrTag;
+};
+
+class LoomMacSndLoader final : public MacSndLoader {
+public:
+	LoomMacSndLoader() : MacSndLoader(false) {}
+	~LoomMacSndLoader() override {}
+
+	bool init() override;
+	bool checkResource(const byte *data, uint32 dataSize) const override;
+	bool blocked(const byte *data, uint32 dataSize) const override { return false; }
+	bool loadSound(byte synthType, const byte *data, uint32 dataSize) override;
+	void unblock() override {}
+
+	bool isInstrUsable(uint16 chan) const override;
+	bool parseNextEvent(uint16 chan, uint16 &duration, uint8 &note, bool &skip, bool &updateInstr) override;
+	uint16 getChanSetup() const override { return _chanSetup; }
+	bool isMusic() const override { return (_chanSetup == 0); }
+	bool restartSoundAfterLoad() const override { return true; }
+	bool ignoreMachineRating() const override { return false; }
+private:
+	const Common::SharedPtr<Instrument> *fetchInstrument(uint16 id) const;
+};
+
+class MonkeyMacSndLoader final : public MacSndLoader {
+public:
+	MonkeyMacSndLoader() : MacSndLoader(true), _numInstrumentsMax(17), _blockSfx(false), _transpose(0) {}
+	~MonkeyMacSndLoader() override {}
+
+	bool init() override;
+	bool checkResource(const byte *data, uint32 dataSize) const override;
+	bool blocked(const byte *data, uint32 dataSize) const override;
+	bool loadSound(byte synthType, const byte *data, uint32 dataSize) override;
+	void unblock() override { _blockSfx = false; }
+
+	bool isInstrUsable(uint16 chan) const override;
+	bool parseNextEvent(uint16 chan, uint16 &duration, uint8 &note, bool &skip, bool &updateInstr) override;
+	uint16 getChanSetup() const override { return _isMusic ? _chanSetup : 7; }
+	bool isMusic() const override { return _isMusic; }
+	bool restartSoundAfterLoad() const override { return _isMusic && _loop; }
+	bool ignoreMachineRating() const override { return true; }
+private:
+	const Common::SharedPtr<Instrument> *fetchInstrument(const byte *data, uint32 dataSize, uint32 tagOrOffset);
+	bool _blockSfx;
+	byte _transpose;
+	const byte _numInstrumentsMax;
+};
+
+MacSndLoader::Instrument::Instrument(uint32 id, Common::SeekableReadStream *&in, Common::String &&name) : _id(id), _name(name) {
+	in->seek(2);
+	uint16 numTypes = in->readUint16BE();
+	in->seek(numTypes * 6 + 4);
+	in->seek(in->readUint16BE() * 8 + numTypes * 6 + 10);
+
+	_snd.len = in->readUint32BE();
+	_snd.rate = in->readUint32BE();
+	_snd.loopst = in->readUint32BE();
+	_snd.loopend = in->readUint32BE();
+	_snd.enc = in->readByte();
+	_snd.baseFreq = in->readByte();
+
+	byte *buff = new byte[_snd.len];
+	if (in->read(buff, _snd.len) != _snd.len)
+		error("MacSndLoader::Instrument::Instrument(): Data error");
+	_snd.data = Common::SharedPtr<const byte>(buff, Common::ArrayDeleter<const byte>());
+}
+
+MacSndLoader::MacSndLoader(bool useInstrTag) : _sndRes6(0), _isMusic(0), _sndRes9(0), _sndRes10(0), _sndRes11(0), _sndRes12(0), _chanSetup(0),
+	_timbre(0), _useInstrTag(useInstrTag), _synth(0), _loop(false) {
+	memset(_chanInstr, 0, sizeof(_chanInstr));
+	memset(_chanInstr2, 0, sizeof(_chanInstr2));
+	memset(_chanSndData, 0, sizeof(_chanSndData));
+	memset(_chanNumEvents, 0, sizeof(_chanNumEvents));
+	memset(_chanCurEvent, 0, sizeof(_chanCurEvent));
+}
+
+const MacLowLevelPCMDriver::PCMSound *MacSndLoader::getInstrData(uint16 chan) {
+	return (chan < ARRAYSIZE(_chanInstr) && _chanInstr[chan]) ? _chanInstr[chan]->get()->data() : nullptr;
+}
+
+bool MacSndLoader::loadInstruments(const char *const *tryFileNames, uint16 numTryFileNames, uint16 numInstruments) {
+	assert(tryFileNames && numTryFileNames && numInstruments);
+	uint32 tag = 0;
+	const Common::CodePage tryCodePages[] = {
+		Common::kMacRoman,
+		Common::kISO8859_1
+	};
+
+	Common::MacResManager resMan;
+	Common::Path resFile;
+	for (int i = 0; resFile.empty() && i < numTryFileNames; ++i) {
+		for (int ii = 0; resFile.empty() && ii < ARRAYSIZE(tryCodePages); ++ii) {
+			Common::U32String fn(tryFileNames[i], tryCodePages[ii]);
+			resFile = Common::Path(fn.encode(Common::kUtf8));
+			if (!resMan.exists(resFile) || !resMan.open(resFile) || !resMan.hasResFork()) {
+				resMan.close();
+				resFile = Common::Path(Common::punycode_encodefilename(fn));
+				if (!resMan.exists(resFile) || !resMan.open(resFile) || !resMan.hasResFork()) {
+					resMan.close();
+					resFile.clear();
+				}
+			}
+		}
+	}
+
+	if (resFile.empty()) {
+		warning("MacSndLoader::loadInstruments(): Resource fork not found");
+		return false;
+	}
+
+	Common::MacResIDArray ids = resMan.getResIDArray(MKTAG('s', 'n', 'd', ' '));
+	for (uint i = 0; i < ids.size(); ++i) {
+		Common::SeekableReadStream *str = resMan.getResource(MKTAG('s', 'n', 'd', ' '), ids[i]);
+		if (!str || str->readUint16BE() != 1) {
+			static const char *const errStr[2] = {"Failed to load", "Invalid sound resource format for"};
+			warning("MacSndLoader::loadInstruments(): %s instrument with id 0x%04x", errStr[str ? 1 : 0], ids[i]);
+			delete str;
+			return false;
+		}
+		Common::String nm(resMan.getResName(MKTAG('s', 'n', 'd', ' '), ids[i]));
+		memcpy(&tag, nm.c_str(), MIN<uint>(nm.size(), sizeof(tag)));
+		uint32 id = _useInstrTag ? FROM_BE_32(tag) : ids[i];
+		_instruments.push_back(Common::SharedPtr<Instrument>(new Instrument(id, str, Common::move(nm))));
+		delete str;
+	}
+
+	if (_instruments.size() != numInstruments)
+		warning("MacSndLoader::loadInstruments(): Unexpected number of instruments found (expected: %d, found: %d)", numInstruments, _instruments.size());
+
+	return true;
+}
+
+bool LoomMacSndLoader::init() {
+	static const char *execNames[] = {
+		"Loom",
+		"Loom\xaa",
+		"Loom PPC",
+		"Loom\xaa PPC"
+	};
+
+	return loadInstruments(execNames, ARRAYSIZE(execNames), 10);
+}
+
+bool LoomMacSndLoader::checkResource(const byte *data, uint32 dataSize) const {
+	return (dataSize >= 14 && READ_BE_UINT16(data + 4) == 'so' && !READ_BE_UINT32(data + 10));
+}
+
+bool LoomMacSndLoader::loadSound(byte synthType, const byte *data, uint32 dataSize) {
+	if (dataSize < 40)
+		return false;
+
+	_sndRes6 = READ_BE_UINT16(data + 6) & 0xff;
+	_isMusic = READ_BE_UINT16(data + 8) >> 8;
+	_sndRes10 = READ_BE_UINT16(data + 10) >> 8;
+	_chanSetup = READ_BE_UINT16(data + 16);
+	_timbre = READ_BE_UINT16(data + 18);
+	for (int i = 0; i < 5; ++i) {
+		_chanInstr[i] = fetchInstrument(READ_BE_UINT16(data + 20 + 2 * i));
+		_chanSndData[i] = data + READ_BE_UINT16(data + 30 + 2 * i) + 6;
+		_chanNumEvents[i] = READ_BE_UINT16(_chanSndData[i] - 2);
+		_chanCurEvent[i] = 0;
+	}
+
+	_synth = synthType;
+
+	return true;
+}
+
+bool LoomMacSndLoader::isInstrUsable(uint16 chan) const {
+	return (chan < ARRAYSIZE(_chanInstr) && _chanInstr[chan] && _chanInstr[chan]->get()->id() != 0x2D1C);
+}
+
+bool LoomMacSndLoader::parseNextEvent(uint16 chan, uint16 &duration, uint8 &note, bool &skip, bool &updateInstr) {
+	if (chan >= ARRAYSIZE(_chanSndData) || !_chanSndData[chan] || _chanCurEvent[chan] >= _chanNumEvents[chan])
+		return false;
+
+	const byte *s = _chanSndData[chan] + (_chanCurEvent[chan]++) * 3;
+	duration = READ_BE_UINT16(s);
+	note = s[2] & 0x7f;
+	skip = false;
+	updateInstr = false;
+
+	if (_synth == 4 && chan != 0 && note == 0)
+		note = 1;
+
+	return true;
+}
+
+const Common::SharedPtr<MacSndLoader::Instrument> *LoomMacSndLoader::fetchInstrument(uint16 id) const {
+	Common::Array<Common::SharedPtr<Instrument> >::const_iterator instr = _instruments.end();
+	for (Common::Array<Common::SharedPtr<Instrument> >::const_iterator i = _instruments.begin(); i != _instruments.end(); ++i) {
+		if ((*i)->id() == id)
+			return i;
+		else if ((*i)->id() == 0x2D1C)
+			instr = i;
+	}
+	return (instr != _instruments.end()) ? instr : nullptr;
+}
+
+bool MonkeyMacSndLoader::init() {
+	static const char *execNames[] = {
+		"Monkey Island"
+	};
+
+	return loadInstruments(execNames, ARRAYSIZE(execNames), _numInstrumentsMax - 1);
+}
+
+bool MonkeyMacSndLoader::checkResource(const byte *data, uint32 dataSize) const {
+	return (dataSize >= 14 && (READ_BE_UINT32(data) == 'Mac0' || READ_BE_UINT32(data) == 'Mac1'));
+}
+
+bool MonkeyMacSndLoader::blocked(const byte *data, uint32 dataSize) const {
+	return (dataSize < 14 || (_blockSfx && !data[13]));
+}
+
+bool MonkeyMacSndLoader::loadSound(byte synthType, const byte *data, uint32 dataSize) {
+	if (dataSize < 32)
+		return false;
+
+	_sndRes9 = data[9];
+	_isMusic = data[13];
+	_sndRes10 = data[10];
+	_chanSetup = data[11];
+	_sndRes12 = data[12];
+
+	for (int i = 0; i < 4; ++i) {
+		uint32 offs = READ_BE_UINT32(data + 16 + 4 * i);
+		_chanCurEvent[i] = 0;
+		if (offs) {
+			if (dataSize < offs + 12)
+				return false;
+			_chanInstr[i] = fetchInstrument(data, dataSize, READ_BE_UINT32(data + offs + 8));
+			_chanInstr2[i] = nullptr;
+			_chanSndData[i] = &data[offs + 12];
+			_chanNumEvents[i] = 0;
+
+			for (const byte *s = _chanSndData[i]; s < &data[dataSize - 4]; s += 4) {
+				uint32 in = READ_BE_UINT32(s);
+				if (in == MKTAG('L', 'o', 'o', 'p') || in == MKTAG('D', 'o', 'n', 'e')) {
+					if (i == 1)
+						_loop = (in == MKTAG('L', 'o', 'o', 'p'));
+					break;
+				}
+				_chanNumEvents[i]++;
+			}
+		} else {
+			_chanInstr[i] = nullptr;
+			_chanSndData[i] = nullptr;
+		}
+	}
+
+	_blockSfx = (_isMusic && _loop);
+	_synth = synthType;
+
+	return true;
+}
+
+bool MonkeyMacSndLoader::isInstrUsable(uint16 chan) const {
+	return (chan < ARRAYSIZE(_chanInstr) && _chanInstr[chan] && _chanInstr[chan]->get()->id() != MKTAG('s', 'i', 'l', 'e'));
+}
+
+bool MonkeyMacSndLoader::parseNextEvent(uint16 chan, uint16 &duration, uint8 &note, bool &skip, bool &updateInstr) {
+	if (chan >= ARRAYSIZE(_chanSndData) || !_chanSndData[chan] || _chanCurEvent[chan] >= _chanNumEvents[chan])
+		return false;
+
+	const byte *s = _chanSndData[chan] + (_chanCurEvent[chan]++) * 4;
+	duration = READ_BE_UINT16(s);
+	note = s[2];
+	skip = false;
+	updateInstr = true;
+
+	if (duration == 0 && _chanCurEvent[chan] == _chanNumEvents[chan])
+		skip = true;
+
+	if (_synth == 4) {
+		if (!skip && note == 0) {
+			note = 60;
+			_chanInstr2[chan] = _chanInstr[chan];
+			_chanInstr[chan] = fetchInstrument(nullptr, 0, MKTAG('s', 'i', 'l', 'e'));
+		} else if (_chanInstr2[chan]) {
+			_chanInstr[chan] = _chanInstr2[chan];
+			_chanInstr2[chan] = nullptr;
+		} else {
+			updateInstr = false;
+		}
+		if (note == 1)
+			skip = true;
+		else if (s[6] == 1)
+			duration += READ_BE_UINT16(s + 4);
+	} else {
+		updateInstr = false;
+		if (note == 1)
+			note = 0;
+		else if (note != 0)
+			note += _transpose;
+	}
+
+	return true;
+}
+
+const Common::SharedPtr<MacSndLoader::Instrument> *MonkeyMacSndLoader::fetchInstrument(const byte *data, uint32 dataSize, uint32 tagOrOffset) {
+	Common::Array<Common::SharedPtr<Instrument> >::const_iterator instr = _instruments.end();
+	if (tagOrOffset & ~0x7fffff) {
+		for (Common::Array<Common::SharedPtr<Instrument> >::const_iterator i = _instruments.begin(); i != _instruments.end(); ++i) {
+			if ((*i)->id() == tagOrOffset)
+				return i;
+			else if ((*i)->id() == MKTAG('s', 'i', 'l', 'e'))
+				instr = i;
+		}
+	} else if (dataSize >= tagOrOffset + 8) {
+		Common::SeekableReadStream *str = new Common::MemoryReadStream(&data[tagOrOffset + 8], READ_BE_UINT32(data + tagOrOffset + 4), DisposeAfterUse::NO);
+		if (_instruments.size() == _numInstrumentsMax)
+			_instruments.pop_back();
+		_instruments.push_back(Common::SharedPtr<Instrument>(new Instrument(READ_BE_UINT32(&data[tagOrOffset]), str, Common::String())));
+		delete str;
+		instr = _instruments.end() - 1;
+	}
+	return (instr != _instruments.end()) ? instr : nullptr;
+}
+
+Common::WeakPtr<LoomMonkeyMacSnd> *LoomMonkeyMacSnd::_inst = nullptr;
+
+LoomMonkeyMacSnd::LoomMonkeyMacSnd(ScummEngine *vm, Audio::Mixer *mixer) : VblTaskClientDriver(), _vm(vm), _mixer(mixer), _curSound(0), _loader(nullptr),
+	_macstr(nullptr), _sdrv(nullptr), _vblTskProc(this, &VblTaskClientDriver::vblCallback), _songTimer(0), _songTimerInternal(0),
+	_machineRating(0), _selectedQuality(2), _effectiveChanConfig(0), _16bit(false), _idRangeMax(200), _sndChannel(0), _chanUse(0), _defaultChanConfig(0),
+	_chanConfigTable(nullptr), _chanPlaying(0), _curChanConfig(0), _curSynthType(0), _curSndType(Audio::Mixer::kPlainSoundType), _mixerThread(false),
+	_restartSound(0), _lastSndType(Audio::Mixer::kPlainSoundType), _chanCbProc(this, &MacLowLevelPCMDriver::CallbackClient::sndChannelCallback),
+	_curSoundSaveVar(0), _saveVersionChange(vm->_game.id == GID_MONKEY ? 115 : 114), _legacySaveUnits(vm->_game.id == GID_MONKEY ? 3 : 5) {
+	assert(_vm);
+	assert(_mixer);
+
+	static const byte cfgtable[] = { 0, 0, 0, 1, 4, 5, 1, 5, 6, 6, 8, 9 };
+	_chanConfigTable = new byte[sizeof(cfgtable)]();
+	memcpy(_chanConfigTable, cfgtable, sizeof(cfgtable));
+
+	if (vm->_game.id == GID_MONKEY)
+		_chanConfigTable[10] = 7;
+
+	memset(_musChannels, 0, sizeof(_musChannels));
+}
+
+LoomMonkeyMacSnd::~LoomMonkeyMacSnd() {
+	_mixer->stopHandle(_soundHandle);
+	delete _macstr;
+	delete[] _chanConfigTable;
+
+	disposeAllChannels();
+	delete _sdrv;
+	delete _loader;
+
+	delete _inst;
+	_inst = nullptr;
+}
+
+Common::SharedPtr<LoomMonkeyMacSnd> LoomMonkeyMacSnd::open(ScummEngine *vm, Audio::Mixer *mixer) {
+	Common::SharedPtr<LoomMonkeyMacSnd> scp = nullptr;
+
+	if (_inst == nullptr) {
+		scp = Common::SharedPtr<LoomMonkeyMacSnd>(new LoomMonkeyMacSnd(vm, mixer));
+		_inst = new Common::WeakPtr<LoomMonkeyMacSnd>(scp);
+		// We can start this with the ScummVM mixer output rate instead of the ASC rate. The Mac sample rate converter can handle it (at
+		// least for up to 48 KHz, I haven't tried higher settings) and we don't have to do another rate conversion in the ScummVM mixer.
+		if ((_inst == nullptr) || (mixer == nullptr) || !(scp->startDevice(mixer->getOutputRate(), mixer->getOutputRate() << 16/*ASC_DEVICE_RATE*/, PCM_BUFFER_SIZE, true, false, true)))
+			error("LoomMonkeyMacSnd::open(): Failed to start player");
+	}
+
+	return _inst->lock();
+}
+
+bool LoomMonkeyMacSnd::startDevice(uint32 outputRate, uint32 pcmDeviceRate, uint32 feedBufferSize, bool enableInterpolation, bool stereo, bool internal16Bit) {
+	_macstr = new MacPlayerAudioStream(this, outputRate, stereo, enableInterpolation, internal16Bit);
+	if (!_macstr || !_mixer)
+		return false;
+
+	if (_vm->_game.id == GID_LOOM)
+		_loader = new LoomMacSndLoader();
+	else if(_vm->_game.id == GID_MONKEY)
+		_loader = new MonkeyMacSndLoader();
+
+	if (!_loader || !_loader->init())
+		return false;
+
+	_sdrv = new MacLowLevelPCMDriver(_mixer->mutex(), pcmDeviceRate, internal16Bit);
+	if (!_sdrv)
+		return false;
+
+	_effectiveChanConfig = 9;
+	_16bit = internal16Bit;
+
+	_macstr->initDrivers();
+	_macstr->initBuffers(feedBufferSize);
+	_macstr->setVblCallback(&_vblTskProc);
+
+	_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, _macstr, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+
+	return true;
+}
+
+void LoomMonkeyMacSnd::setMusicVolume(int vol) {
+	Common::StackLock lock(_mixer->mutex());
+	if (_macstr)
+		_macstr->setMasterVolume(Audio::Mixer::kMusicSoundType, vol);
+}
+
+void LoomMonkeyMacSnd::setSfxVolume(int vol) {
+	Common::StackLock lock(_mixer->mutex());
+	if (_macstr)
+		_macstr->setMasterVolume(Audio::Mixer::kSFXSoundType, vol);
+}
+
+void LoomMonkeyMacSnd::startSound(int id, int jumpToTick) {
+	if (_sdrv == nullptr || id < 0 || id >= _idRangeMax) {
+		warning("LoomMonkeyMacSnd::startSound(): sound id '%d' out of range (0 - %d)", id, _idRangeMax - 1);
+		return;
+	}
+
+	Common::StackLock lock(_mixer->mutex());
+
+	uint32 size = _vm->getResourceSize(rtSound, id);
+	const byte *ptr = _vm->getResourceAddress(rtSound, id);
+	assert(ptr);
+
+	if (!_loader->checkResource(ptr, size)) {
+		warning("LoomMonkeyMacSnd::startSound(): Sound resource '%d' cannot be played", id);
+		return;
+	}
+
+	if (_loader->blocked(ptr, size))
+		return;
+
+	stopActiveSound();
+	if (_chanUse <= 1)
+		disposeAllChannels();
+
+	if (!_defaultChanConfig)
+		detectQuality();
+
+	if (!_loader->loadSound(_curSynthType, ptr, size)) {
+		warning("LoomMonkeyMacSnd::startSound(): Sound resource '%d' cannot be played", id);
+		return;
+	}
+
+	//if (_sndDisableFlags && _loader->isMusic())
+	//	return;
+
+	_effectiveChanConfig = _loader->getChanSetup() ? _loader->getChanSetup() : _defaultChanConfig;
+	_curSndType = _loader->isMusic() ? Audio::Mixer::kMusicSoundType : Audio::Mixer::kSFXSoundType;
+
+	if (_lastSndType != _curSndType)
+		_curChanConfig = 0;
+
+	_curSound = id;
+	_curSoundSaveVar = _loader->isMusic() && _loader->isLooping() ? _curSound : 0;
+
+	setupChannels();
+	sendSoundCommands(jumpToTick);
+
+	if (!jumpToTick) {
+		_songTimer = 0;
+		_songTimerInternal = 0;
+	}
+}
+
+void LoomMonkeyMacSnd::stopSound(int id) {
+	if (id < 0 || id >= _idRangeMax) {
+		warning("LoomMonkeyMacSnd::stopSound(): sound id '%d' out of range (0 - %d)", id, _idRangeMax - 1);
+		return;
+	}
+
+	Common::StackLock lock(_mixer->mutex());
+
+	if (id == _curSound)
+		stopActiveSound();
+}
+
+void LoomMonkeyMacSnd::stopAllSounds() {
+	Common::StackLock lock(_mixer->mutex());
+	stopActiveSound();
+}
+
+int LoomMonkeyMacSnd::getMusicTimer() {
+	Common::StackLock lock(_mixer->mutex());
+	return _songTimer;
+}
+
+int LoomMonkeyMacSnd::getSoundStatus(int id) const {
+	if (id < 0 || id >= _idRangeMax) {
+		warning("LoomMonkeyMacSnd::getSoundStatus(): sound id '%d' out of range (0 - %d)", id, _idRangeMax - 1);
+		return 0;
+	}
+	Common::StackLock lock(_mixer->mutex());
+	return (_curSound == id) ? 1 : 0;
+}
+
+void LoomMonkeyMacSnd::setQuality(int qual) {
+	assert(qual >= MacSound::kQualityAuto && qual <= MacSound::kQualityHighest);
+	Common::StackLock lock(_mixer->mutex());
+
+	if (qual > MacSound::kQualityAuto) {
+		qual--;
+		if (!_loader->ignoreMachineRating())
+			_machineRating = (qual / 3) + 1;
+		_selectedQuality = qual % 3;
+		qual = _chanConfigTable[_machineRating * 3 + _selectedQuality];
+		if (qual && qual == _defaultChanConfig)
+			return;
+	}
+
+	int csnd = _curSound;
+	int32 timeStamp = csnd ? _songTimer * 1000 + ((_songTimerInternal * 1000) / 30) : 0;
+	stopActiveSound();
+	
+	detectQuality();
+	if (csnd)
+		startSound(csnd, timeStamp);
+}
+
+void LoomMonkeyMacSnd::saveLoadWithSerializer(Common::Serializer &ser) {
+	if (ser.isLoading() && ser.getVersion() < VER(94)) {
+		_curSound = _curSoundSaveVar = 0;
+		return;
+	}
+
+	if (ser.isLoading()) {
+		if (ser.getVersion() < VER(_saveVersionChange)) {
+			// Skip over old driver savedata, since it is not needed here.
+			ser.skip(4);
+			// We need only this
+			ser.syncAsSint16LE(_curSound);
+			_curSoundSaveVar = CLIP<int>(_curSound, 0, _idRangeMax - 1);
+			// Skip the rest
+			ser.skip(_legacySaveUnits * (ser.getVersion() >= VER(94) && ser.getVersion() <= VER(103) ? 24 : 20));
+		} else if (ser.getVersion() <= VER(114)) {
+			_curSoundSaveVar = 0;
+			byte tmp = 0;
+			for (int i = 0; !_curSoundSaveVar && i < 200; ++i) {
+				ser.syncAsByte(tmp);
+				if (tmp)
+					_curSoundSaveVar = i;
+			}
+		}
+	}
+	ser.syncAsSint16LE(_curSoundSaveVar, VER(115));
+}
+
+void LoomMonkeyMacSnd::restoreAfterLoad() {
+	int sound = _curSoundSaveVar;
+	stopActiveSound();
+	startSound(sound);
+}
+
+void LoomMonkeyMacSnd::vblCallback() {
+	if (_songTimerInternal++ == 29) {
+		_songTimerInternal = 0;
+		++_songTimer;
+	}
+
+	if (_restartSound) {
+		startSound(_restartSound);
+		_restartSound = 0;
+	}
+}
+
+void LoomMonkeyMacSnd::generateData(int8 *dst, uint32 len, Audio::Mixer::SoundType type, bool expectStereo) const {
+	assert(dst);
+	memset(dst, 0, len);
+	_sdrv->feed(dst, len, type, expectStereo);
+}
+
+const MacSoundDriver::Status &LoomMonkeyMacSnd::getDriverStatus(uint8, Audio::Mixer::SoundType sndType) const {
+	return _sdrv->getStatus(sndType);
+}
+
+void LoomMonkeyMacSnd::sndChannelCallback(uint16 arg1, const void*) {
+	// We do this a little smarter than the original player which would stop the track immediately when
+	// the first channel invoked its end-of-track callback. This would cut of the playback early, in an
+	// unpleasant way. Instead, we stop the playback not before all channels have finished.
+	_chanPlaying &= ~arg1;
+	if (_chanPlaying)
+		return;
+
+	if (_loader->isLooping())
+		_restartSound = _curSound;
+
+	stopActiveSound();
+}
+
+void LoomMonkeyMacSnd::sendSoundCommands(int timeStamp) {
+	if (!_defaultChanConfig || !_curSound)
+		return;
+
+	uint16 duration = 0;
+	byte note = 0;
+	bool skip = false;
+	bool updateInstr = false;
+	_chanPlaying = 0;
+
+	if (_chanUse == 1 && _sndChannel) {
+		while (_loader->parseNextEvent(0, duration, note, skip, updateInstr)) {
+			if (timeStamp > 0) {
+				int ts = timeStamp;
+				timeStamp = MAX<int>(0, timeStamp - duration);
+				duration -= ts;
+			}
+			if (timeStamp)
+				continue;
+
+			if (updateInstr)
+				_sdrv->loadInstrument(_sndChannel, MacLowLevelPCMDriver::kEnqueue, _loader->getInstrData(0));
+
+			if (!skip) {
+				_sdrv->playNote(_sndChannel, MacLowLevelPCMDriver::kEnqueue, note, duration);
+				if (note == 0) // Workaround for tempo glitch in original driver
+					_sdrv->wait(_sndChannel, MacLowLevelPCMDriver::kEnqueue, duration);
+			}
+		}
+		_sdrv->quiet(_sndChannel, MacLowLevelPCMDriver::kEnqueue);
+		_sdrv->callback(_sndChannel, MacLowLevelPCMDriver::kEnqueue, 1, nullptr);
+		_chanPlaying |= 1;
+
+	} else if (_chanUse == 4) {
+		int tmstmp[4];
+		uint8 busy = 0;
+
+		for (int i = 0; i < 4; ++i) {
+			tmstmp[i] = timeStamp;
+			if (_musChannels[i])
+				busy |= (1 << i);
+		}
+
+		while (busy) {
+			for (int i = 0; i < 4; ++i) {
+				if (!(busy & (1 << i)) || !_loader->parseNextEvent(i + 1, duration, note, skip, updateInstr)) {
+					busy &= ~(1 << i);
+					continue;
+				}
+				if (tmstmp[i] > 0) {
+					int ts = tmstmp[i];
+					tmstmp[i] = MAX<int>(0, tmstmp[i] - duration);
+					duration -= ts;
+				}
+
+				if (tmstmp[i])
+					continue;
+
+				if (updateInstr)
+					_sdrv->loadInstrument(_musChannels[i], MacLowLevelPCMDriver::kEnqueue, _loader->getInstrData(i + 1));
+
+				if (!skip) {
+					_sdrv->playNote(_musChannels[i], MacLowLevelPCMDriver::kEnqueue, note, duration);
+					// Workaround for tempo glitch in original driver. For the sampled synth in 4 channel mode, there is
+					// some sort of fix in the original (see parseNextEvent()), but that really does not work well for the other cases.
+					if (note == 0 && _curSynthType != 4)
+						_sdrv->wait(_musChannels[i], MacLowLevelPCMDriver::kEnqueue, duration);
+				}
+				_chanPlaying |= (1 << i);
+			}
+		}
+
+		
+		for (int i = 0; i < 4; ++i) {
+			if (_chanPlaying & (1 << i)) {
+				_sdrv->quiet(_musChannels[i], MacLowLevelPCMDriver::kEnqueue);
+				_sdrv->callback(_musChannels[i], MacLowLevelPCMDriver::kEnqueue, 1 << i, nullptr);
+			}
+		}
+	}
+}
+
+void LoomMonkeyMacSnd::stopActiveSound() {
+	if (_sndChannel) {
+		_sdrv->quiet(_sndChannel, MacLowLevelPCMDriver::kImmediate);
+		_sdrv->flush(_sndChannel, MacLowLevelPCMDriver::kImmediate);
+	}
+
+	for (int i = 0; i < ARRAYSIZE(_musChannels); ++i) {
+		if (_musChannels[i]) {
+			_sdrv->quiet(_musChannels[i], MacLowLevelPCMDriver::kImmediate);
+			_sdrv->flush(_musChannels[i], MacLowLevelPCMDriver::kImmediate);
+		}
+	}
+
+	_chanPlaying = 0;
+	_curSound = 0;
+	_curSoundSaveVar = 0;
+	_loader->unblock();
+}
+
+void LoomMonkeyMacSnd::setupChannels() {
+	static const byte synthType[] =	{ 0x00,	0x01, 0x02, 0x04, 0x04, 0x04, 0x02, 0x04, 0x04, 0x04 };
+	static const byte numChan[] =	{ 0x00,	0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x04, 0x04 };
+	static const byte attrib[] =	{ 0x00, 0x00, 0x04, 0xAC, 0xA4, 0xA0, 0x04, 0xAC, 0xA4, 0xA0 };
+
+	if (!_defaultChanConfig)
+		return;
+
+	if (_curChanConfig != _effectiveChanConfig) {
+		disposeAllChannels();
+		_curChanConfig = _effectiveChanConfig;
+		_curSynthType = synthType[_curChanConfig];
+		_chanUse = numChan[_curChanConfig];
+		_lastSndType = _curSndType;
+
+		switch (_curSynthType) {
+		case 1:
+			if (_chanUse == 1 && !_sndChannel) {
+				_sndChannel = _sdrv->createChannel(_curSndType, MacLowLevelPCMDriver::kSquareWaveSynth, attrib[_curChanConfig], &_chanCbProc);
+			}
+			break;
+		case 2:
+			if (_chanUse == 1 && !_sndChannel) {
+				_sndChannel = _sdrv->createChannel(_curSndType, MacLowLevelPCMDriver::kWaveTableSynth, attrib[_curChanConfig], &_chanCbProc);
+			} else if (_chanUse == 4) {
+				for (int i = 0; i < ARRAYSIZE(_musChannels); ++i) {
+					if (!_musChannels[i] && _loader->isInstrUsable(i + 1))
+						_musChannels[i] = _sdrv->createChannel(_curSndType, MacLowLevelPCMDriver::kWaveTableSynth, attrib[_curChanConfig] + i, &_chanCbProc);
+				}
+			}
+			break;
+		case 4:
+			if (_chanUse == 1 && !_sndChannel) {
+				_sndChannel = _sdrv->createChannel(_curSndType, MacLowLevelPCMDriver::kSampledSynth, attrib[_curChanConfig], &_chanCbProc);
+			} else if (_chanUse == 4) {
+				for (int i = 0; i < ARRAYSIZE(_musChannels); ++i) {
+					if (!_musChannels[i] && _loader->isInstrUsable(i + 1))
+						_musChannels[i] = _sdrv->createChannel(_curSndType, MacLowLevelPCMDriver::kSampledSynth, attrib[_curChanConfig], &_chanCbProc);
+				}
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	switch (_curSynthType) {
+	case 1:
+		if (_sndChannel)
+			_sdrv->setTimbre(_sndChannel, MacLowLevelPCMDriver::kImmediate, _loader->getTimbre());
+		break;
+	case 2:
+		if (_chanUse == 1) {
+			if (_sndChannel)
+				_sdrv->loadWaveTable(_sndChannel, MacLowLevelPCMDriver::kImmediate, _fourToneSynthWaveForm, _fourToneSynthWaveFormSize);
+		} else {
+			for (int i = 0; i < ARRAYSIZE(_musChannels); ++i) {
+				if (_musChannels[i])
+					_sdrv->loadWaveTable(_musChannels[i], MacLowLevelPCMDriver::kImmediate, _fourToneSynthWaveForm, _fourToneSynthWaveFormSize);
+			}
+		}
+		break;
+	case 4:
+		if (_chanUse == 1) {
+			if (_sndChannel && _loader->getInstrData(0))
+				_sdrv->loadInstrument(_sndChannel, MacLowLevelPCMDriver::kImmediate, _loader->getInstrData(0));
+		} else {
+			for (int i = 0; i < ARRAYSIZE(_musChannels); ++i) {
+				if (_musChannels[i] && _loader->getInstrData(i + 1))
+					_sdrv->loadInstrument(_musChannels[i], MacLowLevelPCMDriver::kImmediate, _loader->getInstrData(i + 1));
+			}
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+void LoomMonkeyMacSnd::disposeAllChannels() {
+	if (_sndChannel)
+		_sdrv->disposeChannel(_sndChannel);
+	_sndChannel = 0;
+
+	for (int i = 0; i < ARRAYSIZE(_musChannels); ++i) {
+		if (_musChannels[i])
+			_sdrv->disposeChannel(_musChannels[i]);
+		_musChannels[i] = 0;
+	}
+
+	_curChanConfig = 0;
+}
+
+void LoomMonkeyMacSnd::detectQuality() {
+	if (_machineRating == 0) {
+		if (!_loader->ignoreMachineRating()) {
+			if (isSoundCardType10())
+				_machineRating = 2;
+			/*else if (0)
+				_machineRating = 1;*/
+		}
+		_machineRating ^= 3;
+	}
+
+	_defaultChanConfig = _effectiveChanConfig = _chanConfigTable[_machineRating * 3 + _selectedQuality];
+	_curChanConfig = 0;
+	disposeAllChannels();
+	setupChannels();
+	_chanConfigTable[_machineRating * 3 + _selectedQuality] = _defaultChanConfig;
+}
+
+bool LoomMonkeyMacSnd::isSoundCardType10() const {
+	return _mixerThread ? (_machineRating == 1) : (_vm->VAR_SOUNDCARD != 0xff && _vm->VAR(_vm->VAR_SOUNDCARD) == 10);
+}
+
+#undef ASC_DEVICE_RATE
+#undef PCM_BUFFER_SIZE
+
+} // End of namespace Scumm
diff --git a/engines/scumm/players/player_mac_new.cpp b/engines/scumm/players/player_mac_new.cpp
index 7c0e5b5866d..a37c235641c 100644
--- a/engines/scumm/players/player_mac_new.cpp
+++ b/engines/scumm/players/player_mac_new.cpp
@@ -1050,7 +1050,7 @@ const uint8 _fourToneSynthWaveForm[256] = {
 const uint32 _fourToneSynthWaveFormSize = sizeof(_fourToneSynthWaveForm);
 
 class Indy3MacSnd;
-class LoomMacSnd;
+class LoomMonkeyMacSnd;
 
 template<typename T> class MusicEngineImpl : public MusicEngine {
 public:
@@ -1138,7 +1138,8 @@ MusicEngine *createPlayer(ScummEngine *vm) {
 		res = new MusicEngineImpl<Indy3MacSnd>(vm, vm->_mixer);
 		break;
 	case GID_LOOM:
-		res = new MusicEngineImpl<LoomMacSnd>(vm, vm->_mixer);
+	case GID_MONKEY:
+		res = new MusicEngineImpl<LoomMonkeyMacSnd>(vm, vm->_mixer);
 		break;
 	default:
 		break;
diff --git a/engines/scumm/players/player_mac_new.h b/engines/scumm/players/player_mac_new.h
index 3015880dbc8..d63be962fa5 100644
--- a/engines/scumm/players/player_mac_new.h
+++ b/engines/scumm/players/player_mac_new.h
@@ -32,6 +32,12 @@ namespace MacSound {
 enum {
 	kQualityAuto = 0,
 	kQualityLowest = 1,
+	kHardwareRatingLow = 0,
+	kHardwareRatingMedium = 3,
+	kHardwareRatingHigh = 6,
+	kQualitySelectionGood = 1,
+	kQualitySelectionBetter = 2,
+	kQualitySelectionBest = 3,
 	kQualityHighest = 9
 };
 
diff --git a/engines/scumm/players/player_v5m.cpp b/engines/scumm/players/player_v5m.cpp
index c113aad04c7..cba59227780 100644
--- a/engines/scumm/players/player_v5m.cpp
+++ b/engines/scumm/players/player_v5m.cpp
@@ -83,6 +83,7 @@ namespace Scumm {
 Player_V5M::Player_V5M(ScummEngine *scumm, Audio::Mixer *mixer)
 	: Player_Mac(scumm, mixer, 3, 0x07, false) {
 	assert(_vm->_game.id == GID_MONKEY);
+	//_lastVersionBeforeSaveFormatChange = VER(114);
 }
 
 bool Player_V5M::loadMusic(const byte *ptr) {
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index cd0913afbe0..1f26b094d48 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -69,7 +69,7 @@ struct SaveInfoSection {
 
 #define SaveInfoSectionSize (4+4+4 + 4+4 + 4+2)
 
-#define CURRENT_VER 114
+#define CURRENT_VER 115
 #define INFOSECTION_VERSION 2
 
 #pragma mark -
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index c4787408e87..b529b699ebe 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2166,11 +2166,14 @@ void ScummEngine::setupMusic(int midi, const Common::Path &macInstrumentFile) {
 #endif
 	} else if (_game.platform == Common::kPlatformAmiga && _game.version <= 4) {
 		_musicEngine = new Player_V4A(this, _mixer);
-	} else if (_game.platform == Common::kPlatformMacintosh && (_game.id == GID_INDY3 || _game.id == GID_LOOM)) {
-#if 0
+	} else if (_game.platform == Common::kPlatformMacintosh && (_game.id == GID_INDY3 || _game.id == GID_LOOM || _game.id == GID_MONKEY)) {
+#if 1
 		if (_game.id == GID_LOOM) {
 			_musicEngine = new Player_V3M(this, _mixer, ConfMan.getBool("mac_v3_low_quality_music"));
 			((Player_V3M *)_musicEngine)->init(macInstrumentFile);
+		} else if (_game.id == GID_MONKEY) {
+			_musicEngine = new Player_V5M(this, _mixer);
+			((Player_V5M *)_musicEngine)->init(macInstrumentFile);
 		} else
 #endif
 		{
@@ -2181,9 +2184,6 @@ void ScummEngine::setupMusic(int midi, const Common::Path &macInstrumentFile) {
 				_musicEngine->setQuality(ConfMan.getInt("mac_snd_quality"));
 			_sound->_musicType = MDT_MACINTOSH;
 		}
-	} else if (_game.platform == Common::kPlatformMacintosh && _game.id == GID_MONKEY) {
-		_musicEngine = new Player_V5M(this, _mixer);
-		((Player_V5M *)_musicEngine)->init(macInstrumentFile);
 	} else if (_game.id == GID_MANIAC && _game.version == 1) {
 		_musicEngine = new Player_V1(this, _mixer, MidiDriver::getMusicType(dev) != MT_PCSPK);
 	} else if (_game.version <= 2) {
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index 6526a742a0f..1007fd952b0 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -382,24 +382,6 @@ void Sound::triggerSound(int soundID) {
 		return;
 	}
 
-	// Support for SFX in Monkey Island 1, Mac version
-	// This is rather hackish right now, but works OK. SFX are not sounding
-	// 100% correct, though, not sure right now what is causing this.
-	else if (READ_BE_UINT32(ptr) == MKTAG('M','a','c','1')) {
-		// Read info from the header
-		size = READ_BE_UINT32(ptr+0x60);
-		rate = READ_BE_UINT16(ptr+0x64);
-
-		// Skip over the header (fixed size)
-		ptr += 0x72;
-
-		// Allocate a sound buffer, copy the data into it, and play
-		sound = (byte *)malloc(size);
-		memcpy(sound, ptr, size);
-
-		stream = Audio::makeRawStream(sound, size, rate, Audio::FLAG_UNSIGNED);
-		_mixer->playStream(Audio::Mixer::kSFXSoundType, nullptr, stream, soundID);
-	}
 	// WORKAROUND bug #2221
 	else if (READ_BE_UINT32(ptr) == 0x460e200d) {
 		// This sound resource occurs in the Macintosh version of Monkey Island.
diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp
index ae7c807bf7e..ac6269c70fe 100644
--- a/engines/scumm/vars.cpp
+++ b/engines/scumm/vars.cpp
@@ -862,6 +862,8 @@ void ScummEngine::setSoundCardVarToCurrentConfig() {
 			VAR(VAR_SOUNDCARD) = (ConfMan.hasKey("mac_v3_low_quality_music") && ConfMan.getBool("mac_v3_low_quality_music")) ? 10 : 11;
 		else if (_game.id == GID_LOOM)
 			VAR(VAR_SOUNDCARD) = (ConfMan.hasKey("mac_snd_quality") && ConfMan.getInt("mac_snd_quality") > 0 && ConfMan.getInt("mac_snd_quality") < 4) ? 10 : 11;
+		else if (_game.id == GID_MONKEY)
+			VAR(VAR_SOUNDCARD) = 0xffff;
 		else
 			VAR(VAR_SOUNDCARD) = 3;
 		break;




More information about the Scummvm-git-logs mailing list