From 4762d4bdd743251d2e8d07a7d4d0ce0611c8ea2e Mon Sep 17 00:00:00 2001 From: Scobalula Date: Wed, 2 Nov 2022 18:33:00 +0000 Subject: [PATCH] MW2 Sounds --- src/WraithXCOD/WraithXCOD/CoDAssets.cpp | 2 +- .../WraithXCOD/GameModernWarfare5.cpp | 107 ++++++++++++++---- .../WraithXCOD/GameModernWarfare5.h | 2 + .../WraithXCOD/GameModernWarfare5Structures.h | 26 ++++- 4 files changed, 111 insertions(+), 26 deletions(-) diff --git a/src/WraithXCOD/WraithXCOD/CoDAssets.cpp b/src/WraithXCOD/WraithXCOD/CoDAssets.cpp index c7f9a9b..5287435 100644 --- a/src/WraithXCOD/WraithXCOD/CoDAssets.cpp +++ b/src/WraithXCOD/WraithXCOD/CoDAssets.cpp @@ -1856,7 +1856,7 @@ ExportGameResult CoDAssets::ExportSoundAsset(const CoDSound_t* Sound, const std: if (Sound->IsFileEntry) SoundData = SABSupport::LoadOpusSound(Sound); else - SoundData = GameVanguard::ReadXSound(Sound); + SoundData = GameModernWarfare5::ReadXSound(Sound); break; case SupportedGames::Vanguard: if (Sound->IsFileEntry) diff --git a/src/WraithXCOD/WraithXCOD/GameModernWarfare5.cpp b/src/WraithXCOD/WraithXCOD/GameModernWarfare5.cpp index ea0740e..e737b18 100644 --- a/src/WraithXCOD/WraithXCOD/GameModernWarfare5.cpp +++ b/src/WraithXCOD/WraithXCOD/GameModernWarfare5.cpp @@ -13,10 +13,17 @@ #include "Strings.h" #include "FileSystems.h" #include "MemoryReader.h" +#include "MemoryWriter.h" #include "TextWriter.h" #include "SettingsManager.h" #include "HalfFloats.h" #include "BinaryReader.h" +#include "Sound.h" + +// We need Opus +#include "..\..\External\Opus\include\opus.h" + +#include "SABSupport.h" // We need the QTangent #include "CoDQTangent.h" @@ -172,6 +179,10 @@ bool GameModernWarfare5::LoadAssets() // Validate and load if need be auto AnimName = CoDAssets::GameInstance->ReadNullTerminatedString(AnimResult.NamePtr); + // No multi-buffer for now. + if (AnimResult.DataInfo.OffsetCount > 1) + return; + // Log it CoDAssets::LogXAsset("Anim", AnimName); @@ -246,32 +257,40 @@ bool GameModernWarfare5::LoadAssets() }); } - //if (NeedsRawFiles) - //{ - // auto Pool = CoDAssets::GameInstance->Read(ps::state->PoolsAddress + 37 * sizeof(ps::XAssetPool64)); - // ps::PoolParser64(Pool.FirstXAsset, CoDAssets::ParasyteRequest, [](ps::XAsset64& Asset) - // { - // // Read - // auto SoundResult = CoDAssets::GameInstance->Read(Asset.Header); - // // Validate and load if need be - // auto RawfileName = CoDAssets::GameInstance->ReadNullTerminatedString(SoundResult.NamePtr) + ".sabs"; - - // // Log it - // CoDAssets::LogXAsset("RawFile", RawfileName); + if (NeedsSounds) + { + auto Pool = CoDAssets::GameInstance->Read(ps::state->PoolsAddress + 197 * sizeof(ps::XAssetPool64)); + ps::PoolParser64(Pool.FirstXAsset, CoDAssets::ParasyteRequest, [](ps::XAsset64& Asset) + { + // Read + auto SoundResult = CoDAssets::GameInstance->Read(Asset.Header); + // Mask the name as hashes are 60Bit (Actually 63Bit but maintain with our existing tables) + SoundResult.Name &= 0xFFFFFFFFFFFFFFF; + // Validate and load if need be + auto SoundName = CoDAssets::GetHashedName("xsound", SoundResult.Name); - // // Make and add - // auto LoadedRawfile = new CoDRawFile_t(); - // // Set - // LoadedRawfile->AssetName = FileSystems::GetFileName(RawfileName); - // LoadedRawfile->RawFilePath = FileSystems::GetDirectoryName(RawfileName); - // LoadedRawfile->AssetPointer = Asset.Header; - // LoadedRawfile->AssetSize = SoundResult.SoundBankSize; - // LoadedRawfile->AssetStatus = WraithAssetStatus::Loaded; + // Log it + CoDAssets::LogXAsset("Sound", SoundName); - // // Add - // CoDAssets::GameAssets->LoadedAssets.push_back(LoadedRawfile); - // }); - //} + // Make and add + auto LoadedSound = new CoDSound_t(); + // Set the name, but remove all extensions first + LoadedSound->AssetName = FileSystems::GetFileNamePurgeExtensions(SoundName); + LoadedSound->FullPath = FileSystems::GetDirectoryName(SoundName); + LoadedSound->AssetPointer = Asset.Header; + LoadedSound->AssetStatus = WraithAssetStatus::Loaded; + // Set various properties + LoadedSound->FrameRate = SoundResult.FrameRate; + LoadedSound->FrameCount = SoundResult.FrameCount; + LoadedSound->ChannelsCount = SoundResult.ChannelCount; + LoadedSound->AssetSize = -1; + LoadedSound->AssetStatus = WraithAssetStatus::Loaded; + LoadedSound->IsFileEntry = false; + LoadedSound->Length = (uint32_t)(1000.0f * (float)(LoadedSound->FrameCount / (float)(LoadedSound->FrameRate))); + // Add + CoDAssets::GameAssets->LoadedAssets.push_back(LoadedSound); + }); + } // Success, error only on specific load return true; @@ -573,6 +592,46 @@ std::unique_ptr GameModernWarfare5::ReadXImage(const CoDImage_t* Imag return LoadXImage(XImage_t(ImageUsageType::DiffuseMap, 0, Image->AssetPointer, Image->AssetName)); } +std::unique_ptr GameModernWarfare5::ReadXSound(const CoDSound_t* Sound) +{ + // Read the Sound Asset structure + auto SoundData = CoDAssets::GameInstance->Read(Sound->AssetPointer); + + if (SoundData.StreamKey != 0) + { + // Buffer + std::unique_ptr SoundBuffer = nullptr; + // Extract buffer, these are compressed + uint32_t SoundMemoryResult = 0; + SoundBuffer = CoDAssets::GamePackageCache->ExtractPackageObject(SoundData.StreamKey, (int32_t)(((uint64_t)SoundData.Size + 4095) & 0xFFFFFFFFFFFFF000), SoundMemoryResult); + + if (SoundMemoryResult == 0) + return nullptr; + + if (SoundBuffer == nullptr) + return nullptr; + + return SABSupport::DecodeOpusInterleaved(SoundBuffer.get() + SoundData.SeekTableSize, (size_t)SoundMemoryResult - SoundData.SeekTableSize, 0, SoundData.FrameRate, SoundData.ChannelCount, SoundData.FrameCount); + } + else + { + // Buffer + std::unique_ptr SoundBuffer = nullptr; + // Extract buffer, these are compressed + uint32_t SoundMemoryResult = 0; + SoundBuffer = CoDAssets::GamePackageCache->ExtractPackageObject(SoundData.StreamKeyEx, (int32_t)(((uint64_t)SoundData.LoadedSize + 4095) & 0xFFFFFFFFFFFFF000), SoundMemoryResult); + + if (SoundMemoryResult == 0) + return nullptr; + + if (SoundBuffer == nullptr) + return nullptr; + + return SABSupport::DecodeOpusInterleaved(SoundBuffer.get() + 32 + SoundData.SeekTableSize, (size_t)SoundMemoryResult - 32 - SoundData.SeekTableSize, 0, SoundData.FrameRate, SoundData.ChannelCount, SoundData.FrameCount); + } + +} + void GameModernWarfare5::TranslateRawfile(const CoDRawFile_t * Rawfile, const std::string & ExportPath) { // Build the export path diff --git a/src/WraithXCOD/WraithXCOD/GameModernWarfare5.h b/src/WraithXCOD/WraithXCOD/GameModernWarfare5.h index 5b2a9a9..ef96f70 100644 --- a/src/WraithXCOD/WraithXCOD/GameModernWarfare5.h +++ b/src/WraithXCOD/WraithXCOD/GameModernWarfare5.h @@ -34,6 +34,8 @@ class GameModernWarfare5 static std::unique_ptr ReadXModel(const CoDModel_t* Model); // Reads a XImage from Modern Warfare 5 static std::unique_ptr ReadXImage(const CoDImage_t* Image); + // Reads an XSound from Modern Warfare 5 + static std::unique_ptr ReadXSound(const CoDSound_t* Sound); // Reads an XMaterial from it's logical offset in memory static const XMaterial_t ReadXMaterial(uint64_t MaterialPointer); // Reads a XImage from Modern Warfare 5 diff --git a/src/WraithXCOD/WraithXCOD/GameModernWarfare5Structures.h b/src/WraithXCOD/WraithXCOD/GameModernWarfare5Structures.h index a76a665..5971360 100644 --- a/src/WraithXCOD/WraithXCOD/GameModernWarfare5Structures.h +++ b/src/WraithXCOD/WraithXCOD/GameModernWarfare5Structures.h @@ -289,4 +289,28 @@ struct MW5SoundBank }; #pragma pack(pop) -extern uint32_t MW5DXGIFormats[52]; \ No newline at end of file +extern uint32_t MW5DXGIFormats[52]; + +#pragma pack(push, 1) +struct MW5SndAsset +{ + uint64_t Name; + uint64_t Unk; + uint64_t StreamKeyEx; + uint64_t StreamKey; + uint32_t Size; + uint32_t Unk3; + uint64_t Unk4; + uint64_t Unk5; + uint32_t SeekTableSize; + uint32_t LoadedSize; + uint32_t FrameCount; + uint32_t FrameRate; + uint32_t Unk9; + uint8_t Unk10; + uint8_t Unk11; + uint8_t Unk12; + uint8_t ChannelCount; + uint64_t Unk13; +}; +#pragma pack(pop) \ No newline at end of file