[Scummvm-cvs-logs] scummvm master -> 2756d6226b1567dbe650284c56d93d722af906b2

bgK bastien.bouclet at gmail.com
Thu Aug 11 19:53:52 CEST 2016


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

Summary:
e55758f444 MOHAWK: Move makeMohawkWaveStream out of the Sound class
aeee4888be MOHAWK: Allow the games to have a different sound manager
2756d6226b MOHAWK: Add a Riven specific sound manager


Commit: e55758f444dc99e89efdd3effa225d8b54bbd1fb
    https://github.com/scummvm/scummvm/commit/e55758f444dc99e89efdd3effa225d8b54bbd1fb
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2016-08-11T19:53:20+02:00

Commit Message:
MOHAWK: Move makeMohawkWaveStream out of the Sound class

Changed paths:
    engines/mohawk/sound.cpp
    engines/mohawk/sound.h



diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index 38cb0b3..e52122d 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -37,6 +37,150 @@
 
 namespace Mohawk {
 
+Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList) {
+	uint32 tag = 0;
+	ADPCMStatus adpcmStatus;
+	DataChunk dataChunk;
+	uint32 dataSize = 0;
+
+	memset(&dataChunk, 0, sizeof(DataChunk));
+
+	if (stream->readUint32BE() != ID_MHWK) // MHWK tag again
+		error ("Could not find tag 'MHWK'");
+
+	stream->readUint32BE(); // Skip size
+
+	if (stream->readUint32BE() != ID_WAVE)
+		error ("Could not find tag 'WAVE'");
+
+	while (!dataChunk.audioData) {
+		tag = stream->readUint32BE();
+
+		switch (tag) {
+			case ID_ADPC:
+				debug(2, "Found Tag ADPC");
+				// ADPCM Sound Only
+				//
+				// This is useful for seeking in the stream, and is actually quite brilliant
+				// considering some of the other things Broderbund did with the engine.
+				// Only Riven and CSTime are known to use ADPCM audio and only CSTime
+				// actually requires this for seeking. On the other hand, it may be interesting
+				// to look at that one Riven sample that uses the cue points.
+				//
+				// Basically, the sample frame from the cue list is looked up here and then
+				// sets the starting sample and step index at the point specified. Quite
+				// an elegant/efficient system, really.
+
+				adpcmStatus.size = stream->readUint32BE();
+				adpcmStatus.itemCount = stream->readUint16BE();
+				adpcmStatus.channels = stream->readUint16BE();
+				adpcmStatus.statusItems = new ADPCMStatus::StatusItem[adpcmStatus.itemCount];
+
+				assert(adpcmStatus.channels <= 2);
+
+				for (uint16 i = 0; i < adpcmStatus.itemCount; i++) {
+					adpcmStatus.statusItems[i].sampleFrame = stream->readUint32BE();
+
+					for (uint16 j = 0; j < adpcmStatus.channels; j++) {
+						adpcmStatus.statusItems[i].channelStatus[j].last = stream->readSint16BE();
+						adpcmStatus.statusItems[i].channelStatus[j].stepIndex = stream->readUint16BE();
+					}
+				}
+
+				// TODO: Actually use this chunk. For now, just delete the status items...
+				delete[] adpcmStatus.statusItems;
+				break;
+			case ID_CUE:
+				debug(2, "Found Tag Cue#");
+				// Cues are used for animation sync. There are a couple in Myst and
+				// Riven but are not used there at all.
+
+				if (!cueList) {
+					uint32 size = stream->readUint32BE();
+					stream->skip(size);
+					break;
+				}
+
+				cueList->size = stream->readUint32BE();
+				cueList->pointCount = stream->readUint16BE();
+
+				if (cueList->pointCount == 0)
+					debug(2, "Cue# chunk found with no points!");
+				else
+					debug(2, "Cue# chunk found with %d point(s)!", cueList->pointCount);
+
+				cueList->points.resize(cueList->pointCount);
+				for (uint16 i = 0; i < cueList->pointCount; i++) {
+					cueList->points[i].sampleFrame = stream->readUint32BE();
+
+					byte nameLength = stream->readByte();
+					cueList->points[i].name.clear();
+					for (byte j = 0; j < nameLength; j++)
+						cueList->points[i].name += stream->readByte();
+
+					// Realign to an even boundary
+					if (!(nameLength & 1))
+						stream->readByte();
+
+					debug (3, "Cue# chunk point %d (frame %d): %s", i, cueList->points[i].sampleFrame, cueList->points[i].name.c_str());
+				}
+				break;
+			case ID_DATA:
+				debug(2, "Found Tag DATA");
+				// We subtract 20 from the actual chunk size, which is the total size
+				// of the chunk's header
+				dataSize = stream->readUint32BE() - 20;
+				dataChunk.sampleRate = stream->readUint16BE();
+				dataChunk.sampleCount = stream->readUint32BE();
+				dataChunk.bitsPerSample = stream->readByte();
+				dataChunk.channels = stream->readByte();
+				dataChunk.encoding = stream->readUint16BE();
+				dataChunk.loopCount = stream->readUint16BE();
+				dataChunk.loopStart = stream->readUint32BE();
+				dataChunk.loopEnd = stream->readUint32BE();
+
+				// NOTE: We currently ignore all of the loop parameters here. Myst uses the
+				// loopCount variable but the loopStart and loopEnd are always 0 and the size of
+				// the sample. Myst ME doesn't use the Mohawk Sound format and just standard WAVE
+				// files and therefore does not contain any of this metadata and we have to specify
+				// whether or not to loop elsewhere.
+
+				dataChunk.audioData = stream->readStream(dataSize);
+				break;
+			default:
+				error ("Unknown tag found in 'tWAV' chunk -- '%s'", tag2str(tag));
+		}
+	}
+
+	// makeMohawkWaveStream always takes control of the original stream
+	delete stream;
+
+	// The sound in Myst uses raw unsigned 8-bit data
+	// The sound in the CD version of Riven is encoded in Intel DVI ADPCM
+	// The sound in the DVD version of Riven is encoded in MPEG-2 Layer II or Intel DVI ADPCM
+	if (dataChunk.encoding == kCodecRaw) {
+		byte flags = Audio::FLAG_UNSIGNED;
+
+		if (dataChunk.channels == 2)
+			flags |= Audio::FLAG_STEREO;
+
+		return Audio::makeRawStream(dataChunk.audioData, dataChunk.sampleRate, flags);
+	} else if (dataChunk.encoding == kCodecADPCM) {
+		uint32 blockAlign = dataChunk.channels * dataChunk.bitsPerSample / 8;
+		return Audio::makeADPCMStream(dataChunk.audioData, DisposeAfterUse::YES, dataSize, Audio::kADPCMDVI, dataChunk.sampleRate, dataChunk.channels, blockAlign);
+	} else if (dataChunk.encoding == kCodecMPEG2) {
+#ifdef USE_MAD
+		return Audio::makeMP3Stream(dataChunk.audioData, DisposeAfterUse::YES);
+#else
+		warning ("MAD library not included - unable to play MP2 audio");
+#endif
+	} else {
+		error ("Unknown Mohawk WAVE encoding %d", dataChunk.encoding);
+	}
+
+	return nullptr;
+}
+
 Sound::Sound(MohawkEngine* vm) : _vm(vm) {
 	_midiDriver = NULL;
 	_midiParser = NULL;
@@ -384,150 +528,6 @@ void Sound::resumeSLST() {
 		_vm->_mixer->pauseHandle(*_currentSLSTSounds[i].handle, false);
 }
 
-Audio::RewindableAudioStream *Sound::makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList) {
-	uint32 tag = 0;
-	ADPCMStatus adpcmStatus;
-	DataChunk dataChunk;
-	uint32 dataSize = 0;
-
-	memset(&dataChunk, 0, sizeof(DataChunk));
-
-	if (stream->readUint32BE() != ID_MHWK) // MHWK tag again
-		error ("Could not find tag 'MHWK'");
-
-	stream->readUint32BE(); // Skip size
-
-	if (stream->readUint32BE() != ID_WAVE)
-		error ("Could not find tag 'WAVE'");
-
-	while (!dataChunk.audioData) {
-		tag = stream->readUint32BE();
-
-		switch (tag) {
-		case ID_ADPC:
-			debug(2, "Found Tag ADPC");
-			// ADPCM Sound Only
-			//
-			// This is useful for seeking in the stream, and is actually quite brilliant
-			// considering some of the other things Broderbund did with the engine.
-			// Only Riven and CSTime are known to use ADPCM audio and only CSTime
-			// actually requires this for seeking. On the other hand, it may be interesting
-			// to look at that one Riven sample that uses the cue points.
-			//
-			// Basically, the sample frame from the cue list is looked up here and then
-			// sets the starting sample and step index at the point specified. Quite
-			// an elegant/efficient system, really.
-
-			adpcmStatus.size = stream->readUint32BE();
-			adpcmStatus.itemCount = stream->readUint16BE();
-			adpcmStatus.channels = stream->readUint16BE();
-			adpcmStatus.statusItems = new ADPCMStatus::StatusItem[adpcmStatus.itemCount];
-
-			assert(adpcmStatus.channels <= 2);
-
-			for (uint16 i = 0; i < adpcmStatus.itemCount; i++) {
-				adpcmStatus.statusItems[i].sampleFrame = stream->readUint32BE();
-
-				for (uint16 j = 0; j < adpcmStatus.channels; j++) {
-					adpcmStatus.statusItems[i].channelStatus[j].last = stream->readSint16BE();
-					adpcmStatus.statusItems[i].channelStatus[j].stepIndex = stream->readUint16BE();
-				}
-			}
-
-			// TODO: Actually use this chunk. For now, just delete the status items...
-			delete[] adpcmStatus.statusItems;
-			break;
-		case ID_CUE:
-			debug(2, "Found Tag Cue#");
-			// Cues are used for animation sync. There are a couple in Myst and
-			// Riven but are not used there at all.
-
-			if (!cueList) {
-				uint32 size = stream->readUint32BE();
-				stream->skip(size);
-				break;
-			}
-
-			cueList->size = stream->readUint32BE();
-			cueList->pointCount = stream->readUint16BE();
-
-			if (cueList->pointCount == 0)
-				debug(2, "Cue# chunk found with no points!");
-			else
-				debug(2, "Cue# chunk found with %d point(s)!", cueList->pointCount);
-
-			cueList->points.resize(cueList->pointCount);
-			for (uint16 i = 0; i < cueList->pointCount; i++) {
-				cueList->points[i].sampleFrame = stream->readUint32BE();
-
-				byte nameLength = stream->readByte();
-				cueList->points[i].name.clear();
-				for (byte j = 0; j < nameLength; j++)
-					cueList->points[i].name += stream->readByte();
-
-				// Realign to an even boundary
-				if (!(nameLength & 1))
-					stream->readByte();
-
-				debug (3, "Cue# chunk point %d (frame %d): %s", i, cueList->points[i].sampleFrame, cueList->points[i].name.c_str());
-			}
-			break;
-		case ID_DATA:
-			debug(2, "Found Tag DATA");
-			// We subtract 20 from the actual chunk size, which is the total size
-			// of the chunk's header
-			dataSize = stream->readUint32BE() - 20;
-			dataChunk.sampleRate = stream->readUint16BE();
-			dataChunk.sampleCount = stream->readUint32BE();
-			dataChunk.bitsPerSample = stream->readByte();
-			dataChunk.channels = stream->readByte();
-			dataChunk.encoding = stream->readUint16BE();
-			dataChunk.loopCount = stream->readUint16BE();
-			dataChunk.loopStart = stream->readUint32BE();
-			dataChunk.loopEnd = stream->readUint32BE();
-
-			// NOTE: We currently ignore all of the loop parameters here. Myst uses the
-			// loopCount variable but the loopStart and loopEnd are always 0 and the size of
-			// the sample. Myst ME doesn't use the Mohawk Sound format and just standard WAVE
-			// files and therefore does not contain any of this metadata and we have to specify
-			// whether or not to loop elsewhere.
-
-			dataChunk.audioData = stream->readStream(dataSize);
-			break;
-		default:
-			error ("Unknown tag found in 'tWAV' chunk -- '%s'", tag2str(tag));
-		}
-	}
-
-	// makeMohawkWaveStream always takes control of the original stream
-	delete stream;
-
-	// The sound in Myst uses raw unsigned 8-bit data
-	// The sound in the CD version of Riven is encoded in Intel DVI ADPCM
-	// The sound in the DVD version of Riven is encoded in MPEG-2 Layer II or Intel DVI ADPCM
-	if (dataChunk.encoding == kCodecRaw) {
-		byte flags = Audio::FLAG_UNSIGNED;
-
-		if (dataChunk.channels == 2)
-			flags |= Audio::FLAG_STEREO;
-
-		return Audio::makeRawStream(dataChunk.audioData, dataChunk.sampleRate, flags);
-	} else if (dataChunk.encoding == kCodecADPCM) {
-		uint32 blockAlign = dataChunk.channels * dataChunk.bitsPerSample / 8;
-		return Audio::makeADPCMStream(dataChunk.audioData, DisposeAfterUse::YES, dataSize, Audio::kADPCMDVI, dataChunk.sampleRate, dataChunk.channels, blockAlign);
-	} else if (dataChunk.encoding == kCodecMPEG2) {
-#ifdef USE_MAD
-		return Audio::makeMP3Stream(dataChunk.audioData, DisposeAfterUse::YES);
-#else
-		warning ("MAD library not included - unable to play MP2 audio");
-#endif
-	} else {
-		error ("Unknown Mohawk WAVE encoding %d", dataChunk.encoding);
-	}
-
-	return NULL;
-}
-
 Audio::RewindableAudioStream *Sound::makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream) {
 	uint16 header = stream->readUint16BE();
 	uint16 rate = 0;
diff --git a/engines/mohawk/sound.h b/engines/mohawk/sound.h
index f09706e..a02c0d1 100644
--- a/engines/mohawk/sound.h
+++ b/engines/mohawk/sound.h
@@ -116,6 +116,8 @@ struct DataChunk {
 	Common::SeekableReadStream *audioData;
 };
 
+Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList = nullptr);
+
 class MohawkEngine;
 
 class Sound {
@@ -158,7 +160,6 @@ private:
 	MidiParser *_midiParser;
 	byte *_midiData;
 
-	static Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList = NULL);
 	static Audio::RewindableAudioStream *makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream);
 	void initMidi();
 


Commit: aeee4888beb8ba15a32a438e4ac82c53d250e039
    https://github.com/scummvm/scummvm/commit/aeee4888beb8ba15a32a438e4ac82c53d250e039
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2016-08-11T19:53:20+02:00

Commit Message:
MOHAWK: Allow the games to have a different sound manager

Changed paths:
    engines/mohawk/cstime.cpp
    engines/mohawk/cstime.h
    engines/mohawk/livingbooks.cpp
    engines/mohawk/livingbooks.h
    engines/mohawk/mohawk.cpp
    engines/mohawk/mohawk.h
    engines/mohawk/myst.cpp
    engines/mohawk/myst.h
    engines/mohawk/riven.cpp
    engines/mohawk/riven.h
    engines/mohawk/sound.cpp
    engines/mohawk/sound.h



diff --git a/engines/mohawk/cstime.cpp b/engines/mohawk/cstime.cpp
index 3b26378..b2889be 100644
--- a/engines/mohawk/cstime.cpp
+++ b/engines/mohawk/cstime.cpp
@@ -54,6 +54,7 @@ MohawkEngine_CSTime::MohawkEngine_CSTime(OSystem *syst, const MohawkGameDescript
 
 	_console = 0;
 	_gfx = 0;
+	_sound = 0;
 	_cursor = 0;
 	_interface = 0;
 	_view = 0;
@@ -66,6 +67,7 @@ MohawkEngine_CSTime::~MohawkEngine_CSTime() {
 	delete _interface;
 	delete _view;
 	delete _console;
+	delete _sound;
 	delete _gfx;
 	delete _rnd;
 }
@@ -75,6 +77,7 @@ Common::Error MohawkEngine_CSTime::run() {
 
 	_console = new CSTimeConsole(this);
 	_gfx = new CSTimeGraphics(this);
+	_sound = new Sound(this);
 	_cursor = new DefaultCursorManager(this, ID_CURS);
 
 	_interface = new CSTimeInterface(this);
diff --git a/engines/mohawk/cstime.h b/engines/mohawk/cstime.h
index bfb7daf..393032a 100644
--- a/engines/mohawk/cstime.h
+++ b/engines/mohawk/cstime.h
@@ -136,6 +136,7 @@ public:
 
 	Common::RandomSource *_rnd;
 
+	Sound *_sound;
 	CSTimeGraphics *_gfx;
 	bool _needsUpdate;
 
diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp
index 5af8fac..579e379 100644
--- a/engines/mohawk/livingbooks.cpp
+++ b/engines/mohawk/livingbooks.cpp
@@ -144,6 +144,7 @@ MohawkEngine_LivingBooks::MohawkEngine_LivingBooks(OSystem *syst, const MohawkGa
 
 	_rnd = new Common::RandomSource("livingbooks");
 
+	_sound = NULL;
 	_page = NULL;
 
 	const Common::FSNode gameDataDir(ConfMan.get("path"));
@@ -158,6 +159,7 @@ MohawkEngine_LivingBooks::~MohawkEngine_LivingBooks() {
 	destroyPage();
 
 	delete _console;
+	delete _sound;
 	delete _gfx;
 	delete _rnd;
 	_bookInfoFile.clear();
@@ -182,6 +184,7 @@ Common::Error MohawkEngine_LivingBooks::run() {
 		error("Could not find xRes/yRes variables");
 
 	_gfx = new LBGraphics(this, _screenWidth, _screenHeight);
+	_sound = new Sound(this);
 
 	if (getGameType() != GType_LIVINGBOOKSV1)
 		_cursor = new LivingBooksCursorManager_v2();
diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h
index 1a265a1..cf67c1e 100644
--- a/engines/mohawk/livingbooks.h
+++ b/engines/mohawk/livingbooks.h
@@ -714,6 +714,7 @@ public:
 
 	Common::RandomSource *_rnd;
 
+	Sound *_sound;
 	LBGraphics *_gfx;
 	bool _needsRedraw, _needsUpdate;
 
diff --git a/engines/mohawk/mohawk.cpp b/engines/mohawk/mohawk.cpp
index d740d94..b38409f 100644
--- a/engines/mohawk/mohawk.cpp
+++ b/engines/mohawk/mohawk.cpp
@@ -40,14 +40,12 @@ MohawkEngine::MohawkEngine(OSystem *syst, const MohawkGameDescription *gamedesc)
 	// Setup mixer
 	syncSoundSettings();
 
-	_sound = 0;
 	_video = 0;
 	_pauseDialog = 0;
 	_cursor = 0;
 }
 
 MohawkEngine::~MohawkEngine() {
-	delete _sound;
 	delete _video;
 	delete _pauseDialog;
 	delete _cursor;
@@ -58,7 +56,6 @@ MohawkEngine::~MohawkEngine() {
 }
 
 Common::Error MohawkEngine::run() {
-	_sound = new Sound(this);
 	_video = new VideoManager(this);
 	_pauseDialog = new PauseDialog(this, "The game is paused. Press any key to continue.");
 
@@ -66,14 +63,12 @@ Common::Error MohawkEngine::run() {
 }
 
 void MohawkEngine::pauseEngineIntern(bool pause) {
+	Engine::pauseEngineIntern(pause);
+
 	if (pause) {
 		_video->pauseVideos();
-		_sound->pauseSound();
-		_sound->pauseSLST();
 	} else {
 		_video->resumeVideos();
-		_sound->resumeSound();
-		_sound->resumeSLST();
 		_system->updateScreen();
 	}
 }
diff --git a/engines/mohawk/mohawk.h b/engines/mohawk/mohawk.h
index ac91dca..bc0d642 100644
--- a/engines/mohawk/mohawk.h
+++ b/engines/mohawk/mohawk.h
@@ -100,7 +100,6 @@ public:
 
 	bool hasFeature(EngineFeature f) const;
 
-	Sound *_sound;
 	VideoManager *_video;
 	CursorManager *_cursor;
 
diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp
index a1c6d0e..3c00c1e 100644
--- a/engines/mohawk/myst.cpp
+++ b/engines/mohawk/myst.cpp
@@ -75,6 +75,7 @@ MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription
 	_curResource = -1;
 	_hoverResource = nullptr;
 
+	_sound = nullptr;
 	_gfx = nullptr;
 	_console = nullptr;
 	_scriptParser = nullptr;
@@ -88,6 +89,7 @@ MohawkEngine_Myst::~MohawkEngine_Myst() {
 	DebugMan.clearAllDebugChannels();
 
 	delete _gfx;
+	delete _sound;
 	delete _console;
 	delete _scriptParser;
 	delete _gameState;
@@ -220,6 +222,7 @@ Common::Error MohawkEngine_Myst::run() {
 	MohawkEngine::run();
 
 	_gfx = new MystGraphics(this);
+	_sound = new Sound(this);
 	_console = new MystConsole(this);
 	_gameState = new MystGameState(this, _saveFileMan);
 	_optionsDialog = new MystOptionsDialog(this);
diff --git a/engines/mohawk/myst.h b/engines/mohawk/myst.h
index 0b249e5..0491e85 100644
--- a/engines/mohawk/myst.h
+++ b/engines/mohawk/myst.h
@@ -200,6 +200,7 @@ public:
 
 	bool _showResourceRects;
 
+	Sound *_sound;
 	MystGraphics *_gfx;
 	MystGameState *_gameState;
 	MystScriptParser *_scriptParser;
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index b05b76d..054b6ca 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -59,6 +59,7 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio
 	_curStack = kStackUnknown;
 	_hotspots = nullptr;
 	_gfx = nullptr;
+	_sound = nullptr;
 	_externalScriptHandler = nullptr;
 	_rnd = nullptr;
 	_scriptMan = nullptr;
@@ -92,6 +93,7 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio
 }
 
 MohawkEngine_Riven::~MohawkEngine_Riven() {
+	delete _sound;
 	delete _gfx;
 	delete _console;
 	delete _externalScriptHandler;
@@ -123,6 +125,7 @@ Common::Error MohawkEngine_Riven::run() {
 		SearchMan.add("arcriven.z", &_installerArchive, 0, false);
 
 	_gfx = new RivenGraphics(this);
+	_sound = new Sound(this);
 	_console = new RivenConsole(this);
 	_saveLoad = new RivenSaveLoad(this, _saveFileMan);
 	_externalScriptHandler = new RivenExternal(this);
diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h
index 3ea50bb..4e52dfb 100644
--- a/engines/mohawk/riven.h
+++ b/engines/mohawk/riven.h
@@ -121,6 +121,7 @@ public:
 	MohawkEngine_Riven(OSystem *syst, const MohawkGameDescription *gamedesc);
 	virtual ~MohawkEngine_Riven();
 
+	Sound *_sound;
 	RivenGraphics *_gfx;
 	RivenExternal *_externalScriptHandler;
 	Common::RandomSource *_rnd;
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index e52122d..dd93252 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -518,16 +518,6 @@ void Sound::stopSLSTSound(uint16 index, bool fade) {
 	_currentSLSTSounds.remove_at(index);
 }
 
-void Sound::pauseSLST() {
-	for (uint16 i = 0; i < _currentSLSTSounds.size(); i++)
-		_vm->_mixer->pauseHandle(*_currentSLSTSounds[i].handle, true);
-}
-
-void Sound::resumeSLST() {
-	for (uint16 i = 0; i < _currentSLSTSounds.size(); i++)
-		_vm->_mixer->pauseHandle(*_currentSLSTSounds[i].handle, false);
-}
-
 Audio::RewindableAudioStream *Sound::makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream) {
 	uint16 header = stream->readUint16BE();
 	uint16 rate = 0;
@@ -591,18 +581,6 @@ void Sound::stopSound(uint16 id) {
 		}
 }
 
-void Sound::pauseSound() {
-	for (uint32 i = 0; i < _handles.size(); i++)
-		if (_handles[i].type == kUsedHandle)
-			_vm->_mixer->pauseHandle(_handles[i].handle, true);
-}
-
-void Sound::resumeSound() {
-	for (uint32 i = 0; i < _handles.size(); i++)
-		if (_handles[i].type == kUsedHandle)
-			_vm->_mixer->pauseHandle(_handles[i].handle, false);
-}
-
 bool Sound::isPlaying(uint16 id) {
 	for (uint32 i = 0; i < _handles.size(); i++)
 		if (_handles[i].type == kUsedHandle && _handles[i].id == id)
diff --git a/engines/mohawk/sound.h b/engines/mohawk/sound.h
index a02c0d1..6b50c41 100644
--- a/engines/mohawk/sound.h
+++ b/engines/mohawk/sound.h
@@ -132,8 +132,6 @@ public:
 	void stopMidi();
 	void stopSound();
 	void stopSound(uint16 id);
-	void pauseSound();
-	void resumeSound();
 	bool isPlaying(uint16 id);
 	bool isPlaying();
 	uint getNumSamplesPlayed(uint16 id);
@@ -149,8 +147,6 @@ public:
 	// Riven-specific sound functions
 	void playSLST(uint16 index, uint16 card);
 	void playSLST(SLSTRecord slstRecord);
-	void pauseSLST();
-	void resumeSLST();
 	void stopAllSLST(bool fade = false);
 	static byte convertRivenVolume(uint16 volume);
 


Commit: 2756d6226b1567dbe650284c56d93d722af906b2
    https://github.com/scummvm/scummvm/commit/2756d6226b1567dbe650284c56d93d722af906b2
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2016-08-11T19:53:20+02:00

Commit Message:
MOHAWK: Add a Riven specific sound manager

- Add ambient sound fading
- Fix ambient sound volume to use the list-level volume

Changed paths:
  A engines/mohawk/riven_sound.cpp
  A engines/mohawk/riven_sound.h
    engines/mohawk/console.cpp
    engines/mohawk/module.mk
    engines/mohawk/riven.cpp
    engines/mohawk/riven.h
    engines/mohawk/riven_external.cpp
    engines/mohawk/riven_graphics.cpp
    engines/mohawk/riven_scripts.cpp
    engines/mohawk/sound.cpp
    engines/mohawk/sound.h



diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp
index fd79e53..f08eee9 100644
--- a/engines/mohawk/console.cpp
+++ b/engines/mohawk/console.cpp
@@ -42,6 +42,7 @@
 #ifdef ENABLE_RIVEN
 #include "mohawk/riven.h"
 #include "mohawk/riven_external.h"
+#include "mohawk/riven_sound.h"
 #endif
 
 namespace Mohawk {
diff --git a/engines/mohawk/module.mk b/engines/mohawk/module.mk
index 83e541e..3fc118d 100644
--- a/engines/mohawk/module.mk
+++ b/engines/mohawk/module.mk
@@ -57,6 +57,7 @@ MODULE_OBJS += \
 	riven_graphics.o \
 	riven_saveload.o \
 	riven_scripts.o \
+	riven_sound.o \
 	riven_vars.o
 endif
 
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index 054b6ca..b7c83c0 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -34,8 +34,8 @@
 #include "mohawk/riven_external.h"
 #include "mohawk/riven_graphics.h"
 #include "mohawk/riven_saveload.h"
+#include "mohawk/riven_sound.h"
 #include "mohawk/dialogs.h"
-#include "mohawk/sound.h"
 #include "mohawk/video.h"
 #include "mohawk/console.h"
 
@@ -125,7 +125,7 @@ Common::Error MohawkEngine_Riven::run() {
 		SearchMan.add("arcriven.z", &_installerArchive, 0, false);
 
 	_gfx = new RivenGraphics(this);
-	_sound = new Sound(this);
+	_sound = new RivenSoundManager(this);
 	_console = new RivenConsole(this);
 	_saveLoad = new RivenSaveLoad(this, _saveFileMan);
 	_externalScriptHandler = new RivenExternal(this);
@@ -202,6 +202,7 @@ Common::Error MohawkEngine_Riven::run() {
 void MohawkEngine_Riven::handleEvents() {
 	// Update background running things
 	checkTimer();
+	_sound->updateSLST();
 	bool needsUpdate = _gfx->runScheduledWaterEffects();
 	needsUpdate |= _video->updateMovies();
 
@@ -713,6 +714,7 @@ void MohawkEngine_Riven::delayAndUpdate(uint32 ms) {
 	uint32 startTime = _system->getMillis();
 
 	while (_system->getMillis() < startTime + ms && !shouldQuit()) {
+		_sound->updateSLST();
 		bool needsUpdate = _gfx->runScheduledWaterEffects();
 		needsUpdate |= _video->updateMovies();
 
diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h
index 4e52dfb..ce819ac 100644
--- a/engines/mohawk/riven.h
+++ b/engines/mohawk/riven.h
@@ -41,6 +41,7 @@ class RivenExternal;
 class RivenConsole;
 class RivenSaveLoad;
 class RivenOptionsDialog;
+class RivenSoundManager;
 
 // Riven Stack Types
 enum {
@@ -121,7 +122,7 @@ public:
 	MohawkEngine_Riven(OSystem *syst, const MohawkGameDescription *gamedesc);
 	virtual ~MohawkEngine_Riven();
 
-	Sound *_sound;
+	RivenSoundManager *_sound;
 	RivenGraphics *_gfx;
 	RivenExternal *_externalScriptHandler;
 	Common::RandomSource *_rnd;
diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp
index 0007503..1256304 100644
--- a/engines/mohawk/riven_external.cpp
+++ b/engines/mohawk/riven_external.cpp
@@ -24,7 +24,7 @@
 #include "mohawk/riven.h"
 #include "mohawk/riven_external.h"
 #include "mohawk/riven_graphics.h"
-#include "mohawk/sound.h"
+#include "mohawk/riven_sound.h"
 #include "mohawk/video.h"
 
 #include "gui/message.h"
@@ -2429,7 +2429,7 @@ void RivenExternal::xtexterior300_telescopedown(uint16 argc, uint16 *argv) {
 			// Play the sound of not being able to move
 			_vm->_cursor->setCursor(kRivenHideCursor);
 			_vm->_system->updateScreen();
-			_vm->_sound->playSoundBlocking(13);
+			_vm->_sound->playSound(13);
 		}
 	} else {
 		// We're not at the bottom, and we can move down again
@@ -2463,7 +2463,7 @@ void RivenExternal::xtexterior300_telescopeup(uint16 argc, uint16 *argv) {
 		// Play the sound of not being able to move
 		_vm->_cursor->setCursor(kRivenHideCursor);
 		_vm->_system->updateScreen();
-		_vm->_sound->playSoundBlocking(13);
+		_vm->_sound->playSound(13);
 		return;
 	}
 
diff --git a/engines/mohawk/riven_graphics.cpp b/engines/mohawk/riven_graphics.cpp
index db22dde..b583bc9 100644
--- a/engines/mohawk/riven_graphics.cpp
+++ b/engines/mohawk/riven_graphics.cpp
@@ -23,6 +23,7 @@
 #include "mohawk/resource.h"
 #include "mohawk/riven.h"
 #include "mohawk/riven_graphics.h"
+#include "mohawk/riven_sound.h"
 
 #include "common/system.h"
 #include "engines/util.h"
@@ -111,6 +112,7 @@ void RivenGraphics::drawPLST(uint16 x) {
 void RivenGraphics::updateScreen(Common::Rect updateRect) {
 	if (_updatesEnabled) {
 		_vm->runUpdateScreenScript();
+		_vm->_sound->triggerDrawSound();
 
 		if (_dirtyScreen) {
 			_activatedPLSTs.clear();
diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp
index caa235e..3655452 100644
--- a/engines/mohawk/riven_scripts.cpp
+++ b/engines/mohawk/riven_scripts.cpp
@@ -25,7 +25,7 @@
 #include "mohawk/riven_external.h"
 #include "mohawk/riven_graphics.h"
 #include "mohawk/riven_scripts.h"
-#include "mohawk/sound.h"
+#include "mohawk/riven_sound.h"
 #include "mohawk/video.h"
 
 #include "common/memstream.h"
@@ -309,54 +309,44 @@ void RivenScript::switchCard(uint16 op, uint16 argc, uint16 *argv) {
 
 // Command 3: play an SLST from the script
 void RivenScript::playScriptSLST(uint16 op, uint16 argc, uint16 *argv) {
-	SLSTRecord slstRecord;
 	int offset = 0, j = 0;
+	uint16 soundCount = argv[offset++];
 
+	SLSTRecord slstRecord;
 	slstRecord.index = 0;		// not set by the scripts, so we set it to 0
-	slstRecord.sound_count = argv[0];
-	slstRecord.sound_ids = new uint16[slstRecord.sound_count];
-
-	offset = slstRecord.sound_count;
+	slstRecord.soundIds.resize(soundCount);
 
-	for (j = 0; j < slstRecord.sound_count; j++)
-		slstRecord.sound_ids[j] = argv[offset++];
-	slstRecord.fade_flags = argv[offset++];
+	for (j = 0; j < soundCount; j++)
+		slstRecord.soundIds[j] = argv[offset++];
+	slstRecord.fadeFlags = argv[offset++];
 	slstRecord.loop = argv[offset++];
-	slstRecord.global_volume = argv[offset++];
+	slstRecord.globalVolume = argv[offset++];
 	slstRecord.u0 = argv[offset++];
-	slstRecord.u1 = argv[offset++];
+	slstRecord.suspend = argv[offset++];
 
-	slstRecord.volumes = new uint16[slstRecord.sound_count];
-	slstRecord.balances = new int16[slstRecord.sound_count];
-	slstRecord.u2 = new uint16[slstRecord.sound_count];
+	slstRecord.volumes.resize(soundCount);
+	slstRecord.balances.resize(soundCount);
+	slstRecord.u2.resize(soundCount);
 
-	for (j = 0; j < slstRecord.sound_count; j++)
+	for (j = 0; j < soundCount; j++)
 		slstRecord.volumes[j] = argv[offset++];
 
-	for (j = 0; j < slstRecord.sound_count; j++)
+	for (j = 0; j < soundCount; j++)
 		slstRecord.balances[j] = argv[offset++];	// negative = left, 0 = center, positive = right
 
-	for (j = 0; j < slstRecord.sound_count; j++)
+	for (j = 0; j < soundCount; j++)
 		slstRecord.u2[j] = argv[offset++];			// Unknown
 
 	// Play the requested sound list
 	_vm->_sound->playSLST(slstRecord);
-	_vm->_activatedSLST = true;
-
-	delete[] slstRecord.sound_ids;
-	delete[] slstRecord.volumes;
-	delete[] slstRecord.balances;
-	delete[] slstRecord.u2;
 }
 
 // Command 4: play local tWAV resource (twav_id, volume, block)
 void RivenScript::playSound(uint16 op, uint16 argc, uint16 *argv) {
-	byte volume = Sound::convertRivenVolume(argv[1]);
+	uint16 volume = argv[1];
+	bool playOnDraw = argv[2] == 1;
 
-	if (argv[2] == 1)
-		_vm->_sound->playSoundBlocking(argv[0], volume);
-	else
-		_vm->_sound->playSound(argv[0], volume);
+	_vm->_sound->playSound(argv[0], volume, playOnDraw);
 }
 
 // Command 7: set variable value (variable, value)
diff --git a/engines/mohawk/riven_sound.cpp b/engines/mohawk/riven_sound.cpp
new file mode 100644
index 0000000..dd45f94
--- /dev/null
+++ b/engines/mohawk/riven_sound.cpp
@@ -0,0 +1,459 @@
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/system.h"
+
+#include "audio/audiostream.h"
+
+#include "mohawk/riven_sound.h"
+#include "mohawk/sound.h"
+
+namespace Mohawk {
+
+RivenSoundManager::RivenSoundManager(MohawkEngine *vm) :
+		_vm(vm),
+		_effect(nullptr),
+		_mainAmbientSoundId(-1),
+		_effectPlayOnDraw(false),
+		_nextFadeUpdate(0) {
+
+}
+
+RivenSoundManager::~RivenSoundManager() {
+	stopSound();
+	stopAllSLST(false);
+}
+
+Audio::RewindableAudioStream *RivenSoundManager::makeAudioStream(uint16 id) {
+	return makeMohawkWaveStream(_vm->getResource(ID_TWAV, id));
+}
+
+void RivenSoundManager::playSound(uint16 id, uint16 volume, bool playOnDraw) {
+	debug (0, "Playing sound %d", id);
+
+	stopSound();
+
+	Audio::RewindableAudioStream *rewindStream = makeAudioStream(id);
+	if (!rewindStream) {
+		warning("Unable to play sound with id %d", id);
+		return;
+	}
+
+	_effect = new RivenSound(_vm, rewindStream);
+	_effect->setVolume(volume);
+
+	_effectPlayOnDraw = playOnDraw;
+	if (!playOnDraw) {
+		_effect->play();
+	}
+}
+
+void RivenSoundManager::playSLST(uint16 index, uint16 card) {
+	Common::SeekableReadStream *slstStream = _vm->getResource(ID_SLST, card);
+
+	uint16 recordCount = slstStream->readUint16BE();
+
+	for (uint16 i = 0; i < recordCount; i++) {
+		SLSTRecord slstRecord;
+		slstRecord.index = slstStream->readUint16BE();
+
+		uint16 soundCount = slstStream->readUint16BE();
+		slstRecord.soundIds.resize(soundCount);
+
+		for (uint16 j = 0; j < soundCount; j++)
+			slstRecord.soundIds[j] = slstStream->readUint16BE();
+
+		slstRecord.fadeFlags = slstStream->readUint16BE();
+		slstRecord.loop = slstStream->readUint16BE();
+		slstRecord.globalVolume = slstStream->readUint16BE();
+		slstRecord.u0 = slstStream->readUint16BE();			// Unknown
+
+		if (slstRecord.u0 > 1)
+			warning("slstRecord.u0: %d non-boolean", slstRecord.u0);
+
+		slstRecord.suspend = slstStream->readUint16BE();
+
+		if (slstRecord.suspend != 0)
+			warning("slstRecord.u1: %d non-zero", slstRecord.suspend);
+
+		slstRecord.volumes.resize(soundCount);
+		slstRecord.balances.resize(soundCount);
+		slstRecord.u2.resize(soundCount);
+
+		for (uint16 j = 0; j < soundCount; j++)
+			slstRecord.volumes[j] = slstStream->readUint16BE();
+
+		for (uint16 j = 0; j < soundCount; j++)
+			slstRecord.balances[j] = slstStream->readSint16BE();	// negative = left, 0 = center, positive = right
+
+		for (uint16 j = 0; j < soundCount; j++) {
+			slstRecord.u2[j] = slstStream->readUint16BE();		// Unknown
+
+			if (slstRecord.u2[j] != 255 && slstRecord.u2[j] != 256)
+				warning("slstRecord.u2[%d]: %d not 255 or 256", j, slstRecord.u2[j]);
+		}
+
+		if (slstRecord.index == index) {
+			playSLST(slstRecord);
+			delete slstStream;
+			return;
+		}
+	}
+
+	delete slstStream;
+
+	// If we have no matching entries, we do nothing and just let
+	// the previous ambient sounds continue.
+}
+
+void RivenSoundManager::playSLST(const SLSTRecord &slstRecord) {
+	if (slstRecord.soundIds.empty()) {
+		return;
+	}
+
+	if (slstRecord.soundIds[0] == _mainAmbientSoundId) {
+		if (slstRecord.soundIds.size() > _ambientSounds.sounds.size()) {
+			addAmbientSounds(slstRecord);
+		}
+		setAmbientLooping(slstRecord.loop);
+		setTargetVolumes(slstRecord);
+		_ambientSounds.suspend = slstRecord.suspend;
+		if (slstRecord.suspend) {
+			freePreviousAmbientSounds();
+			pauseAmbientSounds();
+			applyTargetVolumes();
+		} else {
+			playAmbientSounds();
+		}
+	} else {
+		_mainAmbientSoundId = slstRecord.soundIds[0];
+		freePreviousAmbientSounds();
+		moveAmbientSoundsToPreviousSounds();
+		addAmbientSounds(slstRecord);
+		setAmbientLooping(slstRecord.loop);
+		setTargetVolumes(slstRecord);
+		_ambientSounds.suspend = slstRecord.suspend;
+		if (slstRecord.suspend) {
+			freePreviousAmbientSounds();
+			applyTargetVolumes();
+		} else {
+			startFadingAmbientSounds(slstRecord.fadeFlags);
+		}
+	}
+}
+
+void RivenSoundManager::stopAllSLST(bool fade) {
+	_mainAmbientSoundId = -1;
+	freePreviousAmbientSounds();
+	moveAmbientSoundsToPreviousSounds();
+	startFadingAmbientSounds(fade ? kFadeOutPreviousSounds : 0);
+}
+
+void RivenSoundManager::stopSound() {
+	if (_effect) {
+		delete _effect;
+	}
+	_effect = nullptr;
+	_effectPlayOnDraw = false;
+}
+
+void RivenSoundManager::addAmbientSounds(const SLSTRecord &record) {
+	if (record.soundIds.size() > _ambientSounds.sounds.size()) {
+		uint oldSize = _ambientSounds.sounds.size();
+
+		// Resize the list to the new size
+		_ambientSounds.sounds.resize(record.soundIds.size());
+
+		// Add new elements to the list
+		for (uint i = oldSize; i < _ambientSounds.sounds.size(); i++) {
+			Audio::RewindableAudioStream *stream = makeAudioStream(record.soundIds[i]);
+
+			RivenSound *sound = new RivenSound(_vm, stream);
+			sound->setVolume(record.volumes[i]);
+			sound->setBalance(record.balances[i]);
+
+			_ambientSounds.sounds[i].sound = sound;
+			_ambientSounds.sounds[i].targetVolume = record.volumes[i];
+			_ambientSounds.sounds[i].targetBalance = record.balances[i];
+		}
+	}
+}
+
+void RivenSoundManager::setTargetVolumes(const SLSTRecord &record) {
+	for (uint i = 0; i < _ambientSounds.sounds.size(); i++) {
+		_ambientSounds.sounds[i].targetVolume = record.volumes[i] * record.globalVolume / 256;
+		_ambientSounds.sounds[i].targetBalance = record.balances[i];
+	}
+	_ambientSounds.fading = true;
+}
+
+void RivenSoundManager::freePreviousAmbientSounds() {
+	for (uint i = 0; i < _previousAmbientSounds.sounds.size(); i++) {
+		delete _previousAmbientSounds.sounds[i].sound;
+	}
+	_previousAmbientSounds = AmbientSoundList();
+}
+
+void RivenSoundManager::moveAmbientSoundsToPreviousSounds() {
+	_previousAmbientSounds = _ambientSounds;
+	_ambientSounds = AmbientSoundList();
+}
+
+void RivenSoundManager::applyTargetVolumes() {
+	for (uint i = 0; i < _ambientSounds.sounds.size(); i++) {
+		AmbientSound &ambientSound = _ambientSounds.sounds[i];
+		RivenSound *sound = ambientSound.sound;
+		sound->setVolume(ambientSound.targetVolume);
+		sound->setBalance(ambientSound.targetBalance);
+	}
+	_ambientSounds.fading = false;
+}
+
+void RivenSoundManager::startFadingAmbientSounds(uint16 flags) {
+	for (uint i = 0; i < _ambientSounds.sounds.size(); i++) {
+		AmbientSound &ambientSound = _ambientSounds.sounds[i];
+		uint16 volume;
+		if (flags & kFadeInNewSounds) {
+			volume = 0;
+		} else {
+			volume = ambientSound.targetVolume;
+		}
+		ambientSound.sound->setVolume(volume);
+	}
+	_ambientSounds.fading = true;
+	playAmbientSounds();
+
+	if (!_previousAmbientSounds.sounds.empty()) {
+		if (flags) {
+			_previousAmbientSounds.fading = true;
+		} else {
+			freePreviousAmbientSounds();
+		}
+
+		for (uint i = 0; i < _previousAmbientSounds.sounds.size(); i++) {
+			AmbientSound &ambientSound = _previousAmbientSounds.sounds[i];
+			if (flags & kFadeOutPreviousSounds) {
+				ambientSound.targetVolume = 0;
+			} else {
+				ambientSound.sound->setVolume(ambientSound.targetVolume);
+			}
+		}
+	}
+}
+
+void RivenSoundManager::playAmbientSounds() {
+	for (uint i = 0; i < _ambientSounds.sounds.size(); i++) {
+		_ambientSounds.sounds[i].sound->play();
+	}
+}
+
+void RivenSoundManager::setAmbientLooping(bool loop) {
+	for (uint i = 0; i < _ambientSounds.sounds.size(); i++) {
+		_ambientSounds.sounds[i].sound->setLooping(loop);
+	}
+}
+
+void RivenSoundManager::triggerDrawSound() {
+	if (_effectPlayOnDraw && _effect) {
+		_effect->play();
+	}
+	_effectPlayOnDraw = false;
+}
+
+void RivenSoundManager::pauseAmbientSounds() {
+	for (uint i = 0; i < _ambientSounds.sounds.size(); i++) {
+		_ambientSounds.sounds[i].sound->pause();
+	}
+}
+
+void RivenSoundManager::updateSLST() {
+	uint32 time = _vm->_system->getMillis();
+	int32 delta = CLIP<int32>(time - _nextFadeUpdate, -50, 50);
+	if (_nextFadeUpdate == 0 || delta > 0) {
+		_nextFadeUpdate = time + 50 - delta;
+
+		if (_ambientSounds.fading) {
+			fadeAmbientSoundList(_ambientSounds);
+		}
+
+		if (_previousAmbientSounds.fading) {
+			fadeAmbientSoundList(_previousAmbientSounds);
+		}
+
+		if (!_previousAmbientSounds.sounds.empty() && !_ambientSounds.fading && !_previousAmbientSounds.fading) {
+			freePreviousAmbientSounds();
+		}
+	}
+}
+
+void RivenSoundManager::fadeAmbientSoundList(AmbientSoundList &list) {
+	list.fading = false;
+
+	for (uint i = 0; i < list.sounds.size(); i++) {
+		AmbientSound &ambientSound = list.sounds[i];
+		list.fading |= fadeVolume(ambientSound);
+		list.fading |= fadeBalance(ambientSound);
+	}
+}
+
+bool RivenSoundManager::fadeVolume(AmbientSound &ambientSound) {
+	uint16 volume = ambientSound.sound->getVolume();
+	float delta = (ambientSound.targetVolume - volume) / 30.0f;
+
+	if (ABS<float>(delta) < 0.01f) {
+		ambientSound.sound->setVolume(ambientSound.targetVolume);
+		return false;
+	} else {
+		// Make sure the increment is not zero once converted to an integer
+		if (delta > 0 && delta < 1) {
+			delta = 1;
+		} else if (delta < 0 && delta > -1) {
+			delta = -1;
+		}
+
+		ambientSound.sound->setVolume(volume + delta);
+		return true;
+	}
+}
+
+bool RivenSoundManager::fadeBalance(RivenSoundManager::AmbientSound &ambientSound) {
+	int16 balance = ambientSound.sound->getBalance();
+	float delta = (ambientSound.targetBalance - balance) / 10.0f;
+
+	if (ABS<float>(delta) < 0.01) {
+		ambientSound.sound->setBalance(ambientSound.targetBalance);
+		return false;
+	} else {
+		// Make sure the increment is not zero once converted to an integer
+		if (delta > 0 && delta < 1) {
+			delta = 1;
+		} else if (delta < 0 && delta > -1) {
+			delta = -1;
+		}
+
+		ambientSound.sound->setBalance(balance + delta);
+		return true;
+	}
+}
+
+RivenSound::RivenSound(MohawkEngine *vm, Audio::RewindableAudioStream *rewindStream) :
+		_vm(vm),
+		_volume(Audio::Mixer::kMaxChannelVolume),
+		_balance(0),
+		_looping(false),
+		_stream(rewindStream) {
+
+}
+
+bool RivenSound::isPlaying() const {
+	return _vm->_mixer->isSoundHandleActive(_handle);
+}
+
+void RivenSound::pause() {
+	_vm->_mixer->pauseHandle(_handle, true);
+}
+
+void RivenSound::setVolume(uint16 volume) {
+	_volume = volume;
+	if (isPlaying()) {
+		byte mixerVolume = convertVolume(volume);
+		_vm->_mixer->setChannelVolume(_handle, mixerVolume);
+	}
+}
+
+void RivenSound::setBalance(int16 balance) {
+	_balance = balance;
+	if (isPlaying()) {
+		int8 mixerBalance = convertBalance(balance);
+		_vm->_mixer->setChannelBalance(_handle, mixerBalance);
+	}
+}
+
+void RivenSound::setLooping(bool loop) {
+	if (isPlaying() && _looping != loop) {
+		warning("Changing loop state while a sound is playing is not implemented.");
+	}
+	_looping = loop;
+}
+
+void RivenSound::play() {
+	if (isPlaying()) {
+		// If the sound is already playing, make sure it is not paused
+		_vm->_mixer->pauseHandle(_handle, false);
+		return;
+	}
+
+	if (!_stream) {
+		warning("Trying to play a sound without a stream");
+		return;
+	}
+
+	Audio::AudioStream *playStream;
+	if (_looping) {
+		playStream = new Audio::LoopingAudioStream(_stream, 0);
+	} else {
+		playStream = _stream;
+	}
+
+	int8 mixerBalance = convertBalance(_balance);
+	byte mixerVolume = convertVolume(_volume);
+	_vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, playStream, -1, mixerVolume, mixerBalance);
+	_stream = nullptr;
+}
+
+byte RivenSound::convertVolume(uint16 volume) {
+	// The volume is a fixed point value in the Mohawk part of the original engine.
+	// It's not clear what happens when it is higher than one.
+	return (volume > 255) ? 255 : volume;
+}
+
+int8 RivenSound::convertBalance(int16 balance) {
+	return (int8)(balance >> 8);
+}
+
+RivenSound::~RivenSound() {
+	_vm->_mixer->stopHandle(_handle);
+	delete _stream;
+}
+
+int16 RivenSound::getBalance() const {
+	return _balance;
+}
+
+uint16 RivenSound::getVolume() const {
+	return _volume;
+}
+
+RivenSoundManager::AmbientSound::AmbientSound() :
+		sound(nullptr),
+		targetVolume(0),
+		targetBalance(0) {
+
+}
+
+RivenSoundManager::AmbientSoundList::AmbientSoundList() :
+		fading(false),
+		suspend(false) {
+}
+
+} // End of namespace Mohawk
diff --git a/engines/mohawk/riven_sound.h b/engines/mohawk/riven_sound.h
new file mode 100644
index 0000000..f673d1e
--- /dev/null
+++ b/engines/mohawk/riven_sound.h
@@ -0,0 +1,197 @@
+/* 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef MOHAWK_RIVEN_SOUND_H
+#define MOHAWK_RIVEN_SOUND_H
+
+#include "common/array.h"
+#include "common/str.h"
+
+#include "audio/mixer.h"
+
+namespace Audio {
+class RewindableAudioStream;
+}
+
+namespace Mohawk {
+
+class MohawkEngine;
+class RivenSound;
+
+/**
+ * Ambient sound list
+ */
+struct SLSTRecord {
+	uint16 index;
+	Common::Array<uint16> soundIds;
+	uint16 fadeFlags;
+	uint16 loop;
+	uint16 globalVolume;
+	uint16 u0;
+	uint16 suspend;
+	Common::Array<uint16> volumes;
+	Common::Array<int16> balances;
+	Common::Array<uint16> u2;
+};
+
+/**
+ * Sound manager for Riven
+ *
+ * The sound manager can play simulteaneously:
+ * - An effect sound
+ * - A list of ambient sounds
+ *
+ * The list of ambient sounds can be cross faded
+ * with the previously running ambient sounds.
+ */
+class RivenSoundManager {
+public:
+	RivenSoundManager(MohawkEngine *vm);
+	~RivenSoundManager();
+
+	/**
+	 * Play an effect sound
+	 * 
+	 * @param id Sound ID in the stack
+	 * @param volume Playback volume, between 0 and 255
+	 * @param playOnDraw Start playing when the current card is drawn instead of immediatly
+	 */
+	void playSound(uint16 id, uint16 volume = 255, bool playOnDraw = false);
+
+	/** Start playing the scheduled on-draw effect sound, if any. Called by the GraphicsManager. */
+	void triggerDrawSound();
+
+	/** Stop playing the current effect sound, if any */
+	void stopSound();
+
+	/** Start playing an ambient sound list */
+	void playSLST(const SLSTRecord &slstRecord);
+
+	/** Start playing an ambient sound list from a resource */
+	void playSLST(uint16 index, uint16 card);
+
+	/** Stop playing the current ambient sounds */
+	void stopAllSLST(bool fade = false);
+
+	/** Update the ambient sounds for fading. Called once per frame. */
+	void updateSLST();
+
+private:
+	struct AmbientSound {
+		RivenSound *sound;
+		uint16 targetVolume;
+		int16 targetBalance;
+
+		AmbientSound();
+	};
+
+	struct AmbientSoundList {
+		bool fading;
+		bool suspend;
+		Common::Array<AmbientSound> sounds;
+
+		AmbientSoundList();
+	};
+
+	enum FadeFlags {
+		kFadeOutPreviousSounds = 1,
+		kFadeInNewSounds = 2
+	};
+
+	MohawkEngine *_vm;
+
+	int16 _mainAmbientSoundId;
+	AmbientSoundList _ambientSounds;
+	AmbientSoundList _previousAmbientSounds;
+	uint32 _nextFadeUpdate;
+
+	RivenSound *_effect;
+	bool _effectPlayOnDraw;
+
+	Audio::RewindableAudioStream *makeAudioStream(uint16 id);
+
+	// Ambient sound management
+	void addAmbientSounds(const SLSTRecord &record);
+	void playAmbientSounds();
+	void pauseAmbientSounds();
+	void moveAmbientSoundsToPreviousSounds();
+	void freePreviousAmbientSounds();
+
+	// Ambient sound fading
+	void setTargetVolumes(const SLSTRecord &record);
+	void applyTargetVolumes();
+	void startFadingAmbientSounds(uint16 flags);
+	void fadeAmbientSoundList(AmbientSoundList &list);
+	bool fadeVolume(AmbientSound &ambientSound);
+	bool fadeBalance(AmbientSound &ambientSound);
+	void setAmbientLooping(bool loop);
+};
+
+/**
+ * A sound used internally by the SoundManager
+ */
+class RivenSound {
+public:
+	RivenSound(MohawkEngine *vm, Audio::RewindableAudioStream *rewindStream);
+	~RivenSound();
+
+	/** Start playing the sound stream passed to the constructor */
+	void play();
+
+	/** Is the sound currently playing ar paused? */
+	bool isPlaying() const;
+
+	/** Pause the playback, the play method resumes */
+	void pause();
+
+	/** Get the current volume */
+	uint16 getVolume() const;
+
+	/** Change the playback volume */
+	void setVolume(uint16 volume);
+
+	/** Get the current balance */
+	int16 getBalance() const;
+
+	/** Change the balance */
+	void setBalance(int16 balance);
+
+	/** Set the sound to indefinitely loop. Must be called before startting the playback */
+	void setLooping(bool loop);
+
+private:
+	static byte convertVolume(uint16 volume);
+	static int8 convertBalance(int16 balance);
+
+	MohawkEngine *_vm;
+
+	Audio::SoundHandle _handle;
+	Audio::RewindableAudioStream *_stream;
+
+	uint16 _volume;
+	int16 _balance;
+	bool _looping;
+};
+
+} // End of namespace Mohawk
+
+#endif
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index dd93252..0711561 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -191,7 +191,6 @@ Sound::Sound(MohawkEngine* vm) : _vm(vm) {
 
 Sound::~Sound() {
 	stopSound();
-	stopAllSLST();
 	stopBackgroundMyst();
 
 	if (_midiParser) {
@@ -378,146 +377,6 @@ void Sound::stopMidi() {
 	_midiParser->unloadMusic();
 }
 
-byte Sound::convertRivenVolume(uint16 volume) {
-	return (volume == 256) ? 255 : volume;
-}
-
-void Sound::playSLST(uint16 index, uint16 card) {
-	Common::SeekableReadStream *slstStream = _vm->getResource(ID_SLST, card);
-	SLSTRecord slstRecord;
-	uint16 recordCount = slstStream->readUint16BE();
-
-	for (uint16 i = 0; i < recordCount; i++) {
-		slstRecord.index = slstStream->readUint16BE();
-		slstRecord.sound_count = slstStream->readUint16BE();
-		slstRecord.sound_ids = new uint16[slstRecord.sound_count];
-
-		for (uint16 j = 0; j < slstRecord.sound_count; j++)
-			slstRecord.sound_ids[j] = slstStream->readUint16BE();
-
-		slstRecord.fade_flags = slstStream->readUint16BE();
-		slstRecord.loop = slstStream->readUint16BE();
-		slstRecord.global_volume = slstStream->readUint16BE();
-		slstRecord.u0 = slstStream->readUint16BE();			// Unknown
-
-		if (slstRecord.u0 > 1)
-			warning("slstRecord.u0: %d non-boolean", slstRecord.u0);
-
-		slstRecord.u1 = slstStream->readUint16BE();			// Unknown
-
-		if (slstRecord.u1 != 0)
-			warning("slstRecord.u1: %d non-zero", slstRecord.u1);
-
-		slstRecord.volumes = new uint16[slstRecord.sound_count];
-		slstRecord.balances = new int16[slstRecord.sound_count];
-		slstRecord.u2 = new uint16[slstRecord.sound_count];
-
-		for (uint16 j = 0; j < slstRecord.sound_count; j++)
-			slstRecord.volumes[j] = slstStream->readUint16BE();
-
-		for (uint16 j = 0; j < slstRecord.sound_count; j++)
-			slstRecord.balances[j] = slstStream->readSint16BE();	// negative = left, 0 = center, positive = right
-
-		for (uint16 j = 0; j < slstRecord.sound_count; j++) {
-			slstRecord.u2[j] = slstStream->readUint16BE();		// Unknown
-
-			if (slstRecord.u2[j] != 255 && slstRecord.u2[j] != 256)
-				warning("slstRecord.u2[%d]: %d not 255 or 256", j, slstRecord.u2[j]);
-		}
-
-		if (slstRecord.index == index) {
-			playSLST(slstRecord);
-			delete[] slstRecord.sound_ids;
-			delete[] slstRecord.volumes;
-			delete[] slstRecord.balances;
-			delete[] slstRecord.u2;
-			delete slstStream;
-			return;
-		}
-
-		delete[] slstRecord.sound_ids;
-		delete[] slstRecord.volumes;
-		delete[] slstRecord.balances;
-		delete[] slstRecord.u2;
-	}
-
-	delete slstStream;
-
-	// If we have no matching entries, we do nothing and just let
-	// the previous ambient sounds continue.
-}
-
-void Sound::playSLST(SLSTRecord slstRecord) {
-	// End old sounds
-	for (uint16 i = 0; i < _currentSLSTSounds.size(); i++) {
-		bool noLongerPlay = true;
-		for (uint16 j = 0; j < slstRecord.sound_count; j++)
-			if (_currentSLSTSounds[i].id == slstRecord.sound_ids[j])
-				noLongerPlay = false;
-		if (noLongerPlay)
-			stopSLSTSound(i, (slstRecord.fade_flags & 1) != 0);
-	}
-
-	// Start new sounds
-	for (uint16 i = 0; i < slstRecord.sound_count; i++) {
-		bool alreadyPlaying = false;
-		for (uint16 j = 0; j < _currentSLSTSounds.size(); j++) {
-			if (_currentSLSTSounds[j].id == slstRecord.sound_ids[i])
-				alreadyPlaying = true;
-		}
-		if (!alreadyPlaying) {
-			playSLSTSound(slstRecord.sound_ids[i],
-						 (slstRecord.fade_flags & (1 << 1)) != 0,
-						 slstRecord.loop != 0,
-						 slstRecord.volumes[i],
-						 slstRecord.balances[i]);
-		}
-	}
-}
-
-void Sound::stopAllSLST(bool fade) {
-	for (uint16 i = 0; i < _currentSLSTSounds.size(); i++) {
-		// TODO: Fade out, if requested
-		_vm->_mixer->stopHandle(*_currentSLSTSounds[i].handle);
-		delete _currentSLSTSounds[i].handle;
-	}
-
-	_currentSLSTSounds.clear();
-}
-
-static int8 convertBalance(int16 balance) {
-	return (int8)(balance >> 8);
-}
-
-void Sound::playSLSTSound(uint16 id, bool fade, bool loop, uint16 volume, int16 balance) {
-	// WORKAROUND: Some Riven SLST entries have a volume of 0, so we just ignore them.
-	if (volume == 0)
-		return;
-
-	SLSTSndHandle sndHandle;
-	sndHandle.handle = new Audio::SoundHandle();
-	sndHandle.id = id;
-	_currentSLSTSounds.push_back(sndHandle);
-
-	Audio::RewindableAudioStream *rewindStream = makeMohawkWaveStream(_vm->getResource(ID_TWAV, id));
-
-	// Loop here if necessary
-	Audio::AudioStream *audStream = rewindStream;
-	if (loop)
-		audStream = Audio::makeLoopingAudioStream(rewindStream, 0);
-
-	// TODO: Handle fading, possibly just raise the volume of the channel in increments?
-
-	_vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, sndHandle.handle, audStream, -1, convertRivenVolume(volume), convertBalance(balance));
-}
-
-void Sound::stopSLSTSound(uint16 index, bool fade) {
-	// TODO: Fade out, if requested
-	_vm->_mixer->stopHandle(*_currentSLSTSounds[index].handle);
-	delete _currentSLSTSounds[index].handle;
-	_currentSLSTSounds.remove_at(index);
-}
-
 Audio::RewindableAudioStream *Sound::makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream) {
 	uint16 header = stream->readUint16BE();
 	uint16 rate = 0;
diff --git a/engines/mohawk/sound.h b/engines/mohawk/sound.h
index 6b50c41..2b4b1ce 100644
--- a/engines/mohawk/sound.h
+++ b/engines/mohawk/sound.h
@@ -42,20 +42,6 @@ namespace Mohawk {
 
 #define MAX_CHANNELS 2         // Can there be more than 2?
 
-struct SLSTRecord {
-	uint16 index;
-	uint16 sound_count;
-	uint16 *sound_ids;
-	uint16 fade_flags;
-	uint16 loop;
-	uint16 global_volume;
-	uint16 u0;
-	uint16 u1;
-	uint16 *volumes;
-	int16 *balances;
-	uint16 *u2;
-};
-
 enum SndHandleType {
 	kFreeHandle,
 	kUsedHandle
@@ -68,11 +54,6 @@ struct SndHandle {
 	uint16 id;
 };
 
-struct SLSTSndHandle {
-	Audio::SoundHandle *handle;
-	uint16 id;
-};
-
 struct ADPCMStatus { // Holds ADPCM status data, but is irrelevant for us.
 	uint32 size;
 	uint16 itemCount;
@@ -144,12 +125,6 @@ public:
 	void stopBackgroundMyst();
 	void changeBackgroundVolumeMyst(uint16 vol);
 
-	// Riven-specific sound functions
-	void playSLST(uint16 index, uint16 card);
-	void playSLST(SLSTRecord slstRecord);
-	void stopAllSLST(bool fade = false);
-	static byte convertRivenVolume(uint16 volume);
-
 private:
 	MohawkEngine *_vm;
 	MidiDriver *_midiDriver;
@@ -166,11 +141,6 @@ private:
 
 	// Myst-specific
 	SndHandle _mystBackgroundSound;
-
-	// Riven-specific
-	void playSLSTSound(uint16 index, bool fade, bool loop, uint16 volume, int16 balance);
-	void stopSLSTSound(uint16 id, bool fade);
-	Common::Array<SLSTSndHandle> _currentSLSTSounds;
 };
 
 } // End of namespace Mohawk






More information about the Scummvm-git-logs mailing list