diff --git a/src/ObjCommon/Sound/WavTypes.h b/src/ObjCommon/Sound/WavTypes.h new file mode 100644 index 00000000..ebcd93e6 --- /dev/null +++ b/src/ObjCommon/Sound/WavTypes.h @@ -0,0 +1,30 @@ +#pragma once +#include + +#include "Utils/FileUtils.h" + +constexpr uint32_t WAV_WAVE_ID = MakeMagic32('W', 'A', 'V', 'E'); +constexpr uint32_t WAV_CHUNK_ID_RIFF = MakeMagic32('R', 'I', 'F', 'F'); +constexpr uint32_t WAV_CHUNK_ID_FMT = MakeMagic32('f', 'm', 't', ' '); +constexpr uint32_t WAV_CHUNK_ID_DATA = MakeMagic32('d', 'a', 't', 'a'); + +struct WavChunkHeader +{ + uint32_t chunkID; + uint32_t chunkSize; +}; + +enum class WavFormat : int16_t +{ + PCM = 1 +}; + +struct WavFormatChunkPcm +{ + WavFormat wFormatTag; + uint16_t nChannels; + uint32_t nSamplesPerSec; + uint32_t nAvgBytesPerSec; + uint16_t nBlockAlign; + uint16_t wBitsPerSample; +}; \ No newline at end of file diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperLoadedSound.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperLoadedSound.cpp new file mode 100644 index 00000000..66b4ba7b --- /dev/null +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperLoadedSound.cpp @@ -0,0 +1,70 @@ +#include "AssetDumperLoadedSound.h" + +#include "Sound/WavTypes.h" + +using namespace IW4; + +bool AssetDumperLoadedSound::ShouldDump(LoadedSound* asset) +{ + return true; +} + +std::string AssetDumperLoadedSound::GetFileNameForAsset(Zone* zone, LoadedSound* asset) +{ + return "sound/" + std::string(asset->name); +} + +void AssetDumperLoadedSound::DumpWavPcm(Zone* zone, LoadedSound* asset, FileAPI::File* out) +{ + const uint32_t riffMasterChunkSize = sizeof WAV_CHUNK_ID_RIFF + + sizeof uint32_t + + sizeof WAV_WAVE_ID + + sizeof WavChunkHeader + + sizeof WavFormatChunkPcm + + sizeof WavChunkHeader + + sizeof asset->sound.info.data_len; + + out->Write(&WAV_CHUNK_ID_RIFF, sizeof WAV_CHUNK_ID_RIFF, 1); + out->Write(&riffMasterChunkSize, sizeof riffMasterChunkSize, 1); + out->Write(&WAV_WAVE_ID, sizeof WAV_WAVE_ID, 1); + + const WavChunkHeader formatChunkHeader + { + WAV_CHUNK_ID_FMT, + sizeof WavFormatChunkPcm + }; + out->Write(&formatChunkHeader, sizeof formatChunkHeader, 1); + + WavFormatChunkPcm formatChunk + { + WavFormat::PCM, + static_cast(asset->sound.info.channels), + asset->sound.info.rate, + asset->sound.info.rate * asset->sound.info.channels * asset->sound.info.bits / 8, + static_cast(asset->sound.info.block_size), + static_cast(asset->sound.info.bits) + }; + out->Write(&formatChunk, sizeof formatChunk, 1); + + const WavChunkHeader dataChunkHeader + { + WAV_CHUNK_ID_DATA, + asset->sound.info.data_len + }; + out->Write(&dataChunkHeader, sizeof dataChunkHeader, 1); + out->Write(asset->sound.data, 1, asset->sound.info.data_len); +} + +void AssetDumperLoadedSound::DumpAsset(Zone* zone, LoadedSound* asset, FileAPI::File* out) +{ + switch (static_cast(asset->sound.info.format)) + { + case WavFormat::PCM: + DumpWavPcm(zone, asset, out); + break; + + default: + printf("Unknown format %i for loaded sound: %s\n", asset->sound.info.format, asset->name); + break; + } +} diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperLoadedSound.h b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperLoadedSound.h new file mode 100644 index 00000000..e7562a0b --- /dev/null +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperLoadedSound.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/IW4/IW4.h" + +namespace IW4 +{ + class AssetDumperLoadedSound final : public AbstractAssetDumper + { + static void DumpWavPcm(Zone* zone, LoadedSound* asset, FileAPI::File* out); + protected: + bool ShouldDump(LoadedSound* asset) override; + std::string GetFileNameForAsset(Zone* zone, LoadedSound* asset) override; + void DumpAsset(Zone* zone, LoadedSound* asset, FileAPI::File* out) override; + }; +} diff --git a/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp b/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp index 889f3574..473073b3 100644 --- a/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp +++ b/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp @@ -7,6 +7,7 @@ #include "AssetDumpers/AssetDumperStringTable.h" #include "AssetDumpers/AssetDumperLocalizeEntry.h" #include "AssetDumpers/AssetDumperGfxImage.h" +#include "AssetDumpers/AssetDumperLoadedSound.h" using namespace IW4; @@ -38,7 +39,6 @@ bool ZoneDumper::DumpZone(Zone* zone, const std::string& basePath) const DUMP_ASSET_POOL(AssetDumperGfxImage, m_image); // DUMP_ASSET_POOL(AssetDumpersnd_alias_list_t, m_sound); // DUMP_ASSET_POOL(AssetDumperSndCurve, m_sound_curve); - // DUMP_ASSET_POOL(AssetDumperLoadedSound, m_loaded_sound); // DUMP_ASSET_POOL(AssetDumperclipMap_t, m_clip_map); // DUMP_ASSET_POOL(AssetDumperComWorld, m_com_world); // DUMP_ASSET_POOL(AssetDumperGameWorldSp, m_game_world_sp); @@ -62,6 +62,7 @@ bool ZoneDumper::DumpZone(Zone* zone, const std::string& basePath) const // DUMP_ASSET_POOL(AssetDumperTracerDef, m_tracer); // DUMP_ASSET_POOL(AssetDumperVehicleDef, m_vehicle); // DUMP_ASSET_POOL(AssetDumperAddonMapEnts, m_addon_map_ents); + DUMP_ASSET_POOL(AssetDumperLoadedSound, m_loaded_sound) return true; diff --git a/src/Utils/Utils/FileUtils.h b/src/Utils/Utils/FileUtils.h new file mode 100644 index 00000000..1ce5f123 --- /dev/null +++ b/src/Utils/Utils/FileUtils.h @@ -0,0 +1,10 @@ +#pragma once +#include + +constexpr uint32_t MakeMagic32(const char ch0, const char ch1, const char ch2, const char ch3) +{ + return static_cast(ch0) + | static_cast(ch1) << 8 + | static_cast(ch2) << 16 + | static_cast(ch3) << 24; +} diff --git a/src/ZoneCommon/Game/IW4/IW4_Assets.h b/src/ZoneCommon/Game/IW4/IW4_Assets.h index 760d45f7..2c9f97d5 100644 --- a/src/ZoneCommon/Game/IW4/IW4_Assets.h +++ b/src/ZoneCommon/Game/IW4/IW4_Assets.h @@ -876,7 +876,7 @@ namespace IW4 StringTableCell* values; }; - struct _AILSOUNDINFO + struct AILSOUNDINFO { int format; const void* data_ptr; @@ -891,7 +891,7 @@ namespace IW4 struct MssSound { - _AILSOUNDINFO info; + AILSOUNDINFO info; char* data; };