[Scummvm-git-logs] scummvm master -> 6271f8e0aaf226b54b0ae4b36cef4c8d562bde34
bluegr
noreply at scummvm.org
Fri Jan 10 16:33:49 UTC 2025
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
6271f8e0aa SCUMM: Map SE ambience and commentary. Also, refactor the SE audio code
Commit: 6271f8e0aaf226b54b0ae4b36cef4c8d562bde34
https://github.com/scummvm/scummvm/commit/6271f8e0aaf226b54b0ae4b36cef4c8d562bde34
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2025-01-10T18:33:19+02:00
Commit Message:
SCUMM: Map SE ambience and commentary. Also, refactor the SE audio code
Changed paths:
engines/scumm/soundse.cpp
engines/scumm/soundse.h
diff --git a/engines/scumm/soundse.cpp b/engines/scumm/soundse.cpp
index 2b9972ca2de..3c7c70a03ea 100644
--- a/engines/scumm/soundse.cpp
+++ b/engines/scumm/soundse.cpp
@@ -45,58 +45,28 @@ SoundSE::SoundSE(ScummEngine *parent, Audio::Mixer *mixer)
void SoundSE::initSoundFiles() {
switch (_vm->_game.id) {
case GID_MONKEY:
- initAudioMappingMI();
- _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: ambience.xwb
- // TODO: roomsfx.xwb
- break;
case GID_MONKEY2:
initAudioMappingMI();
- _musicFilename = "MusicOriginal.xwb";
- //_musicFilename = "MusicNew.xwb"; // TODO: allow toggle between original and new music
- indexXWBFile(_musicFilename, &_musicEntries);
- indexXSBFile("musiccuesoriginal.xsb", &_musicEntries);
- //_sfxFilename = "SFXOriginal.xwb";
- //_sfxFilename = "SFXNew.xwb"; // TODO: allow toggle between original and new SFX
- // indexXWBFile(_sfxFilename, &_sfxEntries);
- _speechFilename = "Speech.xwb";
- indexXWBFile(_speechFilename, &_speechEntries);
- indexXSBFile("speechcues.xsb", &_speechEntries);
- // TODO: ambience.xwb
- // TODO: commentary.xwb
- // TODO: patch.xwb
+ indexXWBFile(kSoundSETypeMusic);
+ indexXWBFile(kSoundSETypeSFX);
+ indexXWBFile(kSoundSETypeSpeech);
+ indexXWBFile(kSoundSETypeAmbience);
+
+ if (_vm->_game.id == GID_MONKEY2) {
+ indexXWBFile(kSoundSETypeCommentary);
+ // TODO: indexXWBFile for patch.xwb
+ indexSpeechXSBFile();
+ }
break;
- case GID_TENTACLE:
- initAudioMappingDOTTAndFT();
- _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
- // Clear the original offset map, as we no longer need it
- _nameToOffsetDOTTAndFT.clear();
- break;
+ case GID_TENTACLE:
case GID_FT:
initAudioMappingDOTTAndFT();
- _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
+ indexFSBFile(kSoundSETypeMusic);
+ indexFSBFile(kSoundSETypeSFX);
+ indexFSBFile(kSoundSETypeSpeech);
+ indexFSBFile(kSoundSETypeCommentary);
+ // TODO: iMUSEClient_SFX_STREAMING.fsb for FT
// Clear the original offset map, as we no longer need it
_nameToOffsetDOTTAndFT.clear();
@@ -109,12 +79,11 @@ void SoundSE::initSoundFiles() {
#define WARN_AND_RETURN_XWB(message) \
{ \
warning("indexXWBFile: %s", message); \
- f->close(); \
delete f; \
return; \
}
-void SoundSE::indexXWBFile(const Common::String &filename, AudioIndex *audioIndex) {
+void SoundSE::indexXWBFile(SoundSEType type) {
// 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 Special Editions of
@@ -126,8 +95,10 @@ void SoundSE::indexXWBFile(const Common::String &filename, AudioIndex *audioInde
};
SegmentData segments[5] = {};
- Common::File *f = new Common::File();
- f->open(Common::Path(filename));
+ AudioIndex *audioIndex = getAudioEntries(type);
+ Common::SeekableReadStream *f = getAudioFile(type);
+ if (!f)
+ return;
const uint32 magic = f->readUint32BE();
const uint32 version = f->readUint32LE();
@@ -189,29 +160,25 @@ void SoundSE::indexXWBFile(const Common::String &filename, AudioIndex *audioInde
}
}
- f->close();
delete f;
}
#undef WARN_AND_RETURN_XWB
-#define WARN_AND_RETURN_XSB(message) \
- { \
- warning("indexXSBFile: %s", message); \
- f->close(); \
- delete f; \
- return; \
- }
-
-void SoundSE::indexXSBFile(const Common::String &filename, AudioIndex *audioIndex) {
+void SoundSE::indexSpeechXSBFile() {
Common::List<uint16> speechIndices;
- Common::File *f = new Common::File();
- f->open(Common::Path(filename));
+ AudioIndex *audioIndex = getAudioEntries(kSoundSETypeSpeech);
+ Common::SeekableReadStream *f = getAudioFile("speechcues.xsb");
+ if (!f)
+ return;
const uint32 magic = f->readUint32BE();
- if (magic != MKTAG('S', 'D', 'B', 'K'))
- WARN_AND_RETURN_XSB("Invalid XSB file")
+ if (magic != MKTAG('S', 'D', 'B', 'K')) {
+ warning("Invalid XSB file");
+ delete f;
+ return;
+ }
f->skip(15);
const uint32 entryCount = f->readUint32LE();
@@ -235,38 +202,33 @@ void SoundSE::indexXSBFile(const Common::String &filename, AudioIndex *audioInde
Common::String name = f->readString(0);
name.toLowercase();
- if (/*index >= 0 && */index < (*audioIndex).size()) {
+ if (index < (*audioIndex).size()) {
(*audioIndex)[index].name = name;
_nameToIndex[name] = index;
}
}
- f->close();
delete f;
}
-#undef WARN_AND_RETURN_XSB
-
-#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) {
+void SoundSE::indexFSBFile(SoundSEType type) {
// 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));
+
+ AudioIndex *audioIndex = getAudioEntries(type);
+ Common::SeekableReadStream *f = getAudioFile(type);
+ if (!f)
+ return;
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")
+ if (magic != MKTAG('F', 'S', 'B', '5')) {
+ warning("Invalid FSB file");
+ delete f;
+ return;
+ }
/*const uint32 version = */f->readUint32LE();
const uint32 sampleCount = f->readUint32LE();
@@ -368,12 +330,10 @@ void SoundSE::indexFSBFile(const Common::String &filename, AudioIndex *audioInde
//debug("indexFSBFile: %s -> offset %d, index %d", name.c_str(), origOffset, i);
}
- f->close();
delete f;
}
#undef GET_FSB5_OFFSET
-#undef WARN_AND_RETURN_FSB
static int32 calculateStringHash(const char *input) {
int32 hash = 0;
@@ -485,11 +445,9 @@ static int32 calculateStringSimilarity(const char *str1, const char *str2) {
}
void SoundSE::initAudioMappingMI() {
- Common::File *f = new Common::File();
- if (!f->open(Common::Path("speech.info"))) {
- delete f;
+ Common::SeekableReadStream *f = getAudioFile("speech.info");
+ if (!f)
return;
- }
_audioEntriesMI.clear();
@@ -522,13 +480,13 @@ void SoundSE::initAudioMappingMI() {
_audioEntriesMI.emplace_back(entry);
} while (!f->eos());
- f->close();
delete f;
}
void SoundSE::initAudioMappingDOTTAndFT() {
- ScummPAKFile *f = new ScummPAKFile(_vm);
- _vm->openFile(*f, Common::Path("audiomapping.info"));
+ Common::SeekableReadStream *f = getAudioFile("audiomapping.info");
+ if (!f)
+ return;
do {
const uint32 origOffset = f->readUint32LE();
@@ -544,10 +502,84 @@ void SoundSE::initAudioMappingDOTTAndFT() {
_nameToOffsetDOTTAndFT[name] = origOffset;
} while (!f->eos());
- f->close();
delete f;
}
+Common::String SoundSE::getAudioFilename(SoundSEType type) {
+ const bool isMonkey = _vm->_game.id == GID_MONKEY || _vm->_game.id == GID_MONKEY2;
+ const bool isTentacle = _vm->_game.id == GID_TENTACLE;
+ const bool isFT = _vm->_game.id == GID_FT;
+
+ switch (type) {
+ case kSoundSETypeMusic:
+ case kSoundSETypeCDAudio:
+ return isMonkey ? "MusicOriginal.xwb" : "iMUSEClient_Music.fsb";
+ case kSoundSETypeSpeech:
+ if (isMonkey)
+ return "Speech.xwb";
+ else if (isTentacle)
+ return "iMUSEClient_VO.fsb";
+ else if (isFT)
+ return "iMUSEClient_SPEECH.fsb";
+ case kSoundSETypeSFX:
+ if (isMonkey)
+ return "SFXOriginal.xwb";
+ else if (isTentacle)
+ return "iMUSEClient_SFX.fsb";
+ else if (isFT)
+ return "iMUSEClient_SFX_INMEMORY.fsb";
+ case kSoundSETypeAmbience:
+ return "Ambience.xwb";
+ case kSoundSETypeCommentary:
+ return isMonkey ? "commentary.xwb" : "iMUSEClient_Commentary.fsb";
+ default:
+ error("getAudioFilename: unknown SoundSEType %d", type);
+ }
+}
+
+Common::SeekableReadStream *SoundSE::getAudioFile(SoundSEType type) {
+ Common::String audioFileName = getAudioFilename(type);
+ return getAudioFile(audioFileName);
+}
+
+Common::SeekableReadStream *SoundSE::getAudioFile(const Common::String &filename) {
+ if (_vm->_game.id == GID_MONKEY || _vm->_game.id == GID_MONKEY2) {
+ Common::File *audioFile = new Common::File();
+ if (!audioFile->open(Common::Path(filename))) {
+ warning("getAudioFile: failed to open %s", filename.c_str());
+ delete audioFile;
+ return nullptr;
+ }
+ return audioFile;
+ } else {
+ ScummPAKFile *audioFile = new ScummPAKFile(_vm);
+ if (!_vm->openFile(*audioFile, Common::Path(filename))) {
+ warning("getAudioFile: failed to open %s", filename.c_str());
+ delete audioFile;
+ return nullptr;
+ }
+ return audioFile;
+ }
+}
+
+SoundSE::AudioIndex *SoundSE::getAudioEntries(SoundSEType type) {
+ switch (type) {
+ case kSoundSETypeMusic:
+ case kSoundSETypeCDAudio:
+ return &_musicEntries;
+ case kSoundSETypeSpeech:
+ return &_speechEntries;
+ case kSoundSETypeSFX:
+ return &_sfxEntries;
+ case kSoundSETypeAmbience:
+ return &_ambienceEntries;
+ case kSoundSETypeCommentary:
+ return &_commentaryEntries;
+ default:
+ error("getAudioEntries: unknown SoundSEType %d", type);
+ }
+}
+
Audio::SeekableAudioStream *SoundSE::createSoundStream(Common::SeekableSubReadStream *stream, AudioEntry entry, DisposeAfterUse::Flag disposeAfterUse) {
switch (entry.codec) {
case kXWBCodecPCM: {
@@ -605,11 +637,8 @@ Audio::SeekableAudioStream *SoundSE::createSoundStream(Common::SeekableSubReadSt
int32 SoundSE::getSoundIndexFromOffset(uint32 offset) {
if (_vm->_game.id == GID_MONKEY || _vm->_game.id == GID_MONKEY2) {
return offset;
- } else if (_vm->_game.id == GID_TENTACLE) {
- if (_offsetToIndexDOTTAndFT.contains(offset))
- return _offsetToIndexDOTTAndFT[offset];
- else
- return -1;
+ } else if (_vm->_game.id == GID_TENTACLE || _vm->_game.id == GID_FT) {
+ return (_offsetToIndexDOTTAndFT.contains(offset)) ? (int32)_offsetToIndexDOTTAndFT[offset] : -1;
}
return -1;
@@ -617,24 +646,15 @@ int32 SoundSE::getSoundIndexFromOffset(uint32 offset) {
int32 SoundSE::getAppropriateSpeechCue(const char *msgString, const char *speechFilenameSubstitution,
uint16 roomNumber, uint16 actorTalking, uint16 scriptNum, uint16 scriptOffset, uint16 numWaits) {
- uint32 hash;
+ uint32 hash = calculateStringHash(msgString);
+ uint32 tmpHash = hash;
AudioEntryMI *curAudioEntry;
uint16 script;
int32 currentScore;
- int32 bestScore;
- int32 bestScoreIdx;
- uint32 tmpHash;
-
- hash = calculateStringHash(msgString);
-
- tmpHash = hash;
- if (!hash)
- return -1;
-
- bestScore = 0x40000000; // This is the score that we have to minimize...
- bestScoreIdx = -1;
+ int32 bestScore = 0x40000000; // This is the score that we have to minimize...
+ int32 bestScoreIdx = -1;
- if (_audioEntriesMI.empty())
+ if (!hash || _audioEntriesMI.empty())
return -1;
for (uint curEntryIdx = 0; curEntryIdx < _audioEntriesMI.size(); curEntryIdx++) {
@@ -679,9 +699,9 @@ int32 SoundSE::getAppropriateSpeechCue(const char *msgString, const char *speech
}
Audio::SeekableAudioStream *SoundSE::getAudioStream(uint32 offset, SoundSEType type) {
- Common::SeekableReadStream *stream;
- Common::String audioFileName;
+ AudioIndex *audioIndex = getAudioEntries(type);
AudioEntry audioEntry = {};
+
int32 soundIndex = (type != kSoundSETypeCDAudio) ? getSoundIndexFromOffset(offset) : (int32)offset;
if (soundIndex == -1) {
@@ -689,40 +709,14 @@ Audio::SeekableAudioStream *SoundSE::getAudioStream(uint32 offset, SoundSEType t
return nullptr;
}
- switch (type) {
- case kSoundSETypeMusic:
- case kSoundSETypeCDAudio:
- audioFileName = _musicFilename;
- audioEntry = _musicEntries[soundIndex];
- break;
- case kSoundSETypeSpeech:
- audioFileName = _speechFilename;
- audioEntry = _speechEntries[soundIndex];
- break;
- case kSoundSETypeSFX:
- audioFileName = _sfxFilename;
- audioEntry = _sfxEntries[soundIndex];
- break;
- }
+ audioEntry = (*audioIndex)[soundIndex];
- 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 nullptr;
- }
- } else {
- ScummPAKFile *audioFile = new ScummPAKFile(_vm);
- stream = audioFile;
- if (!_vm->openFile(*audioFile, Common::Path(audioFileName))) {
- delete audioFile;
- return nullptr;
- }
- }
+ Common::SeekableReadStream *f = getAudioFile(type);
+ if (!f)
+ return nullptr;
Common::SeekableSubReadStream *subStream = new Common::SeekableSubReadStream(
- stream,
+ f,
audioEntry.offset,
audioEntry.offset + audioEntry.length,
DisposeAfterUse::YES
@@ -732,15 +726,13 @@ Audio::SeekableAudioStream *SoundSE::getAudioStream(uint32 offset, SoundSEType t
}
Common::String calculateCurrentString(const char *msgString) {
- char currentChar;
+ char currentChar = *msgString;
bool shouldContinue = true;
char messageBuffer[512];
char *outMsgBuffer = messageBuffer;
memset(messageBuffer, 0, sizeof(messageBuffer));
- currentChar = *msgString;
-
// Handle empty string case
if (msgString[0] == '\0') {
messageBuffer[0] = 0;
diff --git a/engines/scumm/soundse.h b/engines/scumm/soundse.h
index e74f637cf99..f3dce042425 100644
--- a/engines/scumm/soundse.h
+++ b/engines/scumm/soundse.h
@@ -40,9 +40,11 @@ class ScummEngine;
enum SoundSEType {
kSoundSETypeMusic,
+ kSoundSETypeCDAudio,
kSoundSETypeSpeech,
kSoundSETypeSFX,
- kSoundSETypeCDAudio
+ kSoundSETypeAmbience,
+ kSoundSETypeCommentary
};
class SoundSE {
@@ -124,11 +126,10 @@ private:
NameToIndexMap _nameToIndex;
AudioIndex _musicEntries;
- Common::String _musicFilename;
AudioIndex _speechEntries;
- Common::String _speechFilename;
AudioIndex _sfxEntries;
- Common::String _sfxFilename;
+ AudioIndex _ambienceEntries;
+ AudioIndex _commentaryEntries;
typedef Common::Array<AudioEntryMI> AudioIndexMI;
AudioIndexMI _audioEntriesMI;
@@ -151,11 +152,16 @@ private:
void initSoundFiles();
// Index XWB audio files and XSB cue files - used in MI1SE and MI2SE
- void indexXWBFile(const Common::String &filename, AudioIndex *audioIndex);
- void indexXSBFile(const Common::String &filename, AudioIndex *audioIndex);
+ void indexXWBFile(SoundSEType type);
+ void indexSpeechXSBFile();
// Index FSB audio files - used in DOTT and FT
- void indexFSBFile(const Common::String &filename, AudioIndex *audioIndex);
+ void indexFSBFile(SoundSEType type);
+
+ Common::String getAudioFilename(SoundSEType type);
+ Common::SeekableReadStream *getAudioFile(const Common::String &filename);
+ Common::SeekableReadStream *getAudioFile(SoundSEType type);
+ AudioIndex *getAudioEntries(SoundSEType type);
Audio::SeekableAudioStream *createSoundStream(Common::SeekableSubReadStream *stream, AudioEntry entry, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
};
More information about the Scummvm-git-logs
mailing list