[Scummvm-git-logs] scummvm master -> 75a89a0e51644ab7fb6b983c008f175ffba45c56

bluegr noreply at scummvm.org
Sat Dec 21 17:01:16 UTC 2024


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

Summary:
fe8380fc65 SCUMM: Separate the PAK index reading code
75a89a0e51 SCUMM: Handle the FMOD FSB audio files used in DOTT SE and FT SE


Commit: fe8380fc6501db27734ea2aaf176d9524efdb7f0
    https://github.com/scummvm/scummvm/commit/fe8380fc6501db27734ea2aaf176d9524efdb7f0
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-21T18:55:18+02:00

Commit Message:
SCUMM: Separate the PAK index reading code

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


diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp
index 9a79adb32cb..7e3fd5b8cad 100644
--- a/engines/scumm/file.cpp
+++ b/engines/scumm/file.cpp
@@ -223,13 +223,15 @@ bool ScummSteamFile::openWithSubRange(const Common::Path &filename, int32 subFil
 #pragma mark -
 
 ScummPAKFile::ScummPAKFile(const ScummEngine *vm, bool indexFiles) : ScummFile(vm) {
-	if (!indexFiles)
-		return;
+	if (indexFiles)
+		readIndex(vm->_containerFile, vm->_game.id == GID_FT);
+}
 
-	ScummFile::open(vm->_containerFile);
+void ScummPAKFile::readIndex(const Common::Path &containerFile, bool isFT) {
+	// Based off DoubleFine Explorer: https://github.com/bgbennyboy/DoubleFine-Explorer/blob/master/uDFExplorer_LPAKManager.pas
+	ScummFile::open(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')) {
diff --git a/engines/scumm/file.h b/engines/scumm/file.h
index ddd895a9066..5dd0a15251f 100644
--- a/engines/scumm/file.h
+++ b/engines/scumm/file.h
@@ -161,6 +161,8 @@ class ScummPAKFile : public ScummFile {
 private:
 	PAKFileHashMap _pakIndex;
 
+	void readIndex(const Common::Path &containerFile, bool isFT);
+
 public:
 	ScummPAKFile(const ScummEngine *vm, bool indexFiles = true);
 	~ScummPAKFile() override { _pakIndex.clear(); }


Commit: 75a89a0e51644ab7fb6b983c008f175ffba45c56
    https://github.com/scummvm/scummvm/commit/75a89a0e51644ab7fb6b983c008f175ffba45c56
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2024-12-21T18:55:19+02:00

Commit Message:
SCUMM: Handle the FMOD FSB audio files used in DOTT SE and FT SE

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


diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp
index 7e3fd5b8cad..9403b572b51 100644
--- a/engines/scumm/file.cpp
+++ b/engines/scumm/file.cpp
@@ -276,6 +276,7 @@ void ScummPAKFile::readIndex(const Common::Path &containerFile, bool isFT) {
 			fileName.hasPrefixIgnoreCase("maniac/") ||   // DOTT MM easter egg
 			fileName.hasPrefixIgnoreCase("data/") ||     // FT data folder
 			fileName.hasPrefixIgnoreCase("video/") ||    // FT video folder
+			fileName.hasPrefixIgnoreCase("audio/") ||    // DOTT and FT SE audio 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/sound.cpp b/engines/scumm/sound.cpp
index be5e66757ec..c81ff371b65 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -534,7 +534,7 @@ void Sound::triggerSound(int soundID) {
 		// TODO: If called from MI2SE, this will play the music
 		// multiple times
 		//if (_soundSE) {
-		//	_soundSE->startMusic(soundID);
+		//	_soundSE->startSound(soundID);
 		//	return;
 		//}
 
diff --git a/engines/scumm/soundse.cpp b/engines/scumm/soundse.cpp
index 9d2e0c97bde..54417e93cec 100644
--- a/engines/scumm/soundse.cpp
+++ b/engines/scumm/soundse.cpp
@@ -46,20 +46,35 @@ 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);
+		_musicFilename = "MusicOriginal.xwb";
+		//_musicFilename = "MusicNew.xwb";	// TODO: allow toggle between original and new music
+		indexXWBFile(_musicFilename, &_musicEntries);
+		_sfxFilename = "SFXOriginal.xwb";
+		//_sfxFilename = "SFXNew.xwb";	// TODO: allow toggle between original and new SFX
+		indexXWBFile(_sfxFilename, &_sfxEntries);
+		_speechFilename = "Speech.xwb";
+		indexXWBFile(_speechFilename, &_speechEntries);
+		// TODO: iMUSEClient_Commentary.fsb
 		break;
 	case GID_TENTACLE:
-		// TODO
+		_musicFilename = "iMUSEClient_Music.fsb";
+		indexFSBFile(_musicFilename, &_musicEntries);
+		_sfxFilename = "iMUSEClient_SFX.fsb";
+		indexFSBFile(_sfxFilename, &_sfxEntries);
+		_speechFilename = "iMUSEClient_VO.fsb";
+		indexFSBFile(_speechFilename, &_speechEntries);
+		// TODO: iMUSEClient_Commentary.fsb
 		break;
 	case GID_FT:
-		// TODO
+		_musicFilename = "iMUSEClient_Music.fsb";
+		indexFSBFile(_musicFilename, &_musicEntries);
+		_sfxFilename = "iMUSEClient_SFX_INMEMORY.fsb";
+		indexFSBFile(_sfxFilename, &_sfxEntries);
+		_speechFilename = "iMUSEClient_SPEECH.fsb";
+		indexFSBFile(_speechFilename, &_speechEntries);
+		// TODO: iMUSEClient_SFX_STREAMING.fsb
+		// TODO: iMUSEClient_UI.fsb
+		// TODO: iMUSEClient_Commentary.fsb
 		break;
 	default:
 		error("initSoundFiles: unhandled game");
@@ -69,12 +84,12 @@ void SoundSE::initSoundFiles() {
 Audio::SeekableAudioStream *SoundSE::getXWBTrack(int track) {
 	Common::File *cdAudioFile = new Common::File();
 
-	if (!cdAudioFile->open(Common::Path(_xwbMusicFilename))) {
+	if (!cdAudioFile->open(Common::Path(_musicFilename))) {
 		delete cdAudioFile;
 		return nullptr;
 	}
 
-	XWBEntry entry = _xwbMusicEntries[track];
+	AudioEntry entry = _musicEntries[track];
 
 	auto subStream = new Common::SeekableSubReadStream(
 		cdAudioFile,
@@ -83,7 +98,7 @@ Audio::SeekableAudioStream *SoundSE::getXWBTrack(int track) {
 		DisposeAfterUse::YES
 	);
 
-	return createXWBStream(subStream, entry);
+	return createSoundStream(subStream, entry);
 }
 
 #define WARN_AND_RETURN_XWB(message)          \
@@ -94,7 +109,7 @@ Audio::SeekableAudioStream *SoundSE::getXWBTrack(int track) {
 		return;                               \
 	}
 
-void SoundSE::indexXWBFile(const Common::String &filename, XWBIndex *xwbIndex) {
+void SoundSE::indexXWBFile(const Common::String &filename, AudioIndex *audioIndex) {
 	// 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
@@ -138,7 +153,7 @@ void SoundSE::indexXWBFile(const Common::String &filename, XWBIndex *xwbIndex) {
 	f->seek(segments[kXWBSegmentEntryMetaData].offset);
 
 	for (uint32 i = 0; i < entryCount; i++) {
-		XWBEntry entry;
+		AudioEntry entry;
 		/*uint32 flagsAndDuration = */ f->readUint32LE();
 		uint32 format = f->readUint32LE();
 		entry.offset = f->readUint32LE() + segments[kXWBSegmentEntryWaveData].offset;
@@ -146,13 +161,13 @@ void SoundSE::indexXWBFile(const Common::String &filename, XWBIndex *xwbIndex) {
 		/*uint32 loopOffset = */ f->readUint32LE();
 		/*uint32 loopLength = */ f->readUint32LE();
 
-		entry.codec = static_cast<XWBCodec>(format & ((1 << 2) - 1));
+		entry.codec = static_cast<AudioCodec>(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);
+		audioIndex->push_back(entry);
 	}
 
 	f->close();
@@ -161,7 +176,90 @@ void SoundSE::indexXWBFile(const Common::String &filename, XWBIndex *xwbIndex) {
 
 #undef WARN_AND_RETURN_XWB
 
-Audio::SeekableAudioStream *SoundSE::createXWBStream(Common::SeekableSubReadStream *stream, XWBEntry entry) {
+#define WARN_AND_RETURN_FSB(message)          \
+	{                                         \
+		warning("indexFSBFile: %s", message); \
+		f->close();                           \
+		delete f;                             \
+		return;                               \
+	}
+
+#define GET_FSB5_OFFSET(X) ((((X) >> (uint64)7) << (uint64)5) & (((uint64)1 << (uint64)32) - 1))
+
+void SoundSE::indexFSBFile(const Common::String &filename, AudioIndex *audioIndex) {
+	// Based off DoubleFine Explorer: https://github.com/bgbennyboy/DoubleFine-Explorer/blob/master/uDFExplorer_FSBManager.pas
+	// and fsbext: https://aluigi.altervista.org/search.php?src=fsbext
+	ScummPAKFile *f = new ScummPAKFile(_vm);
+	_vm->openFile(*f, Common::Path(filename));
+
+	const uint32 headerSize = 60; // 4 * 7 + 8 + 16 + 8
+	const uint32 magic = f->readUint32BE();
+	if (magic != MKTAG('F', 'S', 'B', '5'))
+		WARN_AND_RETURN_FSB("Invalid FSB file")
+
+	/*const uint32 version = */f->readUint32LE();
+	const uint32 sampleCount = f->readUint32LE();
+	const uint32 sampleHeaderSize = f->readUint32LE();
+	const uint32 nameSize = f->readUint32LE();
+	const uint32 dataSize = f->readUint32LE();
+	/*const uint32 mode = */f->readUint32LE();
+	f->skip(8);	// skip zero
+	f->skip(16);	// skip hash
+	f->skip(8);	// skip dummy
+	const uint32 nameOffset = sampleHeaderSize + headerSize;
+	const uint32 baseOffset = headerSize + sampleHeaderSize + nameSize;
+
+	for (uint32 i = 0; i < sampleCount; i++) {
+		const uint32 origOffset = f->readUint32LE();
+		f->skip(4); // samples, used in XMA
+		uint32 type = origOffset & ((1 << 7) - 1);
+		const uint32 fileOffset = nameOffset + nameSize + GET_FSB5_OFFSET(origOffset);
+		uint32 size;
+
+		// Meta data, skip it
+		while (type & 1) {
+			const uint32 t = f->readUint32LE();
+			type = t & 1;
+			const uint32 metaDataSize = (t & 0xffffff) >> 1;
+			f->skip(metaDataSize);
+		}
+
+		if (f->pos() < nameOffset) {
+			size = f->readUint32LE();
+			f->seek(-4, SEEK_CUR);
+			if (!size) {
+				size = dataSize + baseOffset;
+			} else {
+				size = GET_FSB5_OFFSET(size) + baseOffset;
+			}
+		} else {
+			size = dataSize + baseOffset;
+		}
+
+		size -= fileOffset;
+
+		AudioEntry entry;
+		entry.length = size;
+		entry.offset = fileOffset;
+		// The following are all unused - they'll
+		// be read from the MP3 streams
+		entry.rate = 48000;
+		entry.channels = 2;
+		entry.codec = kFSBCodecMP3;
+		entry.align = 0;
+		entry.bits = 16;
+
+		audioIndex->push_back(entry);
+	}
+
+	f->close();
+	delete f;
+}
+
+#undef GET_FSB5_OFFSET
+#undef WARN_AND_RETURN_FSB
+
+Audio::SeekableAudioStream *SoundSE::createSoundStream(Common::SeekableSubReadStream *stream, AudioEntry entry) {
 	switch (entry.codec) {
 	case kXWBCodecPCM: {
 		byte flags = Audio::FLAG_LITTLE_ENDIAN;
@@ -173,7 +271,7 @@ Audio::SeekableAudioStream *SoundSE::createXWBStream(Common::SeekableSubReadStre
 	}
 	case kXWBCodecXMA:
 		// Unused in MI1SE and MI2SE
-		error("createXWBStream: XMA codec not supported");
+		error("createSoundStream: XMA codec not supported");
 	case kXWBCodecADPCM: {
 		const uint32 blockAlign = (entry.align + 22) * entry.channels;
 		return Audio::makeADPCMStream(
@@ -196,50 +294,76 @@ Audio::SeekableAudioStream *SoundSE::createXWBStream(Common::SeekableSubReadStre
 			entry.align,
 			stream
 		);*/
-		warning("createXWBStream: WMA codec not implemented");
+		warning("createSoundStream: WMA codec not implemented");
 		delete stream;
 		return nullptr;
+	case kFSBCodecMP3:
+		return Audio::makeMP3Stream(
+			stream,
+			DisposeAfterUse::YES
+		);
 	}
 
-	error("createXWBStream: Unknown XWB codec %d", entry.codec);
+	error("createSoundStream: 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;
-		}
+void SoundSE::startSoundEntry(int soundIndex, SoundSEType type) {
+	Common::SeekableReadStream *stream = nullptr;
+	Audio::SoundHandle *handle = nullptr;
+	Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType;
+	Common::String audioFileName;
+	AudioIndex &audioEntries = _musicEntries;
+
+	switch (type) {
+	case kSoundSETypeMusic:
+		handle = &_musicHandle;
+		soundType = Audio::Mixer::kMusicSoundType;
+		audioFileName = _musicFilename;
+		audioEntries = _musicEntries;
+		break;
+	case kSoundSETypeSpeech:
+		handle = &_speechHandle;
+		soundType = Audio::Mixer::kSpeechSoundType;
+		audioFileName = _speechFilename;
+		audioEntries = _speechEntries;
+		break;
+	case kSoundSETypeSFX:
+		handle = &_sfxHandle;
+		soundType = Audio::Mixer::kSFXSoundType;
+		audioFileName = _sfxFilename;
+		audioEntries = _sfxEntries;
+		break;
 	}
 
-	if (entry == -1)
-		return;
-
-	Common::File *musicFile = new Common::File();
-
-	if (!musicFile->open(Common::Path(_xwbMusicFilename))) {
-		delete musicFile;
-		return;
+	if (_vm->_game.id == GID_MONKEY || _vm->_game.id == GID_MONKEY2) {
+		Common::File *audioFile = new Common::File();
+		stream = audioFile;
+		if (!audioFile->open(Common::Path(audioFileName))) {
+			delete audioFile;
+			return;
+		}
+	} else {
+		ScummPAKFile *audioFile = new ScummPAKFile(_vm);
+		stream = audioFile;
+		if (!_vm->openFile(*audioFile, Common::Path(audioFileName))) {
+			delete audioFile;
+			return;
+		}
 	}
 
-	XWBEntry xwbEntry = _xwbMusicEntries[entry];
-	Common::SeekableSubReadStream *stream = new Common::SeekableSubReadStream(
-		musicFile,
-		xwbEntry.offset,
-		xwbEntry.offset + xwbEntry.length,
+	AudioEntry audioEntry = audioEntries[soundIndex];
+	Common::SeekableSubReadStream *subStream = new Common::SeekableSubReadStream(
+		stream,
+		audioEntry.offset,
+		audioEntry.offset + audioEntry.length,
 		DisposeAfterUse::YES
 	);
 
 	_mixer->playStream(
-		Audio::Mixer::kMusicSoundType,
-		&_musicHandle, createXWBStream(stream, xwbEntry)
+		soundType,
+		handle,
+		createSoundStream(subStream, audioEntry)
 	);
 }
-#endif
 
 } // End of namespace Scumm
diff --git a/engines/scumm/soundse.h b/engines/scumm/soundse.h
index 4540577c072..9bc48e6d60d 100644
--- a/engines/scumm/soundse.h
+++ b/engines/scumm/soundse.h
@@ -38,6 +38,12 @@ namespace Scumm {
 
 class ScummEngine;
 
+enum SoundSEType {
+	kSoundSETypeMusic,
+	kSoundSETypeSpeech,
+	kSoundSETypeSFX
+};
+
 class SoundSE {
 
 protected:
@@ -50,14 +56,15 @@ public:
 
 	Audio::SeekableAudioStream *getXWBTrack(int track);
 
-	//void startMusic(int soundID);
+	void startSoundEntry(int soundIndex, SoundSEType type);
 
 private:
-	enum XWBCodec {
+	enum AudioCodec {
 		kXWBCodecPCM = 0,
 		kXWBCodecXMA = 1,
 		kXWBCodecADPCM = 2,
-		kXWBCodecWMA = 3
+		kXWBCodecWMA = 3,
+		kFSBCodecMP3 = 4
 	};
 
 	enum XWBSegmentType {
@@ -68,33 +75,34 @@ private:
 		kXWBSegmentEntryWaveData = 4
 	};
 
-	struct XWBEntry {
-		uint32 offset;
+	struct AudioEntry {
+		uint64 offset;
 		uint32 length;
-		XWBCodec codec;
+		AudioCodec codec;
 		byte channels;
 		uint16 rate;
 		uint16 align;
 		byte bits;
 	};
 
-	typedef Common::Array<XWBEntry> XWBIndex;
+	typedef Common::Array<AudioEntry> AudioIndex;
 
-	XWBIndex _xwbMusicEntries;
-	Common::String _xwbMusicFilename;
+	AudioIndex _musicEntries;
+	Common::String _musicFilename;
 	Audio::SoundHandle _musicHandle;
 
-	XWBIndex _xwbSpeechEntries;
-	Common::String _xwbSpeechFilename;
+	AudioIndex _speechEntries;
+	Common::String _speechFilename;
 	Audio::SoundHandle _speechHandle;
 
-	XWBIndex _xwbSfxEntries;
-	Common::String _xwbSfxFilename;
+	AudioIndex _sfxEntries;
+	Common::String _sfxFilename;
 	Audio::SoundHandle _sfxHandle;
 
 	void initSoundFiles();
-	void indexXWBFile(const Common::String &filename, XWBIndex *xwbIndex);
-	Audio::SeekableAudioStream *createXWBStream(Common::SeekableSubReadStream *stream, XWBEntry entry);
+	void indexXWBFile(const Common::String &filename, AudioIndex *audioIndex);
+	Audio::SeekableAudioStream *createSoundStream(Common::SeekableSubReadStream *stream, AudioEntry entry);
+	void indexFSBFile(const Common::String &filename, AudioIndex *audioIndex);
 };
 
 




More information about the Scummvm-git-logs mailing list