[Scummvm-git-logs] scummvm master -> 5661a8b4a2db5a009cb0ead99d111acfca92584a

bluegr noreply at scummvm.org
Fri Dec 20 11:21:01 UTC 2024


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

Summary:
6a0965c239 SCUMM: Add support for reading files from DoubleFine PAK files
15fcc87ba8 SCUMM: Hook the new Doublefine PAK file handler
e9400af000 SCUMM: Hook up the new PAK file handler in the sound code
d2d08511b8 SCUMM: Hook up the PAK file manager in INSANE, NUT and SMUSH code
3daad8f5f1 SCUMM: Add SE variants for classic versions of MI1, MI2, DOTT and FT
8dba3ecdbf SCUMM: Use a 64-bit integer for file sizes of detection entries
28889be3d5 SCUMM: Add entries for the SE versions of MI1, MI2, DOTT and FT
3b7e4ac7d6 SCUMM: Add support for SMUSH subtitles in PAK files
a318189cf6 SCUMM: Simplify instantiation of the Doublefine file handler
808fc410f3 SCUMM: Add support for the MM easter egg variant in the DOTT SE version
0cbba7c029 SCUMM: Some renaming for the Loom CD related code
a3d3720f33 SCUMM: Add audio directory for the DoubleFine versions of MI1 and MI2
7b33acb96a SCUMM: Don't warn about missing audio CD tracks for Doublefine MI1
90091e3afb SCUMM: Initial support for XWB audio containers for DoubleFine MI1+MI2
f8a532cfd7 SCUMM: Fix DoubleFine XWB PCM and ADPCM streams. Some cleanup
13a3eca146 SCUMM: Encapsulate the new Doublefine SE sound code in a separate class
b628296f3f SCUMM: Remove obsolete define and TODO
43c06db34a SCUMM: Cleanup WMA codec error handling
5661a8b4a2 SCUMM: Add checksum for the GoG version of DOTT Remastered


Commit: 6a0965c239862d040696e4f59895c780307d7875
    https://github.com/scummvm/scummvm/commit/6a0965c239862d040696e4f59895c780307d7875
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Add support for reading files from DoubleFine PAK files

This will be used when reading the files of the classic versions found in
the DoubleFine remasters. Since the Full Throttle package is over 4GB,
we have adapted the internal sub file range code to use 64-bit integers
for file locations

The implementation is based on the work done in DoubleFine Explorer:
https://github.com/bgbennyboy/DoubleFine-Explorer/blob/master/uDFExplorer_LPAKManager.pas

Changed paths:
    engines/scumm/file.cpp
    engines/scumm/file.h


diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp
index 41c2f88f8bd..5c9962883a2 100644
--- a/engines/scumm/file.cpp
+++ b/engines/scumm/file.cpp
@@ -40,9 +40,9 @@ void BaseScummFile::close() {
 ScummFile::ScummFile(const ScummEngine *vm) : _subFileStart(0), _subFileLen(0), _myEos(false), _isMac(vm->_game.platform == Common::kPlatformMacintosh) {
 }
 
-void ScummFile::setSubfileRange(int32 start, int32 len) {
+void ScummFile::setSubfileRange(int64 start, int32 len) {
 	// TODO: Add sanity checks
-	const int32 fileSize = _baseStream->size();
+	const int64 fileSize = _baseStream->size();
 	assert(start <= fileSize);
 	assert(start + len <= fileSize);
 	_subFileStart = start;
@@ -155,7 +155,7 @@ bool ScummFile::seek(int64 offs, int whence) {
 			offs += _baseStream->pos();
 			break;
 		}
-		assert((int32)_subFileStart <= offs && offs <= (int32)(_subFileStart + _subFileLen));
+		assert(_subFileStart <= offs && offs <= _subFileStart + _subFileLen);
 		whence = SEEK_SET;
 	}
 	bool ret = _baseStream->seek(offs, whence);
@@ -218,6 +218,86 @@ bool ScummSteamFile::openWithSubRange(const Common::Path &filename, int32 subFil
 	}
 }
 
+#pragma mark -
+#pragma mark--- ScummPAKFile ---
+#pragma mark -
+
+ScummPAKFile::ScummPAKFile(const ScummEngine *vm, bool indexFiles) : ScummFile(vm) {
+	if (!indexFiles)
+		return;
+
+	ScummFile::open(vm->_containerFile);
+
+	const uint32 magic = _baseStream->readUint32BE();
+	const bool isFT = vm->_game.id == GID_FT;
+	const byte recordSize = isFT ? 24 : 20;
+
+	if (magic != MKTAG('K', 'A', 'P', 'L')) {
+		warning("ScummPAKFile: invalid PAK file");
+		return;
+	}
+
+	_baseStream->skip(4); // skip version
+
+	if (!isFT)
+		_baseStream->skip(4); // skip start of index
+
+	const uint32 fileEntriesOffset = _baseStream->readUint32LE();
+
+	if (isFT)
+		_baseStream->skip(4); // skip start of index
+
+	const uint32 fileNamesOffset = _baseStream->readUint32LE();
+	const uint32 dataOffset = _baseStream->readUint32LE();
+	_baseStream->skip(4); // skip size of index
+	const uint32 fileEntriesLength = _baseStream->readUint32LE();
+
+	const uint32 fileCount = fileEntriesLength / recordSize;
+	uint32 curNameOffset = 0;
+
+	for (uint32 i = 0; i < fileCount; i++) {
+		PAKFile pakFile;
+
+		_baseStream->seek(fileEntriesOffset + i * recordSize, SEEK_SET);
+		pakFile.start = !isFT ? _baseStream->readUint32LE() : _baseStream->readUint64LE();
+		pakFile.start += dataOffset;
+		_baseStream->skip(4); // skip file name offset
+		pakFile.len = _baseStream->readUint32LE();
+
+		_baseStream->seek(fileNamesOffset + curNameOffset, SEEK_SET);
+		Common::String fileName = _baseStream->readString();
+		curNameOffset += fileName.size() + 1;
+
+		// We only want to index the files of the classic versions
+		// FT data and video folders are located in the root folder
+		if (fileName.hasPrefixIgnoreCase("classic/") ||
+			fileName.hasPrefixIgnoreCase("data/") ||
+			fileName.hasPrefixIgnoreCase("video/")) {
+			// Remove the directory prefix
+			fileName = fileName.substr(fileName.findLastOf("/") + 1);
+			fileName.toLowercase();
+			_pakIndex[fileName] = pakFile;
+		}
+	}
+
+	ScummFile::close();
+}
+
+bool ScummPAKFile::openSubFile(const Common::Path &filePath) {
+	assert(_baseStream);
+
+	Common::String fileName = filePath.toString();
+	fileName.toLowercase();
+
+	if (_pakIndex.contains(fileName)) {
+		PAKFile pakFile = _pakIndex[fileName];
+		setSubfileRange(pakFile.start, pakFile.len);
+		return true;
+	} else {
+		return false;
+	}
+}
+
 #pragma mark -
 #pragma mark --- ScummDiskImage ---
 #pragma mark -
diff --git a/engines/scumm/file.h b/engines/scumm/file.h
index d0d29d98f7b..3320a9ef0f0 100644
--- a/engines/scumm/file.h
+++ b/engines/scumm/file.h
@@ -62,12 +62,12 @@ public:
 
 class ScummFile : public BaseScummFile {
 protected:
-	int32	_subFileStart;
+	int64	_subFileStart;
 	int32	_subFileLen;
 	bool	_myEos; // Have we read past the end of the subfile?
 	bool    _isMac;
 
-	void setSubfileRange(int32 start, int32 len);
+	void setSubfileRange(int64 start, int32 len);
 	void resetSubfile();
 
 public:
@@ -150,6 +150,24 @@ public:
 	bool open(const Common::Path &filename) override;
 };
 
+struct PAKFile {
+	uint64 start;
+	uint32 len;
+};
+
+typedef Common::HashMap<Common::String, PAKFile> PAKFileHashMap;
+
+class ScummPAKFile : public ScummFile {
+private:
+	PAKFileHashMap _pakIndex;
+
+public:
+	ScummPAKFile(const ScummEngine *vm, bool indexFiles = true);
+	~ScummPAKFile() override { _pakIndex.clear(); }
+
+	bool openSubFile(const Common::Path &filePath) override;
+};
+
 } // End of namespace Scumm
 
 #endif


Commit: 15fcc87ba88b82cb46849a4e269f61ae29090acd
    https://github.com/scummvm/scummvm/commit/15fcc87ba88b82cb46849a4e269f61ae29090acd
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Hook the new Doublefine PAK file handler

With this, it's possible to handle the files of the MI1 and MI2
classic versions found in MI1 SE and MI2 SE

Changed paths:
    engines/scumm/detection.h
    engines/scumm/detection_internal.h
    engines/scumm/scumm.cpp


diff --git a/engines/scumm/detection.h b/engines/scumm/detection.h
index d8c258efa48..fa59bc75a96 100644
--- a/engines/scumm/detection.h
+++ b/engines/scumm/detection.h
@@ -105,6 +105,7 @@ struct GameSettings {
 enum FilenameGenMethod {
 	kGenDiskNum,
 	kGenDiskNumSteam,
+	kGenDiskNumPak,
 	kGenRoomNum,
 	kGenRoomNumSteam,
 	kGenHEMac,
@@ -204,8 +205,8 @@ enum GameFeatures {
 	GF_ULTIMATE_TALKIE = 1 << 18,
 
 	/**
-	 *  HE99 games which were ported to a C++ codebase with HE99 opcodes
-	 *  and several HE100 GFX/Wiz features.
+	 * HE99 games which were ported to a C++ codebase with HE99 opcodes
+	 * and several HE100 GFX/Wiz features.
 	 */
 	GF_HE_995 = 1 << 19
 };
diff --git a/engines/scumm/detection_internal.h b/engines/scumm/detection_internal.h
index 6b4baf9c751..08225e9ccb4 100644
--- a/engines/scumm/detection_internal.h
+++ b/engines/scumm/detection_internal.h
@@ -91,6 +91,7 @@ static Common::String generateFilenameForDetection(const char *pattern, Filename
 		break;
 
 	case kGenUnchanged:
+	case kGenDiskNumPak:
 		result = pattern;
 		break;
 
@@ -527,7 +528,7 @@ static void detectGames(const Common::FSList &fslist, Common::List<DetectorResul
 			if (tmp)
 				md5str = computeStreamMD5AsString(*tmp, kMD5FileSizeLimit);
 			if (!md5str.empty()) {
-				int filesize = tmp->size();
+				int64 filesize = tmp->size();
 
 				d.md5 = md5str;
 				d.md5Entry = findInMD5Table(md5str.c_str());
@@ -554,7 +555,7 @@ static void detectGames(const Common::FSList &fslist, Common::List<DetectorResul
 					computeGameSettingsFromMD5(fslist, gfp, d.md5Entry, dr);
 
 					// Print some debug info.
-					debugC(1, kDebugGlobalDetection, "SCUMM detector found matching file '%s' with MD5 %s, size %d\n",
+					debugC(1, kDebugGlobalDetection, "SCUMM detector found matching file '%s' with MD5 %s, size %ld\n",
 						file.c_str(), md5str.c_str(), filesize);
 
 					// Sanity check: We *should* have found a matching gameid/variant at this point.
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 088146aca51..71fadf89e94 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1155,6 +1155,28 @@ Common::Error ScummEngine::init() {
 			} else {
 				_fileHandle = new ScummSteamFile(this, *indexFile);
 			}
+		} else if (_filenamePattern.genMethod == kGenDiskNumPak) {
+			// Container files used in remastered/SE versions
+			_containerFile = _filenamePattern.pattern; // needs to be set before instantiating ScummPAKFile
+			_fileHandle = new ScummPAKFile(this);
+			_filenamePattern.genMethod = kGenDiskNum;
+
+			switch (_game.id) {
+			case GID_MONKEY:
+				_filenamePattern.pattern = "monkey1.%03d";
+				break;
+			case GID_MONKEY2:
+				_filenamePattern.pattern = "monkey2.%03d";
+				break;
+			case GID_TENTACLE:
+				_filenamePattern.pattern = "tentacle.%03d";
+				break;
+			case GID_FT:
+				_filenamePattern.pattern = "ft.la%d";
+				break;
+			default:
+				error("kGenDiskNumPak used with unsupported game");
+			}
 		} else {
 			// Regular access, no container file involved
 			_fileHandle = new ScummFile(this);
@@ -4014,7 +4036,7 @@ bool ScummEngine::startManiac() {
 		_saveLoadSlot = 100;
 		_saveTemporaryState = true;
 
-		// Set up the chanined games to Maniac Mansion, and then back
+		// Set up the chained games to Maniac Mansion, and then back
 		// to the current game again with that save slot.
 		ChainedGamesMan.push(Common::move(maniacTarget));
 		ChainedGamesMan.push(ConfMan.getActiveDomainName(), 100);


Commit: e9400af000ed5b823b90b7e918e968ee1927b241
    https://github.com/scummvm/scummvm/commit/e9400af000ed5b823b90b7e918e968ee1927b241
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Hook up the new PAK file handler in the sound code

We need to cache the location of monster.sou, otherwise we'll end up
reindexing the PAK file on every speech sound.

With this, the classic version of DOTT found in the remaster works

Changed paths:
    engines/scumm/file.cpp
    engines/scumm/file.h
    engines/scumm/sound.cpp
    engines/scumm/sound.h


diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp
index 5c9962883a2..9236e66acc6 100644
--- a/engines/scumm/file.cpp
+++ b/engines/scumm/file.cpp
@@ -298,6 +298,20 @@ bool ScummPAKFile::openSubFile(const Common::Path &filePath) {
 	}
 }
 
+PAKFile *ScummPAKFile::getPAKFileIndex(Common::String fileName) {
+	fileName.toLowercase();
+
+	assert(_pakIndex.contains(fileName));
+
+	return &_pakIndex[fileName];
+}
+
+void ScummPAKFile::setPAKFileIndex(Common::String fileName, const PAKFile &pakFile) {
+	fileName.toLowercase();
+
+	_pakIndex[fileName] = pakFile;
+}
+
 #pragma mark -
 #pragma mark --- ScummDiskImage ---
 #pragma mark -
diff --git a/engines/scumm/file.h b/engines/scumm/file.h
index 3320a9ef0f0..ddd895a9066 100644
--- a/engines/scumm/file.h
+++ b/engines/scumm/file.h
@@ -166,6 +166,8 @@ public:
 	~ScummPAKFile() override { _pakIndex.clear(); }
 
 	bool openSubFile(const Common::Path &filePath) override;
+	PAKFile *getPAKFileIndex(Common::String fileName);
+	void setPAKFileIndex(Common::String fileName, const PAKFile &pakFile);
 };
 
 } // End of namespace Scumm
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index c6a5622bd95..45fa5ae7ebb 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -708,7 +708,21 @@ void Sound::startTalkSound(uint32 offset, uint32 length, int mode, Audio::SoundH
 		int totalOffset, soundSize, fileSize, headerTag, vctlBlockSize;
 
 		if (_vm->_voiceMode != 2) {
-			file.reset(new ScummFile(_vm));
+			if (_vm->_containerFile.empty()) {
+				file.reset(new ScummFile(_vm));
+			} else {
+				// Don't read the index of the PAK file, as we cached the
+				// location and size of monster.sou, which is the only file
+				// we need at this point. We do this to avoid reading the
+				// whole PAK file index for each speech sound.
+				ScummPAKFile *pakFile = new ScummPAKFile(_vm, false);
+				PAKFile tmpPak;
+				tmpPak.start = _cachedSfxLocationInPak;
+				tmpPak.len = _cachedSfxLengthInPak;
+				pakFile->setPAKFileIndex(DEFAULT_SFX_FILE, tmpPak);
+				file.reset(pakFile);
+			}
+
 			if (!file)
 				error("startTalkSound: Out of memory");
 
@@ -825,7 +839,21 @@ void Sound::startTalkSound(uint32 offset, uint32 length, int mode, Audio::SoundH
 			offset += 8;
 		}
 
-		file.reset(new ScummFile(_vm));
+		if (_vm->_containerFile.empty()) {
+			file.reset(new ScummFile(_vm));
+		} else {
+			// Don't read the index of the PAK file, as we cached the
+			// location and size of monster.sou, which is the only file
+			// we need at this point. We do this to avoid reading the
+			// whole PAK file index for each speech sound.
+			ScummPAKFile *pakFile = new ScummPAKFile(_vm, false);
+			PAKFile tmpPak;
+			tmpPak.start = _cachedSfxLocationInPak;
+			tmpPak.len = _cachedSfxLengthInPak;
+			pakFile->setPAKFileIndex(DEFAULT_SFX_FILE, tmpPak);
+			file.reset(pakFile);
+		}
+		
 		if (!file)
 			error("startTalkSound: Out of memory");
 
@@ -1188,7 +1216,7 @@ bool Sound::hasSfxFile() const
 
 ScummFile *Sound::restoreDiMUSESpeechFile(const char *fileName) {
 	Common::ScopedPtr<ScummFile> file;
-	file.reset(new ScummFile(_vm));
+	file.reset(_vm->_containerFile.empty() ? new ScummFile(_vm) : new ScummPAKFile(_vm));
 	if (!_vm->openFile(*file, fileName)) {
 		return NULL;
 	}
@@ -1285,6 +1313,19 @@ void Sound::setupSfxFile() {
 				}
 			}
 		}
+
+		// Handle SFX file for classic game versions packed within remastered ones
+		if (!_vm->_containerFile.empty()) {
+			ScummPAKFile pakFile(_vm);
+			if (_vm->openFile(pakFile, DEFAULT_SFX_FILE)) {
+				_soundMode = kVOCMode;
+				_sfxFilename = DEFAULT_SFX_FILE;
+
+				PAKFile tmpPak = *pakFile.getPAKFileIndex(DEFAULT_SFX_FILE);
+				_cachedSfxLocationInPak = tmpPak.start;
+				_cachedSfxLengthInPak = tmpPak.len;
+			}
+		}
 	}
 
 	if (_soundMode != kVOCMode) {
diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h
index 05227481632..354567214be 100644
--- a/engines/scumm/sound.h
+++ b/engines/scumm/sound.h
@@ -39,6 +39,8 @@
 #define DIGI_SND_MODE_SFX    1
 #define DIGI_SND_MODE_TALKIE 2
 
+#define DEFAULT_SFX_FILE "monster.sou"
+
 namespace Audio {
 class Mixer;
 class SoundHandle;
@@ -87,6 +89,8 @@ protected:
 	SoundMode _soundMode;
 	MP3OffsetTable *_offsetTable;	// For compressed audio
 	int _numSoundEffects;		// For compressed audio
+	int64 _cachedSfxLocationInPak = -1;	// For sfx files in pak files
+	int32 _cachedSfxLengthInPak = 0;    // For sfx files in pak files
 
 	uint32 _queuedSfxOffset, _queuedTalkieOffset, _queuedSfxLen, _queuedTalkieLen;
 	byte _queuedSoundMode, _queuedSfxChannel;


Commit: d2d08511b895306b57796f56a3fc2da19ba2fe41
    https://github.com/scummvm/scummvm/commit/d2d08511b895306b57796f56a3fc2da19ba2fe41
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Hook up the PAK file manager in INSANE, NUT and SMUSH code

With this, the files of the classic version of FT found in the
remastered version are now properly handled

Changed paths:
    engines/scumm/insane/insane.cpp
    engines/scumm/nut_renderer.cpp
    engines/scumm/smush/smush_player.cpp


diff --git a/engines/scumm/insane/insane.cpp b/engines/scumm/insane/insane.cpp
index 8d3deaa475c..566319d6d5a 100644
--- a/engines/scumm/insane/insane.cpp
+++ b/engines/scumm/insane/insane.cpp
@@ -611,14 +611,16 @@ int32 Insane::processKeyboard() {
 }
 
 void Insane::readFileToMem(const char *name, byte **buf) {
-	ScummFile in(_vm);
+	ScummFile *file = _vm->_containerFile.empty() ? new ScummFile(_vm) : new ScummPAKFile(_vm);
 	uint32 len;
 
-	if (!_vm->openFile(in, name))
+	if (!_vm->openFile(*file, name))
 		error("Cannot open file %s", name);
-	len = in.size();
+	len = file->size();
 	*buf = (byte *)malloc(len);
-	in.read(*buf, len);
+	file->read(*buf, len);
+	file->close();
+	delete file;
 }
 
 void Insane::startVideo(const char *filename, int num, int argC, int frameRate,
diff --git a/engines/scumm/nut_renderer.cpp b/engines/scumm/nut_renderer.cpp
index 223fcda612f..4ef3d7c10e2 100644
--- a/engines/scumm/nut_renderer.cpp
+++ b/engines/scumm/nut_renderer.cpp
@@ -101,21 +101,23 @@ void NutRenderer::codec21(byte *dst, const byte *src, int width, int height, int
 }
 
 void NutRenderer::loadFont(const char *filename) {
-	ScummFile file(_vm);
-	_vm->openFile(file, filename);
-	if (!file.isOpen()) {
+	ScummFile *file = _vm->_containerFile.empty() ? new ScummFile(_vm) : new ScummPAKFile(_vm);
+
+	_vm->openFile(*file, filename);
+	if (!file->isOpen()) {
 		error("NutRenderer::loadFont() Can't open font file: %s", filename);
 	}
 
-	uint32 tag = file.readUint32BE();
+	uint32 tag = file->readUint32BE();
 	if (tag != MKTAG('A','N','I','M')) {
 		error("NutRenderer::loadFont() there is no ANIM chunk in font header");
 	}
 
-	uint32 length = file.readUint32BE();
+	uint32 length = file->readUint32BE();
 	byte *dataSrc = new byte[length];
-	file.read(dataSrc, length);
-	file.close();
+	file->read(dataSrc, length);
+	file->close();
+	delete file;
 
 	if (READ_BE_UINT32(dataSrc) != MKTAG('A','H','D','R')) {
 		error("NutRenderer::loadFont() there is no AHDR chunk in font header");
diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp
index 2e54d0fe816..c814b4f5f40 100644
--- a/engines/scumm/smush/smush_player.cpp
+++ b/engines/scumm/smush/smush_player.cpp
@@ -1023,7 +1023,7 @@ void SmushPlayer::parseNextFrame() {
 		if (_seekFile.size() > 0) {
 			delete _base;
 
-			ScummFile *tmp = new ScummFile(_vm);
+			ScummFile *tmp = _vm->_containerFile.empty() ? new ScummFile(_vm) : new ScummPAKFile(_vm);
 			if (!g_scumm->openFile(*tmp, Common::Path(_seekFile)))
 				error("SmushPlayer: Unable to open file %s", _seekFile.c_str());
 			_base = tmp;
@@ -1190,13 +1190,15 @@ void SmushPlayer::unpause() {
 
 void SmushPlayer::play(const char *filename, int32 speed, int32 offset, int32 startFrame) {
 	// Verify the specified file exists
-	ScummFile f(_vm);
-	_vm->openFile(f, filename);
-	if (!f.isOpen()) {
+	ScummFile *file = _vm->_containerFile.empty() ? new ScummFile(_vm) : new ScummPAKFile(_vm);
+
+	_vm->openFile(*file, filename);
+	if (!file->isOpen()) {
 		warning("SmushPlayer::play() File not found %s", filename);
 		return;
 	}
-	f.close();
+	file->close();
+	delete file;
 
 	_updateNeeded = false;
 	_warpNeeded = false;
@@ -1238,7 +1240,7 @@ void SmushPlayer::play(const char *filename, int32 speed, int32 offset, int32 st
 
 		if (_insanity) {
 			// Seeking makes a mess of trying to sync the audio to
-			// the sound. Synt to time instead.
+			// the sound. Sync to time instead.
 			now = _vm->_system->getMillis() - _pauseTime;
 			elapsed = now - _startTime;
 		} else if (_vm->_mixer->isSoundHandleActive(*_compressedFileSoundHandle)) {


Commit: 3daad8f5f1f8a09cab4c40583c4d05c100325880
    https://github.com/scummvm/scummvm/commit/3daad8f5f1f8a09cab4c40583c4d05c100325880
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Add SE variants for classic versions of MI1, MI2, DOTT and FT

These are found within the remastered/SE versions

Changed paths:
    engines/scumm/detection_tables.h


diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h
index 4ec2c769c54..3a14e0dda63 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -193,11 +193,13 @@ static const GameSettings gameVariantsTable[] = {
 	{"monkey", "No AdLib", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR,                        GF_16COLOR,     Common::kPlatformAtariST, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 	{"monkey", "Demo",     "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB,            GF_16COLOR | GF_DEMO,     Common::kPlatformDOS, GUIO6(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGA, GAMEOPTION_ORIGINALGUI)},
 	{"monkey", "CD",           0, GID_MONKEY,     5, 0, MDT_ADLIB,                        GF_AUDIOTRACKS, UNK, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
-	{"monkey", "Mac",		   0, GID_MONKEY,     5, 0, MDT_MACINTOSH,                    0, UNK, GUIO6(GUIO_NOSPEECH, GUIO_NOMIDI, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION, GUIO_NOASPECT)},
+	{"monkey", "SE",           0, GID_MONKEY,     5, 0, MDT_ADLIB,                        GF_AUDIOTRACKS, UNK, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
+	{"monkey", "Mac",          0, GID_MONKEY,     5, 0, MDT_MACINTOSH,                    0, UNK, GUIO6(GUIO_NOSPEECH, GUIO_NOMIDI, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION, GUIO_NOASPECT)},
 	{"monkey", "FM-TOWNS",     0, GID_MONKEY,     5, 0, MDT_TOWNS,                        GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO6(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GAMEOPTION_TRIM_FMTOWNS_TO_200_PIXELS, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 	{"monkey", "SEGA",         0, GID_MONKEY,     5, 0, MDT_NONE,                         GF_AUDIOTRACKS, Common::kPlatformSegaCD, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 	{"monkey", "SE Talkie",    0, GID_MONKEY,     5, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_AUDIOTRACKS | GF_ULTIMATE_TALKIE, UNK, GUIO2(GUIO_RENDEREGA, GAMEOPTION_ORIGINALGUI)},
 	{"monkey2", "", 0, GID_MONKEY2,  5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO5(GUIO_NOSPEECH, GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION)},
+	{"monkey2", "SE", 0, GID_MONKEY2,  5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO5(GUIO_NOSPEECH, GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION)},
 	{"monkey2", "Demo", 0, GID_MONKEY2,  5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_DEMO, UNK, GUIO2(GUIO_NOSPEECH, GAMEOPTION_ENHANCEMENTS)},
 	{"monkey2", "Amiga", 0, GID_MONKEY2,  5, 0, MDT_AMIGA, 0, Common::kPlatformAmiga, GUIO5(GUIO_NOSPEECH, GUIO_MIDIAMIGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION)},
 	{"monkey2", "Mac", 0, GID_MONKEY2,  5, 0, MDT_MACINTOSH, 0, UNK, GUIO5(GUIO_NOSPEECH, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION, GUIO_NOASPECT)},
@@ -212,12 +214,14 @@ static const GameSettings gameVariantsTable[] = {
 	{"atlantis", "FM-TOWNS", 0, GID_INDY4,    5, 0, MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO6(GUIO_MIDITOWNS, GUIO_MIDIADLIB, GUIO_MIDIMT32, GAMEOPTION_TRIM_FMTOWNS_TO_200_PIXELS, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 
 	{"tentacle", "", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO3(GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
+	{"tentacle", "SE", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO3(GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 	{"tentacle", "Floppy", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO4(GUIO_NOSPEECH, GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 
 	{"samnmax",  "", 0, GID_SAMNMAX,  6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO3(GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 	{"samnmax",  "Floppy", 0, GID_SAMNMAX,  6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO4(GUIO_NOSPEECH, GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 
 	{"ft",   "", 0, GID_FT,  7, 0, MDT_NONE, 0, UNK, GUIO4(GUIO_NOMIDI, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_LOWLATENCYAUDIO)},
+	{"ft",   "SE", 0, GID_FT,  7, 0, MDT_NONE, 0, UNK, GUIO4(GUIO_NOMIDI, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_LOWLATENCYAUDIO)},
 	{"ft",   "Demo", 0, GID_FT,  7, 0, MDT_NONE, GF_DEMO, UNK, GUIO3(GUIO_NOMIDI, GAMEOPTION_ORIGINALGUI, GAMEOPTION_LOWLATENCYAUDIO)},
 
 	{"dig",  "", 0, GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO4(GUIO_NOMIDI, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_LOWLATENCYAUDIO)},
@@ -437,10 +441,12 @@ static const GameFilenamePattern gameFilenamesTable[] = {
 	{ "monkey", "%03d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 },		// EGA & VGA versions
 	{ "monkey", "monkey.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
 	{ "monkey", "monkey1.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
+	{ "monkey", "monkey1.pak", kGenDiskNumPak, UNK_LANG, UNK, "SE" },	// Classic version within the remastered one
 	{ "monkey", "monkeyk.%03d", kGenDiskNum, Common::JA_JPN, Common::kPlatformFMTowns, "FM-TOWNS" },
 	{ "monkey", "game.%03d", kGenDiskNum, UNK_LANG, Common::kPlatformSegaCD, "SEGA" }, // SegaCD
 
 	{ "monkey2", "monkey2.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
+ 	{ "monkey2", "monkey2.pak", kGenDiskNumPak, UNK_LANG, UNK, "SE" },	// Classic version within the remastered one
 	{ "monkey2", "mi2demo.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
 
 	{ "atlantis", "atlantis.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
@@ -453,6 +459,7 @@ static const GameFilenamePattern gameFilenamesTable[] = {
 	{ "atlantis", "atlantis.%03d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" },
 
 	{ "tentacle", "tentacle.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
+	{ "tentacle", "tenta.cle", kGenDiskNumPak, UNK_LANG, UNK, "SE" },	// Classic version within the remastered one
 	{ "tentacle", "dottdemo.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
 	{ "tentacle", "Day of the Tentacle Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 },
 	{ "tentacle", "Day of the Tentacle Demo Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 },
@@ -475,6 +482,7 @@ static const GameFilenamePattern gameFilenamesTable[] = {
 	{ "dig", "dig.la%d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" },
 
 	{ "ft", "ft.la%d", kGenDiskNum, UNK_LANG, UNK, 0 },
+	{ "ft", "full.data", kGenDiskNumPak, UNK_LANG, UNK, "SE" },	// Classic version within the remastered one
 	{ "ft", "ft.%03d", kGenDiskNum, UNK_LANG, UNK, "Demo" },    // Used by PC version of Full Throttle demo
 	{ "ft", "ftdemo.la%d", kGenDiskNum, UNK_LANG, UNK, "Demo" },
 	{ "ft", "Full Throttle Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 },


Commit: 8dba3ecdbff9df00fdd1a9a38778aa118eaf0958
    https://github.com/scummvm/scummvm/commit/8dba3ecdbff9df00fdd1a9a38778aa118eaf0958
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Use a 64-bit integer for file sizes of detection entries

Since the PAK files of the remastered versions of DOTT and FT are
very large, we need a 64-bit integer to hold their size

Changed paths:
    devtools/md5table.cpp
    engines/scumm/scumm-md5.h


diff --git a/devtools/md5table.cpp b/devtools/md5table.cpp
index 90221659998..9b1556e0828 100644
--- a/devtools/md5table.cpp
+++ b/devtools/md5table.cpp
@@ -146,7 +146,7 @@ static const char *c_header =
 	"	const char *gameid;\n"
 	"	const char *variant;\n"
 	"	const char *extra;\n"
-	"	int32 filesize;\n"
+	"	int64 filesize;\n"
 	"	Common::Language language;\n"
 	"	Common::Platform platform;\n"
 	"};\n"
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index 801261e4a0e..ff9a2b2bdea 100644
--- a/engines/scumm/scumm-md5.h
+++ b/engines/scumm/scumm-md5.h
@@ -14,7 +14,7 @@ struct MD5Table {
 	const char *gameid;
 	const char *variant;
 	const char *extra;
-	int32 filesize;
+	int64 filesize;
 	Common::Language language;
 	Common::Platform platform;
 };


Commit: 28889be3d571ddfaebd72fa4c7909968786fffb9
    https://github.com/scummvm/scummvm/commit/28889be3d571ddfaebd72fa4c7909968786fffb9
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Add entries for the SE versions of MI1, MI2, DOTT and FT

We now support the classic versions of these game variants

Changed paths:
    devtools/scumm-md5.txt
    engines/scumm/scumm-md5.h


diff --git a/devtools/scumm-md5.txt b/devtools/scumm-md5.txt
index 9a8f847ddbb..9848844327d 100644
--- a/devtools/scumm-md5.txt
+++ b/devtools/scumm-md5.txt
@@ -240,6 +240,7 @@ monkey	The Secret of Monkey Island
 	8776caed014c321272af407c1502a2df	8955	en	Mac	Mac	-	Mac v2.4	Petr Maruska (#3295)
 
 	2d1e891fe52df707c30185e52c50cd92	8955	en	DOS	CD	CD	CD-ROM v2.3	Fingolfin
+	190ab1effbfd186cda821b71a9732c7d	1242812968	en	DOS	SE	SE	SE	Filippos Karapetis
 	aa8a0cb65f3afbbe2c14c3f9f92775a3	8955	fr	DOS	CD	CD	CD-ROM v2.3	Fingolfin, Andrej Sinicyn, Andrea Petrucci
 	305d3dd57c96c65b017bc70c8c7cfb5e	8955	de	DOS	CD	CD	CD-ROM v2.3	Fingolfin
 	da6269b18fcb08189c0aa9c95533cce2	8955	it	DOS	CD	CD	CD-ROM v2.3	Fingolfin, Andrej Sinicyn, Andrea Petrucci
@@ -285,6 +286,7 @@ monkey2	Monkey Island 2: LeChuck's Revenge
 	11ddf1fde76e3156eb3a38da213f484e	-1	it	Amiga	Amiga	-	-	Andrea Petrucci
 	6ea966b4d660c870b9ee790d1fbfc535	-1	es	Amiga	Amiga	-	-	Andreas Bylund
 	3686cf8f89e102ececf4366e1d2c8126	11135	en	DOS	-	-	v1.0 11/21/91
+	d670454da245c19bef988a341c416e40	506101054	en	DOS	SE	SE	SE	Filippos Karapetis
 	8e4ee4db46954bfe2912e259a16fad82	11135	fr	DOS	-	-	v1.0 21/12/91	Nicolas Sauzède, Andrea Petrucci
 	6886e5d08cee329b1f2e743ae2e3ceed	11135	de	DOS	-	-	v1.0D 17Feb92	Fingolfin
 	69ea626f1f87eecb78ea0d6c6b983a1d	-1	it	DOS	-	-	-	Andrea Petrucci
@@ -356,6 +358,7 @@ tentacle	Day of the Tentacle
 	ae94f110a14ce71fc515d5b648827a8f	7932	es	DOS	Floppy	Floppy	-	abnog, Andrea Petrucci
 
 	4167a92a1d46baa4f4127d918d561f88	7932	en	All?	-	CD	1.6	Fingolfin
+	64d07dec2bf0789c4f2a7b656cf5bb83	2731584777	en	DOS	SE	SE	Filippos Karapetis
 	8aa05d3cdb0e795436043f0546af2da2	7932	fr	All?	-	CD	-	Andrea Petrucci
 	6e959d65358eedf9b68b81e304b97fa4	7932	de	All?	-	CD	-	Fingolfin
 	4fbbe9f64b8bc547503a379a301183ce	-1	it	All?	-	CD	-	Andrea Petrucci
@@ -403,6 +406,7 @@ ft	Full Throttle
 	41958e24d03181ff9a381a66d048a581	-1	br	All?	-	-	-	Danilo E.S.
 	09820417db26687bb7fe0c83cc4c553b	19697	en	All?	-	Version A	-	Fingolfin
 	60ba818dc3bede86d40357e3913f8505	19697	en	All?	-	Version B	-	sev, Fingolfin
+	3ad7672a6c4d190f0a08ea524f711dd6	5465581773	en	DOS	SE	SE	SE	Filippos Karapetis
 	4bedb49943df95a9c900a5a82ccbe9de	19752	fr	All?	-	-	-	cyx
 	8bdb0bf87b5e303dd35693afb9351215	-1	de	All?	-	-	-	dhewg
 	55518cd73cf9c6d23ea29c51ee06bdfe	-1	it	All?	-	-	-	delfino
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index ff9a2b2bdea..06c8a824fad 100644
--- a/engines/scumm/scumm-md5.h
+++ b/engines/scumm/scumm-md5.h
@@ -1,5 +1,5 @@
 /*
-  This file was generated by the md5table tool on Wed Dec 11 19:08:57 2024
+  This file was generated by the md5table tool on Sun Dec 15 09:46:30 2024
   DO NOT EDIT MANUALLY!
  */
 
@@ -105,6 +105,7 @@ static const MD5Table md5table[] = {
 	{ "1875b90fade138c9253a8e967007031a", "indy3", "VGA", "VGA", 6295, Common::EN_ANY, Common::kPlatformDOS },
 	{ "187d315f6b5168f68680dfe8c3d76a3e", "loom", "EGA", "EGA", 5748, Common::HE_ISR, Common::kPlatformDOS },
 	{ "1900e501a52fbf55bde6e4196f6d2aa6", "zak", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformDOS },
+	{ "190ab1effbfd186cda821b71a9732c7d", "monkey", "SE", "SE", 1242812968, Common::EN_ANY, Common::kPlatformDOS },
 	{ "19263586f749a560c1adf8b3393a9593", "socks", "HE 85", "", -1, Common::RU_RUS, Common::kPlatformWindows },
 	{ "19bf6938a94698296bcb0c99c31c91a7", "spyfox2", "", "Demo", 14689, Common::EN_GRB, Common::kPlatformWindows },
 	{ "1a6e5ae2777a6a33f06ffc0226210934", "atlantis", "Mac", "CD", 11885, Common::EN_ANY, Common::kPlatformMacintosh },
@@ -211,6 +212,7 @@ static const MD5Table md5table[] = {
 	{ "3a5d13675e9a23aedac0bac7730f0ac1", "samnmax", "", "CD", 228446581, Common::FR_FRA, Common::kPlatformMacintosh },
 	{ "3a5ec90d556d4920976c5578bfbfaf79", "maniac", "NES", "", 2082, Common::DE_DEU, Common::kPlatformNES },
 	{ "3a988de37118873ad129246b452909c0", "maniac", "V2 Demo", "V2 Demo", 1988, Common::RU_RUS, Common::kPlatformDOS },
+	{ "3ad7672a6c4d190f0a08ea524f711dd6", "ft", "SE", "SE", 5465581773, Common::EN_ANY, Common::kPlatformDOS },
 	{ "3ae7f002d9256b8bdf76aaf8a3a069f8", "freddi", "HE 100", "", 34837, Common::EN_ANY, Common::kPlatformWii },
 	{ "3af61c5edf8e15b43dbafd285b2e9777", "puttcircus", "", "Demo", 12364, Common::HE_ISR, Common::kPlatformWindows },
 	{ "3b301b7892f883ce42ab4be6a274fea6", "samnmax", "Floppy", "Floppy", 9040, Common::EN_ANY, Common::kPlatformDOS },
@@ -332,6 +334,7 @@ static const MD5Table md5table[] = {
 	{ "632d2fddb8ba97723fa15334763ae857", "thinker1", "", "", 33270, Common::EN_ANY, Common::kPlatformWindows },
 	{ "63fdcdc95cdeea00060883aed38e5504", "PuttTime", "HE 85", "", 62582, Common::EN_USA, Common::kPlatformUnknown },
 	{ "64a22be96d679018696e5c8d3ca8b71d", "freddi", "HE 73", "", 26375, Common::JA_JPN, Common::kPlatformWindows },
+	{ "64d07dec2bf0789c4f2a7b656cf5bb83", "tentacle", "SE", "SE", 2731584777, Common::EN_ANY, Common::kPlatformDOS },
 	{ "6508fd55530e6915507e1cc37f7f045d", "indy3", "EGA", "EGA", 5361, Common::EN_ANY, Common::kPlatformDOS },
 	{ "65563295c3a06493351870f20a1630cf", "spyozon", "HE CUP", "Preview", 5235008, Common::UNK_LANG, Common::kPlatformUnknown },
 	{ "659942b9a6b519f123a13cca3c333a13", "jungle", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh },
@@ -673,6 +676,7 @@ static const MD5Table md5table[] = {
 	{ "d62047a6729349ab36f7ee065bf26509", "dig", "", "", -1, Common::RU_RUS, Common::kPlatformUnknown },
 	{ "d62d248c3df6ec177405e2cb23d923b2", "indy3", "EGA", "EGA", 5361, Common::IT_ITA, Common::kPlatformDOS },
 	{ "d6334a5a9b61afe18c368540fdf522ca", "airport", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh },
+	{ "d670454da245c19bef988a341c416e40", "monkey2", "SE", "SE", 506101054, Common::EN_ANY, Common::kPlatformDOS },
 	{ "d6dd0646404768a63e963891a96daadd", "atlantis", "Mac Floppy", "Floppy", 12035, Common::EN_ANY, Common::kPlatformMacintosh },
 	{ "d73c851b942af44deb9b6d5f416a0972", "freddi3", "HE 99", "Demo", 22779, Common::HE_ISR, Common::kPlatformWindows },
 	{ "d74122362a77ec24525fdd50297dfd82", "freddi4", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh },


Commit: 3b7e4ac7d68d08ef8ba42b8d7ee4335d8b71e753
    https://github.com/scummvm/scummvm/commit/3b7e4ac7d68d08ef8ba42b8d7ee4335d8b71e753
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Add support for SMUSH subtitles in PAK files

Now, subtitles in FT videos are displayed correctly

Changed paths:
    engines/scumm/file.cpp
    engines/scumm/smush/smush_player.cpp


diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp
index 9236e66acc6..7e27ec4736f 100644
--- a/engines/scumm/file.cpp
+++ b/engines/scumm/file.cpp
@@ -268,11 +268,13 @@ ScummPAKFile::ScummPAKFile(const ScummEngine *vm, bool indexFiles) : ScummFile(v
 		Common::String fileName = _baseStream->readString();
 		curNameOffset += fileName.size() + 1;
 
-		// We only want to index the files of the classic versions
+		// We only want to index the files of the classic versions.
 		// FT data and video folders are located in the root folder
 		if (fileName.hasPrefixIgnoreCase("classic/") ||
 			fileName.hasPrefixIgnoreCase("data/") ||
-			fileName.hasPrefixIgnoreCase("video/")) {
+			fileName.hasPrefixIgnoreCase("video/") ||
+			fileName.hasPrefixIgnoreCase("en/data/") ||  // TODO: Support non-English versions
+			fileName.hasPrefixIgnoreCase("en/video/")) { // TODO: Support non-English versions
 			// Remove the directory prefix
 			fileName = fileName.substr(fileName.findLastOf("/") + 1);
 			fileName.toLowercase();
diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp
index c814b4f5f40..bd00a6340f8 100644
--- a/engines/scumm/smush/smush_player.cpp
+++ b/engines/scumm/smush/smush_player.cpp
@@ -182,17 +182,20 @@ public:
 
 static StringResource *getStrings(ScummEngine *vm, const char *file, bool is_encoded) {
 	debugC(DEBUG_SMUSH, "trying to read text resources from %s", file);
-	ScummFile theFile(vm);
+	ScummFile *theFile = vm->_containerFile.empty() ? new ScummFile(vm) : new ScummPAKFile(vm);
 
-	vm->openFile(theFile, file);
-	if (!theFile.isOpen()) {
+	vm->openFile(*theFile, file);
+	if (!theFile->isOpen()) {
+		delete theFile;
 		return 0;
 	}
-	int32 length = theFile.size();
+	int32 length = theFile->size();
 	char *filebuffer = new char [length + 1];
 	assert(filebuffer);
-	theFile.read(filebuffer, length);
+	theFile->read(filebuffer, length);
 	filebuffer[length] = 0;
+	theFile->close();
+	delete theFile;
 
 	if (is_encoded && READ_BE_UINT32(filebuffer) == MKTAG('E','T','R','S')) {
 		assert(length > ETRS_HEADER_LENGTH);


Commit: a318189cf62153fb2a3f27ab4b7a2b533881cd9b
    https://github.com/scummvm/scummvm/commit/a318189cf62153fb2a3f27ab4b7a2b533881cd9b
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Simplify instantiation of the Doublefine file handler

Add a game flag for Doublefine packed games, and simplify
the instantiation of the PAK file handler. This avoids
clashes with other packed games (e.g. the Mac version of DOTT)

Changed paths:
    engines/scumm/detection.h
    engines/scumm/detection_internal.h
    engines/scumm/detection_tables.h
    engines/scumm/insane/insane.cpp
    engines/scumm/nut_renderer.cpp
    engines/scumm/resource.cpp
    engines/scumm/scumm.cpp
    engines/scumm/scumm.h
    engines/scumm/smush/smush_player.cpp
    engines/scumm/sound.cpp
    engines/scumm/sound.h


diff --git a/engines/scumm/detection.h b/engines/scumm/detection.h
index fa59bc75a96..2ff4a9f2bcf 100644
--- a/engines/scumm/detection.h
+++ b/engines/scumm/detection.h
@@ -105,7 +105,6 @@ struct GameSettings {
 enum FilenameGenMethod {
 	kGenDiskNum,
 	kGenDiskNumSteam,
-	kGenDiskNumPak,
 	kGenRoomNum,
 	kGenRoomNumSteam,
 	kGenHEMac,
@@ -208,7 +207,12 @@ enum GameFeatures {
 	 * HE99 games which were ported to a C++ codebase with HE99 opcodes
 	 * and several HE100 GFX/Wiz features.
 	 */
-	GF_HE_995 = 1 << 19
+	GF_HE_995 = 1 << 19,
+
+	/**
+	 * Games packed within Doublefine PAK containers.
+	 */
+	GF_DOUBLEFINE_PAK = 1 << 20
 };
 
 enum ScummGameId {
diff --git a/engines/scumm/detection_internal.h b/engines/scumm/detection_internal.h
index 08225e9ccb4..4d3dde980a9 100644
--- a/engines/scumm/detection_internal.h
+++ b/engines/scumm/detection_internal.h
@@ -91,7 +91,6 @@ static Common::String generateFilenameForDetection(const char *pattern, Filename
 		break;
 
 	case kGenUnchanged:
-	case kGenDiskNumPak:
 		result = pattern;
 		break;
 
diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h
index 3a14e0dda63..a31d12fc1c5 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -193,13 +193,13 @@ static const GameSettings gameVariantsTable[] = {
 	{"monkey", "No AdLib", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR,                        GF_16COLOR,     Common::kPlatformAtariST, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 	{"monkey", "Demo",     "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB,            GF_16COLOR | GF_DEMO,     Common::kPlatformDOS, GUIO6(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGA, GAMEOPTION_ORIGINALGUI)},
 	{"monkey", "CD",           0, GID_MONKEY,     5, 0, MDT_ADLIB,                        GF_AUDIOTRACKS, UNK, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
-	{"monkey", "SE",           0, GID_MONKEY,     5, 0, MDT_ADLIB,                        GF_AUDIOTRACKS, UNK, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
+	{"monkey", "SE",           0, GID_MONKEY,     5, 0, MDT_ADLIB,                        GF_AUDIOTRACKS | GF_DOUBLEFINE_PAK, UNK, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 	{"monkey", "Mac",          0, GID_MONKEY,     5, 0, MDT_MACINTOSH,                    0, UNK, GUIO6(GUIO_NOSPEECH, GUIO_NOMIDI, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION, GUIO_NOASPECT)},
 	{"monkey", "FM-TOWNS",     0, GID_MONKEY,     5, 0, MDT_TOWNS,                        GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO6(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GAMEOPTION_TRIM_FMTOWNS_TO_200_PIXELS, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 	{"monkey", "SEGA",         0, GID_MONKEY,     5, 0, MDT_NONE,                         GF_AUDIOTRACKS, Common::kPlatformSegaCD, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 	{"monkey", "SE Talkie",    0, GID_MONKEY,     5, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_AUDIOTRACKS | GF_ULTIMATE_TALKIE, UNK, GUIO2(GUIO_RENDEREGA, GAMEOPTION_ORIGINALGUI)},
 	{"monkey2", "", 0, GID_MONKEY2,  5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO5(GUIO_NOSPEECH, GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION)},
-	{"monkey2", "SE", 0, GID_MONKEY2,  5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO5(GUIO_NOSPEECH, GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION)},
+	{"monkey2", "SE", 0, GID_MONKEY2,  5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_DOUBLEFINE_PAK, UNK, GUIO5(GUIO_NOSPEECH, GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION)},
 	{"monkey2", "Demo", 0, GID_MONKEY2,  5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_DEMO, UNK, GUIO2(GUIO_NOSPEECH, GAMEOPTION_ENHANCEMENTS)},
 	{"monkey2", "Amiga", 0, GID_MONKEY2,  5, 0, MDT_AMIGA, 0, Common::kPlatformAmiga, GUIO5(GUIO_NOSPEECH, GUIO_MIDIAMIGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION)},
 	{"monkey2", "Mac", 0, GID_MONKEY2,  5, 0, MDT_MACINTOSH, 0, UNK, GUIO5(GUIO_NOSPEECH, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION, GUIO_NOASPECT)},
@@ -214,14 +214,14 @@ static const GameSettings gameVariantsTable[] = {
 	{"atlantis", "FM-TOWNS", 0, GID_INDY4,    5, 0, MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO6(GUIO_MIDITOWNS, GUIO_MIDIADLIB, GUIO_MIDIMT32, GAMEOPTION_TRIM_FMTOWNS_TO_200_PIXELS, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 
 	{"tentacle", "", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO3(GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
-	{"tentacle", "SE", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO3(GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
+	{"tentacle", "SE", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY | GF_DOUBLEFINE_PAK, UNK, GUIO3(GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 	{"tentacle", "Floppy", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO4(GUIO_NOSPEECH, GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 
 	{"samnmax",  "", 0, GID_SAMNMAX,  6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO3(GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 	{"samnmax",  "Floppy", 0, GID_SAMNMAX,  6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO4(GUIO_NOSPEECH, GUIO_RENDEREGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 
 	{"ft",   "", 0, GID_FT,  7, 0, MDT_NONE, 0, UNK, GUIO4(GUIO_NOMIDI, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_LOWLATENCYAUDIO)},
-	{"ft",   "SE", 0, GID_FT,  7, 0, MDT_NONE, 0, UNK, GUIO4(GUIO_NOMIDI, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_LOWLATENCYAUDIO)},
+	{"ft",   "SE", 0, GID_FT,  7, 0, MDT_NONE, GF_DOUBLEFINE_PAK, UNK, GUIO4(GUIO_NOMIDI, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_LOWLATENCYAUDIO)},
 	{"ft",   "Demo", 0, GID_FT,  7, 0, MDT_NONE, GF_DEMO, UNK, GUIO3(GUIO_NOMIDI, GAMEOPTION_ORIGINALGUI, GAMEOPTION_LOWLATENCYAUDIO)},
 
 	{"dig",  "", 0, GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO4(GUIO_NOMIDI, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_LOWLATENCYAUDIO)},
@@ -441,12 +441,12 @@ static const GameFilenamePattern gameFilenamesTable[] = {
 	{ "monkey", "%03d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 },		// EGA & VGA versions
 	{ "monkey", "monkey.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
 	{ "monkey", "monkey1.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
-	{ "monkey", "monkey1.pak", kGenDiskNumPak, UNK_LANG, UNK, "SE" },	// Classic version within the remastered one
+	{ "monkey", "monkey1.pak", kGenUnchanged, UNK_LANG, UNK, "SE" },	// Classic version within the remastered one
 	{ "monkey", "monkeyk.%03d", kGenDiskNum, Common::JA_JPN, Common::kPlatformFMTowns, "FM-TOWNS" },
 	{ "monkey", "game.%03d", kGenDiskNum, UNK_LANG, Common::kPlatformSegaCD, "SEGA" }, // SegaCD
 
 	{ "monkey2", "monkey2.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
- 	{ "monkey2", "monkey2.pak", kGenDiskNumPak, UNK_LANG, UNK, "SE" },	// Classic version within the remastered one
+ 	{ "monkey2", "monkey2.pak", kGenUnchanged, UNK_LANG, UNK, "SE" },	// Classic version within the remastered one
 	{ "monkey2", "mi2demo.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
 
 	{ "atlantis", "atlantis.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
@@ -459,7 +459,7 @@ static const GameFilenamePattern gameFilenamesTable[] = {
 	{ "atlantis", "atlantis.%03d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" },
 
 	{ "tentacle", "tentacle.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
-	{ "tentacle", "tenta.cle", kGenDiskNumPak, UNK_LANG, UNK, "SE" },	// Classic version within the remastered one
+	{ "tentacle", "tenta.cle", kGenUnchanged, UNK_LANG, UNK, "SE" },	// Classic version within the remastered one
 	{ "tentacle", "dottdemo.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },
 	{ "tentacle", "Day of the Tentacle Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 },
 	{ "tentacle", "Day of the Tentacle Demo Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 },
@@ -482,7 +482,7 @@ static const GameFilenamePattern gameFilenamesTable[] = {
 	{ "dig", "dig.la%d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" },
 
 	{ "ft", "ft.la%d", kGenDiskNum, UNK_LANG, UNK, 0 },
-	{ "ft", "full.data", kGenDiskNumPak, UNK_LANG, UNK, "SE" },	// Classic version within the remastered one
+	{ "ft", "full.data", kGenUnchanged, UNK_LANG, UNK, "SE" },	// Classic version within the remastered one
 	{ "ft", "ft.%03d", kGenDiskNum, UNK_LANG, UNK, "Demo" },    // Used by PC version of Full Throttle demo
 	{ "ft", "ftdemo.la%d", kGenDiskNum, UNK_LANG, UNK, "Demo" },
 	{ "ft", "Full Throttle Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 },
diff --git a/engines/scumm/insane/insane.cpp b/engines/scumm/insane/insane.cpp
index 566319d6d5a..5d8698ab3f9 100644
--- a/engines/scumm/insane/insane.cpp
+++ b/engines/scumm/insane/insane.cpp
@@ -611,7 +611,7 @@ int32 Insane::processKeyboard() {
 }
 
 void Insane::readFileToMem(const char *name, byte **buf) {
-	ScummFile *file = _vm->_containerFile.empty() ? new ScummFile(_vm) : new ScummPAKFile(_vm);
+	ScummFile *file = _vm->instantiateScummFile();
 	uint32 len;
 
 	if (!_vm->openFile(*file, name))
diff --git a/engines/scumm/nut_renderer.cpp b/engines/scumm/nut_renderer.cpp
index 4ef3d7c10e2..31420030686 100644
--- a/engines/scumm/nut_renderer.cpp
+++ b/engines/scumm/nut_renderer.cpp
@@ -101,7 +101,7 @@ void NutRenderer::codec21(byte *dst, const byte *src, int width, int height, int
 }
 
 void NutRenderer::loadFont(const char *filename) {
-	ScummFile *file = _vm->_containerFile.empty() ? new ScummFile(_vm) : new ScummPAKFile(_vm);
+	ScummFile *file = _vm->instantiateScummFile();
 
 	_vm->openFile(*file, filename);
 	if (!file->isOpen()) {
diff --git a/engines/scumm/resource.cpp b/engines/scumm/resource.cpp
index 7e97aa33534..e630e6b601f 100644
--- a/engines/scumm/resource.cpp
+++ b/engines/scumm/resource.cpp
@@ -182,6 +182,10 @@ void ScummEngine::readRoomsOffsets() {
 	}
 }
 
+ScummFile *ScummEngine::instantiateScummFile(bool indexPAKFiles) {
+	return !(_game.features & GF_DOUBLEFINE_PAK) ? new ScummFile(this) : new ScummPAKFile(this, indexPAKFiles);
+}
+
 bool ScummEngine::openFile(BaseScummFile &file, const Common::Path &filename, bool resourceFile) {
 	bool result = false;
 
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 71fadf89e94..d4079d71e5b 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1041,12 +1041,33 @@ Common::Error ScummEngine::init() {
 
 	// The	kGenUnchanged method is only used for 'container files', i.e. files
 	// that contain the real game files bundled together in an archive format.
-	// This is the case of the NES, v0 and Mac versions of certain games.
+	// This is the case of the DoubleFine, NES, v0 and Mac versions of certain games.
 	// Note: All of these can also occur in 'extracted' form, in which case they
 	// are treated like any other SCUMM game.
 	if (_filenamePattern.genMethod == kGenUnchanged) {
+		if (_game.platform == Common::kPlatformDOS && (_game.features & GF_DOUBLEFINE_PAK)) {
+			// Container files used in remastered/SE versions
+			_containerFile = _filenamePattern.pattern; // needs to be set before instantiating ScummPAKFile
+			_fileHandle = new ScummPAKFile(this);
+			_filenamePattern.genMethod = kGenDiskNum;
 
-		if (_game.platform == Common::kPlatformNES) {
+			switch (_game.id) {
+			case GID_MONKEY:
+				_filenamePattern.pattern = "monkey1.%03d";
+				break;
+			case GID_MONKEY2:
+				_filenamePattern.pattern = "monkey2.%03d";
+				break;
+			case GID_TENTACLE:
+				_filenamePattern.pattern = "tentacle.%03d";
+				break;
+			case GID_FT:
+				_filenamePattern.pattern = "ft.la%d";
+				break;
+			default:
+				error("Unsupported Doublefine packed game");
+			}
+		} else if (_game.platform == Common::kPlatformNES) {
 			// We read data directly from NES ROM instead of extracting it with
 			// external tool
 			assert(_game.id == GID_MANIAC);
@@ -1155,28 +1176,6 @@ Common::Error ScummEngine::init() {
 			} else {
 				_fileHandle = new ScummSteamFile(this, *indexFile);
 			}
-		} else if (_filenamePattern.genMethod == kGenDiskNumPak) {
-			// Container files used in remastered/SE versions
-			_containerFile = _filenamePattern.pattern; // needs to be set before instantiating ScummPAKFile
-			_fileHandle = new ScummPAKFile(this);
-			_filenamePattern.genMethod = kGenDiskNum;
-
-			switch (_game.id) {
-			case GID_MONKEY:
-				_filenamePattern.pattern = "monkey1.%03d";
-				break;
-			case GID_MONKEY2:
-				_filenamePattern.pattern = "monkey2.%03d";
-				break;
-			case GID_TENTACLE:
-				_filenamePattern.pattern = "tentacle.%03d";
-				break;
-			case GID_FT:
-				_filenamePattern.pattern = "ft.la%d";
-				break;
-			default:
-				error("kGenDiskNumPak used with unsupported game");
-			}
 		} else {
 			// Regular access, no container file involved
 			_fileHandle = new ScummFile(this);
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index f2ff324684d..b9f53d322ca 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -40,6 +40,7 @@
 #include "graphics/sjis.h"
 #include "graphics/palette.h"
 
+#include "scumm/file.h"
 #include "scumm/gfx.h"
 #include "scumm/detection.h"
 #include "scumm/script.h"
@@ -1089,6 +1090,7 @@ public:
 	Common::Path _macCursorFile;
 
 	bool openFile(BaseScummFile &file, const Common::Path &filename, bool resourceFile = false);
+	ScummFile *instantiateScummFile(bool indexPAKFiles = true);
 
 protected:
 	int _resourceHeaderSize = 8;
diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp
index bd00a6340f8..efbc734d1f8 100644
--- a/engines/scumm/smush/smush_player.cpp
+++ b/engines/scumm/smush/smush_player.cpp
@@ -182,7 +182,7 @@ public:
 
 static StringResource *getStrings(ScummEngine *vm, const char *file, bool is_encoded) {
 	debugC(DEBUG_SMUSH, "trying to read text resources from %s", file);
-	ScummFile *theFile = vm->_containerFile.empty() ? new ScummFile(vm) : new ScummPAKFile(vm);
+	ScummFile *theFile = vm->instantiateScummFile();
 
 	vm->openFile(*theFile, file);
 	if (!theFile->isOpen()) {
@@ -1026,8 +1026,8 @@ void SmushPlayer::parseNextFrame() {
 		if (_seekFile.size() > 0) {
 			delete _base;
 
-			ScummFile *tmp = _vm->_containerFile.empty() ? new ScummFile(_vm) : new ScummPAKFile(_vm);
-			if (!g_scumm->openFile(*tmp, Common::Path(_seekFile)))
+			ScummFile *tmp = _vm->instantiateScummFile();
+			if (!_vm->openFile(*tmp, Common::Path(_seekFile)))
 				error("SmushPlayer: Unable to open file %s", _seekFile.c_str());
 			_base = tmp;
 			_base->readUint32BE();
@@ -1193,7 +1193,7 @@ void SmushPlayer::unpause() {
 
 void SmushPlayer::play(const char *filename, int32 speed, int32 offset, int32 startFrame) {
 	// Verify the specified file exists
-	ScummFile *file = _vm->_containerFile.empty() ? new ScummFile(_vm) : new ScummPAKFile(_vm);
+	ScummFile *file = _vm->instantiateScummFile();
 
 	_vm->openFile(*file, filename);
 	if (!file->isOpen()) {
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index 45fa5ae7ebb..4ed03ab0518 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -708,20 +708,18 @@ void Sound::startTalkSound(uint32 offset, uint32 length, int mode, Audio::SoundH
 		int totalOffset, soundSize, fileSize, headerTag, vctlBlockSize;
 
 		if (_vm->_voiceMode != 2) {
-			if (_vm->_containerFile.empty()) {
-				file.reset(new ScummFile(_vm));
-			} else {
-				// Don't read the index of the PAK file, as we cached the
-				// location and size of monster.sou, which is the only file
-				// we need at this point. We do this to avoid reading the
-				// whole PAK file index for each speech sound.
-				ScummPAKFile *pakFile = new ScummPAKFile(_vm, false);
+			// Don't read the index of the PAK file, as we cached the
+			// location and size of monster.sou, which is the only file
+			// we need at this point. We do this to avoid reading the
+			// whole PAK file index for each speech sound.
+			ScummFile *scummFile = _vm->instantiateScummFile(false);
+			if (_vm->_game.features & GF_DOUBLEFINE_PAK) {
 				PAKFile tmpPak;
 				tmpPak.start = _cachedSfxLocationInPak;
 				tmpPak.len = _cachedSfxLengthInPak;
-				pakFile->setPAKFileIndex(DEFAULT_SFX_FILE, tmpPak);
-				file.reset(pakFile);
+				dynamic_cast<ScummPAKFile *>(scummFile)->setPAKFileIndex(_sfxFilename, tmpPak);
 			}
+			file.reset(scummFile);
 
 			if (!file)
 				error("startTalkSound: Out of memory");
@@ -839,20 +837,18 @@ void Sound::startTalkSound(uint32 offset, uint32 length, int mode, Audio::SoundH
 			offset += 8;
 		}
 
-		if (_vm->_containerFile.empty()) {
-			file.reset(new ScummFile(_vm));
-		} else {
-			// Don't read the index of the PAK file, as we cached the
-			// location and size of monster.sou, which is the only file
-			// we need at this point. We do this to avoid reading the
-			// whole PAK file index for each speech sound.
-			ScummPAKFile *pakFile = new ScummPAKFile(_vm, false);
+		// Don't read the index of the PAK file, as we cached the
+		// location and size of monster.sou, which is the only file
+		// we need at this point. We do this to avoid reading the
+		// whole PAK file index for each speech sound.
+		ScummFile *scummFile = _vm->instantiateScummFile(false);
+		if (_vm->_game.features & GF_DOUBLEFINE_PAK) {
 			PAKFile tmpPak;
 			tmpPak.start = _cachedSfxLocationInPak;
 			tmpPak.len = _cachedSfxLengthInPak;
-			pakFile->setPAKFileIndex(DEFAULT_SFX_FILE, tmpPak);
-			file.reset(pakFile);
+			dynamic_cast<ScummPAKFile *>(scummFile)->setPAKFileIndex(_sfxFilename, tmpPak);
 		}
+		file.reset(scummFile);
 		
 		if (!file)
 			error("startTalkSound: Out of memory");
@@ -1216,7 +1212,7 @@ bool Sound::hasSfxFile() const
 
 ScummFile *Sound::restoreDiMUSESpeechFile(const char *fileName) {
 	Common::ScopedPtr<ScummFile> file;
-	file.reset(_vm->_containerFile.empty() ? new ScummFile(_vm) : new ScummPAKFile(_vm));
+	file.reset(_vm->instantiateScummFile());
 	if (!_vm->openFile(*file, fileName)) {
 		return NULL;
 	}
@@ -1265,7 +1261,7 @@ void Sound::setupSfxFile() {
 		{ nullptr, kVOCMode }
 	};
 
-	ScummFile file(_vm);
+	ScummFile *file = _vm->instantiateScummFile();
 	_offsetTable = nullptr;
 	_sfxFileEncByte = 0;
 	_sfxFilename.clear();
@@ -1294,7 +1290,7 @@ void Sound::setupSfxFile() {
 			tmp.appendInPlace("tlk");
 		}
 
-		if (file.open(Common::Path(tmp)))
+		if (file->open(Common::Path(tmp)))
 			_sfxFilename = tmp.toString('/');
 
 		if (_vm->_game.heversion <= 74)
@@ -1302,30 +1298,25 @@ void Sound::setupSfxFile() {
 
 		_soundMode = kVOCMode;
 	} else {
-		for (uint j = 0; j < 2 && !file.isOpen(); ++j) {
+		for (uint j = 0; j < 2 && !file->isOpen(); ++j) {
 			for (int i = 0; extensions[i].ext; ++i) {
 				tmp = basename[j];
 				tmp.appendInPlace(extensions[i].ext);
-				if (_vm->openFile(file, tmp)) {
+				if (_vm->openFile(*file, tmp)) {
 					_soundMode = extensions[i].mode;
 					_sfxFilename = tmp.toString('/');
+
+					// Cache SFX file location for classic game versions
+					// packed within remastered ones
+					if (_vm->_game.features & GF_DOUBLEFINE_PAK) {
+						PAKFile *tmpPak = dynamic_cast<ScummPAKFile *>(file)->getPAKFileIndex(_sfxFilename);
+						_cachedSfxLocationInPak = tmpPak->start;
+						_cachedSfxLengthInPak = tmpPak->len;
+					}
 					break;
 				}
 			}
 		}
-
-		// Handle SFX file for classic game versions packed within remastered ones
-		if (!_vm->_containerFile.empty()) {
-			ScummPAKFile pakFile(_vm);
-			if (_vm->openFile(pakFile, DEFAULT_SFX_FILE)) {
-				_soundMode = kVOCMode;
-				_sfxFilename = DEFAULT_SFX_FILE;
-
-				PAKFile tmpPak = *pakFile.getPAKFileIndex(DEFAULT_SFX_FILE);
-				_cachedSfxLocationInPak = tmpPak.start;
-				_cachedSfxLengthInPak = tmpPak.len;
-			}
-		}
 	}
 
 	if (_soundMode != kVOCMode) {
@@ -1345,21 +1336,24 @@ void Sound::setupSfxFile() {
 		 */
 		int size, compressed_offset;
 		MP3OffsetTable *cur;
-		compressed_offset = file.readUint32BE();
+		compressed_offset = file->readUint32BE();
 		_offsetTable = (MP3OffsetTable *) malloc(compressed_offset);
 		_numSoundEffects = compressed_offset / 16;
 
 		size = compressed_offset;
 		cur = _offsetTable;
 		while (size > 0) {
-			cur->org_offset = file.readUint32BE();
-			cur->new_offset = file.readUint32BE() + compressed_offset + 4; /* The + 4 is to take into accound the 'size' field */
-			cur->num_tags = file.readUint32BE();
-			cur->compressed_size = file.readUint32BE();
+			cur->org_offset = file->readUint32BE();
+			cur->new_offset = file->readUint32BE() + compressed_offset + 4; /* The + 4 is to take into accound the 'size' field */
+			cur->num_tags = file->readUint32BE();
+			cur->compressed_size = file->readUint32BE();
 			size -= 4 * 4;
 			cur++;
 		}
 	}
+
+	file->close();
+	delete file;
 }
 
 bool Sound::isSfxFinished() const {
diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h
index 354567214be..e48aac25b85 100644
--- a/engines/scumm/sound.h
+++ b/engines/scumm/sound.h
@@ -39,8 +39,6 @@
 #define DIGI_SND_MODE_SFX    1
 #define DIGI_SND_MODE_TALKIE 2
 
-#define DEFAULT_SFX_FILE "monster.sou"
-
 namespace Audio {
 class Mixer;
 class SoundHandle;


Commit: 808fc410f30eea940d0e7936a848337970782407
    https://github.com/scummvm/scummvm/commit/808fc410f30eea940d0e7936a848337970782407
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Add support for the MM easter egg variant in the DOTT SE version

Changed paths:
    devtools/scumm-md5.txt
    engines/scumm/detection_tables.h
    engines/scumm/file.cpp
    engines/scumm/scumm-md5.h
    engines/scumm/scumm.cpp


diff --git a/devtools/scumm-md5.txt b/devtools/scumm-md5.txt
index 9848844327d..21061920c93 100644
--- a/devtools/scumm-md5.txt
+++ b/devtools/scumm-md5.txt
@@ -73,6 +73,7 @@ maniac	Maniac Mansion
 	be83e882b44f2767bc08d4f766ebc347	-1	de	Atari	V2	V2	-	Joachim Eberhard
 	15240c59d3681ed53f714f8d925cb2d6	-1	es	Atari	V2	V2	-	VooD
 	624cdb93654667c869d204a64af7e57f	1988	en	DOS	V2	V2	-	Kirben, Andrea Petrucci
+	ff678e9ef8e4af2a37ca8658833c795a	1988	en	DOS	SE	SE	-	Filippos Karapetis
 	b250d0f9cc83f80ced56fe11a4fb057c	1988	en	DOS	V2	V2	alt?	Andrea Petrucci, Fingolfin
 	114acdc2659a273c220f86ee9edb24c1	-1	fr	DOS	V2	V2	-	Nicolas Sauzède
 	99a3699f80b8f776efae592b44b9b991	1988	fr	DOS	V2	V2	from DOTT	Nicolas Sauzède, Andrea Petrucci
diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h
index a31d12fc1c5..cbe89be8f1f 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -161,6 +161,7 @@ static const GameSettings gameVariantsTable[] = {
 	{"maniac", "NES",        0, GID_MANIAC, 1, 0, MDT_NONE,  0, Common::kPlatformNES, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_NOASPECT, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI)},
 	{"maniac", "V2",      "v2", GID_MANIAC, 2, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO9(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGA, GUIO_RENDERAMIGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION)},
 	{"maniac", "V2 Demo", "v2", GID_MANIAC, 2, 0, MDT_PCSPK | MDT_PCJR, GF_DEMO, Common::kPlatformDOS, GUIO7(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGA, GUIO_RENDERAMIGA, GAMEOPTION_ORIGINALGUI)},
+	{"maniac", "SE",         0, GID_MANIAC, 2, 0, MDT_PCSPK | MDT_PCJR, GF_DOUBLEFINE_PAK, Common::kPlatformDOS, GUIO9(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGA, GUIO_RENDERAMIGA, GAMEOPTION_ENHANCEMENTS, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION)},
 
 	{"zak", "V1",       "v1", GID_ZAK, 1, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO9(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGABW, GUIO_RENDERCGACOMP, GUIO_RENDERCGA, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION)},
 	{"zak", "V2",       "v2", GID_ZAK, 2, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO8(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGA, GUIO_RENDERAMIGA, GAMEOPTION_ORIGINALGUI, GAMEOPTION_COPY_PROTECTION)},
@@ -409,6 +410,7 @@ using Common::UNK_LANG;
 static const GameFilenamePattern gameFilenamesTable[] = {
 	{ "maniac", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 },
 	{ "maniac", "%02d.MAN", kGenRoomNum, UNK_LANG, UNK, "V1 Demo" },
+	{ "maniac", "dott.exe", kGenUnchanged, UNK_LANG, UNK, "SE" },	// Classic version within the remastered one. We don't really need this file, but it has to be different from DOTT's tenta.cle file
 	{ "maniac", "maniac1.d64", kGenUnchanged, UNK_LANG, Common::kPlatformC64, "C64" },   // ... and maniac2.d64
 	{ "maniac", "maniac1.dsk", kGenUnchanged, UNK_LANG, Common::kPlatformApple2GS, "Apple II" },   // ... and maniac2.dsk
 	{ "maniac", "maniacdemo.d64", kGenUnchanged, UNK_LANG, Common::kPlatformC64, "C64 Demo" },
diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp
index 7e27ec4736f..9a79adb32cb 100644
--- a/engines/scumm/file.cpp
+++ b/engines/scumm/file.cpp
@@ -271,8 +271,9 @@ ScummPAKFile::ScummPAKFile(const ScummEngine *vm, bool indexFiles) : ScummFile(v
 		// We only want to index the files of the classic versions.
 		// FT data and video folders are located in the root folder
 		if (fileName.hasPrefixIgnoreCase("classic/") ||
-			fileName.hasPrefixIgnoreCase("data/") ||
-			fileName.hasPrefixIgnoreCase("video/") ||
+			fileName.hasPrefixIgnoreCase("maniac/") ||   // DOTT MM easter egg
+			fileName.hasPrefixIgnoreCase("data/") ||     // FT data folder
+			fileName.hasPrefixIgnoreCase("video/") ||    // FT video folder
 			fileName.hasPrefixIgnoreCase("en/data/") ||  // TODO: Support non-English versions
 			fileName.hasPrefixIgnoreCase("en/video/")) { // TODO: Support non-English versions
 			// Remove the directory prefix
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index 06c8a824fad..740113cc3d7 100644
--- a/engines/scumm/scumm-md5.h
+++ b/engines/scumm/scumm-md5.h
@@ -1,5 +1,5 @@
 /*
-  This file was generated by the md5table tool on Sun Dec 15 09:46:30 2024
+  This file was generated by the md5table tool on Sun Dec 15 22:58:56 2024
   DO NOT EDIT MANUALLY!
  */
 
@@ -784,6 +784,7 @@ static const MD5Table md5table[] = {
 	{ "fe60d6b5ff51b0553ac59963123b5777", "comi", "", "", 76791, Common::UNK_LANG, Common::kPlatformWindows },
 	{ "febf4a983ea5faea1c9dd6c710ebb09c", "puttcircus", "", "", 36655, Common::DE_DEU, Common::kPlatformWindows },
 	{ "ff05c07990061d97647f059c48c1d05a", "zak", "V2", "V2", -1, Common::DE_DEU, Common::kPlatformAtariST },
+	{ "ff678e9ef8e4af2a37ca8658833c795a", "maniac", "SE", "SE", 1988, Common::EN_ANY, Common::kPlatformDOS },
 	{ "ff90541cd06403ebea117274a3203c49", "baseball", "", "Steam", -1, Common::EN_ANY, Common::kPlatformWindows },
 	{ 0, 0, 0, 0, 0, Common::UNK_LANG, Common::kPlatformUnknown }
 };
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index d4079d71e5b..6864c8b9d3a 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1048,6 +1048,8 @@ Common::Error ScummEngine::init() {
 		if (_game.platform == Common::kPlatformDOS && (_game.features & GF_DOUBLEFINE_PAK)) {
 			// Container files used in remastered/SE versions
 			_containerFile = _filenamePattern.pattern; // needs to be set before instantiating ScummPAKFile
+			if (_game.id == GID_MANIAC)
+				_containerFile = "tenta.cle";
 			_fileHandle = new ScummPAKFile(this);
 			_filenamePattern.genMethod = kGenDiskNum;
 
@@ -1064,6 +1066,10 @@ Common::Error ScummEngine::init() {
 			case GID_FT:
 				_filenamePattern.pattern = "ft.la%d";
 				break;
+			case GID_MANIAC:
+				_filenamePattern.pattern = "%.2d.LFL";
+				_filenamePattern.genMethod = kGenRoomNum;
+				break;
 			default:
 				error("Unsupported Doublefine packed game");
 			}
@@ -4007,11 +4013,13 @@ void ScummEngine_v90he::runBootscript() {
 
 bool ScummEngine::startManiac() {
 	Common::Path currentPath = ConfMan.getPath("path");
+	Common::String gameId = ConfMan.get("gameid");
 	Common::String maniacTarget;
 
 	if (!ConfMan.hasKey("easter_egg")) {
 		// Look for a game with a game path pointing to a 'Maniac' directory
-		// as a subdirectory to the current game.
+		// as a subdirectory to the current game. For the Double Fine SE version,
+		// we'll look for a game with the same path as the current game.
 		Common::ConfigManager::DomainMap::iterator iter = ConfMan.beginGameDomains();
 		for (; iter != ConfMan.endGameDomains(); ++iter) {
 			Common::ConfigManager::Domain &dom = iter->_value;
@@ -4023,6 +4031,16 @@ bool ScummEngine::startManiac() {
 					maniacTarget = iter->_key;
 					break;
 				}
+
+				// Since DOTT and MM are enclosed in the same PAK file, find
+				// a target with the same path as the current game and a game
+				// ID containing "maniac".
+				if (path.empty() && (_game.features & GF_DOUBLEFINE_PAK)) {
+					if (iter->_key != gameId && iter->_key.contains("maniac")) {
+						maniacTarget = iter->_key;
+						break;
+					}
+				}
 			}
 		}
 	} else {


Commit: 0cbba7c02994180f6c1f96982d9168a5eb4ae1a9
    https://github.com/scummvm/scummvm/commit/0cbba7c02994180f6c1f96982d9168a5eb4ae1a9
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Some renaming for the Loom CD related code

No functional changes. This will be reused for the DoubleFine MI1 CD
audio functionality

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


diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index 4ed03ab0518..ddded4f65f9 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -92,18 +92,18 @@ Sound::Sound(ScummEngine *parent, Audio::Mixer *mixer, bool useReplacementAudioT
 
 	_musicType = MDT_NONE;
 
-	_loomSteamCD.playing = false;
-	_loomSteamCD.track = 0;
-	_loomSteamCD.start = 0;
-	_loomSteamCD.duration = 0;
-	_loomSteamCD.numLoops = 0;
-	_loomSteamCD.volume = Audio::Mixer::kMaxChannelVolume;
-	_loomSteamCD.balance = 0;
-
-	_isLoomSteam = _vm->_game.id == GID_LOOM && Common::File::exists("CDDA.SOU");
+	_fileBasedCDStatus.playing = false;
+	_fileBasedCDStatus.track = 0;
+	_fileBasedCDStatus.start = 0;
+	_fileBasedCDStatus.duration = 0;
+	_fileBasedCDStatus.numLoops = 0;
+	_fileBasedCDStatus.volume = Audio::Mixer::kMaxChannelVolume;
+	_fileBasedCDStatus.balance = 0;
+
+	_hasFileBasedCDAudio = _vm->_game.id == GID_LOOM && Common::File::exists("CDDA.SOU");
 	_loomOvertureTransition = DEFAULT_LOOM_OVERTURE_TRANSITION + ConfMan.getInt("loom_overture_ticks");
 
-	_loomSteamCDAudioHandle = new Audio::SoundHandle();
+	_fileBasedCDAudioHandle = new Audio::SoundHandle();
 	_talkChannelHandle = new Audio::SoundHandle();
 
 	// This timer targets every talkie game, except for LOOM CD
@@ -118,7 +118,7 @@ Sound::~Sound() {
 	stopCDTimer();
 	stopCD();
 	free(_offsetTable);
-	delete _loomSteamCDAudioHandle;
+	delete _fileBasedCDAudioHandle;
 	delete _talkChannelHandle;
 	if (_vm->_game.version >= 5 && _vm->_game.version <= 7 && _vm->_game.heversion == 0) {
 		stopSpeechTimer();
@@ -1414,7 +1414,7 @@ void Sound::startCDTimer() {
 	// LOOM Steam uses a fixed 240Hz rate. This was probably done to get rid of some
 	// audio glitches which are confirmed to be in the original. So let's activate this
 	// fix for the DOS version of LOOM as well, if enhancements are enabled.
-	if (_isLoomSteam || (_vm->_game.id == GID_LOOM && _vm->enhancementEnabled(kEnhMinorBugFixes)))
+	if (_vm->_game.id == GID_LOOM && (_hasFileBasedCDAudio || _vm->enhancementEnabled(kEnhMinorBugFixes)))
 		interval = 1000000 / LOOM_STEAM_CDDA_RATE;
 
 	_vm->getTimerManager()->removeTimerProc(&cdTimerHandler);
@@ -1445,16 +1445,16 @@ void Sound::playCDTrack(int track, int numLoops, int startFrame, int duration) {
 }
 
 void Sound::playCDTrackInternal(int track, int numLoops, int startFrame, int duration) {
-	_loomSteamCD.track = track;
-	_loomSteamCD.numLoops = numLoops;
-	_loomSteamCD.start = startFrame;
-	_loomSteamCD.duration = duration;
+	_fileBasedCDStatus.track = track;
+	_fileBasedCDStatus.numLoops = numLoops;
+	_fileBasedCDStatus.start = startFrame;
+	_fileBasedCDStatus.duration = duration;
 
-	if (!_isLoomSteam) {
+	if (!_hasFileBasedCDAudio) {
 		g_system->getAudioCDManager()->play(track, numLoops, startFrame, duration);
 	} else {
 		// Stop any currently playing track
-		_mixer->stopHandle(*_loomSteamCDAudioHandle);
+		_mixer->stopHandle(*_fileBasedCDAudioHandle);
 
 		Common::File *cddaFile = new Common::File();
 		if (cddaFile->open("CDDA.SOU")) {
@@ -1462,7 +1462,7 @@ void Sound::playCDTrackInternal(int track, int numLoops, int startFrame, int dur
 			Audio::Timestamp end = Audio::Timestamp(0, startFrame + duration, 75);
 			Audio::SeekableAudioStream *stream = makeCDDAStream(cddaFile, DisposeAfterUse::YES);
 
-			_mixer->playStream(Audio::Mixer::kMusicSoundType, _loomSteamCDAudioHandle,
+			_mixer->playStream(Audio::Mixer::kMusicSoundType, _fileBasedCDAudioHandle,
 			                    Audio::makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops));
 		} else {
 			delete cddaFile;
@@ -1471,30 +1471,30 @@ void Sound::playCDTrackInternal(int track, int numLoops, int startFrame, int dur
 }
 
 void Sound::stopCD() {
-	if (!_isLoomSteam)
+	if (!_hasFileBasedCDAudio)
 		g_system->getAudioCDManager()->stop();
 	else
-		_mixer->stopHandle(*_loomSteamCDAudioHandle);
+		_mixer->stopHandle(*_fileBasedCDAudioHandle);
 }
 
 int Sound::pollCD() const {
-	if (!_isLoomSteam)
+	if (!_hasFileBasedCDAudio)
 		return g_system->getAudioCDManager()->isPlaying();
 	else
-		return _mixer->isSoundHandleActive(*_loomSteamCDAudioHandle);
+		return _mixer->isSoundHandleActive(*_fileBasedCDAudioHandle);
 }
 
 void Sound::updateCD() {
-	if (!_isLoomSteam)
+	if (!_hasFileBasedCDAudio)
 		g_system->getAudioCDManager()->update();
 }
 
 AudioCDManager::Status Sound::getCDStatus() {
-	if (!_isLoomSteam)
+	if (!_hasFileBasedCDAudio)
 		return g_system->getAudioCDManager()->getStatus();
 	else {
-		AudioCDManager::Status info = _loomSteamCD;
-		info.playing = _mixer->isSoundHandleActive(*_loomSteamCDAudioHandle);
+		AudioCDManager::Status info = _fileBasedCDStatus;
+		info.playing = _mixer->isSoundHandleActive(*_fileBasedCDAudioHandle);
 		return info;
 	}
 }
diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h
index e48aac25b85..ef638aa334a 100644
--- a/engines/scumm/sound.h
+++ b/engines/scumm/sound.h
@@ -100,9 +100,9 @@ protected:
 	int16 _currentCDSound;
 	int16 _currentMusic;
 
-	Audio::SoundHandle *_loomSteamCDAudioHandle;
-	bool _isLoomSteam;
-	AudioCDManager::Status _loomSteamCD;
+	Audio::SoundHandle *_fileBasedCDAudioHandle;
+	bool _hasFileBasedCDAudio;
+	AudioCDManager::Status _fileBasedCDStatus;
 	bool _useReplacementAudioTracks;
 	int _musicTimer;
 	int _loomOvertureTransition;


Commit: a3d3720f33fb47f70e73bb084c768db127c0ba82
    https://github.com/scummvm/scummvm/commit/a3d3720f33fb47f70e73bb084c768db127c0ba82
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Add audio directory for the DoubleFine versions of MI1 and MI2

Changed paths:
    engines/scumm/scumm.cpp


diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 6864c8b9d3a..312f2766d66 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -975,6 +975,11 @@ Common::Error ScummEngine::init() {
 		// This is for the Amiga version of Indy3/Loom/Maniac/Zak
 		SearchMan.addSubDirectoryMatching(gameDataDir, "rooms");
 	}
+	
+	if ((_game.id == GID_MONKEY || _game.id == GID_MONKEY2) && (_game.features & GF_DOUBLEFINE_PAK)) {
+		// This is for the DoubleFine SE versions of Monkey Island 1 and 2
+		SearchMan.addSubDirectoryMatching(gameDataDir, "audio");
+	}
 
 	if ((_game.platform == Common::kPlatformMacintosh) && (_game.version == 3)) {
 		// This is for the Mac version of Indy3/Loom


Commit: 7b33acb96ab3784b8a56d0ad167f44047b107b10
    https://github.com/scummvm/scummvm/commit/7b33acb96ab3784b8a56d0ad167f44047b107b10
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Don't warn about missing audio CD tracks for Doublefine MI1

The audio CD tracks in that version are handled as files

Changed paths:
    engines/scumm/scumm.cpp


diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 312f2766d66..a3efc1adda9 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1562,7 +1562,8 @@ void ScummEngine::setupScumm(const Common::Path &macResourceFile) {
 		// fallback with MIDI music when CD tracks are not found.
 		if (!existExtractedCDAudioFiles(track)
 		    && !isDataAndCDAudioReadFromSameCD()
-			&& !(_game.id == GID_MONKEY && _game.features & GF_ULTIMATE_TALKIE)) {
+			&& !(_game.id == GID_MONKEY && _game.features & GF_ULTIMATE_TALKIE)
+			&& !(_game.id == GID_MONKEY && _game.features & GF_DOUBLEFINE_PAK)) {
 			warnMissingExtractedCDAudio();
 		}
 		_system->getAudioCDManager()->open();


Commit: 90091e3afbd6367ad81cb8981bebf1e1f2339075
    https://github.com/scummvm/scummvm/commit/90091e3afbd6367ad81cb8981bebf1e1f2339075
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Initial support for XWB audio containers for DoubleFine MI1+MI2

All the functionality is hooked in the same manner as the Loom Steam
CD audio code. It's still disabled though, since WMA decoding isn't
implemented yet.

There are three known audio formats in MI1 SE and MI2 SE:
- PCM (tested and working)
- WMA (missing implementation)
- MP3 (currently crashes)

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


diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index ddded4f65f9..c9880d174f9 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -106,6 +106,13 @@ Sound::Sound(ScummEngine *parent, Audio::Mixer *mixer, bool useReplacementAudioT
 	_fileBasedCDAudioHandle = new Audio::SoundHandle();
 	_talkChannelHandle = new Audio::SoundHandle();
 
+#ifdef ENABLE_DOUBLEFINE_XWB
+	if (_vm->_game.id == GID_MONKEY && (_vm->_game.features & GF_DOUBLEFINE_PAK)) {
+		_hasFileBasedCDAudio = true;
+		indexXWBFile("MusicOriginal.xwb");
+	}
+#endif
+
 	// This timer targets every talkie game, except for LOOM CD
 	// which is handled differently, and except for COMI which
 	// handles lipsync within Digital iMUSE.
@@ -1444,6 +1451,37 @@ void Sound::playCDTrack(int track, int numLoops, int startFrame, int duration) {
 	startCDTimer();
 }
 
+#ifdef ENABLE_DOUBLEFINE_XWB
+Audio::SeekableAudioStream *Sound::createXWBStream(Common::SeekableSubReadStream *stream, XWBEntry entry) {
+	byte flags = Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_16BITS;
+	if (entry.channels == 2)
+		flags |= Audio::FLAG_STEREO;
+
+	switch (entry.codec) {
+	case kXWBCodecPCM:
+		return Audio::makeRawStream(stream, entry.rate, flags, DisposeAfterUse::YES);
+	case kXWBCodecADPCM:
+		error("createXWBStream: ADPCM codec not supported");
+	case kXWBCodecMP3:
+#ifdef USE_MAD
+		return Audio::makeMP3Stream(stream, DisposeAfterUse::YES);
+#endif
+	case kXWBCodecWMA:
+		// TODO: Implement WMA stream
+		/*return new Audio::WMACodec(
+			2,
+			entry.rate,
+			entry.channels,
+			entry.bits,
+			entry.align,
+			stream
+		);*/
+	default:
+		error("createXWBStream: Unknown XWB codec %d", entry.codec);
+	}
+}
+#endif
+
 void Sound::playCDTrackInternal(int track, int numLoops, int startFrame, int duration) {
 	_fileBasedCDStatus.track = track;
 	_fileBasedCDStatus.numLoops = numLoops;
@@ -1456,17 +1494,44 @@ void Sound::playCDTrackInternal(int track, int numLoops, int startFrame, int dur
 		// Stop any currently playing track
 		_mixer->stopHandle(*_fileBasedCDAudioHandle);
 
-		Common::File *cddaFile = new Common::File();
-		if (cddaFile->open("CDDA.SOU")) {
-			Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
-			Audio::Timestamp end = Audio::Timestamp(0, startFrame + duration, 75);
-			Audio::SeekableAudioStream *stream = makeCDDAStream(cddaFile, DisposeAfterUse::YES);
+		Common::File *cdAudioFile = new Common::File();
+		Audio::SeekableAudioStream *stream = nullptr;
 
-			_mixer->playStream(Audio::Mixer::kMusicSoundType, _fileBasedCDAudioHandle,
-			                    Audio::makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops));
-		} else {
-			delete cddaFile;
+		if (_vm->_game.id == GID_LOOM) {
+			if (!cdAudioFile->open("CDDA.SOU")) {
+				delete cdAudioFile;
+				return;
+			}
+			stream = makeCDDAStream(cdAudioFile, DisposeAfterUse::YES);
+
+#ifdef ENABLE_DOUBLEFINE_XWB
+		} else if (_vm->_game.id == GID_MONKEY) {
+			if (!cdAudioFile->open("MusicOriginal.xwb")) {
+				delete cdAudioFile;
+				return;
+			}
+
+			// HACK: Since we don't support WMA files yet, we'll just play a PCM entry
+			// TODO: Remove this, once WMA streams are supported!
+			track = 20;
+
+			XWBEntry entry = _xwbEntries[track];
+			auto subStream = new Common::SeekableSubReadStream(
+				cdAudioFile,
+				entry.offset,
+				entry.offset + entry.length,
+				DisposeAfterUse::YES
+			);
+
+			stream = createXWBStream(subStream, entry);
+#endif
 		}
+
+		Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
+		Audio::Timestamp end = Audio::Timestamp(0, startFrame + duration, 75);
+		
+		_mixer->playStream(Audio::Mixer::kMusicSoundType, _fileBasedCDAudioHandle,
+		                    Audio::makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops));
 	}
 }
 
@@ -1583,6 +1648,88 @@ bool Sound::isAudioDisabled() {
 	return false;
 }
 
+#ifdef ENABLE_DOUBLEFINE_XWB
+void Sound::indexXWBFile(const Common::String &filename) {
+	// This implementation is based off unxwb: https://github.com/mariodon/unxwb/
+	// Only the parts that apply to the Doublefine releases of
+	// MI1 and MI2 have been implemented.
+
+	struct SegmentData {
+		uint32 offset;
+		uint32 length;
+	};
+	SegmentData segments[5] = {};
+
+	Common::File *f = new Common::File();
+	f->open(Common::Path(filename));
+
+	const uint32 magic = f->readUint32BE();
+	if (magic != MKTAG('W', 'B', 'N', 'D')) {
+		warning("Invalid XWB file");
+		f->close();
+		delete f;
+		return;
+	}
+
+	const uint32 version = f->readUint32LE();
+	if (version < 42) {
+		warning("Unsupported XWB version: %d", version);
+		f->close();
+		delete f;
+		return;
+	}
+
+	f->skip(4); // skip dwHeaderVersion
+
+	for (uint32 i = 0; i < 5; i++) {
+		segments[i].offset = f->readUint32LE();
+		segments[i].length = f->readUint32LE();
+	}
+
+	f->seek(segments[kXWBSegmentBankData].offset);
+	const uint32 flags = f->readUint32LE();
+	const uint32 entryCount = f->readUint32LE();
+	f->skip(64); // skip bank name
+	const uint32 entrySize = f->readUint32LE();
+	if (entrySize < 24) {
+		warning("Unsupported XWB entry size: %d", entrySize);
+		f->close();
+		delete f;
+		return;
+	}
+
+	if (flags & 0x00020000) {
+		warning("XWB compact format is not supported");
+		f->close();
+		delete f;
+		return;
+	}
+
+	f->seek(segments[kXWBSegmentEntryMetaData].offset);
+
+	for (uint32 i = 0; i < entryCount; i++) {
+		XWBEntry entry;
+		/*uint32 flagsAndDuration = */ f->readUint32LE();
+		uint32 format = f->readUint32LE();
+		entry.offset = f->readUint32LE() + segments[kXWBSegmentEntryWaveData].offset;
+		entry.length = f->readUint32LE();
+		/*uint32 loopOffset = */ f->readUint32LE();
+		/*uint32 loopLength = */ f->readUint32LE();
+
+		entry.codec = static_cast<XWBCodec>(format & ((1 << 2) - 1));
+		entry.channels = (format >> (2)) & ((1 << 3) - 1);
+		entry.rate = (format >> (2 + 3)) & ((1 << 18) - 1);
+		entry.align = (format >> (2 + 3 + 18)) & ((1 << 8) - 1);
+		entry.bits = (format >> (2 + 3 + 18 + 8)) & ((1 << 1) - 1);
+
+		_xwbEntries.push_back(entry);
+	}
+
+	f->close();
+	delete f;
+}
+#endif
+
 #pragma mark -
 #pragma mark --- Sound resource handling ---
 #pragma mark -
diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h
index ef638aa334a..a32f43dff4e 100644
--- a/engines/scumm/sound.h
+++ b/engines/scumm/sound.h
@@ -39,9 +39,14 @@
 #define DIGI_SND_MODE_SFX    1
 #define DIGI_SND_MODE_TALKIE 2
 
+namespace Common {
+class SeekableSubReadStream;
+}
+
 namespace Audio {
 class Mixer;
 class SoundHandle;
+class SeekableAudioStream;
 }
 
 namespace Scumm {
@@ -54,6 +59,11 @@ enum {
 	kTalkSoundID = 10000
 };
 
+// TODO: XWB audio packages, used in Doublefine MI1 and MI2.
+// We're still missing WMA support in SCUMM, so we can't play
+// the audio files contained in these packages.
+//#define ENABLE_DOUBLEFINE_XWB 1
+
 // TODO: Consider splitting Sound into even more subclasses.
 // E.g. for v1-v4, v5, v6+, ...
 class Sound : public Common::Serializable {
@@ -182,6 +192,41 @@ protected:
 	virtual void processSoundQueues();
 
 	int getReplacementAudioTrack(int soundID);
+
+#ifdef ENABLE_DOUBLEFINE_XWB
+private:
+
+	// For XWB files in Doublefine game variants
+	enum XWBCodec {
+		kXWBCodecPCM = 0,
+		kXWBCodecADPCM = 1,
+		kXWBCodecMP3 = 2,
+		kXWBCodecWMA = 3
+	};
+
+	enum XWBSegmentType {
+		kXWBSegmentBankData = 0,
+		kXWBSegmentEntryMetaData = 1,
+		kXWBSegmentSeekTables = 2,
+		kXWBSegmentEntryNames = 3,
+		kXWBSegmentEntryWaveData = 4
+	};
+
+	struct XWBEntry {
+		uint32 offset;
+		uint32 length;
+		XWBCodec codec;
+		byte channels;
+		uint16 rate;
+		uint16 align;
+		byte bits;
+	};
+
+	Common::Array<XWBEntry> _xwbEntries;
+
+	void indexXWBFile(const Common::String &filename);
+	Audio::SeekableAudioStream *createXWBStream(Common::SeekableSubReadStream *stream, XWBEntry entry);
+#endif
 };
 
 


Commit: f8a532cfd76b19a07f811639b8bb42e23f42124c
    https://github.com/scummvm/scummvm/commit/f8a532cfd76b19a07f811639b8bb42e23f42124c
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Fix DoubleFine XWB PCM and ADPCM streams. Some cleanup

Now, speech and SFX in MI1SE and MI2SE, which use PCM and ADPCM, are
handled correctly. WMA audio is still not handled.

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


diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index c9880d174f9..1632f483faf 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -39,6 +39,7 @@
 #include "audio/decoders/flac.h"
 #include "audio/mididrv.h"
 #include "audio/mixer.h"
+#include "audio/decoders/adpcm.h"
 #include "audio/decoders/mp3.h"
 #include "audio/decoders/raw.h"
 #include "audio/decoders/voc.h"
@@ -1451,37 +1452,6 @@ void Sound::playCDTrack(int track, int numLoops, int startFrame, int duration) {
 	startCDTimer();
 }
 
-#ifdef ENABLE_DOUBLEFINE_XWB
-Audio::SeekableAudioStream *Sound::createXWBStream(Common::SeekableSubReadStream *stream, XWBEntry entry) {
-	byte flags = Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_16BITS;
-	if (entry.channels == 2)
-		flags |= Audio::FLAG_STEREO;
-
-	switch (entry.codec) {
-	case kXWBCodecPCM:
-		return Audio::makeRawStream(stream, entry.rate, flags, DisposeAfterUse::YES);
-	case kXWBCodecADPCM:
-		error("createXWBStream: ADPCM codec not supported");
-	case kXWBCodecMP3:
-#ifdef USE_MAD
-		return Audio::makeMP3Stream(stream, DisposeAfterUse::YES);
-#endif
-	case kXWBCodecWMA:
-		// TODO: Implement WMA stream
-		/*return new Audio::WMACodec(
-			2,
-			entry.rate,
-			entry.channels,
-			entry.bits,
-			entry.align,
-			stream
-		);*/
-	default:
-		error("createXWBStream: Unknown XWB codec %d", entry.codec);
-	}
-}
-#endif
-
 void Sound::playCDTrackInternal(int track, int numLoops, int startFrame, int duration) {
 	_fileBasedCDStatus.track = track;
 	_fileBasedCDStatus.numLoops = numLoops;
@@ -1649,8 +1619,18 @@ bool Sound::isAudioDisabled() {
 }
 
 #ifdef ENABLE_DOUBLEFINE_XWB
+
+#define WARN_AND_RETURN_XWB(message)          \
+	{                                         \
+		warning("indexXWBFile: %s", message); \
+		f->close();                           \
+		delete f;                             \
+		return;                               \
+	}
+
 void Sound::indexXWBFile(const Common::String &filename) {
 	// This implementation is based off unxwb: https://github.com/mariodon/unxwb/
+	// as well as xwbdump: https://raw.githubusercontent.com/wiki/Microsoft/DirectXTK/xwbdump.cpp
 	// Only the parts that apply to the Doublefine releases of
 	// MI1 and MI2 have been implemented.
 
@@ -1664,23 +1644,15 @@ void Sound::indexXWBFile(const Common::String &filename) {
 	f->open(Common::Path(filename));
 
 	const uint32 magic = f->readUint32BE();
-	if (magic != MKTAG('W', 'B', 'N', 'D')) {
-		warning("Invalid XWB file");
-		f->close();
-		delete f;
-		return;
-	}
-
 	const uint32 version = f->readUint32LE();
-	if (version < 42) {
-		warning("Unsupported XWB version: %d", version);
-		f->close();
-		delete f;
-		return;
-	}
-
 	f->skip(4); // skip dwHeaderVersion
 
+	if (magic != MKTAG('W', 'B', 'N', 'D'))
+		WARN_AND_RETURN_XWB("Invalid XWB file")
+
+	if (version < 42)
+		WARN_AND_RETURN_XWB("Unsupported XWB version")
+
 	for (uint32 i = 0; i < 5; i++) {
 		segments[i].offset = f->readUint32LE();
 		segments[i].length = f->readUint32LE();
@@ -1691,19 +1663,11 @@ void Sound::indexXWBFile(const Common::String &filename) {
 	const uint32 entryCount = f->readUint32LE();
 	f->skip(64); // skip bank name
 	const uint32 entrySize = f->readUint32LE();
-	if (entrySize < 24) {
-		warning("Unsupported XWB entry size: %d", entrySize);
-		f->close();
-		delete f;
-		return;
-	}
+	if (entrySize < 24)
+		WARN_AND_RETURN_XWB("Unsupported XWB entry size")
 
-	if (flags & 0x00020000) {
-		warning("XWB compact format is not supported");
-		f->close();
-		delete f;
-		return;
-	}
+	if (flags & 0x00020000)
+		WARN_AND_RETURN_XWB("XWB compact format is not supported")
 
 	f->seek(segments[kXWBSegmentEntryMetaData].offset);
 
@@ -1728,6 +1692,51 @@ void Sound::indexXWBFile(const Common::String &filename) {
 	f->close();
 	delete f;
 }
+
+#undef WARN_AND_RETURN_XWB
+
+Audio::SeekableAudioStream *Sound::createXWBStream(Common::SeekableSubReadStream *stream, XWBEntry entry) {
+	switch (entry.codec) {
+	case kXWBCodecPCM: {
+		byte flags = Audio::FLAG_LITTLE_ENDIAN;
+		if (entry.bits == 1)	// 0: 8 bits, 1: 16 bits
+			flags |= Audio::FLAG_16BITS;
+		if (entry.channels == 2)
+			flags |= Audio::FLAG_STEREO;
+		return Audio::makeRawStream(stream, entry.rate, flags, DisposeAfterUse::YES);
+	}
+	case kXWBCodecXMA:
+		// Unused in MI1SE and MI2SE
+		error("createXWBStream: XMA codec not supported");
+	case kXWBCodecADPCM: {
+		const uint32 blockAlign = (entry.align + 22) * entry.channels;
+		return Audio::makeADPCMStream(
+			stream,
+			DisposeAfterUse::YES,
+			entry.length,
+			Audio::kADPCMMS,
+			entry.rate,
+			entry.channels,
+			blockAlign
+		);
+	}
+	case kXWBCodecWMA:
+		error("createXWBStream: WMA codec not implemented");
+		// TODO: Implement WMA codec
+		/*return new Audio::WMACodec(
+			2,
+			entry.rate,
+			entry.channels,
+			entry.bits,
+			entry.align,
+			stream
+		);*/
+
+	}
+
+	error("createXWBStream: Unknown XWB codec %d", entry.codec);
+}
+
 #endif
 
 #pragma mark -
diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h
index a32f43dff4e..242c08a9ed9 100644
--- a/engines/scumm/sound.h
+++ b/engines/scumm/sound.h
@@ -199,8 +199,8 @@ private:
 	// For XWB files in Doublefine game variants
 	enum XWBCodec {
 		kXWBCodecPCM = 0,
-		kXWBCodecADPCM = 1,
-		kXWBCodecMP3 = 2,
+		kXWBCodecXMA = 1,
+		kXWBCodecADPCM = 2,
 		kXWBCodecWMA = 3
 	};
 


Commit: 13a3eca146d7b6230020efda7b0a8fdf58bd6da5
    https://github.com/scummvm/scummvm/commit/13a3eca146d7b6230020efda7b0a8fdf58bd6da5
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Encapsulate the new Doublefine SE sound code in a separate class

Also, change the Loom CDDA class so that it instantiates the CD audio
stream internally, to streamline and simplify the code in the Sound
class

Changed paths:
  A engines/scumm/soundse.cpp
  A engines/scumm/soundse.h
    engines/scumm/cdda.cpp
    engines/scumm/cdda.h
    engines/scumm/module.mk
    engines/scumm/sound.cpp
    engines/scumm/sound.h


diff --git a/engines/scumm/cdda.cpp b/engines/scumm/cdda.cpp
index 113918b75c1..8f1785ce3bf 100644
--- a/engines/scumm/cdda.cpp
+++ b/engines/scumm/cdda.cpp
@@ -20,6 +20,7 @@
  */
 
 #include "scumm/cdda.h"
+#include "common/file.h"
 #include "common/stream.h"
 #include "audio/audiostream.h"
 
@@ -104,16 +105,22 @@ int CDDAStream::readBuffer(int16 *buffer, const int numSamples) {
 #pragma mark -
 
 Audio::SeekableAudioStream *makeCDDAStream(
-	Common::SeekableReadStream *stream,
+	const Common::String &filename,
 	DisposeAfterUse::Flag disposeAfterUse) {
-	Audio::SeekableAudioStream *s = new CDDAStream(stream, disposeAfterUse);
+	Common::File *cdAudioFile = new Common::File();
+
+	if (!cdAudioFile->open(Common::Path(filename))) {
+		delete cdAudioFile;
+		return nullptr;
+	}
+
+	Audio::SeekableAudioStream *s = new CDDAStream(cdAudioFile, disposeAfterUse);
 	if (s && s->endOfData()) {
 		delete s;
 		return nullptr;
 	} else {
 		return s;
 	}
-	return nullptr;
 }
 
 } // End of namespace Scumm
diff --git a/engines/scumm/cdda.h b/engines/scumm/cdda.h
index 5289113e986..1ba0a187fea 100644
--- a/engines/scumm/cdda.h
+++ b/engines/scumm/cdda.h
@@ -27,6 +27,7 @@
 #ifndef SCUMM_CDDA_H
 #define SCUMM_CDDA_H
 
+#include "common/str.h"
 #include "common/types.h"
 
 namespace Common {
@@ -43,12 +44,12 @@ namespace Scumm {
  * Create a new SeekableAudioStream from the CDDA data in the given stream.
  * Allows for seeking (which is why we require a SeekableReadStream).
  *
- * @param stream          The SeekableReadStream from which to read the CDDA data
+ * @param filename          The file name from which to read the CDDA data
  * @param disposeAfterUse Whether to delete the stream after use
  * @return a new SeekableAudioStream, or NULL, if an error occurred
  */
 Audio::SeekableAudioStream *makeCDDAStream(
-	Common::SeekableReadStream *stream,
+	const Common::String &filename,
 	DisposeAfterUse::Flag disposeAfterUse);
 
 } // End of namespace Audio
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 6783741c648..46bc0a2019e 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -84,6 +84,7 @@ MODULE_OBJS := \
 	script.o \
 	scumm.o \
 	sound.o \
+	soundse.o \
 	string.o \
 	usage_bits.o \
 	util.o \
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index 1632f483faf..be5e66757ec 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -107,12 +107,12 @@ Sound::Sound(ScummEngine *parent, Audio::Mixer *mixer, bool useReplacementAudioT
 	_fileBasedCDAudioHandle = new Audio::SoundHandle();
 	_talkChannelHandle = new Audio::SoundHandle();
 
-#ifdef ENABLE_DOUBLEFINE_XWB
-	if (_vm->_game.id == GID_MONKEY && (_vm->_game.features & GF_DOUBLEFINE_PAK)) {
-		_hasFileBasedCDAudio = true;
-		indexXWBFile("MusicOriginal.xwb");
+	if (_vm->_game.features & GF_DOUBLEFINE_PAK) {
+		_soundSE = new SoundSE(_vm, _mixer);
+
+		if (_vm->_game.id == GID_MONKEY)
+			_hasFileBasedCDAudio = true;
 	}
-#endif
 
 	// This timer targets every talkie game, except for LOOM CD
 	// which is handled differently, and except for COMI which
@@ -128,6 +128,7 @@ Sound::~Sound() {
 	free(_offsetTable);
 	delete _fileBasedCDAudioHandle;
 	delete _talkChannelHandle;
+	delete _soundSE;
 	if (_vm->_game.version >= 5 && _vm->_game.version <= 7 && _vm->_game.heversion == 0) {
 		stopSpeechTimer();
 	}
@@ -530,6 +531,13 @@ void Sound::triggerSound(int soundID) {
 			}
 		}
 
+		// TODO: If called from MI2SE, this will play the music
+		// multiple times
+		//if (_soundSE) {
+		//	_soundSE->startMusic(soundID);
+		//	return;
+		//}
+
 		if (_vm->_musicEngine)
 			_vm->_musicEngine->startSound(soundID);
 
@@ -1464,39 +1472,17 @@ void Sound::playCDTrackInternal(int track, int numLoops, int startFrame, int dur
 		// Stop any currently playing track
 		_mixer->stopHandle(*_fileBasedCDAudioHandle);
 
-		Common::File *cdAudioFile = new Common::File();
 		Audio::SeekableAudioStream *stream = nullptr;
 
 		if (_vm->_game.id == GID_LOOM) {
-			if (!cdAudioFile->open("CDDA.SOU")) {
-				delete cdAudioFile;
-				return;
-			}
-			stream = makeCDDAStream(cdAudioFile, DisposeAfterUse::YES);
-
-#ifdef ENABLE_DOUBLEFINE_XWB
-		} else if (_vm->_game.id == GID_MONKEY) {
-			if (!cdAudioFile->open("MusicOriginal.xwb")) {
-				delete cdAudioFile;
-				return;
-			}
-
-			// HACK: Since we don't support WMA files yet, we'll just play a PCM entry
-			// TODO: Remove this, once WMA streams are supported!
-			track = 20;
-
-			XWBEntry entry = _xwbEntries[track];
-			auto subStream = new Common::SeekableSubReadStream(
-				cdAudioFile,
-				entry.offset,
-				entry.offset + entry.length,
-				DisposeAfterUse::YES
-			);
-
-			stream = createXWBStream(subStream, entry);
-#endif
+			stream = makeCDDAStream("CDDA.SOU", DisposeAfterUse::YES);
+		} else if (_soundSE) {
+			stream = _soundSE->getXWBTrack(track);
 		}
 
+		if (!stream)
+			return;
+
 		Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
 		Audio::Timestamp end = Audio::Timestamp(0, startFrame + duration, 75);
 		
@@ -1618,127 +1604,6 @@ bool Sound::isAudioDisabled() {
 	return false;
 }
 
-#ifdef ENABLE_DOUBLEFINE_XWB
-
-#define WARN_AND_RETURN_XWB(message)          \
-	{                                         \
-		warning("indexXWBFile: %s", message); \
-		f->close();                           \
-		delete f;                             \
-		return;                               \
-	}
-
-void Sound::indexXWBFile(const Common::String &filename) {
-	// This implementation is based off unxwb: https://github.com/mariodon/unxwb/
-	// as well as xwbdump: https://raw.githubusercontent.com/wiki/Microsoft/DirectXTK/xwbdump.cpp
-	// Only the parts that apply to the Doublefine releases of
-	// MI1 and MI2 have been implemented.
-
-	struct SegmentData {
-		uint32 offset;
-		uint32 length;
-	};
-	SegmentData segments[5] = {};
-
-	Common::File *f = new Common::File();
-	f->open(Common::Path(filename));
-
-	const uint32 magic = f->readUint32BE();
-	const uint32 version = f->readUint32LE();
-	f->skip(4); // skip dwHeaderVersion
-
-	if (magic != MKTAG('W', 'B', 'N', 'D'))
-		WARN_AND_RETURN_XWB("Invalid XWB file")
-
-	if (version < 42)
-		WARN_AND_RETURN_XWB("Unsupported XWB version")
-
-	for (uint32 i = 0; i < 5; i++) {
-		segments[i].offset = f->readUint32LE();
-		segments[i].length = f->readUint32LE();
-	}
-
-	f->seek(segments[kXWBSegmentBankData].offset);
-	const uint32 flags = f->readUint32LE();
-	const uint32 entryCount = f->readUint32LE();
-	f->skip(64); // skip bank name
-	const uint32 entrySize = f->readUint32LE();
-	if (entrySize < 24)
-		WARN_AND_RETURN_XWB("Unsupported XWB entry size")
-
-	if (flags & 0x00020000)
-		WARN_AND_RETURN_XWB("XWB compact format is not supported")
-
-	f->seek(segments[kXWBSegmentEntryMetaData].offset);
-
-	for (uint32 i = 0; i < entryCount; i++) {
-		XWBEntry entry;
-		/*uint32 flagsAndDuration = */ f->readUint32LE();
-		uint32 format = f->readUint32LE();
-		entry.offset = f->readUint32LE() + segments[kXWBSegmentEntryWaveData].offset;
-		entry.length = f->readUint32LE();
-		/*uint32 loopOffset = */ f->readUint32LE();
-		/*uint32 loopLength = */ f->readUint32LE();
-
-		entry.codec = static_cast<XWBCodec>(format & ((1 << 2) - 1));
-		entry.channels = (format >> (2)) & ((1 << 3) - 1);
-		entry.rate = (format >> (2 + 3)) & ((1 << 18) - 1);
-		entry.align = (format >> (2 + 3 + 18)) & ((1 << 8) - 1);
-		entry.bits = (format >> (2 + 3 + 18 + 8)) & ((1 << 1) - 1);
-
-		_xwbEntries.push_back(entry);
-	}
-
-	f->close();
-	delete f;
-}
-
-#undef WARN_AND_RETURN_XWB
-
-Audio::SeekableAudioStream *Sound::createXWBStream(Common::SeekableSubReadStream *stream, XWBEntry entry) {
-	switch (entry.codec) {
-	case kXWBCodecPCM: {
-		byte flags = Audio::FLAG_LITTLE_ENDIAN;
-		if (entry.bits == 1)	// 0: 8 bits, 1: 16 bits
-			flags |= Audio::FLAG_16BITS;
-		if (entry.channels == 2)
-			flags |= Audio::FLAG_STEREO;
-		return Audio::makeRawStream(stream, entry.rate, flags, DisposeAfterUse::YES);
-	}
-	case kXWBCodecXMA:
-		// Unused in MI1SE and MI2SE
-		error("createXWBStream: XMA codec not supported");
-	case kXWBCodecADPCM: {
-		const uint32 blockAlign = (entry.align + 22) * entry.channels;
-		return Audio::makeADPCMStream(
-			stream,
-			DisposeAfterUse::YES,
-			entry.length,
-			Audio::kADPCMMS,
-			entry.rate,
-			entry.channels,
-			blockAlign
-		);
-	}
-	case kXWBCodecWMA:
-		error("createXWBStream: WMA codec not implemented");
-		// TODO: Implement WMA codec
-		/*return new Audio::WMACodec(
-			2,
-			entry.rate,
-			entry.channels,
-			entry.bits,
-			entry.align,
-			stream
-		);*/
-
-	}
-
-	error("createXWBStream: Unknown XWB codec %d", entry.codec);
-}
-
-#endif
-
 #pragma mark -
 #pragma mark --- Sound resource handling ---
 #pragma mark -
diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h
index 242c08a9ed9..5d481090deb 100644
--- a/engines/scumm/sound.h
+++ b/engines/scumm/sound.h
@@ -28,6 +28,7 @@
 #include "audio/mididrv.h"
 #include "backends/audiocd/audiocd.h"
 #include "scumm/file.h"
+#include "scumm/soundse.h"
 
 // The number of "ticks" (1/10th of a second) into the Overture that the
 // LucasFilm logo should appear. This corresponds to a timer value of 204.
@@ -118,6 +119,8 @@ protected:
 	int _loomOvertureTransition;
 	uint32 _replacementTrackStartTime;
 
+	SoundSE *_soundSE = nullptr;
+
 public:
 	Audio::SoundHandle *_talkChannelHandle;	// Handle of mixer channel actor is talking on
 
@@ -192,41 +195,6 @@ protected:
 	virtual void processSoundQueues();
 
 	int getReplacementAudioTrack(int soundID);
-
-#ifdef ENABLE_DOUBLEFINE_XWB
-private:
-
-	// For XWB files in Doublefine game variants
-	enum XWBCodec {
-		kXWBCodecPCM = 0,
-		kXWBCodecXMA = 1,
-		kXWBCodecADPCM = 2,
-		kXWBCodecWMA = 3
-	};
-
-	enum XWBSegmentType {
-		kXWBSegmentBankData = 0,
-		kXWBSegmentEntryMetaData = 1,
-		kXWBSegmentSeekTables = 2,
-		kXWBSegmentEntryNames = 3,
-		kXWBSegmentEntryWaveData = 4
-	};
-
-	struct XWBEntry {
-		uint32 offset;
-		uint32 length;
-		XWBCodec codec;
-		byte channels;
-		uint16 rate;
-		uint16 align;
-		byte bits;
-	};
-
-	Common::Array<XWBEntry> _xwbEntries;
-
-	void indexXWBFile(const Common::String &filename);
-	Audio::SeekableAudioStream *createXWBStream(Common::SeekableSubReadStream *stream, XWBEntry entry);
-#endif
 };
 
 
diff --git a/engines/scumm/soundse.cpp b/engines/scumm/soundse.cpp
new file mode 100644
index 00000000000..fe75803191e
--- /dev/null
+++ b/engines/scumm/soundse.cpp
@@ -0,0 +1,250 @@
+/* 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/config-manager.h"
+#include "common/timer.h"
+#include "common/util.h"
+#include "common/substream.h"
+
+#include "scumm/file.h"
+#include "scumm/scumm.h"
+#include "scumm/soundse.h"
+
+#include "audio/audiostream.h"
+#include "audio/decoders/adpcm.h"
+#include "audio/decoders/mp3.h"
+#include "audio/decoders/raw.h"
+
+namespace Scumm {
+
+SoundSE::SoundSE(ScummEngine *parent, Audio::Mixer *mixer)
+	: _vm(parent),
+	_mixer(mixer) {
+
+	initSoundFiles();
+}
+
+void SoundSE::initSoundFiles() {
+	switch (_vm->_game.id) {
+	case GID_MONKEY:
+	case GID_MONKEY2:
+		_xwbMusicFilename = "MusicOriginal.xwb";
+		//_xwbMusicFilename = "MusicNew.xwb";	// TODO: allow toggle between original and new music
+		indexXWBFile(_xwbMusicFilename, &_xwbMusicEntries);
+		_xwbSfxFilename = "SFXOriginal.xwb";
+		//_xwbSfxFilename = "SFXNew.xwb";	// TODO: allow toggle between original and new SFX
+		indexXWBFile(_xwbSfxFilename, &_xwbSfxEntries);
+		_xwbSpeechFilename = "Speech.xwb";
+		indexXWBFile(_xwbSpeechFilename, &_xwbSpeechEntries);
+		break;
+	case GID_TENTACLE:
+		// TODO
+		break;
+	case GID_FT:
+		// TODO
+		break;
+	default:
+		error("initSoundFiles: unhandled game");
+	}
+}
+
+Audio::SeekableAudioStream *SoundSE::getXWBTrack(int track) {
+	Common::File *cdAudioFile = new Common::File();
+
+	if (!cdAudioFile->open(Common::Path(_xwbMusicFilename))) {
+		delete cdAudioFile;
+		return nullptr;
+	}
+
+	XWBEntry entry = _xwbMusicEntries[track];
+
+	// TODO: Remove this, once WMA streams are supported!
+	if (entry.codec == kXWBCodecWMA) {
+		delete cdAudioFile;
+		return nullptr;
+	}
+
+	auto subStream = new Common::SeekableSubReadStream(
+		cdAudioFile,
+		entry.offset,
+		entry.offset + entry.length,
+		DisposeAfterUse::YES
+	);
+
+	return createXWBStream(subStream, entry);
+}
+
+#define WARN_AND_RETURN_XWB(message)          \
+	{                                         \
+		warning("indexXWBFile: %s", message); \
+		f->close();                           \
+		delete f;                             \
+		return;                               \
+	}
+
+void SoundSE::indexXWBFile(const Common::String &filename, XWBIndex *xwbIndex) {
+	// This implementation is based off unxwb: https://github.com/mariodon/unxwb/
+	// as well as xwbdump: https://raw.githubusercontent.com/wiki/Microsoft/DirectXTK/xwbdump.cpp
+	// Only the parts that apply to the Doublefine releases of
+	// MI1 and MI2 have been implemented.
+
+	struct SegmentData {
+		uint32 offset;
+		uint32 length;
+	};
+	SegmentData segments[5] = {};
+
+	Common::File *f = new Common::File();
+	f->open(Common::Path(filename));
+
+	const uint32 magic = f->readUint32BE();
+	const uint32 version = f->readUint32LE();
+	f->skip(4); // skip dwHeaderVersion
+
+	if (magic != MKTAG('W', 'B', 'N', 'D'))
+		WARN_AND_RETURN_XWB("Invalid XWB file")
+
+	if (version < 42)
+		WARN_AND_RETURN_XWB("Unsupported XWB version")
+
+	for (uint32 i = 0; i < 5; i++) {
+		segments[i].offset = f->readUint32LE();
+		segments[i].length = f->readUint32LE();
+	}
+
+	f->seek(segments[kXWBSegmentBankData].offset);
+	const uint32 flags = f->readUint32LE();
+	const uint32 entryCount = f->readUint32LE();
+	f->skip(64); // skip bank name
+	const uint32 entrySize = f->readUint32LE();
+	if (entrySize < 24)
+		WARN_AND_RETURN_XWB("Unsupported XWB entry size")
+
+	if (flags & 0x00020000)
+		WARN_AND_RETURN_XWB("XWB compact format is not supported")
+
+	f->seek(segments[kXWBSegmentEntryMetaData].offset);
+
+	for (uint32 i = 0; i < entryCount; i++) {
+		XWBEntry entry;
+		/*uint32 flagsAndDuration = */ f->readUint32LE();
+		uint32 format = f->readUint32LE();
+		entry.offset = f->readUint32LE() + segments[kXWBSegmentEntryWaveData].offset;
+		entry.length = f->readUint32LE();
+		/*uint32 loopOffset = */ f->readUint32LE();
+		/*uint32 loopLength = */ f->readUint32LE();
+
+		entry.codec = static_cast<XWBCodec>(format & ((1 << 2) - 1));
+		entry.channels = (format >> (2)) & ((1 << 3) - 1);
+		entry.rate = (format >> (2 + 3)) & ((1 << 18) - 1);
+		entry.align = (format >> (2 + 3 + 18)) & ((1 << 8) - 1);
+		entry.bits = (format >> (2 + 3 + 18 + 8)) & ((1 << 1) - 1);
+
+		xwbIndex->push_back(entry);
+	}
+
+	f->close();
+	delete f;
+}
+
+#undef WARN_AND_RETURN_XWB
+
+Audio::SeekableAudioStream *SoundSE::createXWBStream(Common::SeekableSubReadStream *stream, XWBEntry entry) {
+	switch (entry.codec) {
+	case kXWBCodecPCM: {
+		byte flags = Audio::FLAG_LITTLE_ENDIAN;
+		if (entry.bits == 1)	// 0: 8 bits, 1: 16 bits
+			flags |= Audio::FLAG_16BITS;
+		if (entry.channels == 2)
+			flags |= Audio::FLAG_STEREO;
+		return Audio::makeRawStream(stream, entry.rate, flags, DisposeAfterUse::YES);
+	}
+	case kXWBCodecXMA:
+		// Unused in MI1SE and MI2SE
+		error("createXWBStream: XMA codec not supported");
+	case kXWBCodecADPCM: {
+		const uint32 blockAlign = (entry.align + 22) * entry.channels;
+		return Audio::makeADPCMStream(
+			stream,
+			DisposeAfterUse::YES,
+			entry.length,
+			Audio::kADPCMMS,
+			entry.rate,
+			entry.channels,
+			blockAlign
+		);
+	}
+	case kXWBCodecWMA:
+		error("createXWBStream: WMA codec not implemented");
+		// TODO: Implement WMA codec
+		/*return new Audio::WMACodec(
+			2,
+			entry.rate,
+			entry.channels,
+			entry.bits,
+			entry.align,
+			stream
+		);*/
+
+	}
+
+	error("createXWBStream: Unknown XWB codec %d", entry.codec);
+}
+
+#if 0
+void SoundSE::startMusic(int soundID) {
+	int entry = -1;
+
+	// HACK: Find the first entry with offset 8192 (MI2 theme)
+	// TODO: Map soundID to entry (*.xsb files)
+	for (int i = 0; i < _xwbMusicEntries.size(); i++) {
+		if (_xwbMusicEntries[i].offset == 8192) {
+			entry = i;
+			break;
+		}
+	}
+
+	if (entry == -1)
+		return;
+
+	Common::File *musicFile = new Common::File();
+
+	if (!musicFile->open(Common::Path(_xwbMusicFilename))) {
+		delete musicFile;
+		return;
+	}
+
+	XWBEntry xwbEntry = _xwbMusicEntries[entry];
+	Common::SeekableSubReadStream *stream = new Common::SeekableSubReadStream(
+		musicFile,
+		xwbEntry.offset,
+		xwbEntry.offset + xwbEntry.length,
+		DisposeAfterUse::YES
+	);
+
+	_mixer->playStream(
+		Audio::Mixer::kMusicSoundType,
+		&_musicHandle, createXWBStream(stream, xwbEntry)
+	);
+}
+#endif
+
+} // End of namespace Scumm
diff --git a/engines/scumm/soundse.h b/engines/scumm/soundse.h
new file mode 100644
index 00000000000..4540577c072
--- /dev/null
+++ b/engines/scumm/soundse.h
@@ -0,0 +1,103 @@
+/* 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_SOUNDSE_H
+#define SCUMM_SOUNDSE_H
+
+#include "common/scummsys.h"
+#include "audio/mixer.h"
+#include "scumm/file.h"
+
+namespace Common {
+class SeekableSubReadStream;
+}
+
+namespace Audio {
+class SeekableAudioStream;
+}
+
+namespace Scumm {
+
+class ScummEngine;
+
+class SoundSE {
+
+protected:
+	ScummEngine *_vm;
+	Audio::Mixer *_mixer;
+
+public:
+	SoundSE(ScummEngine *parent, Audio::Mixer *mixer);
+	~SoundSE() = default;
+
+	Audio::SeekableAudioStream *getXWBTrack(int track);
+
+	//void startMusic(int soundID);
+
+private:
+	enum XWBCodec {
+		kXWBCodecPCM = 0,
+		kXWBCodecXMA = 1,
+		kXWBCodecADPCM = 2,
+		kXWBCodecWMA = 3
+	};
+
+	enum XWBSegmentType {
+		kXWBSegmentBankData = 0,
+		kXWBSegmentEntryMetaData = 1,
+		kXWBSegmentSeekTables = 2,
+		kXWBSegmentEntryNames = 3,
+		kXWBSegmentEntryWaveData = 4
+	};
+
+	struct XWBEntry {
+		uint32 offset;
+		uint32 length;
+		XWBCodec codec;
+		byte channels;
+		uint16 rate;
+		uint16 align;
+		byte bits;
+	};
+
+	typedef Common::Array<XWBEntry> XWBIndex;
+
+	XWBIndex _xwbMusicEntries;
+	Common::String _xwbMusicFilename;
+	Audio::SoundHandle _musicHandle;
+
+	XWBIndex _xwbSpeechEntries;
+	Common::String _xwbSpeechFilename;
+	Audio::SoundHandle _speechHandle;
+
+	XWBIndex _xwbSfxEntries;
+	Common::String _xwbSfxFilename;
+	Audio::SoundHandle _sfxHandle;
+
+	void initSoundFiles();
+	void indexXWBFile(const Common::String &filename, XWBIndex *xwbIndex);
+	Audio::SeekableAudioStream *createXWBStream(Common::SeekableSubReadStream *stream, XWBEntry entry);
+};
+
+
+} // End of namespace Scumm
+
+#endif


Commit: b628296f3f7e83958979b20764c13a68e2038043
    https://github.com/scummvm/scummvm/commit/b628296f3f7e83958979b20764c13a68e2038043
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Remove obsolete define and TODO

Changed paths:
    engines/scumm/sound.h


diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h
index 5d481090deb..ccc862006b6 100644
--- a/engines/scumm/sound.h
+++ b/engines/scumm/sound.h
@@ -60,11 +60,6 @@ enum {
 	kTalkSoundID = 10000
 };
 
-// TODO: XWB audio packages, used in Doublefine MI1 and MI2.
-// We're still missing WMA support in SCUMM, so we can't play
-// the audio files contained in these packages.
-//#define ENABLE_DOUBLEFINE_XWB 1
-
 // TODO: Consider splitting Sound into even more subclasses.
 // E.g. for v1-v4, v5, v6+, ...
 class Sound : public Common::Serializable {


Commit: 43c06db34acc247d35e4c002e94260a471112f03
    https://github.com/scummvm/scummvm/commit/43c06db34acc247d35e4c002e94260a471112f03
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Cleanup WMA codec error handling

Changed paths:
    engines/scumm/soundse.cpp


diff --git a/engines/scumm/soundse.cpp b/engines/scumm/soundse.cpp
index fe75803191e..9d2e0c97bde 100644
--- a/engines/scumm/soundse.cpp
+++ b/engines/scumm/soundse.cpp
@@ -76,12 +76,6 @@ Audio::SeekableAudioStream *SoundSE::getXWBTrack(int track) {
 
 	XWBEntry entry = _xwbMusicEntries[track];
 
-	// TODO: Remove this, once WMA streams are supported!
-	if (entry.codec == kXWBCodecWMA) {
-		delete cdAudioFile;
-		return nullptr;
-	}
-
 	auto subStream = new Common::SeekableSubReadStream(
 		cdAudioFile,
 		entry.offset,
@@ -193,7 +187,6 @@ Audio::SeekableAudioStream *SoundSE::createXWBStream(Common::SeekableSubReadStre
 		);
 	}
 	case kXWBCodecWMA:
-		error("createXWBStream: WMA codec not implemented");
 		// TODO: Implement WMA codec
 		/*return new Audio::WMACodec(
 			2,
@@ -203,7 +196,9 @@ Audio::SeekableAudioStream *SoundSE::createXWBStream(Common::SeekableSubReadStre
 			entry.align,
 			stream
 		);*/
-
+		warning("createXWBStream: WMA codec not implemented");
+		delete stream;
+		return nullptr;
 	}
 
 	error("createXWBStream: Unknown XWB codec %d", entry.codec);


Commit: 5661a8b4a2db5a009cb0ead99d111acfca92584a
    https://github.com/scummvm/scummvm/commit/5661a8b4a2db5a009cb0ead99d111acfca92584a
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-20T13:20:51+02:00

Commit Message:
SCUMM: Add checksum for the GoG version of DOTT Remastered

Changed paths:
    devtools/scumm-md5.txt
    engines/scumm/scumm-md5.h


diff --git a/devtools/scumm-md5.txt b/devtools/scumm-md5.txt
index 21061920c93..887d2a2f31c 100644
--- a/devtools/scumm-md5.txt
+++ b/devtools/scumm-md5.txt
@@ -360,6 +360,7 @@ tentacle	Day of the Tentacle
 
 	4167a92a1d46baa4f4127d918d561f88	7932	en	All?	-	CD	1.6	Fingolfin
 	64d07dec2bf0789c4f2a7b656cf5bb83	2731584777	en	DOS	SE	SE	Filippos Karapetis
+	7ff69e4905f3c30f3a86ab8fb8cfe34b	2731425417	en	DOS	SE	SE	Filippos Karapetis
 	8aa05d3cdb0e795436043f0546af2da2	7932	fr	All?	-	CD	-	Andrea Petrucci
 	6e959d65358eedf9b68b81e304b97fa4	7932	de	All?	-	CD	-	Fingolfin
 	4fbbe9f64b8bc547503a379a301183ce	-1	it	All?	-	CD	-	Andrea Petrucci
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index 740113cc3d7..d37c699bef8 100644
--- a/engines/scumm/scumm-md5.h
+++ b/engines/scumm/scumm-md5.h
@@ -1,5 +1,5 @@
 /*
-  This file was generated by the md5table tool on Sun Dec 15 22:58:56 2024
+  This file was generated by the md5table tool on Fri Dec 20 09:25:44 2024
   DO NOT EDIT MANUALLY!
  */
 
@@ -427,6 +427,7 @@ static const MD5Table md5table[] = {
 	{ "7f945525abcd48015adf1632637a44a1", "pajama", "", "Demo", 18354, Common::FR_FRA, Common::kPlatformUnknown },
 	{ "7fbcff27c323499beaedd605e1ebd47d", "indy3", "Steam", "Steam", 561152, Common::EN_ANY, Common::kPlatformWindows },
 	{ "7fc6cdb46b4c9d384c52327f4bca6416", "football", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown },
+	{ "7ff69e4905f3c30f3a86ab8fb8cfe34b", "tentacle", "SE", "SE", 2731425417, Common::EN_ANY, Common::kPlatformDOS },
 	{ "810a9da887aefa597b0cf3c77d262897", "BluesABCTime", "", "Demo", 12186, Common::EN_ANY, Common::kPlatformUnknown },
 	{ "813af095ff338dacf349aca377e48041", "pajama", "HE 101", "", 66878, Common::DE_DEU, Common::kPlatformWii },
 	{ "813fbcd24a46728cf142cb62057a69cd", "comi", "", "", 76791, Common::HE_ISR, Common::kPlatformWindows },




More information about the Scummvm-git-logs mailing list