Skip to content

Commit

Permalink
Dump T6 sound PCM data as wav
Browse files Browse the repository at this point in the history
  • Loading branch information
Laupetin committed Oct 26, 2023
1 parent 8c2bb09 commit 51899d4
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 41 deletions.
8 changes: 4 additions & 4 deletions src/ObjLoading/ObjContainer/SoundBank/SoundBankTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ struct SoundAssetBankEntry
unsigned int size;
unsigned int offset;
unsigned int frameCount;
char frameRateIndex;
char channelCount;
char looping;
char format;
unsigned char frameRateIndex;
unsigned char channelCount;
unsigned char looping;
unsigned char format;
};
42 changes: 8 additions & 34 deletions src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperLoadedSound.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "AssetDumperLoadedSound.h"

#include "Sound/WavTypes.h"
#include "Sound/WavWriter.h"

using namespace IW4;

Expand All @@ -11,43 +12,16 @@ bool AssetDumperLoadedSound::ShouldDump(XAssetInfo<LoadedSound>* asset)

void AssetDumperLoadedSound::DumpWavPcm(AssetDumpingContext& context, const LoadedSound* asset, std::ostream& stream)
{
const auto 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);
const WavWriter writer(stream);

stream.write(reinterpret_cast<const char*>(&WAV_CHUNK_ID_RIFF), sizeof(WAV_CHUNK_ID_RIFF));
stream.write(reinterpret_cast<const char*>(&riffMasterChunkSize), sizeof(riffMasterChunkSize));
stream.write(reinterpret_cast<const char*>(&WAV_WAVE_ID), sizeof(WAV_WAVE_ID));

const WavChunkHeader formatChunkHeader
{
WAV_CHUNK_ID_FMT,
sizeof(WavFormatChunkPcm)
const WavMetaData metaData{
static_cast<unsigned>(asset->sound.info.channels),
static_cast<unsigned>(asset->sound.info.rate),
static_cast<unsigned>(asset->sound.info.bits)
};
stream.write(reinterpret_cast<const char*>(&formatChunkHeader), sizeof(formatChunkHeader));

WavFormatChunkPcm formatChunk
{
WavFormat::PCM,
static_cast<uint16_t>(asset->sound.info.channels),
asset->sound.info.rate,
asset->sound.info.rate * asset->sound.info.channels * asset->sound.info.bits / 8,
static_cast<uint16_t>(asset->sound.info.block_size),
static_cast<uint16_t>(asset->sound.info.bits)
};
stream.write(reinterpret_cast<const char*>(&formatChunk), sizeof(formatChunk));

const WavChunkHeader dataChunkHeader
{
WAV_CHUNK_ID_DATA,
asset->sound.info.data_len
};
stream.write(reinterpret_cast<const char*>(&dataChunkHeader), sizeof(dataChunkHeader));
stream.write(asset->sound.data, asset->sound.info.data_len);
writer.WritePcmHeader(metaData, asset->sound.info.data_len);
writer.WritePcmData(asset->sound.data, asset->sound.info.data_len);
}

void AssetDumperLoadedSound::DumpAsset(AssetDumpingContext& context, XAssetInfo<LoadedSound>* asset)
Expand Down
50 changes: 47 additions & 3 deletions src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "Utils/ClassUtils.h"
#include "Csv/CsvStream.h"
#include "ObjContainer/SoundBank/SoundBank.h"
#include "Sound/WavWriter.h"

using namespace T6;
namespace fs = std::filesystem;
Expand Down Expand Up @@ -85,6 +86,19 @@ namespace
"raw/",
"devraw/",
};

constexpr size_t FRAME_RATE_FOR_INDEX[]
{
8000,
12000,
16000,
24000,
32000,
44100,
48000,
96000,
192000
};
}

class AssetDumperSndBank::Internal
Expand Down Expand Up @@ -258,6 +272,37 @@ class AssetDumperSndBank::Internal
return {};
}

void DumpSoundFilePcm(const char* assetFileName, const SoundBankEntryInputStream& soundFile, const unsigned bitsPerSample) const
{
const auto outFile = OpenAssetOutputFile(assetFileName, ".wav");
if (!outFile)
{
std::cerr << "Failed to open sound output file: \"" << assetFileName << "\"\n";
return;
}

const WavWriter writer(*outFile);

if (soundFile.m_entry.frameRateIndex >= std::extent_v<decltype(FRAME_RATE_FOR_INDEX)>)
return;

const WavMetaData metaData{
soundFile.m_entry.channelCount,
FRAME_RATE_FOR_INDEX[soundFile.m_entry.frameRateIndex],
bitsPerSample
};

writer.WritePcmHeader(metaData, soundFile.m_entry.size);

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);
}
}

void DumpSoundFilePassthrough(const char* assetFileName, const SoundBankEntryInputStream& soundFile, const std::string& extension) const
{
const auto outFile = OpenAssetOutputFile(assetFileName, extension);
Expand All @@ -284,15 +329,14 @@ class AssetDumperSndBank::Internal
const auto format = static_cast<snd_asset_format>(soundFile.m_entry.format);
switch (format)
{
case SND_ASSET_FORMAT_MP3:
DumpSoundFilePassthrough(alias.assetFileName, soundFile, ".mp3");
case SND_ASSET_FORMAT_PCMS16:
DumpSoundFilePcm(alias.assetFileName, soundFile, 16u);
break;

case SND_ASSET_FORMAT_FLAC:
DumpSoundFilePassthrough(alias.assetFileName, soundFile, ".flac");
break;

case SND_ASSET_FORMAT_PCMS16:
case SND_ASSET_FORMAT_PCMS24:
case SND_ASSET_FORMAT_PCMS32:
case SND_ASSET_FORMAT_IEEE:
Expand Down
53 changes: 53 additions & 0 deletions src/ObjWriting/Sound/WavWriter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include "WavWriter.h"

#include "Sound/WavTypes.h"

WavWriter::WavWriter(std::ostream& stream)
: m_stream(stream)
{
}

void WavWriter::WritePcmHeader(const WavMetaData& metaData, const size_t dataLen) const
{
constexpr auto riffMasterChunkSize = sizeof(WAV_CHUNK_ID_RIFF)
+ sizeof(uint32_t)
+ sizeof(WAV_WAVE_ID)
+ sizeof(WavChunkHeader)
+ sizeof(WavFormatChunkPcm)
+ sizeof(WavChunkHeader)
+ sizeof(dataLen);

m_stream.write(reinterpret_cast<const char*>(&WAV_CHUNK_ID_RIFF), sizeof(WAV_CHUNK_ID_RIFF));
m_stream.write(reinterpret_cast<const char*>(&riffMasterChunkSize), sizeof(riffMasterChunkSize));
m_stream.write(reinterpret_cast<const char*>(&WAV_WAVE_ID), sizeof(WAV_WAVE_ID));

constexpr WavChunkHeader formatChunkHeader
{
WAV_CHUNK_ID_FMT,
sizeof(WavFormatChunkPcm)
};
m_stream.write(reinterpret_cast<const char*>(&formatChunkHeader), sizeof(formatChunkHeader));

const WavFormatChunkPcm formatChunk
{
WavFormat::PCM,
static_cast<uint16_t>(metaData.channelCount),
metaData.samplesPerSec,
metaData.samplesPerSec * metaData.channelCount * metaData.bitsPerSample / 8,
static_cast<uint16_t>(metaData.channelCount * (metaData.bitsPerSample / 8)),
static_cast<uint16_t>(metaData.bitsPerSample)
};
m_stream.write(reinterpret_cast<const char*>(&formatChunk), sizeof(formatChunk));

const WavChunkHeader dataChunkHeader
{
WAV_CHUNK_ID_DATA,
dataLen
};
m_stream.write(reinterpret_cast<const char*>(&dataChunkHeader), sizeof(dataChunkHeader));
}

void WavWriter::WritePcmData(const void* data, const size_t dataLen) const
{
m_stream.write(static_cast<const char*>(data), dataLen);
}
21 changes: 21 additions & 0 deletions src/ObjWriting/Sound/WavWriter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once
#include <ostream>

struct WavMetaData
{
unsigned channelCount;
unsigned samplesPerSec;
unsigned bitsPerSample;
};

class WavWriter
{
public:
explicit WavWriter(std::ostream& stream);

void WritePcmHeader(const WavMetaData& metaData, size_t dataLen) const;
void WritePcmData(const void* data, size_t dataLen) const;

private:
std::ostream& m_stream;
};

0 comments on commit 51899d4

Please sign in to comment.