From 1caa54f16e0920cd1bc9196acf22c2cbf3d8a48e Mon Sep 17 00:00:00 2001 From: Jbleezy Date: Sun, 15 Sep 2024 21:19:22 -0700 Subject: [PATCH 1/9] Change SndAlias struct members type from char to uint8_t --- src/Common/Game/T6/T6_Assets.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 99cea761..5396a2f7 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -6248,16 +6248,16 @@ namespace T6 int16_t fadeIn; int16_t fadeOut; int16_t dopplerScale; - char minPriorityThreshold; - char maxPriorityThreshold; - char probability; - char occlusionLevel; - char minPriority; - char maxPriority; - char pan; - char limitCount; - char entityLimitCount; - char duckGroup; + uint8_t minPriorityThreshold; + uint8_t maxPriorityThreshold; + uint8_t probability; + uint8_t occlusionLevel; + uint8_t minPriority; + uint8_t maxPriority; + uint8_t pan; + uint8_t limitCount; + uint8_t entityLimitCount; + uint8_t duckGroup; }; #ifndef __zonecodegenerator From 3dcd89540bce83ad45789bedc59c893bc689badc Mon Sep 17 00:00:00 2001 From: Jbleezy Date: Sun, 15 Sep 2024 21:19:41 -0700 Subject: [PATCH 2/9] Fix order of some SoundConstantsT6 enums --- src/ObjCommon/Game/T6/SoundConstantsT6.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/ObjCommon/Game/T6/SoundConstantsT6.h b/src/ObjCommon/Game/T6/SoundConstantsT6.h index feb7cff6..735ed8a9 100644 --- a/src/ObjCommon/Game/T6/SoundConstantsT6.h +++ b/src/ObjCommon/Game/T6/SoundConstantsT6.h @@ -30,7 +30,6 @@ namespace T6 "grp_air", "grp_bink", "grp_announcer", - "", }; inline const std::string SOUND_CURVES[]{ @@ -51,7 +50,6 @@ namespace T6 "cos", "rev60", "rev65", - "", }; inline const std::string SOUND_DUCK_GROUPS[]{ @@ -121,17 +119,15 @@ namespace T6 "bus_pfutz", "bus_hdrfx", "bus_ui", - "bus_reference", "bus_music", "bus_movie", "bus_reference", - "", }; inline const std::string SOUND_RANDOMIZE_TYPES[]{ + "", "volume", "pitch", "variant", - "", }; } // namespace T6 From fed488d391acfd9de441f8f5fde48a8fbc599df4 Mon Sep 17 00:00:00 2001 From: Jbleezy Date: Sun, 15 Sep 2024 21:20:17 -0700 Subject: [PATCH 3/9] Dump sound extension --- .../T6/AssetDumpers/AssetDumperSndBank.cpp | 125 +++++++++++------- 1 file changed, 79 insertions(+), 46 deletions(-) diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp index 532cb3fa..a0da2901 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp @@ -208,13 +208,28 @@ class AssetDumperSndBank::Internal return ""; } - static void WriteAliasToFile(CsvOutputStream& stream, const SndAlias* alias, const SndBank* bank) + std::string ConvertSndFormatToExtension(snd_asset_format format) const + { + switch (format) + { + case SND_ASSET_FORMAT_PCMS16: + return ".wav"; + + case SND_ASSET_FORMAT_FLAC: + return ".flac"; + + default: + return ""; + } + } + + static void WriteAliasToFile(CsvOutputStream& stream, const SndAlias* alias, std::string& extension, const SndBank* bank) { // name stream.WriteColumn(alias->name); - + // file - stream.WriteColumn(alias->assetFileName ? alias->assetFileName : ""); + stream.WriteColumn(alias->assetFileName ? alias->assetFileName + extension : ""); // template stream.WriteColumn(""); @@ -255,7 +270,7 @@ class AssetDumperSndBank::Internal // volume_min_falloff_curve stream.WriteColumn(SOUND_CURVES[alias->flags.volumeMinFalloffCurve]); - // reverb_min_falloff_curve" + // reverb_min_falloff_curve stream.WriteColumn(SOUND_CURVES[alias->flags.reverbMinFalloffCurve]); // limit_count @@ -303,103 +318,103 @@ class AssetDumperSndBank::Internal // randomize_type stream.WriteColumn(SOUND_RANDOMIZE_TYPES[std::min(alias->flags.randomizeType, 3u)]); - // probability", + // probability stream.WriteColumn(std::to_string(alias->probability)); - // start_delay", + // start_delay stream.WriteColumn(std::to_string(alias->startDelay)); - // reverb_send", + // reverb_send stream.WriteColumn(std::to_string(alias->reverbSend)); - // duck", + // duck stream.WriteColumn(FindNameForDuck(alias->duck, bank)); - // duck_group", + // duck_group stream.WriteColumn(SOUND_DUCK_GROUPS[alias->duckGroup]); - // pan", + // pan stream.WriteColumn(alias->flags.panType == SA_PAN_2D ? "2d" : "3d"); - // center_send", + // center_send stream.WriteColumn(std::to_string(alias->centerSend)); - // envelop_min", + // envelop_min stream.WriteColumn(std::to_string(alias->envelopMin)); - // envelop_max", + // envelop_max stream.WriteColumn(std::to_string(alias->envelopMax)); - // envelop_percentage", + // envelop_percentage stream.WriteColumn(std::to_string(alias->envelopPercentage)); - // occlusion_level", + // occlusion_level stream.WriteColumn(std::to_string(alias->occlusionLevel)); - // occlusion_wet_dry", + // occlusion_wet_dry stream.WriteColumn(""); - // is_big", + // is_big stream.WriteColumn(alias->flags.isBig ? "yes" : "no"); - // distance_lpf" + // distance_lpf stream.WriteColumn(alias->flags.distanceLpf ? "yes" : "no"); - // move_type", + // move_type stream.WriteColumn(SOUND_MOVE_TYPES[alias->flags.fluxType]); - // move_time", + // move_time stream.WriteColumn(std::to_string(alias->fluxTime)); - // real_delay", + // real_delay stream.WriteColumn(""); - // subtitle", + // subtitle stream.WriteColumn((alias->subtitle && *alias->subtitle) ? alias->subtitle : ""); - // mature", + // mature stream.WriteColumn(""); - // doppler", + // doppler stream.WriteColumn(alias->flags.doppler ? "yes" : "no"); - // futz", + // futz stream.WriteColumn(std::to_string(alias->futzPatch)); - // context_type", + // context_type stream.WriteColumn(std::to_string(alias->contextType)); - // context_value", + // context_value stream.WriteColumn(std::to_string(alias->contextValue)); - // compression", + // compression stream.WriteColumn(""); - // timescale", + // timescale stream.WriteColumn(alias->flags.timescale ? "yes" : "no"); - // music", + // music stream.WriteColumn(alias->flags.isMusic ? "yes" : "no"); - // fade_in", + // fade_in stream.WriteColumn(std::to_string(alias->fadeIn)); - // fade_out", + // fade_out stream.WriteColumn(std::to_string(alias->fadeOut)); - // pc_format", + // pc_format stream.WriteColumn(""); - // pause", + // pause stream.WriteColumn(alias->flags.pauseable ? "yes" : "no"); - // stop_on_death", + // stop_on_death stream.WriteColumn(alias->flags.stopOnDeath ? "yes" : "no"); - // bus", + // bus stream.WriteColumn(SOUND_BUS_IDS[alias->flags.busType]); - // snapshot", + // snapshot stream.WriteColumn(""); } @@ -460,7 +475,7 @@ class AssetDumperSndBank::Internal } } - void DumpSndAlias(const SndAlias& alias) const + std::optional DumpSndAlias(const SndAlias& alias) const { const auto soundFile = FindSoundDataInSoundBanks(alias.assetId); if (soundFile.IsOpen()) @@ -492,16 +507,20 @@ class AssetDumperSndBank::Internal std::cerr << "Cannot dump sound (Unknown sound format " << format << "): \"" << alias.assetFileName << "\"\n"; break; } + + return format; } else { std::cerr << "Could not find data for sound \"" << alias.assetFileName << "\"\n"; } + + return {}; } void DumpSndBankAliases(const SndBank* sndBank) const { - std::unordered_set dumpedAssets; + std::unordered_map dumpedAssets; const auto outFile = OpenAssetOutputFile("soundbank/" + std::string(sndBank->name) + ".aliases", ".csv"); if (!outFile) @@ -520,15 +539,29 @@ class AssetDumperSndBank::Internal for (auto j = 0; j < aliasList.count; j++) { const auto& alias = aliasList.head[j]; - - WriteAliasToFile(csvStream, &alias, sndBank); - csvStream.NextRow(); - - if (alias.assetId && alias.assetFileName && dumpedAssets.find(alias.assetId) == dumpedAssets.end()) + std::string extension = ""; + + if (alias.assetId && alias.assetFileName) { - DumpSndAlias(alias); - dumpedAssets.emplace(alias.assetId); + if (dumpedAssets.find(alias.assetId) == dumpedAssets.end()) + { + std::optional format = DumpSndAlias(alias); + + if (format.has_value()) + { + extension = ConvertSndFormatToExtension(format.value()); + } + + dumpedAssets[alias.assetId] = extension; + } + else + { + extension = dumpedAssets[alias.assetId]; + } } + + WriteAliasToFile(csvStream, &alias, extension, sndBank); + csvStream.NextRow(); } } } From d21c6aef4d6ce5216c057534d2606d9f162a5a2a Mon Sep 17 00:00:00 2001 From: Jbleezy Date: Sun, 15 Sep 2024 21:20:55 -0700 Subject: [PATCH 4/9] Find a file for the sound path including extension --- .../SoundBank/SoundBankWriter.cpp | 70 +++++++++---------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/src/ObjLoading/ObjContainer/SoundBank/SoundBankWriter.cpp b/src/ObjLoading/ObjContainer/SoundBank/SoundBankWriter.cpp index 7294ff81..2263f6ef 100644 --- a/src/ObjLoading/ObjContainer/SoundBank/SoundBankWriter.cpp +++ b/src/ObjLoading/ObjContainer/SoundBank/SoundBankWriter.cpp @@ -130,14 +130,22 @@ public: size_t soundSize; std::unique_ptr soundData; - // try to find a wav file for the sound path - const auto wavFile = m_asset_search_path->Open(soundFilePath + ".wav"); - if (wavFile.IsOpen()) + // try to find a file for the sound path + const auto file = m_asset_search_path->Open(soundFilePath); + if (!file.IsOpen()) + { + std::cerr << "Unable to find a compatible file for sound " << soundFilePath << "\n"; + return false; + } + + // check if sound path ends in .wav + const std::string extension = ".wav"; + if (soundFilePath.size() >= extension.size() && soundFilePath.compare(soundFilePath.size() - extension.size(), extension.size(), extension) == 0) { WavHeader header{}; - wavFile.m_stream->read(reinterpret_cast(&header), sizeof(WavHeader)); + file.m_stream->read(reinterpret_cast(&header), sizeof(WavHeader)); - soundSize = static_cast(wavFile.m_length - sizeof(WavHeader)); + soundSize = static_cast(file.m_length - sizeof(WavHeader)); const auto frameCount = soundSize / (header.formatChunk.nChannels * (header.formatChunk.wBitsPerSample / 8)); const auto frameRateIndex = INDEX_FOR_FRAMERATE[header.formatChunk.nSamplesPerSec]; @@ -155,45 +163,35 @@ public: m_entries.push_back(entry); soundData = std::make_unique(soundSize); - wavFile.m_stream->read(soundData.get(), soundSize); + file.m_stream->read(soundData.get(), soundSize); } else { - // if there is no wav file, try flac file - const auto flacFile = m_asset_search_path->Open(soundFilePath + ".flac"); - if (flacFile.IsOpen()) + soundSize = static_cast(file.m_length); + + soundData = std::make_unique(soundSize); + file.m_stream->read(soundData.get(), soundSize); + + flac::FlacMetaData metaData; + if (flac::GetFlacMetaData(soundData.get(), soundSize, metaData)) { - soundSize = static_cast(flacFile.m_length); + const auto frameRateIndex = INDEX_FOR_FRAMERATE[metaData.m_sample_rate]; + SoundAssetBankEntry entry{ + soundId, + soundSize, + static_cast(m_current_offset), + static_cast(metaData.m_total_samples), + frameRateIndex, + metaData.m_number_of_channels, + sound.m_looping, + 8, + }; - soundData = std::make_unique(soundSize); - flacFile.m_stream->read(soundData.get(), soundSize); - - flac::FlacMetaData metaData; - if (flac::GetFlacMetaData(soundData.get(), soundSize, metaData)) - { - const auto frameRateIndex = INDEX_FOR_FRAMERATE[metaData.m_sample_rate]; - SoundAssetBankEntry entry{ - soundId, - soundSize, - static_cast(m_current_offset), - static_cast(metaData.m_total_samples), - frameRateIndex, - metaData.m_number_of_channels, - sound.m_looping, - 8, - }; - - m_entries.push_back(entry); - } - else - { - std::cerr << "Unable to decode .flac file for sound " << soundFilePath << "\n"; - return false; - } + m_entries.push_back(entry); } else { - std::cerr << "Unable to find a compatible file for sound " << soundFilePath << "\n"; + std::cerr << "Unable to decode .flac file for sound " << soundFilePath << "\n"; return false; } } From fe766a734ff03594e7ee495e8d8bcf213e186b2f Mon Sep 17 00:00:00 2001 From: Jbleezy Date: Sun, 15 Sep 2024 21:21:05 -0700 Subject: [PATCH 5/9] Use decltype of variable being set --- .../T6/AssetLoaders/AssetLoaderSoundBank.cpp | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp index 8269dc81..c269a450 100644 --- a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp @@ -75,7 +75,7 @@ bool AssetLoaderSoundBank::CanLoadFromRaw() const size_t GetValueIndex(const std::string& value, const std::string* lookupTable, size_t len) { if (value.empty()) - return 0; + return 0; for (auto i = 0u; i < len; i++) { @@ -140,34 +140,34 @@ bool LoadSoundAlias(MemoryManager* memory, SndAlias* alias, const ParsedCsvRow& alias->subtitle = memory->Dup(subtitle.data()); alias->duck = Common::SND_HashName(row.GetValue("duck").data()); - - alias->volMin = row.GetValueInt("vol_min"); - alias->volMax = row.GetValueInt("vol_max"); - alias->distMin = row.GetValueInt("dist_min"); - alias->distMax = row.GetValueInt("dist_max"); - alias->distReverbMax = row.GetValueInt("dist_reverb_max"); - alias->limitCount = row.GetValueInt("limit_count"); - alias->entityLimitCount = row.GetValueInt("entity_limit_count"); - alias->pitchMin = row.GetValueInt("pitch_min"); - alias->pitchMax = row.GetValueInt("pitch_max"); - alias->minPriority = row.GetValueInt("min_priority"); - alias->maxPriority = row.GetValueInt("max_priority"); - alias->minPriorityThreshold = row.GetValueInt("min_priority_threshold"); - alias->maxPriorityThreshold = row.GetValueInt("max_priority_threshold"); - alias->probability = row.GetValueInt("probability"); - alias->startDelay = row.GetValueInt("start_delay"); - alias->reverbSend = row.GetValueInt("reverb_send"); - alias->centerSend = row.GetValueInt("center_send"); - alias->envelopMin = row.GetValueInt("envelop_min"); - alias->envelopMax = row.GetValueInt("envelop_max"); - alias->envelopPercentage = row.GetValueInt("envelop_percentage"); - alias->occlusionLevel = row.GetValueInt("occlusion_level"); - alias->fluxTime = row.GetValueInt("move_time"); - alias->futzPatch = row.GetValueInt("futz"); - alias->contextType = row.GetValueInt("context_type"); - alias->contextValue = row.GetValueInt("context_value"); - alias->fadeIn = row.GetValueInt("fade_in"); - alias->fadeOut = row.GetValueInt("fade_out"); + + alias->volMin = row.GetValueIntvolMin)>("vol_min"); + alias->volMax = row.GetValueIntvolMax)>("vol_max"); + alias->distMin = row.GetValueIntdistMin)>("dist_min"); + alias->distMax = row.GetValueIntdistMax)>("dist_max"); + alias->distReverbMax = row.GetValueIntdistReverbMax)>("dist_reverb_max"); + alias->limitCount = row.GetValueIntlimitCount)>("limit_count"); + alias->entityLimitCount = row.GetValueIntentityLimitCount)>("entity_limit_count"); + alias->pitchMin = row.GetValueIntpitchMin)>("pitch_min"); + alias->pitchMax = row.GetValueIntpitchMax)>("pitch_max"); + alias->minPriority = row.GetValueIntminPriority)>("min_priority"); + alias->maxPriority = row.GetValueIntmaxPriority)>("max_priority"); + alias->minPriorityThreshold = row.GetValueIntminPriorityThreshold)>("min_priority_threshold"); + alias->maxPriorityThreshold = row.GetValueIntmaxPriorityThreshold)>("max_priority_threshold"); + alias->probability = row.GetValueIntprobability)>("probability"); + alias->startDelay = row.GetValueIntstartDelay)>("start_delay"); + alias->reverbSend = row.GetValueIntreverbSend)>("reverb_send"); + alias->centerSend = row.GetValueIntcenterSend)>("center_send"); + alias->envelopMin = row.GetValueIntenvelopMin)>("envelop_min"); + alias->envelopMax = row.GetValueIntenvelopMax)>("envelop_max"); + alias->envelopPercentage = row.GetValueIntenvelopPercentage)>("envelop_percentage"); + alias->occlusionLevel = row.GetValueIntocclusionLevel)>("occlusion_level"); + alias->fluxTime = row.GetValueIntfluxTime)>("move_time"); + alias->futzPatch = row.GetValueIntfutzPatch)>("futz"); + alias->contextType = row.GetValueIntcontextType)>("context_type"); + alias->contextValue = row.GetValueIntcontextValue)>("context_value"); + alias->fadeIn = row.GetValueIntfadeIn)>("fade_in"); + alias->fadeOut = row.GetValueIntfadeOut)>("fade_out"); alias->flags.looping = row.GetValue("loop") == "looping"; alias->flags.panType = row.GetValue("pan") == "3d"; @@ -179,7 +179,7 @@ bool LoadSoundAlias(MemoryManager* memory, SndAlias* alias, const ParsedCsvRow& alias->flags.pauseable = row.GetValue("pause") == "yes"; alias->flags.stopOnDeath = row.GetValue("stop_on_death") == "yes"; - alias->duckGroup = static_cast(GetValueIndex(row.GetValue("duck_group"), SOUND_DUCK_GROUPS, std::extent_v)); + alias->duckGroup = static_castduckGroup)>(GetValueIndex(row.GetValue("duck_group"), SOUND_DUCK_GROUPS, std::extent_v)); alias->flags.volumeGroup = GetValueIndex(row.GetValue("group"), SOUND_GROUPS, std::extent_v); alias->flags.fluxType = GetValueIndex(row.GetValue("move_type"), SOUND_MOVE_TYPES, std::extent_v); alias->flags.loadType = GetValueIndex(row.GetValue("type"), SOUND_LOAD_TYPES, std::extent_v); From 4ff138c67bc1f687f837686a04d85e3324b48754 Mon Sep 17 00:00:00 2001 From: Jbleezy Date: Sun, 15 Sep 2024 21:27:13 -0700 Subject: [PATCH 6/9] Fix whitespace --- src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp | 4 ++-- src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp index c269a450..25d47c74 100644 --- a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp @@ -75,7 +75,7 @@ bool AssetLoaderSoundBank::CanLoadFromRaw() const size_t GetValueIndex(const std::string& value, const std::string* lookupTable, size_t len) { if (value.empty()) - return 0; + return 0; for (auto i = 0u; i < len; i++) { @@ -140,7 +140,7 @@ bool LoadSoundAlias(MemoryManager* memory, SndAlias* alias, const ParsedCsvRow& alias->subtitle = memory->Dup(subtitle.data()); alias->duck = Common::SND_HashName(row.GetValue("duck").data()); - + alias->volMin = row.GetValueIntvolMin)>("vol_min"); alias->volMax = row.GetValueIntvolMax)>("vol_max"); alias->distMin = row.GetValueIntdistMin)>("dist_min"); diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp index a0da2901..87d9c818 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp @@ -227,7 +227,7 @@ class AssetDumperSndBank::Internal { // name stream.WriteColumn(alias->name); - + // file stream.WriteColumn(alias->assetFileName ? alias->assetFileName + extension : ""); From 8d41e28a52dca671eb839686beea6c792968692d Mon Sep 17 00:00:00 2001 From: Jbleezy Date: Sun, 15 Sep 2024 21:35:53 -0700 Subject: [PATCH 7/9] Fix more whitespace --- src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp | 3 ++- src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp index 25d47c74..837be1b6 100644 --- a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp @@ -179,7 +179,8 @@ bool LoadSoundAlias(MemoryManager* memory, SndAlias* alias, const ParsedCsvRow& alias->flags.pauseable = row.GetValue("pause") == "yes"; alias->flags.stopOnDeath = row.GetValue("stop_on_death") == "yes"; - alias->duckGroup = static_castduckGroup)>(GetValueIndex(row.GetValue("duck_group"), SOUND_DUCK_GROUPS, std::extent_v)); + alias->duckGroup = + static_castduckGroup)>(GetValueIndex(row.GetValue("duck_group"), SOUND_DUCK_GROUPS, std::extent_v)); alias->flags.volumeGroup = GetValueIndex(row.GetValue("group"), SOUND_GROUPS, std::extent_v); alias->flags.fluxType = GetValueIndex(row.GetValue("move_type"), SOUND_MOVE_TYPES, std::extent_v); alias->flags.loadType = GetValueIndex(row.GetValue("type"), SOUND_LOAD_TYPES, std::extent_v); diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp index 87d9c818..45dda9fd 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp @@ -540,13 +540,13 @@ class AssetDumperSndBank::Internal { const auto& alias = aliasList.head[j]; std::string extension = ""; - + if (alias.assetId && alias.assetFileName) { if (dumpedAssets.find(alias.assetId) == dumpedAssets.end()) { std::optional format = DumpSndAlias(alias); - + if (format.has_value()) { extension = ConvertSndFormatToExtension(format.value()); From e0218dce2e921231d7d005db1f8fb47ba998f40a Mon Sep 17 00:00:00 2001 From: Jbleezy Date: Mon, 16 Sep 2024 10:07:04 -0700 Subject: [PATCH 8/9] Disable clang-format on SOUND_GROUPS array elements --- src/ObjCommon/Game/T6/SoundConstantsT6.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ObjCommon/Game/T6/SoundConstantsT6.h b/src/ObjCommon/Game/T6/SoundConstantsT6.h index 735ed8a9..bb347d36 100644 --- a/src/ObjCommon/Game/T6/SoundConstantsT6.h +++ b/src/ObjCommon/Game/T6/SoundConstantsT6.h @@ -4,6 +4,7 @@ namespace T6 { inline const std::string SOUND_GROUPS[]{ + // clang-format off "grp_reference", "grp_master", "grp_wpn_lfe", @@ -30,6 +31,7 @@ namespace T6 "grp_air", "grp_bink", "grp_announcer", + // clang-format on }; inline const std::string SOUND_CURVES[]{ From ae73f81a807e0cd7d19d386f2d58f4cc1f0fe6ba Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 18 Sep 2024 23:01:13 +0200 Subject: [PATCH 9/9] chore: address code review comments --- src/Common/Game/T6/T6_Assets.h | 38 ++- src/ObjCommon/Game/T6/SoundConstantsT6.h | 29 ++- .../T6/AssetLoaders/AssetLoaderSoundBank.cpp | 2 +- .../SoundBank/SoundBankWriter.cpp | 216 ++++++++++-------- .../T6/AssetDumpers/AssetDumperSndBank.cpp | 75 +++--- 5 files changed, 217 insertions(+), 143 deletions(-) diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 5396a2f7..5711f232 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -6182,7 +6182,43 @@ namespace T6 SA_LOADED = 0x1, SA_STREAMED = 0x2, SA_PRIMED = 0x3, - SA_COUNT = 0x4, + + SA_COUNT + }; + + enum SndLimitType + { + SND_LIMIT_NONE = 0x0, + SND_LIMIT_OLDEST = 0x1, + SND_LIMIT_REJECT = 0x2, + SND_LIMIT_PRIORITY = 0x3, + + SND_LIMIT_COUNT + }; + + enum SndBus + { + SND_BUS_REVERB = 0x0, + SND_BUS_FX = 0x1, + SND_BUS_VOICE = 0x2, + SND_BUS_PFUTZ = 0x3, + SND_BUS_HDRFX = 0x4, + SND_BUS_UI = 0x5, + SND_BUS_MUSIC = 0x6, + SND_BUS_MOVIE = 0x7, + SND_BUS_REFERENCE = 0x8, + + SND_BUS_COUNT + }; + + enum SndRandomizeType + { + SND_RANDOMIZE_INSTANCE = 0x0, + SND_RANDOMIZE_ENTITY_VOLUME = 0x1, + SND_RANDOMIZE_ENTITY_PITCH = 0x2, + SND_RANDOMIZE_ENTITY_VARIANT = 0x4, + + SND_RANDOMIZE_ENTITY_COUNT }; struct SndAliasFlags diff --git a/src/ObjCommon/Game/T6/SoundConstantsT6.h b/src/ObjCommon/Game/T6/SoundConstantsT6.h index bb347d36..878db002 100644 --- a/src/ObjCommon/Game/T6/SoundConstantsT6.h +++ b/src/ObjCommon/Game/T6/SoundConstantsT6.h @@ -1,9 +1,13 @@ #pragma once -#include + +#include "Game/T6/T6.h" + +#include namespace T6 { - inline const std::string SOUND_GROUPS[]{ + // From SndDriverGlobals + inline constexpr const char* SOUND_GROUPS[]{ // clang-format off "grp_reference", "grp_master", @@ -34,7 +38,8 @@ namespace T6 // clang-format on }; - inline const std::string SOUND_CURVES[]{ + // From SndDriverGlobals + inline constexpr const char* SOUND_CURVES[]{ "default", "defaultmin", "allon", @@ -54,7 +59,8 @@ namespace T6 "rev65", }; - inline const std::string SOUND_DUCK_GROUPS[]{ + // From SndDriverGlobals + inline constexpr const char* SOUND_DUCK_GROUPS[]{ "snp_alerts_gameplay", "snp_ambience", "snp_claw", @@ -89,14 +95,16 @@ namespace T6 "snp_x3", }; - inline const std::string SOUND_LIMIT_TYPES[]{ + inline constexpr const char* SOUND_LIMIT_TYPES[]{ "none", "oldest", "reject", "priority", }; + static_assert(std::extent_v == SND_LIMIT_COUNT); - inline const std::string SOUND_MOVE_TYPES[]{ + // From executable + inline constexpr const char* SOUND_MOVE_TYPES[]{ "none", "left_player", "center_player", @@ -107,14 +115,15 @@ namespace T6 "right_shot", }; - inline const std::string SOUND_LOAD_TYPES[]{ + inline constexpr const char* SOUND_LOAD_TYPES[]{ "unknown", "loaded", "streamed", "primed", }; + static_assert(std::extent_v == SA_COUNT); - inline const std::string SOUND_BUS_IDS[]{ + inline constexpr const char* SOUND_BUS_IDS[]{ "bus_reverb", "bus_fx", "bus_voice", @@ -125,8 +134,10 @@ namespace T6 "bus_movie", "bus_reference", }; + static_assert(std::extent_v == SND_BUS_COUNT); - inline const std::string SOUND_RANDOMIZE_TYPES[]{ + // From executable + inline constexpr const char* SOUND_RANDOMIZE_TYPES[]{ "", "volume", "pitch", diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp index 837be1b6..371187ab 100644 --- a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderSoundBank.cpp @@ -72,7 +72,7 @@ bool AssetLoaderSoundBank::CanLoadFromRaw() const return true; } -size_t GetValueIndex(const std::string& value, const std::string* lookupTable, size_t len) +size_t GetValueIndex(const std::string& value, const char* const* lookupTable, const size_t len) { if (value.empty()) return 0; diff --git a/src/ObjLoading/ObjContainer/SoundBank/SoundBankWriter.cpp b/src/ObjLoading/ObjContainer/SoundBank/SoundBankWriter.cpp index 2263f6ef..0c60f554 100644 --- a/src/ObjLoading/ObjContainer/SoundBank/SoundBankWriter.cpp +++ b/src/ObjLoading/ObjContainer/SoundBank/SoundBankWriter.cpp @@ -5,12 +5,16 @@ #include "Sound/FlacDecoder.h" #include "Sound/WavTypes.h" #include "Utils/FileUtils.h" +#include "Utils/StringUtils.h" #include #include +#include #include #include +namespace fs = std::filesystem; + std::unordered_map INDEX_FOR_FRAMERATE{ {8000, 0}, {12000, 1}, @@ -32,6 +36,30 @@ class SoundBankWriterImpl : public SoundBankWriter inline static const std::string PAD_DATA = std::string(16, '\x00'); + class SoundBankEntryInfo + { + public: + SoundBankEntryInfo() + : m_sound_id(0u), + m_looping(false), + m_streamed(false) + { + } + + SoundBankEntryInfo(std::string filePath, const unsigned int soundId, const bool looping, const bool streamed) + : m_file_path(std::move(filePath)), + m_sound_id(soundId), + m_looping(looping), + m_streamed(streamed) + { + } + + std::string m_file_path; + unsigned int m_sound_id; + bool m_looping; + bool m_streamed; + }; + public: explicit SoundBankWriterImpl(std::string fileName, std::ostream& stream, ISearchPath* assetSearchPath) : m_file_name(std::move(fileName)), @@ -118,6 +146,100 @@ public: Write(&header, sizeof(header)); } + bool LoadWavFile(const SearchPathOpenFile& file, const SoundBankEntryInfo& sound, std::unique_ptr& soundData, size_t& soundSize) + { + WavHeader header{}; + file.m_stream->read(reinterpret_cast(&header), sizeof(WavHeader)); + + soundSize = static_cast(file.m_length - sizeof(WavHeader)); + const auto frameCount = soundSize / (header.formatChunk.nChannels * (header.formatChunk.wBitsPerSample / 8)); + const auto frameRateIndex = INDEX_FOR_FRAMERATE[header.formatChunk.nSamplesPerSec]; + + SoundAssetBankEntry entry{ + sound.m_sound_id, + soundSize, + static_cast(m_current_offset), + frameCount, + frameRateIndex, + static_cast(header.formatChunk.nChannels), + sound.m_looping, + 0, + }; + + m_entries.push_back(entry); + + soundData = std::make_unique(soundSize); + file.m_stream->read(soundData.get(), soundSize); + + return true; + } + + bool LoadFlacFile( + const SearchPathOpenFile& file, const std::string& filePath, const SoundBankEntryInfo& sound, std::unique_ptr& soundData, size_t& soundSize) + { + soundSize = static_cast(file.m_length); + + soundData = std::make_unique(soundSize); + file.m_stream->read(soundData.get(), soundSize); + + flac::FlacMetaData metaData; + if (flac::GetFlacMetaData(soundData.get(), soundSize, metaData)) + { + const auto frameRateIndex = INDEX_FOR_FRAMERATE[metaData.m_sample_rate]; + SoundAssetBankEntry entry{ + sound.m_sound_id, + soundSize, + static_cast(m_current_offset), + static_cast(metaData.m_total_samples), + frameRateIndex, + metaData.m_number_of_channels, + sound.m_looping, + 8, + }; + + m_entries.push_back(entry); + return true; + } + + std::cerr << std::format("Unable to decode .flac file for sound {}\n", filePath); + return false; + } + + bool LoadFileByExtension(const std::string& filePath, const SoundBankEntryInfo& sound, std::unique_ptr& soundData, size_t& soundSize) + { + auto extension = fs::path(filePath).extension().string(); + utils::MakeStringLowerCase(extension); + if (extension.empty()) + return false; + + const auto file = m_asset_search_path->Open(filePath); + if (!file.IsOpen()) + return false; + + if (extension == ".wav") + return LoadWavFile(file, sound, soundData, soundSize); + + if (extension == ".flac") + return LoadFlacFile(file, filePath, sound, soundData, soundSize); + + return false; + } + + bool GuessFilenameAndLoadFile(const std::string& filePath, const SoundBankEntryInfo& sound, std::unique_ptr& soundData, size_t& soundSize) + { + fs::path pathWithExtension = fs::path(filePath).replace_extension(".wav"); + auto file = m_asset_search_path->Open(pathWithExtension.string()); + if (file.IsOpen()) + return LoadWavFile(file, sound, soundData, soundSize); + + pathWithExtension = fs::path(filePath).replace_extension(".flac"); + file = m_asset_search_path->Open(pathWithExtension.string()); + if (file.IsOpen()) + return LoadFlacFile(file, pathWithExtension.string(), sound, soundData, soundSize); + + return false; + } + bool WriteEntries() { GoTo(DATA_OFFSET); @@ -125,85 +247,23 @@ public: for (auto& sound : m_sounds) { const auto& soundFilePath = sound.m_file_path; - const auto soundId = sound.m_sound_id; size_t soundSize; std::unique_ptr soundData; - // try to find a file for the sound path - const auto file = m_asset_search_path->Open(soundFilePath); - if (!file.IsOpen()) + if (!LoadFileByExtension(soundFilePath, sound, soundData, soundSize) && !GuessFilenameAndLoadFile(soundFilePath, sound, soundData, soundSize)) { - std::cerr << "Unable to find a compatible file for sound " << soundFilePath << "\n"; + std::cerr << std::format("Unable to find a compatible file for sound {}\n", soundFilePath); return false; } - // check if sound path ends in .wav - const std::string extension = ".wav"; - if (soundFilePath.size() >= extension.size() && soundFilePath.compare(soundFilePath.size() - extension.size(), extension.size(), extension) == 0) - { - WavHeader header{}; - file.m_stream->read(reinterpret_cast(&header), sizeof(WavHeader)); - - soundSize = static_cast(file.m_length - sizeof(WavHeader)); - const auto frameCount = soundSize / (header.formatChunk.nChannels * (header.formatChunk.wBitsPerSample / 8)); - const auto frameRateIndex = INDEX_FOR_FRAMERATE[header.formatChunk.nSamplesPerSec]; - - SoundAssetBankEntry entry{ - soundId, - soundSize, - static_cast(m_current_offset), - frameCount, - frameRateIndex, - static_cast(header.formatChunk.nChannels), - sound.m_looping, - 0, - }; - - m_entries.push_back(entry); - - soundData = std::make_unique(soundSize); - file.m_stream->read(soundData.get(), soundSize); - } - else - { - soundSize = static_cast(file.m_length); - - soundData = std::make_unique(soundSize); - file.m_stream->read(soundData.get(), soundSize); - - flac::FlacMetaData metaData; - if (flac::GetFlacMetaData(soundData.get(), soundSize, metaData)) - { - const auto frameRateIndex = INDEX_FOR_FRAMERATE[metaData.m_sample_rate]; - SoundAssetBankEntry entry{ - soundId, - soundSize, - static_cast(m_current_offset), - static_cast(metaData.m_total_samples), - frameRateIndex, - metaData.m_number_of_channels, - sound.m_looping, - 8, - }; - - m_entries.push_back(entry); - } - else - { - std::cerr << "Unable to decode .flac file for sound " << soundFilePath << "\n"; - return false; - } - } - const auto lastEntry = m_entries.rbegin(); if (!sound.m_streamed && lastEntry->frameRateIndex != 6) { - std::cout << "WARNING: Loaded sound \"" << soundFilePath - << "\" should have a framerate of 48000 but doesn't. This sound may not work on all games!\n"; + std::cout << std::format("WARNING: Loaded sound \"{}\" should have a framerate of 48000 but doesn't. This sound may not work on all games!\n", + soundFilePath); } - // calculate checksum SoundAssetBankChecksum checksum{}; const auto md5Crypt = Crypto::CreateMD5(); @@ -276,30 +336,6 @@ public: } private: - class SoundBankEntryInfo - { - public: - SoundBankEntryInfo() - : m_sound_id(0u), - m_looping(false), - m_streamed(false) - { - } - - SoundBankEntryInfo(std::string filePath, const unsigned int soundId, const bool looping, const bool streamed) - : m_file_path(std::move(filePath)), - m_sound_id(soundId), - m_looping(looping), - m_streamed(streamed) - { - } - - std::string m_file_path; - unsigned int m_sound_id; - bool m_looping; - bool m_streamed; - }; - std::string m_file_name; std::ostream& m_stream; ISearchPath* m_asset_search_path; diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp index 45dda9fd..d37b4905 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp @@ -8,6 +8,7 @@ #include "nlohmann/json.hpp" #include +#include #include #include @@ -124,7 +125,7 @@ namespace { std::unordered_map result; for (auto i = 0u; i < std::extent_v; i++) - result.emplace(T6::Common::SND_HashName(SOUND_CURVES[i].data()), SOUND_CURVES[i]); + result.emplace(T6::Common::SND_HashName(SOUND_CURVES[i]), SOUND_CURVES[i]); return result; } @@ -195,7 +196,7 @@ class AssetDumperSndBank::Internal stream.NextRow(); } - static const char* FindNameForDuck(unsigned int id, const SndBank* bank) + static const char* FindNameForDuck(const unsigned int id, const SndBank* bank) { for (auto i = 0u; i < bank->duckCount; i++) { @@ -208,7 +209,7 @@ class AssetDumperSndBank::Internal return ""; } - std::string ConvertSndFormatToExtension(snd_asset_format format) const + static const char* ExtensionForSndFormat(const snd_asset_format format) { switch (format) { @@ -219,17 +220,19 @@ class AssetDumperSndBank::Internal return ".flac"; default: + assert(false); return ""; } } - static void WriteAliasToFile(CsvOutputStream& stream, const SndAlias* alias, std::string& extension, const SndBank* bank) + static void WriteAliasToFile(CsvOutputStream& stream, const SndAlias* alias, const std::optional maybeFormat, const SndBank* bank) { // name stream.WriteColumn(alias->name); // file - stream.WriteColumn(alias->assetFileName ? alias->assetFileName + extension : ""); + const auto* extension = maybeFormat ? ExtensionForSndFormat(*maybeFormat) : ""; + stream.WriteColumn(alias->assetFileName ? std::format("{}{}", alias->assetFileName, extension) : ""); // template stream.WriteColumn(""); @@ -435,7 +438,7 @@ class AssetDumperSndBank::Internal const auto outFile = OpenAssetOutputFile(assetFileName, ".wav"); if (!outFile) { - std::cerr << "Failed to open sound output file: \"" << assetFileName << "\"\n"; + std::cerr << std::format("Failed to open sound output file: \"{}\"\n", assetFileName); return; } @@ -462,7 +465,7 @@ class AssetDumperSndBank::Internal const auto outFile = OpenAssetOutputFile(assetFileName, extension); if (!outFile) { - std::cerr << "Failed to open sound output file: \"" << assetFileName << "\"\n"; + std::cerr << std::format("Failed to open sound output file: \"{}\"\n", assetFileName); return; } @@ -499,33 +502,30 @@ class AssetDumperSndBank::Internal case SND_ASSET_FORMAT_WMA: case SND_ASSET_FORMAT_WIIUADPCM: case SND_ASSET_FORMAT_MPC: - std::cerr << "Cannot dump sound (Unsupported sound format " << format << "): \"" << alias.assetFileName << "\"\n"; + std::cerr << std::format("Cannot dump sound (Unknown sound format {}): \"{}\"\n", static_cast(format), alias.assetFileName); break; default: assert(false); - std::cerr << "Cannot dump sound (Unknown sound format " << format << "): \"" << alias.assetFileName << "\"\n"; + std::cerr << std::format("Cannot dump sound (Unknown sound format {}): \"{}\"\n", static_cast(format), alias.assetFileName); break; } return format; } - else - { - std::cerr << "Could not find data for sound \"" << alias.assetFileName << "\"\n"; - } + std::cerr << std::format("Could not find data for sound \"{}\"\n", alias.assetFileName); return {}; } void DumpSndBankAliases(const SndBank* sndBank) const { - std::unordered_map dumpedAssets; + std::unordered_map> dumpedAssets; - const auto outFile = OpenAssetOutputFile("soundbank/" + std::string(sndBank->name) + ".aliases", ".csv"); + const auto outFile = OpenAssetOutputFile(std::format("soundbank/{}.aliases", sndBank->name), ".csv"); if (!outFile) { - std::cerr << "Failed to open sound alias output file: \"" << sndBank->name << "\"\n"; + std::cerr << std::format("Failed to open sound alias output file: \"\"\n", sndBank->name); return; } @@ -539,28 +539,23 @@ class AssetDumperSndBank::Internal for (auto j = 0; j < aliasList.count; j++) { const auto& alias = aliasList.head[j]; - std::string extension = ""; + std::optional maybeFormat; if (alias.assetId && alias.assetFileName) { - if (dumpedAssets.find(alias.assetId) == dumpedAssets.end()) + const auto previouslyDeterminedFormat = dumpedAssets.find(alias.assetId); + if (previouslyDeterminedFormat == dumpedAssets.end()) { - std::optional format = DumpSndAlias(alias); - - if (format.has_value()) - { - extension = ConvertSndFormatToExtension(format.value()); - } - - dumpedAssets[alias.assetId] = extension; + maybeFormat = DumpSndAlias(alias); + dumpedAssets[alias.assetId] = maybeFormat; } else { - extension = dumpedAssets[alias.assetId]; + maybeFormat = previouslyDeterminedFormat->second; } } - WriteAliasToFile(csvStream, &alias, extension, sndBank); + WriteAliasToFile(csvStream, &alias, maybeFormat, sndBank); csvStream.NextRow(); } } @@ -569,14 +564,12 @@ class AssetDumperSndBank::Internal void DumpSoundRadverb(const SndBank* sndBank) const { if (sndBank->radverbCount <= 0) - { return; - } - const auto outFile = OpenAssetOutputFile("soundbank/" + std::string(sndBank->name) + ".reverbs", ".csv"); + const auto outFile = OpenAssetOutputFile(std::format("soundbank/{}.reverbs", sndBank->name), ".csv"); if (!outFile) { - std::cerr << "Failed to open sound reverb output file: \"" << sndBank->name << "\"\n"; + std::cerr << std::format("Failed to open sound reverb output file: \"{}\"\n", sndBank->name); return; } @@ -610,14 +603,12 @@ class AssetDumperSndBank::Internal void DumpSoundDucks(const SndBank* sndBank) const { if (sndBank->duckCount <= 0) - { return; - } - const auto outFile = OpenAssetOutputFile("soundbank/" + std::string(sndBank->name) + ".ducklist", ".csv"); + const auto outFile = OpenAssetOutputFile(std::format("soundbank/{}.ducklist", sndBank->name), ".csv"); if (!outFile) { - std::cerr << "Failed to open sound reverb output file: \"" << sndBank->name << "\"\n"; + std::cerr << std::format("Failed to open sound reverb output file: \"{}\"\n", sndBank->name); return; } @@ -631,10 +622,10 @@ class AssetDumperSndBank::Internal csvStream.WriteColumn(duck.name); csvStream.NextRow(); - const auto duckFile = OpenAssetOutputFile("soundbank/ducks/" + std::string(duck.name), ".duk"); + const auto duckFile = OpenAssetOutputFile(std::format("soundbank/ducks/{}", duck.name), ".duk"); if (!outFile) { - std::cerr << "Failed to open sound duck output file: \"" << duck.name << "\"\n"; + std::cerr << std::format("Failed to open sound duck output file: \"{}\"\n", duck.name); return; } @@ -661,12 +652,12 @@ class AssetDumperSndBank::Internal } auto values = std::vector{}; - for (auto i = 0u; i < 32u; i++) + for (auto j = 0u; j < 32u; j++) { values.push_back({ - {"duckGroup", SOUND_DUCK_GROUPS[i]}, - {"attenuation", duck.attenuation[i] }, - {"filter", duck.filter[i] } + {"duckGroup", SOUND_DUCK_GROUPS[j]}, + {"attenuation", duck.attenuation[j] }, + {"filter", duck.filter[j] } }); }