[Scummvm-git-logs] scummvm master -> 157bd196db280df8c93fc2ee68ae83b174caaed2

AndywinXp noreply at scummvm.org
Sat Apr 16 21:25:38 UTC 2022


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

Summary:
024aa1f22b SCUMM: SMUSH: Implement audio sub-engine
71816ec701 SCUMM: DiMUSE: Fix startup volume setup for SMUSH
5c63294632 SCUMM: DiMUSE: Fix mixer behavior for 8-bit audio and mixBufStartIndex != 0
157bd196db SCUMM: INSANE: Remove instruction not present in the interpreter


Commit: 024aa1f22b307b48fbaca2395436375fb3d41875
    https://github.com/scummvm/scummvm/commit/024aa1f22b307b48fbaca2395436375fb3d41875
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-04-16T23:25:31+02:00

Commit Message:
SCUMM: SMUSH: Implement audio sub-engine

Changed paths:
  R engines/scumm/smush/channel.cpp
  R engines/scumm/smush/channel.h
  R engines/scumm/smush/saud_channel.cpp
  R engines/scumm/smush/smush_mixer.cpp
  R engines/scumm/smush/smush_mixer.h
    engines/scumm/imuse_digi/dimuse_defs.h
    engines/scumm/imuse_digi/dimuse_engine.cpp
    engines/scumm/imuse_digi/dimuse_engine.h
    engines/scumm/imuse_digi/dimuse_tracks.cpp
    engines/scumm/imuse_digi/dimuse_waveout.cpp
    engines/scumm/insane/insane.cpp
    engines/scumm/insane/insane.h
    engines/scumm/insane/insane_scenes.cpp
    engines/scumm/module.mk
    engines/scumm/scumm.cpp
    engines/scumm/smush/smush_player.cpp
    engines/scumm/smush/smush_player.h


diff --git a/engines/scumm/imuse_digi/dimuse_defs.h b/engines/scumm/imuse_digi/dimuse_defs.h
index 14a6e396e5e..1eb71d3b12e 100644
--- a/engines/scumm/imuse_digi/dimuse_defs.h
+++ b/engines/scumm/imuse_digi/dimuse_defs.h
@@ -41,6 +41,7 @@ namespace Scumm {
 #define DIMUSE_SMALL_FADE_DIM 44100
 
 #define DIMUSE_SAMPLERATE     22050
+#define DIMUSE_FEEDSIZE       512
 #define DIMUSE_NUM_WAVE_BUFS  8
 #define DIMUSE_SMUSH_SOUNDID  12345678
 #define DIMUSE_BUN_CHUNK_SIZE 0x2000
diff --git a/engines/scumm/imuse_digi/dimuse_engine.cpp b/engines/scumm/imuse_digi/dimuse_engine.cpp
index 055be9a8e96..de40eb00ff9 100644
--- a/engines/scumm/imuse_digi/dimuse_engine.cpp
+++ b/engines/scumm/imuse_digi/dimuse_engine.cpp
@@ -50,6 +50,7 @@ IMuseDigital::IMuseDigital(ScummEngine_v7 *scumm, Audio::Mixer *mixer)
 	_callbackFps = 50;
 	_usecPerInt = 20000;
 
+	_splayer = nullptr;
 	_isEarlyDiMUSE = (_vm->_game.id == GID_FT || (_vm->_game.id == GID_DIG && _vm->_game.features & GF_DEMO));
 
 	if (_isEarlyDiMUSE) {
@@ -642,6 +643,14 @@ int IMuseDigital::getSoundIdByName(const char *soundName) {
 	return 0;
 }
 
+void IMuseDigital::setSmushPlayer(SmushPlayer *splayer) {
+	_splayer = splayer;
+}
+
+void IMuseDigital::receiveAudioFromSMUSH(uint8 *srcBuf, int32 inFrameCount, int32 feedSize, int32 mixBufStartIndex, int volume, int pan, bool is11025Hz) {
+	_internalMixer->mix(srcBuf, inFrameCount, 8, 1, feedSize, mixBufStartIndex, volume, pan, is11025Hz);
+}
+
 void IMuseDigital::parseScriptCmds(int cmd, int soundId, int sub_cmd, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o, int p) {
 	int b = soundId;
 	int c = sub_cmd;
@@ -802,16 +811,22 @@ int IMuseDigital::diMUSELipSync(int soundId, int syncId, int msPos, int32 &width
 
 int IMuseDigital::diMUSESetMusicGroupVol(int volume) {
 	debug(5, "IMuseDigital::diMUSESetMusicGroupVol(): %d", volume);
+	if (_isEarlyDiMUSE)
+		_splayer->setGroupVolume(GRP_BKGMUS, volume);
 	return diMUSESetGroupVol(3, volume);
 }
 
 int IMuseDigital::diMUSESetSFXGroupVol(int volume) {
 	debug(5, "IMuseDigital::diMUSESetSFXGroupVol(): %d", volume);
+	if (_isEarlyDiMUSE)
+		_splayer->setGroupVolume(GRP_SFX, volume);
 	return diMUSESetGroupVol(1, volume);
 }
 
 int IMuseDigital::diMUSESetVoiceGroupVol(int volume) {
 	debug(5, "IMuseDigital::diMUSESetVoiceGroupVol(): %d", volume);
+	if (_isEarlyDiMUSE)
+		_splayer->setGroupVolume(GRP_SPEECH, volume);
 	return diMUSESetGroupVol(2, volume);
 }
 
diff --git a/engines/scumm/imuse_digi/dimuse_engine.h b/engines/scumm/imuse_digi/dimuse_engine.h
index 89451d161e2..23e6931537a 100644
--- a/engines/scumm/imuse_digi/dimuse_engine.h
+++ b/engines/scumm/imuse_digi/dimuse_engine.h
@@ -44,6 +44,8 @@
 #include "scumm/imuse_digi/dimuse_sndmgr.h"
 #include "scumm/imuse_digi/dimuse_tables.h"
 
+#include "scumm/smush/smush_player.h"
+
 #include "audio/mixer.h"
 #include "audio/decoders/raw.h"
 
@@ -55,6 +57,7 @@ class QueuingAudioStream;
 
 namespace Scumm {
 class ScummEngine_v7;
+class SmushPlayer;
 
 struct imuseDigTable;
 struct imuseComiTable;
@@ -67,6 +70,7 @@ private:
 	Common::Mutex _mutex;
 	ScummEngine_v7 *_vm;
 	Audio::Mixer *_mixer;
+	SmushPlayer *_splayer;
 
 	IMuseDigiInternalMixer *_internalMixer;
 	IMuseDigiGroupsHandler *_groupsHandler;
@@ -327,6 +331,8 @@ public:
 	void disableEngine();
 	bool isEngineDisabled();
 	void stopSMUSHAudio();
+	void receiveAudioFromSMUSH(uint8 *srcBuf, int32 inFrameCount, int32 feedSize, int32 mixBufStartIndex, int volume, int pan, bool is11025Hz);
+	void setSmushPlayer(SmushPlayer *splayer);
 
 	bool isFTSoundEngine(); // Used in the handlers to check if we're using the FT version of the engine
 
diff --git a/engines/scumm/imuse_digi/dimuse_tracks.cpp b/engines/scumm/imuse_digi/dimuse_tracks.cpp
index c2694a3c9a8..407cccfc5ba 100644
--- a/engines/scumm/imuse_digi/dimuse_tracks.cpp
+++ b/engines/scumm/imuse_digi/dimuse_tracks.cpp
@@ -162,6 +162,10 @@ void IMuseDigital::tracksCallback() {
 
 		if (_outputFeedSize != 0) {
 			_internalMixer->clearMixerBuffer();
+			if (_isEarlyDiMUSE && _splayer && _splayer->isAudioCallbackEnabled()) {
+				_splayer->processDispatches(_outputFeedSize);
+			}
+
 			if (!_tracksPauseTimer) {
 				IMuseDigiTrack *track = _trackList;
 
diff --git a/engines/scumm/imuse_digi/dimuse_waveout.cpp b/engines/scumm/imuse_digi/dimuse_waveout.cpp
index 1d0c8378894..7311ad9b8f9 100644
--- a/engines/scumm/imuse_digi/dimuse_waveout.cpp
+++ b/engines/scumm/imuse_digi/dimuse_waveout.cpp
@@ -29,7 +29,7 @@ int IMuseDigital::waveOutInit(int sampleRate, waveOutParamsStruct *waveOutSettin
 	_waveOutBytesPerSample = 2;
 	_waveOutNumChannels = 2;
 	_waveOutZeroLevel = 0;
-	_waveOutPreferredFeedSize = 512;
+	_waveOutPreferredFeedSize = DIMUSE_FEEDSIZE;
 
 	// Nine buffers (waveOutPreferredFeedSize * 4 bytes each), two will be used for the mixer
 	_waveOutOutputBuffer = (uint8 *)malloc(_waveOutNumChannels * _waveOutBytesPerSample * _waveOutPreferredFeedSize * 9);
diff --git a/engines/scumm/insane/insane.cpp b/engines/scumm/insane/insane.cpp
index c21a360d591..37997f0c968 100644
--- a/engines/scumm/insane/insane.cpp
+++ b/engines/scumm/insane/insane.cpp
@@ -104,6 +104,10 @@ void Insane::setSmushParams(int speed) {
 	_speed = speed;
 }
 
+void Insane::setSmushPlayer(SmushPlayer *player) {
+	_player = player;
+}
+
 void Insane::initvars() {
 	int i, j;
 
@@ -768,6 +772,7 @@ int32 Insane::idx2Tweak() {
 void Insane::smush_setToFinish() {
 	debugC(DEBUG_INSANE, "Video is set to finish");
 	_vm->_smushVideoShouldFinish = true;
+	_player->resetAudioTracks();
 }
 
 // smlayer_stopSound
diff --git a/engines/scumm/insane/insane.h b/engines/scumm/insane/insane.h
index 798138ad6e3..4d2ad351295 100644
--- a/engines/scumm/insane/insane.h
+++ b/engines/scumm/insane/insane.h
@@ -54,6 +54,7 @@ class Insane {
 	~Insane();
 
 	void setSmushParams(int speed);
+	void setSmushPlayer(SmushPlayer *player);
 	void runScene(int arraynum);
 
 	void procPreRendering();
diff --git a/engines/scumm/insane/insane_scenes.cpp b/engines/scumm/insane/insane_scenes.cpp
index 2a87146da5d..1e59a6115f3 100644
--- a/engines/scumm/insane/insane_scenes.cpp
+++ b/engines/scumm/insane/insane_scenes.cpp
@@ -34,7 +34,6 @@ namespace Scumm {
 
 void Insane::runScene(int arraynum) {
 	_insaneIsRunning = true;
-	_player = _vm->_splayer;
 	_player->insanity(true);
 
 	_numberArray = arraynum;
@@ -278,17 +277,17 @@ void Insane::stopSceneSounds(int sceneId) {
 	default:
 		break;
 	}
-	if (!flag)
-		return;
 
-	smlayer_setActorCostume(0, 2, 0);
-	smlayer_setActorCostume(0, 0, 0);
-	smlayer_setActorCostume(0, 1, 0);
-	smlayer_setActorCostume(1, 2, 0);
-	smlayer_setActorCostume(1, 0, 0);
-	smlayer_setActorCostume(1, 1, 0);
+	_player->resetAudioTracks();
 
-	return;
+	if (flag) {
+		smlayer_setActorCostume(0, 2, 0);
+		smlayer_setActorCostume(0, 0, 0);
+		smlayer_setActorCostume(0, 1, 0);
+		smlayer_setActorCostume(1, 2, 0);
+		smlayer_setActorCostume(1, 0, 0);
+		smlayer_setActorCostume(1, 1, 0);
+	}
 }
 
 void Insane::shutCurrentScene() {
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 31fafa428f4..02f4802739c 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -112,14 +112,11 @@ MODULE_OBJS += \
 	insane/insane_enemy.o \
 	insane/insane_scenes.o \
 	insane/insane_iact.o \
-	smush/channel.o \
 	smush/codec1.o \
 	smush/codec20.o \
 	smush/codec37.o \
 	smush/codec47.o \
-	smush/smush_player.o \
-	smush/saud_channel.o \
-	smush/smush_mixer.o
+	smush/smush_player.o
 
 ifdef USE_ARM_SMUSH_ASM
 MODULE_OBJS += \
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index c25c611aadc..c5e81284617 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -42,7 +42,6 @@
 #include "scumm/file_nes.h"
 #include "scumm/imuse/imuse.h"
 #include "scumm/imuse_digi/dimuse_engine.h"
-#include "scumm/smush/smush_mixer.h"
 #include "scumm/smush/smush_player.h"
 #include "scumm/players/player_towns.h"
 #include "scumm/insane/insane.h"
@@ -1084,10 +1083,6 @@ ScummEngine_v7::ScummEngine_v7(OSystem *syst, const DetectorResult &dr)
 }
 
 ScummEngine_v7::~ScummEngine_v7() {
-	if (_smixer) {
-		_smixer->stop();
-		delete _smixer;
-	}
 	if (_splayer) {
 		_splayer->release();
 		delete _splayer;
@@ -1695,11 +1690,9 @@ void ScummEngine_v7::setupScumm(const Common::String &macResourceFile) {
 	if (_game.id == GID_FT)
 		_insane = new Insane(this);
 	else
-		_insane = 0;
-
-	_smixer = new SmushMixer(_mixer);
+		_insane = nullptr;
 
-	_splayer = new SmushPlayer(this, _imuseDigital);
+	_splayer = new SmushPlayer(this, _imuseDigital, _insane);
 }
 #endif
 
@@ -2921,9 +2914,8 @@ void ScummEngine_v7::scummLoop_handleSound() {
 		_imuseDigital->refreshScripts();
 	}
 
-	if (_smixer) {
-		_smixer->flush();
-	}
+	_splayer->setChanFlag(0, VAR(VAR_VOICE_MODE) != 0);
+	_splayer->setChanFlag(2, VAR(VAR_VOICE_MODE) != 2);
 }
 #endif
 
diff --git a/engines/scumm/smush/channel.cpp b/engines/scumm/smush/channel.cpp
deleted file mode 100644
index 728602247b1..00000000000
--- a/engines/scumm/smush/channel.cpp
+++ /dev/null
@@ -1,116 +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 "common/textconsole.h"
-
-#include "scumm/smush/channel.h"
-
-namespace Scumm {
-
-SmushChannel::SmushChannel(int32 track) :
-	_track(track),
-	_tbuffer(nullptr),
-	_tbufferSize(0),
-	_sbuffer(nullptr),
-	_sbufferSize(0),
-	_dataSize(-1),
-	_inData(false),
-	_volume(0),
-	_pan(0) {
-}
-
-SmushChannel::~SmushChannel() {
-	free(_tbuffer);
-	free(_sbuffer);
-}
-
-void SmushChannel::processBuffer() {
-	assert(_tbuffer != nullptr);
-	assert(_tbufferSize != 0);
-	assert(_sbuffer == nullptr);
-	assert(_sbufferSize == 0);
-
-	if (_inData) {
-		if (_dataSize < _tbufferSize) {
-			int32 offset = _dataSize;
-			while (handleSubTags(offset))
-				;
-			_sbufferSize = _dataSize;
-			_sbuffer = _tbuffer;
-			if (offset < _tbufferSize) {
-				int new_size = _tbufferSize - offset;
-				_tbuffer = (byte *)malloc(new_size);
-				// FIXME: _tbuffer might be 0 if new_size is 0.
-				// NB: Also check other "if (_tbuffer)" locations in smush
-				if (!_tbuffer)
-					error("smush channel failed to allocate memory");
-				memcpy(_tbuffer, _sbuffer + offset, new_size);
-				_tbufferSize = new_size;
-			} else {
-				_tbuffer = nullptr;
-				_tbufferSize = 0;
-			}
-			if (_sbufferSize == 0) {
-				free(_sbuffer);
-				_sbuffer = nullptr;
-			}
-		} else {
-			_sbufferSize = _tbufferSize;
-			_sbuffer = _tbuffer;
-			_tbufferSize = 0;
-			_tbuffer = nullptr;
-		}
-	} else {
-		int32 offset = 0;
-		while (handleSubTags(offset))
-			;
-		if (_inData) {
-			_sbufferSize = _tbufferSize - offset;
-			assert(_sbufferSize);
-			_sbuffer = (byte *)malloc(_sbufferSize);
-			if (!_sbuffer)
-				error("smush channel failed to allocate memory");
-			memcpy(_sbuffer, _tbuffer + offset, _sbufferSize);
-			free(_tbuffer);
-			_tbuffer = nullptr;
-			_tbufferSize = 0;
-		} else {
-			if (offset) {
-				byte *old = _tbuffer;
-				int32 new_size = _tbufferSize - offset;
-				_tbuffer = (byte *)malloc(new_size);
-				// NB: Also check other "if (_tbuffer)" locations in smush
-				if (!_tbuffer) {
-					if (new_size)
-						error("smush channel failed to allocate memory");
-				} else {
-					memcpy(_tbuffer, old + offset, new_size);
-				}
-				_tbufferSize = new_size;
-				free(old);
-			}
-		}
-	}
-}
-
-
-} // End of namespace Scumm
diff --git a/engines/scumm/smush/channel.h b/engines/scumm/smush/channel.h
deleted file mode 100644
index c2dee0b4ed7..00000000000
--- a/engines/scumm/smush/channel.h
+++ /dev/null
@@ -1,97 +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/>.
- *
- */
-
-#ifndef SCUMM_SMUSH_CHANNEL_H
-#define SCUMM_SMUSH_CHANNEL_H
-
-#include "common/util.h"
-
-namespace Common {
-class SeekableReadStream;
-}
-
-namespace Scumm {
-
-class SmushChannel {
-protected:
-	int32 _track;				///< the track number
-	byte *_tbuffer;	///< data temporary buffer
-	int32 _tbufferSize;			///< temporary buffer size
-	byte *_sbuffer;	///< sound buffer
-	int32 _sbufferSize;			///< sound buffer size
-
-	int32 _dataSize;			///< remaining size of sound data in the iMUS buffer
-
-	bool _inData;
-
-	int32 _volume;
-	int32 _pan;
-
-	void processBuffer();
-
-	virtual bool handleSubTags(int32 &offset) = 0;
-
-public:
-	SmushChannel(int32 track);
-	virtual ~SmushChannel();
-	virtual bool appendData(Common::SeekableReadStream &b, int32 size) = 0;
-	virtual bool setParameters(int32, int32, int32, int32, int32) = 0;
-	virtual bool checkParameters(int32, int32, int32, int32, int32) = 0;
-	virtual bool isTerminated() const = 0;
-	virtual byte *getSoundData() = 0;
-	virtual int32 getRate() = 0;
-	virtual bool getParameters(bool &stereo, bool &is_16bit, int32 &vol, int32 &pan) = 0;
-
-	int32 getAvailableSoundDataSize() const { return _sbufferSize; }
-	int32 getTrackIdentifier() const { return _track; }
-};
-
-class SaudChannel : public SmushChannel {
-private:
-	int32 _nbframes;
-	bool _markReached;
-	int32 _flags;
-	int32 _index;
-	bool _keepSize;
-
-protected:
-	bool handleSubTags(int32 &offset) override;
-
-public:
-	SaudChannel(int32 track);
-	bool isTerminated() const override;
-	bool setParameters(int32 duration, int32 flags, int32 vol1, int32 vol2, int32 index) override;
-	bool checkParameters(int32 index, int32 duration, int32 flags, int32 vol1, int32 vol2) override;
-	bool appendData(Common::SeekableReadStream &b, int32 size) override;
-	byte *getSoundData() override;
-	int32 getRate() override { return 22050; }
-	bool getParameters(bool &stereo, bool &is_16bit, int32 &vol, int32 &pan) override {
-		stereo = false;
-		is_16bit = false;
-		vol = _volume;
-		pan = _pan;
-		return true;
-	}
-};
-
-} // End of namespace Scumm
-
-#endif
diff --git a/engines/scumm/smush/saud_channel.cpp b/engines/scumm/smush/saud_channel.cpp
deleted file mode 100644
index cdbb4af1e9a..00000000000
--- a/engines/scumm/smush/saud_channel.cpp
+++ /dev/null
@@ -1,172 +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 "common/endian.h"
-#include "common/stream.h"
-#include "common/textconsole.h"
-
-#include "scumm/util.h"
-#include "scumm/smush/channel.h"
-
-namespace Scumm {
-
-SaudChannel::SaudChannel(int32 track) : SmushChannel(track),
-	_nbframes(0),
-	_markReached(false),
-	_index(0),
-	_keepSize(false),
-	_flags(0) {
-}
-
-bool SaudChannel::isTerminated() const {
-	return (_markReached && _dataSize == 0 && _sbuffer == nullptr);
-}
-
-bool SaudChannel::handleSubTags(int32 &offset) {
-	if (_tbufferSize - offset >= 8) {
-		uint32 type = READ_BE_UINT32(_tbuffer + offset);
-		uint32 size = READ_BE_UINT32(_tbuffer + offset + 4);
-		uint32 available_size = _tbufferSize - offset;
-
-		switch (type) {
-		case MKTAG('S','T','R','K'):
-			_inData = false;
-			if (available_size >= (size + 8)) {
-				int32 subSize = READ_BE_UINT32((byte *)_tbuffer + offset + 4);
-				if (subSize != 14 && subSize != 10) {
-					error("STRK has an invalid size : %d", subSize);
-				}
-			} else
-				return false;
-			break;
-		case MKTAG('S','M','R','K'):
-			_inData = false;
-			if (available_size >= (size + 8))
-				_markReached = true;
-			else
-				return false;
-			break;
-		case MKTAG('S','H','D','R'):
-			_inData = false;
-			if (available_size >= (size + 8)) {
-				int32 subSize = READ_BE_UINT32((byte *)_tbuffer + offset + 4);
-				if (subSize != 4)
-					error("SHDR has an invalid size : %d", subSize);
-			} else
-				return false;
-			break;
-		case MKTAG('S','D','A','T'):
-			_inData = true;
-			_dataSize = size;
-			offset += 8;
-			return false;
-		default:
-			error("unknown Chunk in SAUD track : %s ", tag2str(type));
-		}
-		offset += size + 8;
-		return true;
-	}
-	return false;
-}
-
-bool SaudChannel::setParameters(int32 nb, int32 flags, int32 volume, int32 pan, int32 index) {
-	_nbframes = nb;
-	_flags = flags; // bit 7 == IS_VOICE, bit 6 == IS_BACKGROUND_MUSIC, other ??
-	_volume = volume;
-	_pan = pan;
-	_index = index;
-	if (index != 0) {
-		_dataSize = -2;
-		_keepSize = true;
-		_inData = true;
-	}
-	return true;
-}
-
-bool SaudChannel::checkParameters(int32 index, int32 nb, int32 flags, int32 volume, int32 pan) {
-	if (++_index != index)
-		error("invalid index in SaudChannel::checkParameters()");
-	if (_nbframes != nb)
-		error("invalid duration in SaudChannel::checkParameters()");
-	if (_flags != flags)
-		error("invalid flags in SaudChannel::checkParameters()");
-	if (_volume != volume || _pan != pan) {
-		_volume = volume;
-		_pan = pan;
-	}
-	return true;
-}
-
-bool SaudChannel::appendData(Common::SeekableReadStream &b, int32 size) {
-	if (_dataSize == -1) {
-		assert(size > 8);
-		uint32 saud_type = b.readUint32BE();
-		/*uint32 saud_size =*/ b.readUint32BE();
-		if (saud_type != MKTAG('S','A','U','D'))
-			error("Invalid Chunk for SaudChannel : %X", saud_type);
-		size -= 8;
-		_dataSize = -2;
-	}
-	if (_tbuffer) {
-		byte *old = _tbuffer;
-		_tbuffer = (byte *)malloc(_tbufferSize + size);
-		if (!_tbuffer)
-			error("saud_channel failed to allocate memory");
-		memcpy(_tbuffer, old, _tbufferSize);
-		free(old);
-		b.read(_tbuffer + _tbufferSize, size);
-		_tbufferSize += size;
-	} else {
-		_tbufferSize = size;
-		_tbuffer = (byte *)malloc(_tbufferSize);
-		if (!_tbuffer)
-			error("saud_channel failed to allocate memory");
-		b.read(_tbuffer, _tbufferSize);
-	}
-
-	if (_keepSize) {
-		_sbufferSize = _tbufferSize;
-		_sbuffer = _tbuffer;
-		_tbufferSize = 0;
-		_tbuffer = nullptr;
-	} else {
-		processBuffer();
-	}
-
-	return true;
-}
-
-byte *SaudChannel::getSoundData() {
-	byte *tmp = _sbuffer;
-
-	if (!_keepSize) {
-		assert(_dataSize > 0);
-		_dataSize -= _sbufferSize;
-	}
-
-	_sbuffer = nullptr;
-	_sbufferSize = 0;
-
-	return tmp;
-}
-
-} // End of namespace Scumm
diff --git a/engines/scumm/smush/smush_mixer.cpp b/engines/scumm/smush/smush_mixer.cpp
deleted file mode 100644
index 44a087c7beb..00000000000
--- a/engines/scumm/smush/smush_mixer.cpp
+++ /dev/null
@@ -1,168 +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/smush/smush_mixer.h"
-#include "scumm/smush/channel.h"
-#include "scumm/scumm.h"
-
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
-#include "audio/decoders/raw.h"
-
-
-namespace Scumm {
-
-SmushMixer::SmushMixer(Audio::Mixer *m) :
-	_mixer(m),
-	_soundFrequency(22050) {
-	for (int32 i = 0; i < NUM_CHANNELS; i++) {
-		_channels[i].id = -1;
-		_channels[i].chan = nullptr;
-		_channels[i].stream = nullptr;
-	}
-}
-
-SmushMixer::~SmushMixer() {
-	for (int32 i = 0; i < NUM_CHANNELS; i++) {
-		_mixer->stopHandle(_channels[i].handle);
-	}
-}
-
-SmushChannel *SmushMixer::findChannel(int32 track) {
-	debugC(DEBUG_SMUSH, "SmushMixer::findChannel(%d)", track);
-	for (int32 i = 0; i < NUM_CHANNELS; i++) {
-		if (_channels[i].id == track)
-			return _channels[i].chan;
-	}
-	return nullptr;
-}
-
-void SmushMixer::addChannel(SmushChannel *c) {
-	int32 track = c->getTrackIdentifier();
-	int i;
-
-	debugC(DEBUG_SMUSH, "SmushMixer::addChannel(%d)", track);
-
-	for (i = 0; i < NUM_CHANNELS; i++) {
-		if (_channels[i].id == track)
-			debugC(DEBUG_SMUSH, "SmushMixer::addChannel(%d): channel already exists", track);
-	}
-
-	for (i = 0; i < NUM_CHANNELS; i++) {
-		if ((_channels[i].chan == nullptr || _channels[i].id == -1) && !_mixer->isSoundHandleActive(_channels[i].handle)) {
-			_channels[i].chan = c;
-			_channels[i].id = track;
-			return;
-		}
-	}
-
-	for (i = 0; i < NUM_CHANNELS; i++) {
-		debugC(DEBUG_SMUSH, "channel %d : %p(%d, %d)", i, (void *)_channels[i].chan,
-			_channels[i].chan ? _channels[i].chan->getTrackIdentifier() : -1,
-			_channels[i].chan ? _channels[i].chan->isTerminated() : 1);
-	}
-
-	error("SmushMixer::addChannel(%d): no channel available", track);
-}
-
-bool SmushMixer::handleFrame() {
-	debugC(DEBUG_SMUSH, "SmushMixer::handleFrame()");
-	for (int i = 0; i < NUM_CHANNELS; i++) {
-		if (_channels[i].id != -1) {
-			if (_channels[i].chan->isTerminated()) {
-				delete _channels[i].chan;
-				_channels[i].id = -1;
-				_channels[i].chan = nullptr;
-				if (_channels[i].stream) {
-					_channels[i].stream->finish();
-					_channels[i].stream = nullptr;
-				}
-			} else {
-				int32 vol, pan;
-				bool stereo, is_16bit;
-
-				_channels[i].chan->getParameters(stereo, is_16bit, vol, pan);
-
-				// Grab the audio data from the channel
-				int32 size = _channels[i].chan->getAvailableSoundDataSize();
-				byte *data = _channels[i].chan->getSoundData();
-
-				byte flags = stereo ? Audio::FLAG_STEREO : 0;
-				if (is_16bit) {
-					flags |= Audio::FLAG_16BITS;
-				} else {
-					flags |= Audio::FLAG_UNSIGNED;
-				}
-
-				if (_mixer->isReady()) {
-					// Stream the data
-					if (!_channels[i].stream) {
-						_channels[i].stream = Audio::makeQueuingAudioStream(_channels[i].chan->getRate(), stereo);
-						_mixer->playStream(Audio::Mixer::kSFXSoundType, &_channels[i].handle, _channels[i].stream);
-					}
-					_mixer->setChannelVolume(_channels[i].handle, vol);
-					_mixer->setChannelBalance(_channels[i].handle, pan);
-					_channels[i].stream->queueBuffer(data, size, DisposeAfterUse::YES, flags);	// The stream will free the buffer for us
-				} else
-					delete[] data;
-			}
-		}
-	}
-	return true;
-}
-
-bool SmushMixer::stop() {
-	debugC(DEBUG_SMUSH, "SmushMixer::stop()");
-	for (int i = 0; i < NUM_CHANNELS; i++) {
-		if (_channels[i].id != -1) {
-			delete _channels[i].chan;
-			_channels[i].id = -1;
-			_channels[i].chan = nullptr;
-			if (_channels[i].stream) {
-				_channels[i].stream->finish();
-				_channels[i].stream = nullptr;
-			}
-			_mixer->stopHandle(_channels[i].handle);
-		}
-	}
-
-	return true;
-}
-
-bool SmushMixer::flush() {
-	debugC(DEBUG_SMUSH, "SmushMixer::flush()");
-	for (int i = 0; i < NUM_CHANNELS; i++) {
-		if (_channels[i].id != -1) {
-			if (_channels[i].stream->endOfStream()) {
-				_mixer->stopHandle(_channels[i].handle);
-				delete _channels[i].chan;
-				_channels[i].id = -1;
-				_channels[i].chan = nullptr;
-				_channels[i].stream = nullptr;
-			}
-		}
-	}
-
-	return true;
-}
-
-} // End of namespace Scumm
diff --git a/engines/scumm/smush/smush_mixer.h b/engines/scumm/smush/smush_mixer.h
deleted file mode 100644
index c3c47530981..00000000000
--- a/engines/scumm/smush/smush_mixer.h
+++ /dev/null
@@ -1,70 +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/>.
- *
- */
-
-#ifndef SCUMM_SMUSH_MIXER_H
-#define SCUMM_SMUSH_MIXER_H
-
-
-#include "audio/mixer.h"
-#include "common/mutex.h"
-#include "scumm/sound.h"
-
-namespace Audio {
-class QueuingAudioStream;
-}
-
-namespace Scumm {
-
-class SmushChannel;
-
-class SmushMixer {
-	enum {
-		NUM_CHANNELS = 16
-	};
-private:
-
-	Audio::Mixer *_mixer;
-	struct channels {
-		int id;
-		SmushChannel *chan;
-		Audio::SoundHandle handle;
-		Audio::QueuingAudioStream *stream;
-	} _channels[NUM_CHANNELS];
-
-	int _soundFrequency;
-
-	Common::Mutex _mutex;
-
-public:
-
-	SmushMixer(Audio::Mixer *);
-	virtual ~SmushMixer();
-	SmushChannel *findChannel(int32 track);
-	void addChannel(SmushChannel *c);
-	bool handleFrame();
-	bool stop();
-	bool flush();
-	bool update();
-};
-
-} // End of namespace Scumm
-
-#endif
diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp
index 9f1e10462c6..f3a51bcd390 100644
--- a/engines/scumm/smush/smush_player.cpp
+++ b/engines/scumm/smush/smush_player.cpp
@@ -35,11 +35,9 @@
 #include "scumm/scumm.h"
 #include "scumm/scumm_v7.h"
 #include "scumm/sound.h"
-#include "scumm/smush/channel.h"
 #include "scumm/smush/codec37.h"
 #include "scumm/smush/codec47.h"
 #include "scumm/smush/smush_font.h"
-#include "scumm/smush/smush_mixer.h"
 #include "scumm/smush/smush_player.h"
 
 #include "scumm/insane/insane.h"
@@ -74,10 +72,10 @@ public:
 	StringResource() :
 		_nbStrings(0),
 		_lastId(-1),
-		_lastString(NULL) {
+		_lastString(nullptr) {
 		for (int i = 0; i < MAX_STRINGS; i++) {
 			_strings[i].id = 0;
-			_strings[i].string = NULL;
+			_strings[i].string = nullptr;
 		}
 	}
 	~StringResource() {
@@ -88,9 +86,9 @@ public:
 
 	bool init(char *buffer, int32 length) {
 		char *def_start = strchr(buffer, '#');
-		while (def_start != NULL) {
+		while (def_start != nullptr) {
 			char *def_end = strchr(def_start, '\n');
-			assert(def_end != NULL);
+			assert(def_end != nullptr);
 
 			char *id_end = def_end;
 			while (id_end >= def_start && !Common::isDigit(*(id_end-1))) {
@@ -215,27 +213,27 @@ void SmushPlayer::timerCallback() {
 	parseNextFrame();
 }
 
-SmushPlayer::SmushPlayer(ScummEngine_v7 *scumm, IMuseDigital *imuseDigital) {
+SmushPlayer::SmushPlayer(ScummEngine_v7 *scumm, IMuseDigital *imuseDigital, Insane *insane) {
 	_vm = scumm;
 	_imuseDigital = imuseDigital;
+	_insane = insane;
 	_nbframes = 0;
 	_codec37 = 0;
 	_codec47 = 0;
-	_smixer = NULL;
-	_strings = NULL;
-	_sf[0] = NULL;
-	_sf[1] = NULL;
-	_sf[2] = NULL;
-	_sf[3] = NULL;
-	_sf[4] = NULL;
-	_base = NULL;
-	_frameBuffer = NULL;
-	_specialBuffer = NULL;
+	_strings = nullptr;
+	_sf[0] = nullptr;
+	_sf[1] = nullptr;
+	_sf[2] = nullptr;
+	_sf[3] = nullptr;
+	_sf[4] = nullptr;
+	_base = nullptr;
+	_frameBuffer = nullptr;
+	_specialBuffer = nullptr;
 
 	_seekPos = -1;
 
 	_skipNext = false;
-	_dst = NULL;
+	_dst = nullptr;
 	_storeFrame = false;
 	_compressedFileMode = false;
 	_width = 0;
@@ -245,8 +243,7 @@ SmushPlayer::SmushPlayer(ScummEngine_v7 *scumm, IMuseDigital *imuseDigital) {
 	_insanity = false;
 	_middleAudio = false;
 	_skipPalette = false;
-	_IACTstream = NULL;
-	_smixer = _vm->_smixer;
+	_IACTstream = nullptr;
 	_paused = false;
 	_pauseStartTime = 0;
 	_pauseTime = 0;
@@ -256,11 +253,22 @@ SmushPlayer::SmushPlayer(ScummEngine_v7 *scumm, IMuseDigital *imuseDigital) {
 
 	_IACTchannel = new Audio::SoundHandle();
 	_compressedFileSoundHandle = new Audio::SoundHandle();
+
+	_smushNumTracks = 0;
+	_gainReductionLowerBound = 64;
+	_gainReductionFactor = 256;
+	_gainReductionMultiplier = 256;
+	_smushTracksNeedInit = true;
+	_smushAudioInitialized = false;
+	_smushAudioCallbackEnabled = false;
+
+	initAudio(DIMUSE_SAMPLERATE, 200000);
 }
 
 SmushPlayer::~SmushPlayer() {
 	delete _IACTchannel;
 	delete _compressedFileSoundHandle;
+	terminateAudio();
 }
 
 void SmushPlayer::init(int32 speed) {
@@ -290,7 +298,7 @@ void SmushPlayer::init(int32 speed) {
 	_vm->_mixer->stopHandle(*_compressedFileSoundHandle);
 	_vm->_mixer->stopHandle(*_IACTchannel);
 	_IACTpos = 0;
-	_vm->_smixer->stop();
+	resetAudioTracks();
 }
 
 void SmushPlayer::release() {
@@ -298,22 +306,22 @@ void SmushPlayer::release() {
 
 	for (int i = 0; i < 5; i++) {
 		delete _sf[i];
-		_sf[i] = NULL;
+		_sf[i] = nullptr;
 	}
 
 	delete _strings;
-	_strings = NULL;
+	_strings = nullptr;
 
 	delete _base;
-	_base = NULL;
+	_base = nullptr;
 
 	free(_specialBuffer);
-	_specialBuffer = NULL;
+	_specialBuffer = nullptr;
 
 	free(_frameBuffer);
-	_frameBuffer = NULL;
+	_frameBuffer = nullptr;
 
-	_IACTstream = NULL;
+	_IACTstream = nullptr;
 
 	_vm->_smushActive = false;
 	_vm->_fullRedraw = true;
@@ -329,45 +337,6 @@ void SmushPlayer::release() {
 	_codec47 = 0;
 }
 
-void SmushPlayer::handleSoundBuffer(int32 track_id, int32 index, int32 max_frames, int32 flags, int32 vol, int32 pan, Common::SeekableReadStream &b, int32 size) {
-	debugC(DEBUG_SMUSH, "SmushPlayer::handleSoundBuffer(%d, %d)", track_id, index);
-//	if ((flags & 128) == 128) {
-//		return;
-//	}
-//	if ((flags & 64) == 64) {
-//		return;
-//	}
-	SmushChannel *c = _smixer->findChannel(track_id);
-	if (c == NULL) {
-		c = new SaudChannel(track_id);
-		_smixer->addChannel(c);
-	}
-
-	if (_middleAudio || index == 0) {
-		c->setParameters(max_frames, flags, vol, pan, index);
-	} else {
-		c->checkParameters(index, max_frames, flags, vol, pan);
-	}
-	_middleAudio = false;
-	c->appendData(b, size);
-}
-
-void SmushPlayer::handleSoundFrame(int32 subSize, Common::SeekableReadStream &b) {
-	debugC(DEBUG_SMUSH, "SmushPlayer::handleSoundFrame()");
-
-	int32 track_id = b.readUint16LE();
-	int32 index = b.readUint16LE();
-	int32 max_frames = b.readUint16LE();
-	int32 flags = b.readUint16LE();
-	int32 vol = b.readByte();
-	int32 pan = b.readSByte();
-	if (index == 0) {
-		debugC(DEBUG_SMUSH, "track_id:%d, max_frames:%d, flags:%d, vol:%d, pan:%d", track_id, max_frames, flags, vol, pan);
-	}
-	int32 size = subSize - 10;
-	handleSoundBuffer(track_id, index, max_frames, flags, vol, pan, b, size);
-}
-
 void SmushPlayer::handleStore(int32 subSize, Common::SeekableReadStream &b) {
 	debugC(DEBUG_SMUSH, "SmushPlayer::handleStore()");
 	assert(subSize >= 4);
@@ -378,7 +347,7 @@ void SmushPlayer::handleFetch(int32 subSize, Common::SeekableReadStream &b) {
 	debugC(DEBUG_SMUSH, "SmushPlayer::handleFetch()");
 	assert(subSize >= 6);
 
-	if (_frameBuffer != NULL) {
+	if (_frameBuffer != nullptr) {
 		memcpy(_dst, _frameBuffer, _width * _height);
 	}
 }
@@ -402,7 +371,7 @@ void SmushPlayer::handleIACT(int32 subSize, Common::SeekableReadStream &b) {
 	}
 
 	assert(flags == 46 && unknown == 0);
-	/*int track_id =*/ b.readUint16LE();
+	/*int trkId =*/ b.readUint16LE();
 	int index = b.readUint16LE();
 	int nbframes = b.readUint16LE();
 	/*int32 size =*/ b.readUint32LE();
@@ -585,7 +554,7 @@ void SmushPlayer::handleTextResource(uint32 subType, int32 subSize, Common::Seek
 	/*int32 unk2 =*/ b.readUint16LE();
 
 	const char *str;
-	char *string = NULL, *string2 = NULL;
+	char *string = nullptr, *string2 = nullptr;
 	if (subType == MKTAG('T','E','X','T')) {
 		string = (char *)malloc(subSize - 16);
 		str = string;
@@ -654,7 +623,7 @@ void SmushPlayer::handleTextResource(uint32 subType, int32 subSize, Common::Seek
 	}
 
 	SmushFont *sf = getFont(fontId);
-	assert(sf != NULL);
+	assert(sf != nullptr);
 
 	// The hack that used to be here to prevent bug #2220 is no longer necessary and
 	// has been removed. The font renderer can handle all ^codes it encounters (font
@@ -706,7 +675,7 @@ const char *SmushPlayer::getString(int id) {
 
 bool SmushPlayer::readString(const char *file) {
 	const char *i = strrchr(file, '.');
-	if (i == NULL) {
+	if (i == nullptr) {
 		error("invalid filename : %s", file);
 	}
 	char fname[260];
@@ -820,7 +789,7 @@ void SmushPlayer::decodeFrameObject(int codec, const uint8 *src, int left, int t
 	}
 
 	if (_storeFrame) {
-		if (_frameBuffer == NULL) {
+		if (_frameBuffer == nullptr) {
 			_frameBuffer = (byte *)malloc(_width * _height);
 		}
 		memcpy(_frameBuffer, _dst, _width * _height);
@@ -887,6 +856,7 @@ void SmushPlayer::handleFrameObject(int32 subSize, Common::SeekableReadStream &b
 
 void SmushPlayer::handleFrame(int32 frameSize, Common::SeekableReadStream &b) {
 	debugC(DEBUG_SMUSH, "SmushPlayer::handleFrame(%d)", _frame);
+	uint8 *audioChunk = nullptr;
 	_skipNext = false;
 
 	if (_insanity) {
@@ -910,8 +880,15 @@ void SmushPlayer::handleFrame(int32 frameSize, Common::SeekableReadStream &b) {
 			break;
 #endif
 		case MKTAG('P','S','A','D'):
-			if (!_compressedFileMode)
-				handleSoundFrame(subSize, b);
+			if (!_compressedFileMode) {
+				audioChunk = (uint8 *)malloc(subSize + 8);
+				b.seek(-8, SEEK_CUR);
+				b.read(audioChunk, subSize + 8);
+				feedAudio(audioChunk, 0, 127, 0, 0);
+				free(audioChunk);
+				audioChunk = nullptr;
+			}
+
 			break;
 		case MKTAG('T','R','E','S'):
 			handleTextResource(subType, subSize, b);
@@ -953,7 +930,6 @@ void SmushPlayer::handleFrame(int32 frameSize, Common::SeekableReadStream &b) {
 	if (_width != 0 && _height != 0) {
 		updateScreen();
 	}
-	_smixer->handleFrame();
 
 	_frame++;
 }
@@ -1014,9 +990,6 @@ SmushFont *SmushPlayer::getFont(int font) {
 void SmushPlayer::parseNextFrame() {
 
 	if (_seekPos >= 0) {
-		if (_smixer)
-			_smixer->stop();
-
 		if (_seekFile.size() > 0) {
 			delete _base;
 
@@ -1288,11 +1261,12 @@ void SmushPlayer::play(const char *filename, int32 speed, int32 offset, int32 st
 		if (_endOfFile)
 			break;
 		if (_vm->shouldQuit() || _vm->_saveLoadFlag || _vm->_smushVideoShouldFinish) {
-			_smixer->stop();
 			_vm->_mixer->stopHandle(*_compressedFileSoundHandle);
 			_vm->_mixer->stopHandle(*_IACTchannel);
 			_IACTpos = 0;
-			_imuseDigital->stopSMUSHAudio();
+
+			resetAudioTracks(); // For DIG demo
+			_imuseDigital->stopSMUSHAudio(); // For DIG & COMI
 			break;
 		}
 		_vm->_system->delayMillis(10);
@@ -1304,4 +1278,763 @@ void SmushPlayer::play(const char *filename, int32 speed, int32 offset, int32 st
 	CursorMan.showMouse(oldMouseState);
 }
 
+void SmushPlayer::initAudio(int samplerate, int32 maxChunkSize) {
+	int32 maxSizes[SMUSH_MAX_TRACKS] = {100000, 100000, 100000, 400000};
+
+	_imuseDigital->setSmushPlayer(this);
+
+	// DIG demo uses this audio system but doesn't use INSANE
+	if (_insane)
+		_insane->setSmushPlayer(this);
+
+	setGainReductionParams(114, 2048);
+
+	memset(_smushAudioTable, 0, sizeof(_smushAudioTable));
+
+	for (int i = 0; i < SMUSH_MAX_TRACKS; i++) {
+		_smushTrackVols[i] = 127;
+		_smushTrackFlags[i] = 1;
+		addAudioTrack(maxSizes[i], maxChunkSize);
+	}
+
+	_smushAudioSampleRate = samplerate;
+	_smushAudioInitialized = true;
+	_smushAudioCallbackEnabled = true;
+}
+
+void SmushPlayer::terminateAudio() {
+	if (_smushAudioInitialized) {
+		_smushAudioInitialized = false;
+		_smushAudioCallbackEnabled = false;
+	}
+
+	for (int i = 0; i < _smushNumTracks; i++) {
+		free(_smushTracks[i].blockPtr);
+		free(_smushTracks[i].fadeBuf);
+	}
+	_smushNumTracks = 0;
+}
+
+int SmushPlayer::isChanActive(int flagId) {
+	return _smushTrackFlags[flagId];
+}
+
+int SmushPlayer::setChanFlag(int id, int flagVal) {
+	if (id >= 0 && id <= _smushNumTracks)
+		_smushTrackFlags[id] = flagVal;
+
+	return id;
+}
+
+int SmushPlayer::addAudioTrack(int32 trackBlockSize, int32 maxBlockSize) {
+	int id = _smushNumTracks;
+	_smushTracks[id].state = TRK_STATE_INACTIVE;
+	_smushTracks[id].audioRemaining = 0;
+	_smushTracks[id].flags = 0;
+	_smushTracks[id].groupId = GRP_MASTER;
+	_smushTracks[id].blockSize = trackBlockSize;
+	_smushTracks[id].parsedChunks = 0;
+
+	_smushTracks[id].fadeBuf = (uint8 *)malloc(SMUSH_FADE_SIZE);
+	if (!_smushTracks[id].fadeBuf)
+		return -1;
+
+	_smushTracks[id].blockPtr = (uint8 *)malloc(_smushTracks[id].blockSize);
+	if (!_smushTracks[id].blockPtr)
+		return -1;
+
+	memset(_smushTracks[id].blockPtr, 127, _smushTracks[id].blockSize);
+	// Track the effective number of tracks, so that if only one fails,
+	// the others can carry on as they should
+	_smushNumTracks++;
+
+	return 0;
+}
+
+void SmushPlayer::resetAudioTracks() {
+	for (int i = 0; i < _smushNumTracks; i++) {
+		_smushTracks[i].state = TRK_STATE_INACTIVE;
+		_smushTracks[i].groupId = GRP_MASTER;
+	}
+}
+
+void SmushPlayer::setGainReductionParams(int16 gainReductionLowerBound, int16 gainReductionMultiplier) {
+	if (gainReductionLowerBound)
+		_gainReductionLowerBound = gainReductionLowerBound;
+	if (gainReductionMultiplier)
+		_gainReductionFactor = gainReductionMultiplier;
+}
+
+void SmushPlayer::setGroupVolume(int groupId, int volValue) {
+	switch (groupId) {
+	case GRP_MASTER:
+		_smushTrackVols[0] = volValue; // Master
+		break;
+	case GRP_SFX:
+		_smushTrackVols[1] = volValue; // Sfx
+		break;
+	case GRP_BKGMUS:
+		_smushTrackVols[3] = volValue; // Music
+		break;
+	case GRP_SPEECH:
+		_smushTrackVols[2] = volValue; // Voice
+		break;
+	default: // Internal groups
+		for (int i = 0; i < SMUSH_MAX_TRACKS; i++) {
+			if (_smushTracks[i].groupId == groupId)
+				_smushTracks[i].volume = volValue;
+		}
+	}
+}
+
+void SmushPlayer::handleSAUDChunk(uint8 *srcBuf, uint32 size, int groupId, int vol, int pan, int16 flags, int trkId, int index, int maxFrames) {
+	int targetTrk, diff1, diff2;
+	uint32 dataSize, mod;
+	int32 maxBlockSize, saudSize;
+	uint16 flagsAccumulator[SMUSH_MAX_TRACKS];
+
+	if (!index) {
+		saudSize = READ_BE_UINT32(&srcBuf[4]);
+
+		// Find the maximum block sizes between the current ones
+		maxBlockSize = 0;
+		for (int i = 0; i < _smushNumTracks; i++) {
+			if (_smushTracks[i].blockSize > maxBlockSize) {
+				maxBlockSize = _smushTracks[i].blockSize;
+			}
+		}
+
+		diff2 = 10000000;
+		if ((flags & TRK_TYPE_MASK) != IS_BKG_MUSIC) {
+			for (int i = 0; i < _smushNumTracks; i++) {
+				if (_smushTracks[i].blockSize - saudSize >= 0) {
+					diff1 = _smushTracks[i].blockSize - saudSize;
+				} else {
+					diff1 = saudSize - _smushTracks[i].blockSize;
+				}
+
+				if (diff1 < diff2 && saudSize < 3 * _smushTracks[i].blockSize / 2) {
+					if (_smushTracks[i].blockSize - saudSize >= 0) {
+						diff2 = _smushTracks[i].blockSize - saudSize;
+					} else {
+						diff2 = saudSize - _smushTracks[i].blockSize;
+					}
+
+					maxBlockSize = _smushTracks[i].blockSize;
+				}
+			}
+		}
+
+		for (int i = 0; i < _smushNumTracks; i++) {
+			flagsAccumulator[i] = 0;
+			if (_smushTracks[i].blockSize == maxBlockSize) {
+				if (_smushTracks[i].state == TRK_STATE_INACTIVE ||
+					_smushTracks[i].state == TRK_STATE_ENDING   ||
+					_smushTracks[i].flags <= flags) {
+					if (_smushTracks[i].state == TRK_STATE_INACTIVE)
+						flagsAccumulator[i] = 0x1000;
+
+					if (_smushTracks[i].state == TRK_STATE_ENDING)
+						flagsAccumulator[i] += 0x200;
+
+					if (_smushTracks[i].flags == flags)
+						flagsAccumulator[i] += 0x400;
+
+					if (_smushTracks[i].flags < flags)
+						flagsAccumulator[i] += 0x800;
+
+					flagsAccumulator[i] += _smushTracks[i].parsedChunks + 1;
+				}
+			}
+		}
+		fillAudioTrackInfo(srcBuf, flagsAccumulator, size, groupId, vol, pan, flags, trkId, index, maxFrames);
+		return;
+	}
+
+	targetTrk = -1;
+	for (int i = 0; i < _smushNumTracks; i++) {
+		if (_smushTracks[i].state != TRK_STATE_INACTIVE &&
+			trkId == _smushTrackIds[i] &&
+			index == (_smushTrackIdxs[i] + 1) &&
+			maxFrames == _smushMaxFrames[i]) {
+			targetTrk = i;
+			break;
+		}
+	}
+
+	if (targetTrk != -1) {
+		_smushTrackIdxs[targetTrk]++;
+		dataSize = _smushTracks[targetTrk].dataSize;
+		mod = _smushTracks[targetTrk].availableSize % dataSize;
+
+		if (mod + size <= dataSize) {
+			memcpy(&_smushTracks[targetTrk].subChunkPtr[mod], srcBuf, size);
+		} else {
+			memcpy(&_smushTracks[targetTrk].subChunkPtr[mod], srcBuf, dataSize - mod);
+			memcpy(
+				_smushTracks[targetTrk].subChunkPtr,
+				&srcBuf[_smushTracks[targetTrk].dataSize - mod],
+				size + mod - _smushTracks[targetTrk].dataSize);
+		}
+
+		if (vol >= 0 && vol < 128)
+			_smushTracks[targetTrk].volume = vol;
+
+		if (pan > -128 && pan < 128)
+			_smushTracks[targetTrk].pan = pan;
+
+		_smushTracks[targetTrk].availableSize += size;
+	}
+}
+
+void SmushPlayer::fillAudioTrackInfo(uint8 *srcBuf, uint16 *flagsAccumulator, uint32 size, int groupId, int vol, int pan, int16 flags, int trkId, int index, int maxFrames) {
+	uint32 sdatSize, subChunkOffset, chunkSize;
+
+	int maxFlagAcc = -1;
+	int maxAccId = -1;
+
+	for (int i = 0; i < _smushNumTracks; i++) {
+		if (flagsAccumulator[i] && flagsAccumulator[i] > maxFlagAcc) {
+			maxFlagAcc = flagsAccumulator[i];
+			maxAccId = i;
+		}
+	}
+
+	if (maxAccId != -1) {
+		for (int i = 0; i < _smushNumTracks; i++) {
+			if (_smushTracks[i].parsedChunks < 255) {
+				_smushTracks[i].parsedChunks++;
+			}
+		}
+
+		_smushTracks[maxAccId].parsedChunks = 0;
+		_smushTracks[maxAccId].state = TRK_STATE_INACTIVE;
+		_smushTrackIds[maxAccId] = trkId;
+		_smushTrackIdxs[maxAccId] = 0;
+		_smushMaxFrames[maxAccId] = maxFrames;
+		subChunkOffset = READ_BE_UINT32(&srcBuf[12]);
+		sdatSize = READ_BE_UINT32(&srcBuf[subChunkOffset + 20]);
+
+		chunkSize = _smushTracks[maxAccId].blockSize;
+
+		if (size < chunkSize)
+			chunkSize = size;
+
+		memset(_smushTracks[maxAccId].blockPtr, 127, _smushTracks[maxAccId].blockSize);
+		memcpy(_smushTracks[maxAccId].blockPtr, srcBuf, chunkSize);
+		_smushTracks[maxAccId].dataBuf = _smushTracks[maxAccId].blockPtr + 16;
+		_smushTracks[maxAccId].dataSize = _smushTracks[maxAccId].blockSize - subChunkOffset - 24;
+		_smushTracks[maxAccId].subChunkPtr = &_smushTracks[maxAccId].dataBuf[subChunkOffset + 8];
+		_smushTracks[maxAccId].availableSize = size - subChunkOffset - 24;
+		_smushTracks[maxAccId].sdatSize = sdatSize;
+		_smushTracks[maxAccId].groupId = groupId;
+		_smushTracks[maxAccId].volume = 127;
+		_smushTracks[maxAccId].pan = 0;
+
+		if (vol >= 0 && vol < 128)
+			_smushTracks[maxAccId].volume = vol;
+
+		if (pan > -128 && pan < 128)
+			_smushTracks[maxAccId].pan = pan;
+
+		_smushTracks[maxAccId].flags = flags;
+		_smushTracks[maxAccId].audioRemaining = 0;
+		_smushTracks[maxAccId].state = TRK_STATE_FADING;
+	}
+
+	return;
+}
+
+void SmushPlayer::processDispatches(int16 feedSize) {
+	int32 fadeStartOffset, cpySize, fadeRemaining, fadeFeedSize, mixFeedSize, mixInFrameCount;
+	int32 offset, tmpFeedSize, maxFadeChunkSize;
+	int16 fadeInFrameCount, flags, fadeMixStartingPoint;
+
+	int fadePan, fadeVolume, mixPan, mixVolume, baseVolume, mixStartingPoint;
+
+	bool isPlayableTrack;
+	bool speechIsPlaying = false;
+
+	if (!_paused) {
+		if (_smushTracksNeedInit) {
+			_smushTracksNeedInit = false;
+			for (int i = 0; i < SMUSH_MAX_TRACKS; i++) {
+				_smushDispatch[i].fadeRemaining = 0;
+				_smushDispatch[i].audioLength = 0;
+			}
+		}
+
+		for (int i = 0; i < _smushNumTracks; i++) {
+			isPlayableTrack = ((_smushTracks[i].flags & TRK_TYPE_MASK) == IS_SPEECH    && isChanActive(CHN_SPEECH)) ||
+							  ((_smushTracks[i].flags & TRK_TYPE_MASK) == IS_BKG_MUSIC && isChanActive(CHN_BKGMUS)) ||
+							  ((_smushTracks[i].flags & TRK_TYPE_MASK) == IS_SFX       && isChanActive(CHN_OTHER));
+			flags = _smushTracks[i].flags;
+
+			switch (flags & TRK_TYPE_MASK) {
+			case IS_SFX:
+				baseVolume = (_smushTrackVols[1] * _smushTracks[i].volume) >> 7;
+				break;
+			case IS_BKG_MUSIC:
+				baseVolume = (_smushTrackVols[3] * _smushTracks[i].volume) >> 7;
+				break;
+			case IS_SPEECH:
+				baseVolume = (_smushTrackVols[2] * _smushTracks[i].volume) >> 7;
+				break;
+			default:
+				error("SmushPlayer::processDispatches(): unrecognized flag %d", _smushTracks[i].flags & TRK_TYPE_MASK);
+			};
+
+			mixVolume = baseVolume * _smushTrackVols[0] / 127;
+			if ((flags & TRK_TYPE_MASK) == IS_BKG_MUSIC && isChanActive(CHN_SPEECH))
+				mixVolume = ((baseVolume * _smushTrackVols[0] / 127) * _gainReductionMultiplier) >> 8;
+
+			// Check if there's the need to allocate a crossfade
+			if (_smushTracks[i].state == TRK_STATE_FADING && _smushDispatch[i].state == TRK_STATE_PLAYING) {
+				fadeStartOffset = _smushDispatch[i].audioRemaining % _smushDispatch[i].dataSize;
+				_smushDispatch[i].fadeRemaining = SMUSH_FADE_SIZE;
+				_smushDispatch[i].fadeVolume = _smushTracks[i].volume;
+				_smushDispatch[i].fadeSampleRate = _smushDispatch[i].sampleRate;
+
+				memset(_smushTracks[i].fadeBuf, 127, _smushDispatch[i].fadeRemaining);
+				cpySize = _smushDispatch[i].dataSize - fadeStartOffset;
+
+				if (cpySize > _smushDispatch[i].fadeRemaining)
+					cpySize = _smushDispatch[i].fadeRemaining;
+				memcpy(_smushTracks[i].fadeBuf, &_smushDispatch[i].dataBuf[fadeStartOffset], cpySize);
+
+				_smushDispatch[i].volumeStep = 0;
+			} else if (_smushTracks[i].state == TRK_STATE_PLAYING) {
+				if (_smushDispatch[i].audioRemaining < _smushTracks[i].availableSize - _smushTracks[i].dataSize + 15000) {
+					if (_smushTracks[i].availableSize < _smushTracks[i].sdatSize) {
+						_smushDispatch[i].volumeStep = 0;
+						mixInFrameCount = _smushTracks[i].availableSize - _smushDispatch[i].audioRemaining - 15000;
+
+						if (mixInFrameCount > _smushDispatch[i].currentOffset)
+							mixInFrameCount = _smushDispatch[i].currentOffset;
+
+						if (_smushDispatch[i].audioRemaining + mixInFrameCount > _smushTracks[i].sdatSize - _smushDispatch[i].dataSize)
+							mixInFrameCount = _smushTracks[i].sdatSize - _smushDispatch[i].dataSize - _smushDispatch[i].audioRemaining;
+
+						if (mixInFrameCount > 0) {
+							_smushDispatch[i].fadeRemaining = SMUSH_FADE_SIZE;
+							_smushDispatch[i].fadeSampleRate = _smushDispatch[i].sampleRate;
+
+							memcpy(
+								_smushTracks[i].fadeBuf,
+								&_smushDispatch[i].dataBuf[_smushDispatch[i].audioRemaining % _smushDispatch[i].dataSize],
+								_smushDispatch[i].fadeRemaining);
+
+							_smushDispatch[i].audioRemaining += mixInFrameCount;
+							_smushDispatch[i].currentOffset -= mixInFrameCount;
+						}
+					}
+				}
+			}
+
+			// If the fade has been allocated, flush it in the mixer
+			if (_smushDispatch[i].fadeRemaining) {
+				maxFadeChunkSize = _smushDispatch[i].fadeSampleRate * feedSize / _smushAudioSampleRate;
+
+				if (_smushDispatch[i].fadeRemaining > maxFadeChunkSize) {
+					fadeRemaining = maxFadeChunkSize;
+				} else {
+					fadeRemaining = _smushDispatch[i].fadeRemaining;
+				}
+
+				fadeMixStartingPoint = 0;
+				while (fadeRemaining) {
+					fadeInFrameCount = (fadeRemaining < DIMUSE_FEEDSIZE / 2) ? fadeRemaining : DIMUSE_FEEDSIZE / 2;
+
+					if (fadeInFrameCount == maxFadeChunkSize) {
+						fadeFeedSize = feedSize;
+					} else {
+						fadeFeedSize = _smushAudioSampleRate * fadeInFrameCount / _smushDispatch[i].fadeSampleRate;
+					}
+
+					if (isPlayableTrack) {
+						fadeVolume = _smushDispatch[i].fadeRemaining * _smushDispatch[i].fadeVolume * _smushTrackVols[0] / (SMUSH_FADE_SIZE * 127);
+						fadePan = _smushTracks[i].pan;
+
+						sendAudioToDiMUSE(
+							&_smushTracks[i].fadeBuf[SMUSH_FADE_SIZE - _smushDispatch[i].fadeRemaining],
+							fadeMixStartingPoint,
+							fadeFeedSize,
+							fadeInFrameCount,
+							fadeVolume,
+							fadePan);
+					}
+
+					fadeMixStartingPoint += fadeFeedSize;
+					fadeRemaining -= fadeInFrameCount;
+					_smushDispatch[i].fadeRemaining -= fadeInFrameCount;
+				}
+			}
+
+			if (_smushTracks[i].state == TRK_STATE_FADING) {
+				if (_smushDispatch[i].state != TRK_STATE_PLAYING)
+					_smushDispatch[i].volumeStep = 16;
+
+				_smushDispatch[i].headerPtr = _smushTracks[i].dataBuf;
+				_smushDispatch[i].dataBuf = _smushTracks[i].subChunkPtr;
+				_smushDispatch[i].dataSize = _smushTracks[i].dataSize;
+				_smushDispatch[i].currentOffset = 0;
+				_smushDispatch[i].audioLength = 0;
+				_smushTracks[i].state = TRK_STATE_PLAYING;
+			}
+
+			if (_smushTracks[i].state != TRK_STATE_INACTIVE) {
+				tmpFeedSize = feedSize;
+				mixStartingPoint = 0;
+				if (feedSize > 0) {
+					while (1) {
+						mixInFrameCount = _smushDispatch[i].currentOffset;
+						if (mixInFrameCount > 0) {
+							offset = _smushDispatch[i].audioRemaining % _smushDispatch[i].dataSize;
+
+							if (mixInFrameCount > _smushDispatch[i].sampleRate * tmpFeedSize / _smushAudioSampleRate)
+								mixInFrameCount = _smushDispatch[i].sampleRate * tmpFeedSize / _smushAudioSampleRate;
+
+							if (offset + mixInFrameCount > _smushDispatch[i].dataSize)
+								mixInFrameCount = _smushDispatch[i].dataSize - offset;
+
+							if (mixInFrameCount + _smushDispatch[i].audioRemaining <= _smushTracks[i].availableSize) {
+								// Fade-in until full volume is reached
+								if (_smushDispatch[i].volumeStep < 16)
+									_smushDispatch[i].volumeStep++;
+
+								if (mixInFrameCount > DIMUSE_FEEDSIZE / 2)
+									mixInFrameCount = DIMUSE_FEEDSIZE / 2;
+
+								_smushTracks[i].state = TRK_STATE_PLAYING;
+
+								// This flag is toggled one time per chunk: if it's yields "true" for
+								// even one track, it stays like that for the whole chunk
+								speechIsPlaying = !speechIsPlaying ? (_smushTracks[i].flags & TRK_TYPE_MASK) == IS_SPEECH : true;
+							} else {
+								// Fade-out until silent
+								if (_smushDispatch[i].volumeStep)
+									_smushDispatch[i].volumeStep--;
+
+								_smushTracks[i].state = TRK_STATE_ENDING;
+
+								if (mixInFrameCount > DIMUSE_FEEDSIZE / 2)
+									mixInFrameCount = DIMUSE_FEEDSIZE / 2;
+
+								_smushDispatch[i].audioRemaining -= mixInFrameCount;
+								_smushDispatch[i].currentOffset += mixInFrameCount;
+								offset = _smushDispatch[i].audioRemaining % _smushDispatch[i].dataSize;
+							}
+
+							if (mixInFrameCount == _smushDispatch[i].sampleRate * tmpFeedSize / _smushAudioSampleRate) {
+								mixFeedSize = tmpFeedSize;
+							} else {
+								mixFeedSize = mixInFrameCount * _smushAudioSampleRate / _smushDispatch[i].sampleRate;
+							}
+
+							if (isPlayableTrack) {
+								mixPan = _smushTracks[i].pan;
+								sendAudioToDiMUSE(
+									&_smushDispatch[i].dataBuf[offset],
+									mixStartingPoint,
+									mixFeedSize,
+									mixInFrameCount,
+									(mixVolume * _smushDispatch[i].volumeStep) >> 4,
+									mixPan);
+							}
+
+							_smushDispatch[i].currentOffset -= mixInFrameCount;
+							_smushDispatch[i].audioRemaining += mixInFrameCount;
+							tmpFeedSize -= mixFeedSize;
+							mixStartingPoint += mixFeedSize;
+						}
+
+						if (_smushDispatch[i].currentOffset <= 0) {
+							if (processAudioCodes(i, tmpFeedSize, mixVolume) && tmpFeedSize <= 0) {
+								break;
+							}
+						} else if (tmpFeedSize <= 0) {
+							break;
+						}
+					}
+				}
+			}
+
+			_smushTracks[i].audioRemaining = _smushDispatch[i].audioRemaining;
+			_smushDispatch[i].state = _smushTracks[i].state;
+		};
+
+		if (speechIsPlaying) {
+			if (_gainReductionMultiplier > _gainReductionLowerBound) {
+				_gainReductionMultiplier -= (feedSize * 2 * _gainReductionFactor) >> 13;
+				if (_gainReductionMultiplier < _gainReductionLowerBound)
+					_gainReductionMultiplier = _gainReductionLowerBound;
+			}
+		} else {
+			if (_gainReductionMultiplier < 256) {
+				_gainReductionMultiplier += (feedSize * 2 * _gainReductionFactor) >> 15;
+				if (_gainReductionMultiplier > 256)
+					_gainReductionMultiplier = 256;
+			}
+		}
+	}
+}
+
+bool SmushPlayer::processAudioCodes(int idx, int &tmpFeedSize, int &mixVolume) {
+	uint8 *code, *buf, subcode, value;
+	int chunk;
+
+	while (tmpFeedSize) {
+		code = _smushDispatch[idx].headerPtr;
+
+		switch (code[0]) {
+		case 1: // Init
+			_smushDispatch[idx].audioLength = 0;
+			buf = _smushDispatch[idx].headerPtr;
+			_smushDispatch[idx].audioRemaining = READ_BE_UINT32(buf + 2);
+			_smushDispatch[idx].currentOffset = READ_BE_UINT32(buf + 6);
+			_smushDispatch[idx].sampleRate = _smushAudioSampleRate;
+			_smushDispatch[idx].headerPtr += _smushDispatch[idx].headerPtr[1] + 2;
+			if (_smushDispatch[idx].audioRemaining < _smushTracks[idx].availableSize + (_smushTracks[idx].availableSize >= _smushTracks[idx].sdatSize ? 0 : 15000) - _smushTracks[idx].dataSize) {
+				chunk = _smushTracks[idx].availableSize - _smushTracks[idx].dataSize - _smushDispatch[idx].audioRemaining + 15000;
+				if (chunk > _smushDispatch[idx].currentOffset) {
+					_smushTracks[idx].state = TRK_STATE_INACTIVE;
+					_smushTracks[idx].groupId = GRP_MASTER;
+					tmpFeedSize = 0;
+					break;
+				}
+
+				_smushDispatch[idx].audioRemaining += chunk;
+				_smushDispatch[idx].currentOffset -= chunk;
+			}
+			break;
+		case 2:   //
+		case 8:	  //
+		case 9:	  // Compare params
+		case 0xA: //
+		case 0xB: //
+			subcode = code[4];
+			switch (subcode) {
+			case 0xFF:
+				value = _smushTrackVols[0];
+				break;
+			case 0xFE:
+				value = _smushTracks[idx].volume;
+				break;
+			case 0xFD:
+				value = _smushTracks[idx].pan;
+				break;
+			default:
+				value = _smushAudioTable[subcode];
+				break;
+			}
+
+			switch (code[0]) {
+			case 2:
+				if (value || (subcode == 0)) {
+					_smushDispatch[idx].headerPtr = &code[READ_BE_UINT16(&code[2])];
+				}
+				break;
+			case 8:
+				value = value > code[5];
+				break;
+			case 9:
+				value = value < code[5];
+				break;
+			case 0xA:
+				value = value == code[5];
+				break;
+			case 0xB:
+				value = value != code[5];
+				break;
+			default:
+				break;
+			}
+
+			if (!value) {
+				_smushDispatch[idx].headerPtr = &code[code[1] + 2];
+			} else {
+				_smushDispatch[idx].headerPtr = &code[READ_BE_UINT16(&code[2])];
+			}
+
+			break;
+		case 3: // Set params
+			switch (code[2]) {
+			case 0xFF:
+				_smushTrackVols[0] = code[3];
+				break;
+			case 0xFE:
+				_smushTracks[idx].volume = code[3];
+				mixVolume = (_smushTrackVols[0] * _smushTracks[idx].volume) / 127;
+
+				// Set a lower mix volume of the background music if speech is active
+				if ((_smushTracks[idx].flags & TRK_TYPE_MASK) == IS_BKG_MUSIC && isChanActive(CHN_SPEECH))
+					mixVolume = (mixVolume * _gainReductionMultiplier) >> 8;
+				break;
+			case 0xFD:
+				_smushTracks[idx].pan = code[3];
+				break;
+			default:
+				_smushAudioTable[code[2]] = code[3];
+				break;
+			}
+			_smushDispatch[idx].headerPtr = &code[code[1] + 2];
+			break;
+		case 4: // Increment params
+			switch (code[2]) {
+			case 0xFF:
+				_smushTrackVols[0] += code[3];
+				break;
+			case 0xFE:
+				_smushTracks[idx].volume += code[3];
+				break;
+			case 0xFD:
+				_smushTracks[idx].pan += code[3];
+				break;
+			default:
+				_smushAudioTable[code[2]] += code[3];
+				break;
+			}
+			_smushDispatch[idx].headerPtr = &code[code[1] + 2];
+			break;
+		case 6: // Set offset
+			_smushDispatch[idx].audioLength = 0;
+			buf = _smushDispatch[idx].headerPtr;
+			_smushDispatch[idx].audioRemaining = READ_BE_UINT32(buf + 2);
+			_smushDispatch[idx].currentOffset = READ_BE_UINT32(buf + 6);
+			_smushDispatch[idx].sampleRate = _smushAudioSampleRate;
+
+			_smushDispatch[idx].headerPtr += _smushDispatch[idx].headerPtr[1] + 2;
+			if (_smushDispatch[idx].audioRemaining < _smushTracks[idx].availableSize + (_smushTracks[idx].availableSize >= _smushTracks[idx].sdatSize ? 0 : 15000) - _smushTracks[idx].dataSize) {
+				chunk = _smushTracks[idx].availableSize - _smushTracks[idx].dataSize - _smushDispatch[idx].audioRemaining + 15000;
+				if (chunk > _smushDispatch[idx].currentOffset) {
+					_smushTracks[idx].state = TRK_STATE_INACTIVE;
+					_smushTracks[idx].groupId = GRP_MASTER;
+					tmpFeedSize = 0;
+					break;
+				}
+
+				_smushDispatch[idx].audioRemaining += chunk;
+				_smushDispatch[idx].currentOffset -= chunk;
+			}
+			break;
+		case 7: // Set audio length
+			if (!_smushDispatch[idx].audioLength) {
+				_smushDispatch[idx].audioLength = READ_BE_UINT32(&code[6]);
+				_smushDispatch[idx].elapsedAudio = 0;
+			}
+
+			buf = _smushDispatch[idx].headerPtr;
+			_smushDispatch[idx].audioRemaining = _smushDispatch[idx].elapsedAudio + READ_BE_UINT32(buf + 2);
+
+			_smushDispatch[idx].currentOffset = READ_BE_UINT32(buf + 14);
+			if (_smushDispatch[idx].currentOffset > _smushDispatch[idx].audioLength)
+				_smushDispatch[idx].currentOffset = _smushDispatch[idx].audioLength;
+
+			_smushDispatch[idx].sampleRate = _smushAudioSampleRate;
+
+			_smushDispatch[idx].audioLength -= _smushDispatch[idx].currentOffset;
+			_smushDispatch[idx].elapsedAudio += _smushDispatch[idx].currentOffset;
+
+			if (_smushDispatch[idx].audioLength) {
+				_smushDispatch[idx].headerPtr = &code[code[1] + 2];
+			} else {
+				_smushDispatch[idx].headerPtr = &code[READ_BE_UINT16(&code[18])];
+			}
+
+			if (_smushDispatch[idx].audioRemaining >= _smushTracks[idx].availableSize + (_smushTracks[idx].availableSize >= _smushTracks[idx].sdatSize ? 0 : 15000) - _smushTracks[idx].dataSize) {
+				chunk = _smushTracks[idx].availableSize - _smushTracks[idx].dataSize - _smushDispatch[idx].audioRemaining + 15000;
+				if (chunk > _smushDispatch[idx].currentOffset) {
+					_smushTracks[idx].state = TRK_STATE_INACTIVE;
+					_smushTracks[idx].groupId = GRP_MASTER;
+					tmpFeedSize = 0;
+				} else {
+					_smushDispatch[idx].audioRemaining += chunk;
+					_smushDispatch[idx].currentOffset -= chunk;
+				}
+			}
+
+			break;
+		default:
+			_smushTracks[idx].state = TRK_STATE_INACTIVE;
+			_smushTracks[idx].groupId = GRP_MASTER;
+			tmpFeedSize = 0;
+		}
+
+		if (_smushDispatch[idx].currentOffset > 0) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+void SmushPlayer::sendAudioToDiMUSE(uint8 *mixBuf, int32 mixStartingPoint, int32 mixFeedSize, int32 mixInFrameCount, int volume, int pan) {
+	int clampedVol, clampedPan;
+	bool is11025Hz = false;
+
+	if (mixFeedSize == 2 * mixInFrameCount) {
+		is11025Hz = true;
+	} else if (mixFeedSize != mixInFrameCount) {
+		return;
+	}
+
+	clampedPan = CLIP<int>((pan / 2) + 64, 0, 127);
+	clampedVol = CLIP<int>(volume, 0, 127);
+	_imuseDigital->receiveAudioFromSMUSH(mixBuf, mixInFrameCount, mixFeedSize, mixStartingPoint, clampedVol, clampedPan, is11025Hz);
+}
+
+void SmushPlayer::feedAudio(uint8 *srcBuf, int groupId, int volume, int pan, int16 flags) {
+	int panDelta, effPan;
+	int32 maxFrames;
+	uint16 trkId, index;
+
+	if (_smushAudioInitialized) {
+		// Check file encoding
+		if (srcBuf[8] == 0 && srcBuf[9] == 0 && srcBuf[12] == 0 && srcBuf[13] == 0 && srcBuf[16] == 0 && srcBuf[17] == 0) {
+			trkId = READ_BE_INT16(&srcBuf[10]);
+			index = READ_BE_INT16(&srcBuf[14]);
+			maxFrames = READ_BE_INT16(&srcBuf[18]);
+
+			handleSAUDChunk(
+				srcBuf + 20,
+				READ_BE_UINT32(&srcBuf[4]) - 12,
+				groupId,
+				volume,
+				pan,
+				flags,
+				trkId,
+				index,
+				maxFrames);
+		} else {
+			trkId = READ_LE_INT16(&srcBuf[8]);
+			index = READ_LE_INT16(&srcBuf[10]);
+			maxFrames = READ_LE_INT16(&srcBuf[12]);
+			flags |= READ_LE_INT16(&srcBuf[14]);
+			volume = (volume * srcBuf[16]) >> 7;
+			panDelta = srcBuf[17];
+
+			if (panDelta == 128) {
+				effPan = 128;
+			} else {
+				effPan = pan + panDelta;
+			}
+
+			handleSAUDChunk(
+				srcBuf + 18,
+				READ_BE_UINT32(&srcBuf[4]) - 10,
+				groupId,
+				(volume * srcBuf[16]) >> 7,
+				effPan,
+				flags,
+				trkId,
+				index,
+				maxFrames);
+		}
+	}
+}
+
+bool SmushPlayer::isAudioCallbackEnabled() {
+	return _smushAudioCallbackEnabled;
+}
+
 } // End of namespace Scumm
diff --git a/engines/scumm/smush/smush_player.h b/engines/scumm/smush/smush_player.h
index f6440ee08d7..5f957908b79 100644
--- a/engines/scumm/smush/smush_player.h
+++ b/engines/scumm/smush/smush_player.h
@@ -31,6 +31,29 @@ class QueuingAudioStream;
 
 namespace Scumm {
 
+#define SMUSH_MAX_TRACKS 4
+#define SMUSH_FADE_SIZE  0xC00
+
+#define IS_SFX       0x00
+#define IS_BKG_MUSIC 0x40
+#define IS_SPEECH    0x80
+
+#define CHN_BKGMUS 1
+#define CHN_SPEECH 2
+#define CHN_OTHER  3
+
+#define GRP_MASTER 0xFF01
+#define GRP_SFX    0xFF02
+#define GRP_BKGMUS 0xFF03
+#define GRP_SPEECH 0xFF04
+
+#define TRK_STATE_INACTIVE 0
+#define TRK_STATE_PLAYING  1
+#define TRK_STATE_FADING   2
+#define TRK_STATE_ENDING   3
+
+#define TRK_TYPE_MASK 0xC0
+
 class ScummEngine_v7;
 class SmushFont;
 class SmushMixer;
@@ -38,14 +61,49 @@ class StringResource;
 class Codec37Decoder;
 class Codec47Decoder;
 class IMuseDigital;
+class Insane;
 
 class SmushPlayer {
 	friend class Insane;
 private:
+	struct SmushAudioDispatch {
+		uint8 *headerPtr;
+		uint8 *dataBuf;
+		int32 dataSize;
+		int32 audioRemaining;
+		int32 currentOffset;
+		int sampleRate;
+		int state;
+		int fadeSampleRate;
+		int fadeVolume;
+		int32 fadeRemaining;
+		int volumeStep;
+		int32 elapsedAudio;
+		int32 audioLength;
+	};
+
+	struct SmushAudioTrack {
+		uint8 *blockPtr;
+		uint8 *fadeBuf;
+		uint8 *dataBuf;
+		uint8 *subChunkPtr;
+		int32 blockSize;
+		byte volume;
+		byte pan;
+		int16 state;
+		int16 flags;
+		int groupId;
+		int parsedChunks;
+		int32 dataSize;
+		int32 availableSize;
+		int32 audioRemaining;
+		int32 sdatSize;
+	};
+
 	ScummEngine_v7 *_vm;
 	IMuseDigital *_imuseDigital;
+	Insane *_insane;
 	int32 _nbframes;
-	SmushMixer *_smixer;
 	int16 _deltaPal[0x300];
 	byte _pal[0x300];
 	SmushFont *_sf[5];
@@ -87,8 +145,29 @@ private:
 	bool _middleAudio;
 	bool _skipPalette;
 	int _iactTable[4];
+
+	SmushAudioTrack _smushTracks[SMUSH_MAX_TRACKS];
+	SmushAudioDispatch _smushDispatch[SMUSH_MAX_TRACKS];
+
+	int _smushMaxFrames[SMUSH_MAX_TRACKS];
+	int _smushTrackIds[SMUSH_MAX_TRACKS];
+	int _smushTrackIdxs[SMUSH_MAX_TRACKS];
+	uint8 _smushAudioTable[256];
+	int _smushNumTracks;
+	int _smushTrackFlags[SMUSH_MAX_TRACKS];
+	int _smushTrackVols[SMUSH_MAX_TRACKS];
+
+	int _smushAudioSampleRate;
+	int _gainReductionLowerBound;
+	int _gainReductionFactor;
+	int _gainReductionMultiplier;
+
+	bool _smushTracksNeedInit;
+	bool _smushAudioInitialized;
+	bool _smushAudioCallbackEnabled;
+
 public:
-	SmushPlayer(ScummEngine_v7 *scumm, IMuseDigital *_imuseDigital);
+	SmushPlayer(ScummEngine_v7 *scumm, IMuseDigital *_imuseDigital, Insane *insane);
 	~SmushPlayer();
 
 	void pause();
@@ -97,6 +176,10 @@ public:
 	void play(const char *filename, int32 speed, int32 offset = 0, int32 startFrame = 0);
 	void release();
 	void warpMouse(int x, int y, int buttons);
+	int setChanFlag(int id, int flagVal);
+	void setGroupVolume(int groupId, int volValue);
+	void processDispatches(int16 feedSize);
+	bool isAudioCallbackEnabled();
 
 protected:
 	int _width, _height;
@@ -130,8 +213,7 @@ private:
 	void handleZlibFrameObject(int32 subSize, Common::SeekableReadStream &b);
 #endif
 	void handleFrameObject(int32 subSize, Common::SeekableReadStream &);
-	void handleSoundBuffer(int32, int32, int32, int32, int32, int32, Common::SeekableReadStream &, int32);
-	void handleSoundFrame(int32 subSize, Common::SeekableReadStream &);
+	void handleSAUDChunk(uint8 *srcBuf, uint32 size, int groupId, int vol, int pan, int16 flags, int trkId, int index, int maxFrames);
 	void handleStore(int32 subSize, Common::SeekableReadStream &);
 	void handleFetch(int32 subSize, Common::SeekableReadStream &);
 	void handleIACT(int32 subSize, Common::SeekableReadStream &);
@@ -139,6 +221,17 @@ private:
 	void handleDeltaPalette(int32 subSize, Common::SeekableReadStream &);
 	void readPalette(byte *, Common::SeekableReadStream &);
 
+	void initAudio(int samplerate, int32 maxChunkSize);
+	void terminateAudio();
+	int isChanActive(int flagId);
+	int addAudioTrack(int32 trackBlockSize, int32 maxBlockSize);
+	void resetAudioTracks();
+	void setGainReductionParams(int16 gainReductionLowerBound, int16 gainReductionMultiplier);
+	void fillAudioTrackInfo(uint8 *srcBuf, uint16 *flagsAccumulator, uint32 size, int groupId, int vol, int pan, int16 flags, int trkId, int index, int maxFrames);
+	bool processAudioCodes(int idx, int32 &tmpFeedSize, int &mixVolume);
+	void feedAudio(uint8 *srcBuf, int groupId, int volume, int pan, int16 flags);
+	void sendAudioToDiMUSE(uint8 *mixBuf, int32 mixStartingPoint, int32 mixFeedSize, int32 mixInFrameCount, int volume, int pan);
+
 	void timerCallback();
 };
 


Commit: 71816ec70138316c243ccaec79d9598683d90db2
    https://github.com/scummvm/scummvm/commit/71816ec70138316c243ccaec79d9598683d90db2
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-04-16T23:25:31+02:00

Commit Message:
SCUMM: DiMUSE: Fix startup volume setup for SMUSH

Changed paths:
    engines/scumm/imuse_digi/dimuse_engine.cpp


diff --git a/engines/scumm/imuse_digi/dimuse_engine.cpp b/engines/scumm/imuse_digi/dimuse_engine.cpp
index de40eb00ff9..d59dad6264e 100644
--- a/engines/scumm/imuse_digi/dimuse_engine.cpp
+++ b/engines/scumm/imuse_digi/dimuse_engine.cpp
@@ -645,6 +645,10 @@ int IMuseDigital::getSoundIdByName(const char *soundName) {
 
 void IMuseDigital::setSmushPlayer(SmushPlayer *splayer) {
 	_splayer = splayer;
+	// Perform a first-time volume update for both SMUSH and iMUSE
+	diMUSESetMusicGroupVol(CLIP(_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) / 2, 0, 127));
+	diMUSESetVoiceGroupVol(CLIP(_mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType) / 2, 0, 127));
+	diMUSESetSFXGroupVol(CLIP(_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 2, 0, 127));
 }
 
 void IMuseDigital::receiveAudioFromSMUSH(uint8 *srcBuf, int32 inFrameCount, int32 feedSize, int32 mixBufStartIndex, int volume, int pan, bool is11025Hz) {
@@ -813,21 +817,21 @@ int IMuseDigital::diMUSESetMusicGroupVol(int volume) {
 	debug(5, "IMuseDigital::diMUSESetMusicGroupVol(): %d", volume);
 	if (_isEarlyDiMUSE)
 		_splayer->setGroupVolume(GRP_BKGMUS, volume);
-	return diMUSESetGroupVol(3, volume);
+	return diMUSESetGroupVol(DIMUSE_GROUP_MUSIC, volume);
 }
 
 int IMuseDigital::diMUSESetSFXGroupVol(int volume) {
 	debug(5, "IMuseDigital::diMUSESetSFXGroupVol(): %d", volume);
 	if (_isEarlyDiMUSE)
 		_splayer->setGroupVolume(GRP_SFX, volume);
-	return diMUSESetGroupVol(1, volume);
+	return diMUSESetGroupVol(DIMUSE_GROUP_SFX, volume);
 }
 
 int IMuseDigital::diMUSESetVoiceGroupVol(int volume) {
 	debug(5, "IMuseDigital::diMUSESetVoiceGroupVol(): %d", volume);
 	if (_isEarlyDiMUSE)
 		_splayer->setGroupVolume(GRP_SPEECH, volume);
-	return diMUSESetGroupVol(2, volume);
+	return diMUSESetGroupVol(DIMUSE_GROUP_SPEECH, volume);
 }
 
 void IMuseDigital::diMUSEUpdateGroupVolumes() {


Commit: 5c632946323a4567c779fb27d31d38a66753968b
    https://github.com/scummvm/scummvm/commit/5c632946323a4567c779fb27d31d38a66753968b
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-04-16T23:25:31+02:00

Commit Message:
SCUMM: DiMUSE: Fix mixer behavior for 8-bit audio and mixBufStartIndex != 0
This fixes some ugly audio pops and glitches on The Dig (full and demo) and FT
Also, fix formatting

Changed paths:
    engines/scumm/imuse_digi/dimuse_internalmixer.cpp


diff --git a/engines/scumm/imuse_digi/dimuse_internalmixer.cpp b/engines/scumm/imuse_digi/dimuse_internalmixer.cpp
index 61bc2dad338..91ee7c26eb1 100644
--- a/engines/scumm/imuse_digi/dimuse_internalmixer.cpp
+++ b/engines/scumm/imuse_digi/dimuse_internalmixer.cpp
@@ -701,7 +701,7 @@ void IMuseDigiInternalMixer::mixBits8ConvertToStereo(uint8 *srcBuf, int32 inFram
 	int value;
 	int residualLength;
 
-	mixBufCurCell = (uint16 *)(&_mixBuf[2 * mixBufStartIndex]);
+	mixBufCurCell = (uint16 *)(&_mixBuf[4 * mixBufStartIndex]);
 	if (_isEarlyDiMUSE) {
 		if (ftIs11025Hz) {
 			srcBuf_ptr = srcBuf;
@@ -909,11 +909,11 @@ void IMuseDigiInternalMixer::mixBits12ConvertToStereo(uint8 *srcBuf, int32 inFra
 }
 
 void IMuseDigiInternalMixer::mixBits16ConvertToStereo(uint8 *srcBuf, int32 inFrameCount, int feedSize, int32 mixBufStartIndex, int32 *leftAmpTable, int32 *rightAmpTable) {
-	uint16* mixBufCurCell;
+	uint16 *mixBufCurCell;
 	uint16 *srcBuf_tmp;
 	int residualLength;
 
-	mixBufCurCell = (uint16*)(&_mixBuf[2 * mixBufStartIndex]);
+	mixBufCurCell = (uint16 *)(&_mixBuf[2 * mixBufStartIndex]);
 
 	if (feedSize == inFrameCount) {
 		if (feedSize) {
@@ -976,7 +976,7 @@ void IMuseDigiInternalMixer::mixBits8Stereo(uint8 *srcBuf, int32 inFrameCount, i
 	uint8 *srcBuf_ptr;
 	int residualLength;
 
-	mixBufCurCell = (uint16*)(&_mixBuf[4 * mixBufStartIndex]);
+	mixBufCurCell = (uint16 *)(&_mixBuf[4 * mixBufStartIndex]);
 	if (feedSize == inFrameCount) {
 		if (feedSize) {
 			srcBuf_ptr = srcBuf;
@@ -1099,7 +1099,7 @@ void IMuseDigiInternalMixer::mixBits16Stereo(uint8 *srcBuf, int32 inFrameCount,
 	uint16 *srcBuf_ptr;
 	int residualLength;
 
-	mixBufCurCell = (uint16*)(&_mixBuf[4 * mixBufStartIndex]);
+	mixBufCurCell = (uint16 *)(&_mixBuf[4 * mixBufStartIndex]);
 	if (feedSize == inFrameCount) {
 		if (feedSize) {
 			srcBuf_ptr = (uint16 *)srcBuf;


Commit: 157bd196db280df8c93fc2ee68ae83b174caaed2
    https://github.com/scummvm/scummvm/commit/157bd196db280df8c93fc2ee68ae83b174caaed2
Author: Andrea Boscarino (andywinxp at gmail.com)
Date: 2022-04-16T23:25:31+02:00

Commit Message:
SCUMM: INSANE: Remove instruction not present in the interpreter
With this instruction in place (probably an unseen typo), there are instances in which the road noise is started and then immediately stopped cyclically (e.g. when Ben puts on the goggles)

Changed paths:
    engines/scumm/insane/insane_scenes.cpp


diff --git a/engines/scumm/insane/insane_scenes.cpp b/engines/scumm/insane/insane_scenes.cpp
index 1e59a6115f3..75d92affbca 100644
--- a/engines/scumm/insane/insane_scenes.cpp
+++ b/engines/scumm/insane/insane_scenes.cpp
@@ -853,7 +853,6 @@ void Insane::procPostRendering(byte *renderBitmap, int32 codecparam, int32 setup
 			postCase17(renderBitmap, codecparam, setupsan12, setupsan13, curFrame, maxFrame);
 			smlayer_stopSound(95);
 			smlayer_stopSound(87);
-			smlayer_stopSound(88);
 			if (!smlayer_isSoundRunning(88))
 				smlayer_startSfx(88);
 			break;




More information about the Scummvm-git-logs mailing list