From 4e8d1806cc47516d0367cd7c37159b6d246165fc Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 11 Apr 2021 09:04:58 +0200 Subject: [PATCH] t6 alias dumping stuff --- src/Common/Game/T6/T6_Assets.h | 16 ++++++ src/ObjLoading/Game/T6/ObjLoaderT6.cpp | 6 +- .../ObjContainer/SoundBank/SoundBank.cpp | 46 ++++++++++----- .../ObjContainer/SoundBank/SoundBank.h | 23 ++++++-- .../ObjContainer/SoundBank/SoundBankTypes.h | 8 +-- .../T6/AssetDumpers/AssetDumperSndBank.cpp | 57 ++++++++++++++++--- .../Game/T6/AssetDumpers/AssetDumperSndBank.h | 7 ++- 7 files changed, 128 insertions(+), 35 deletions(-) diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 44c4a180..9d9ab2d8 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -2874,6 +2874,22 @@ namespace T6 int updateWhilePaused; }; + enum snd_asset_format + { + SND_ASSET_FORMAT_PCMS16 = 0x0, + SND_ASSET_FORMAT_PCMS24 = 0x1, + SND_ASSET_FORMAT_PCMS32 = 0x2, + SND_ASSET_FORMAT_IEEE = 0x3, + SND_ASSET_FORMAT_XMA4 = 0x4, + SND_ASSET_FORMAT_MP3 = 0x5, + SND_ASSET_FORMAT_MSADPCM = 0x6, + SND_ASSET_FORMAT_WMA = 0x7, + SND_ASSET_FORMAT_FLAC = 0x8, + SND_ASSET_FORMAT_WIIUADPCM = 0x9, + SND_ASSET_FORMAT_MPC = 0xA, + + SND_ASSET_FORMAT_COUNT + }; struct SndAssetBankEntry { diff --git a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp index dd92470a..38673a97 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp @@ -98,9 +98,9 @@ namespace T6 bool ObjLoader::VerifySoundBankChecksum(const SoundBank* soundBank, const SndRuntimeAssetBank& sndRuntimeAssetBank) { - SndAssetBankChecksum checksum{}; - static_assert(sizeof(SndAssetBankChecksum::checksumBytes) == sizeof(SndRuntimeAssetBank::linkTimeChecksum)); - for (auto i = 0u; i < sizeof(SndAssetBankChecksum::checksumBytes); i++) + SoundAssetBankChecksum checksum{}; + static_assert(sizeof(SoundAssetBankChecksum::checksumBytes) == sizeof(SndRuntimeAssetBank::linkTimeChecksum)); + for (auto i = 0u; i < sizeof(SoundAssetBankChecksum::checksumBytes); i++) checksum.checksumBytes[i] = sndRuntimeAssetBank.linkTimeChecksum[i]; return soundBank->VerifyChecksum(checksum); diff --git a/src/ObjLoading/ObjContainer/SoundBank/SoundBank.cpp b/src/ObjLoading/ObjContainer/SoundBank/SoundBank.cpp index d35aec0d..7bdaadff 100644 --- a/src/ObjLoading/ObjContainer/SoundBank/SoundBank.cpp +++ b/src/ObjLoading/ObjContainer/SoundBank/SoundBank.cpp @@ -61,12 +61,12 @@ protected: pos_type seekoff(const off_type off, const std::ios_base::seekdir dir, const std::ios_base::openmode mode) override { - if(dir == std::ios_base::beg) + if (dir == std::ios_base::beg) { return seekpos(off, mode); } - if(dir == std::ios_base::end) + if (dir == std::ios_base::end) { if (off > m_size) return pos_type(-1); @@ -110,6 +110,22 @@ public: } }; +SoundBankEntryInputStream::SoundBankEntryInputStream() + : m_entry{} +{ +} + +SoundBankEntryInputStream::SoundBankEntryInputStream(std::unique_ptr stream, SoundAssetBankEntry entry) + : m_stream(std::move(stream)), + m_entry(entry) +{ +} + +bool SoundBankEntryInputStream::IsOpen() const +{ + return m_stream.get() != nullptr; +} + bool SoundBank::ReadHeader() { m_stream->read(reinterpret_cast(&m_header), sizeof(m_header)); @@ -131,9 +147,9 @@ bool SoundBank::ReadHeader() return false; } - if (m_header.entrySize != sizeof(SndAssetBankEntry)) + if (m_header.entrySize != sizeof(SoundAssetBankEntry)) { - std::cout << "Invalid sndbank entry size 0x" << std::hex << m_header.entrySize << " (should be 0x" << std::hex << sizeof(SndAssetBankEntry) << ")" << std::endl; + std::cout << "Invalid sndbank entry size 0x" << std::hex << m_header.entrySize << " (should be 0x" << std::hex << sizeof(SoundAssetBankEntry) << ")" << std::endl; return false; } @@ -144,19 +160,19 @@ bool SoundBank::ReadHeader() } if (m_header.entryCount - && (m_header.entryOffset <= 0 || m_header.entryOffset + sizeof(SndAssetBankEntry) * m_header.entryCount > m_file_size)) + && (m_header.entryOffset <= 0 || m_header.entryOffset + sizeof(SoundAssetBankEntry) * m_header.entryCount > m_file_size)) { std::cout << "Invalid sndbank entry offset " << m_header.entryOffset << " (filesize is " << m_file_size << ")" << std::endl; return false; } - if (m_header.checksumOffset <= 0 || m_header.checksumOffset + sizeof(SndAssetBankChecksum) * m_header.entryCount > m_file_size) + if (m_header.checksumOffset <= 0 || m_header.checksumOffset + sizeof(SoundAssetBankChecksum) * m_header.entryCount > m_file_size) { std::cout << "Invalid sndbank checksum offset " << m_header.checksumOffset << " (filesize is " << m_file_size << ")" << std::endl; return false; } - if (m_header.dependencyCount * m_header.dependencySize > sizeof(SndAssetBankHeader::dependencies)) + if (m_header.dependencyCount * m_header.dependencySize > sizeof(SoundAssetBankHeader::dependencies)) { std::cout << "Invalid sndbank dependency sizes (count is " << m_header.dependencyCount << "; size is " << m_header.dependencySize << ")" << std::endl; return false; @@ -182,7 +198,7 @@ bool SoundBank::ReadEntries() for (auto i = 0u; i < m_header.entryCount; i++) { - SndAssetBankEntry entry{}; + SoundAssetBankEntry entry{}; m_stream->read(reinterpret_cast(&entry), sizeof(entry)); if (m_stream->gcount() != sizeof(entry)) @@ -210,7 +226,7 @@ bool SoundBank::ReadChecksums() for (auto i = 0u; i < m_header.entryCount; i++) { - SndAssetBankChecksum checksum{}; + SoundAssetBankChecksum checksum{}; m_stream->read(reinterpret_cast(&checksum), sizeof(checksum)); if (m_stream->gcount() != sizeof(checksum)) @@ -278,23 +294,23 @@ const std::vector& SoundBank::GetDependencies() const return m_dependencies; } -bool SoundBank::VerifyChecksum(const SndAssetBankChecksum& checksum) const +bool SoundBank::VerifyChecksum(const SoundAssetBankChecksum& checksum) const { - return m_initialized && memcmp(checksum.checksumBytes, m_header.checksumChecksum.checksumBytes, sizeof(SndAssetBankChecksum)) == 0; + return m_initialized && memcmp(checksum.checksumBytes, m_header.checksumChecksum.checksumBytes, sizeof(SoundAssetBankChecksum)) == 0; } -SearchPathOpenFile SoundBank::GetEntryStream(const unsigned id) const +SoundBankEntryInputStream SoundBank::GetEntryStream(const unsigned id) const { const auto foundEntry = m_entries_by_id.find(id); if (foundEntry != m_entries_by_id.end()) { const auto& entry = m_entries[foundEntry->second]; - + m_stream->seekg(entry.offset); - return SearchPathOpenFile(std::make_unique(std::make_unique(*m_stream, entry.offset, entry.size)), entry.size); + return SoundBankEntryInputStream(std::make_unique(std::make_unique(*m_stream, entry.offset, entry.size)), entry); } - return SearchPathOpenFile(); + return SoundBankEntryInputStream(); } diff --git a/src/ObjLoading/ObjContainer/SoundBank/SoundBank.h b/src/ObjLoading/ObjContainer/SoundBank/SoundBank.h index f7ab2c4a..af046222 100644 --- a/src/ObjLoading/ObjContainer/SoundBank/SoundBank.h +++ b/src/ObjLoading/ObjContainer/SoundBank/SoundBank.h @@ -11,6 +11,18 @@ #include "Utils/ObjStream.h" #include "Zone/Zone.h" +class SoundBankEntryInputStream +{ +public: + std::unique_ptr m_stream; + SoundAssetBankEntry m_entry; + + SoundBankEntryInputStream(); + SoundBankEntryInputStream(std::unique_ptr stream, SoundAssetBankEntry entry); + + _NODISCARD bool IsOpen() const; +}; + class SoundBank final : public ObjContainerReferenceable { static constexpr uint32_t MAGIC = FileUtils::MakeMagic32('2', 'U', 'X', '#'); @@ -21,10 +33,10 @@ class SoundBank final : public ObjContainerReferenceable int64_t m_file_size; bool m_initialized; - SndAssetBankHeader m_header; + SoundAssetBankHeader m_header; std::vector m_dependencies; - std::vector m_entries; - std::vector m_checksums; + std::vector m_entries; + std::vector m_checksums; std::unordered_map m_entries_by_id; bool ReadHeader(); @@ -37,6 +49,7 @@ public: static std::string GetFileNameForDefinition(bool streamed, const char* zone, const char* language); SoundBank(std::string fileName, std::unique_ptr stream, int64_t fileSize); + ~SoundBank() override = default; SoundBank(const SoundBank& other) = delete; SoundBank(SoundBank&& other) noexcept = default; SoundBank& operator=(const SoundBank& other) = delete; @@ -47,6 +60,6 @@ public: bool Initialize(); _NODISCARD const std::vector& GetDependencies() const; - _NODISCARD bool VerifyChecksum(const SndAssetBankChecksum& checksum) const; - _NODISCARD SearchPathOpenFile GetEntryStream(unsigned int id) const; + _NODISCARD bool VerifyChecksum(const SoundAssetBankChecksum& checksum) const; + _NODISCARD SoundBankEntryInputStream GetEntryStream(unsigned int id) const; }; diff --git a/src/ObjLoading/ObjContainer/SoundBank/SoundBankTypes.h b/src/ObjLoading/ObjContainer/SoundBank/SoundBankTypes.h index 0995b0ef..46927c27 100644 --- a/src/ObjLoading/ObjContainer/SoundBank/SoundBankTypes.h +++ b/src/ObjLoading/ObjContainer/SoundBank/SoundBankTypes.h @@ -10,12 +10,12 @@ public: static constexpr unsigned OFFSET_DATA_START = 0x800; }; -struct SndAssetBankChecksum +struct SoundAssetBankChecksum { char checksumBytes[16]; }; -struct SndAssetBankHeader +struct SoundAssetBankHeader { unsigned int magic; // + 0x0 unsigned int version; // + 0x4 @@ -28,11 +28,11 @@ struct SndAssetBankHeader int64_t fileSize; // + 0x20 int64_t entryOffset; // + 0x28 int64_t checksumOffset; // + 0x30 - SndAssetBankChecksum checksumChecksum; // + 0x38 + SoundAssetBankChecksum checksumChecksum; // + 0x38 char dependencies[512]; // + 0x48 }; -struct SndAssetBankEntry +struct SoundAssetBankEntry { unsigned int id; unsigned int size; diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp index e7dca534..efd4efc3 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp @@ -1,6 +1,7 @@ #include "AssetDumperSndBank.h" #include +#include #include "Csv/CsvStream.h" #include "ObjContainer/SoundBank/SoundBank.h" @@ -8,7 +9,36 @@ using namespace T6; namespace fs = std::filesystem; -std::unique_ptr AssetDumperSndBank::OpenOutputFile(AssetDumpingContext& context, const std::string& outputFileName) const +std::string AssetDumperSndBank::GetExtensionForFormat(const snd_asset_format format) +{ + switch(format) + { + case SND_ASSET_FORMAT_MP3: + return ".mp3"; + + case SND_ASSET_FORMAT_FLAC: + return ".flac"; + + case SND_ASSET_FORMAT_PCMS16: + case SND_ASSET_FORMAT_PCMS24: + case SND_ASSET_FORMAT_PCMS32: + case SND_ASSET_FORMAT_IEEE: + case SND_ASSET_FORMAT_XMA4: + case SND_ASSET_FORMAT_MSADPCM: + case SND_ASSET_FORMAT_WMA: + case SND_ASSET_FORMAT_WIIUADPCM: + case SND_ASSET_FORMAT_MPC: + std::cout << "Unsupported sound format " << format << std::endl; + return std::string(); + + default: + assert(false); + std::cout << "Unknown sound format " << format << std::endl; + return std::string(); + } +} + +std::unique_ptr AssetDumperSndBank::OpenAssetOutputFile(AssetDumpingContext& context, const std::string& outputFileName, const SoundAssetBankEntry& entry) const { fs::path assetPath(context.m_base_path); @@ -27,6 +57,10 @@ std::unique_ptr AssetDumperSndBank::OpenOutputFile(AssetDumpingCon assetPath.append(part.string()); } + const auto extension = GetExtensionForFormat(static_cast(entry.format)); + if(!extension.empty()) + assetPath.concat(extension); + auto assetDir(assetPath); assetDir.remove_filename(); @@ -42,11 +76,13 @@ std::unique_ptr AssetDumperSndBank::OpenOutputFile(AssetDumpingCon return nullptr; } -void AssetDumperSndBank::DumpSndBank(AssetDumpingContext& context, const XAssetInfo* sndBankInfo) +std::unique_ptr AssetDumperSndBank::OpenAliasOutputFile(AssetDumpingContext& context, SndBank* sndBank) const { - const auto* sndBank = sndBankInfo->Asset(); + return nullptr; +} - std::map aliasMappings; +void AssetDumperSndBank::DumpSndBankAliases(AssetDumpingContext& context, SndBank* sndBank, std::unordered_map& aliasFiles) +{ for (auto i = 0u; i < sndBank->aliasCount; i++) { const auto& aliasList = sndBank->alias[i]; @@ -54,9 +90,16 @@ void AssetDumperSndBank::DumpSndBank(AssetDumpingContext& context, const XAssetI { const auto& alias = aliasList.head[j]; if (alias.assetId && alias.assetFileName) - aliasMappings[alias.assetId] = alias.assetFileName; + aliasFiles[alias.assetId] = alias.assetFileName; } } +} + +void AssetDumperSndBank::DumpSndBank(AssetDumpingContext& context, const XAssetInfo* sndBankInfo) +{ + const auto* sndBank = sndBankInfo->Asset(); + + std::unordered_map aliasMappings; for (const auto& [id, filename] : aliasMappings) { @@ -67,16 +110,16 @@ void AssetDumperSndBank::DumpSndBank(AssetDumpingContext& context, const XAssetI auto soundFile = soundBank->GetEntryStream(id); if (soundFile.IsOpen()) { - auto outFile = OpenOutputFile(context, filename); + auto outFile = OpenAssetOutputFile(context, filename, soundFile.m_entry); if (!outFile) { std::cout << "Failed to open sound outputfile: \"" << filename << "\"" << std::endl; break; } - char buffer[2048]; while (!soundFile.m_stream->eof()) { + char buffer[2048]; soundFile.m_stream->read(buffer, sizeof(buffer)); const auto readSize = soundFile.m_stream->gcount(); outFile->write(buffer, readSize); diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.h b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.h index a5b347f1..9a05fc74 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.h +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.h @@ -2,15 +2,20 @@ #include #include +#include #include "Dumping/AbstractAssetDumper.h" #include "Game/T6/T6.h" +#include "ObjContainer/SoundBank/SoundBankTypes.h" namespace T6 { class AssetDumperSndBank final : public IAssetDumper { - std::unique_ptr OpenOutputFile(AssetDumpingContext& context, const std::string& outputFileName) const; + static std::string GetExtensionForFormat(snd_asset_format format); + std::unique_ptr OpenAssetOutputFile(AssetDumpingContext& context, const std::string& outputFileName, const SoundAssetBankEntry& entry) const; + std::unique_ptr OpenAliasOutputFile(AssetDumpingContext& context, SndBank* sndBank) const; + void DumpSndBankAliases(AssetDumpingContext& context, SndBank* sndBank, std::unordered_map& aliasFiles); void DumpSndBank(AssetDumpingContext& context, const XAssetInfo* sndBankInfo); public: