Dump soundbank data without having to dump aliases

This commit is contained in:
Jan 2023-10-25 21:44:07 +02:00
parent 4ac04dc866
commit 8c2bb09b28

View File

@ -2,7 +2,7 @@
#include <fstream> #include <fstream>
#include <filesystem> #include <filesystem>
#include <unordered_map> #include <unordered_set>
#include "Utils/ClassUtils.h" #include "Utils/ClassUtils.h"
#include "Csv/CsvStream.h" #include "Csv/CsvStream.h"
@ -11,9 +11,9 @@
using namespace T6; using namespace T6;
namespace fs = std::filesystem; namespace fs = std::filesystem;
class AssetDumperSndBank::Internal namespace
{ {
inline static const std::string ALIAS_HEADERS[] const std::string ALIAS_HEADERS[]
{ {
"# name", "# name",
"# file", "# file",
@ -80,66 +80,41 @@ class AssetDumperSndBank::Internal
"# snapshot", "# snapshot",
}; };
const std::string PREFIXES_TO_DROP[]
{
"raw/",
"devraw/",
};
}
class AssetDumperSndBank::Internal
{
AssetDumpingContext& m_context; AssetDumpingContext& m_context;
static std::string GetExtensionForFormat(const snd_asset_format format) _NODISCARD std::string GetAssetFilename(std::string outputFileName, const std::string& extension) const
{
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();
}
}
_NODISCARD std::string GetAssetFilename(const std::string& outputFileName, const SoundAssetBankEntry& entry) const
{ {
fs::path assetPath(m_context.m_base_path); fs::path assetPath(m_context.m_base_path);
fs::path assetName(outputFileName); std::replace(outputFileName.begin(), outputFileName.end(), '\\', '/');
auto firstPart = true; for (const auto& droppedPrefix : PREFIXES_TO_DROP)
for (const auto& part : assetName)
{ {
if (firstPart) if (outputFileName.rfind(droppedPrefix, 0) != std::string::npos)
{ {
firstPart = false; outputFileName.erase(0, droppedPrefix.size());
if (part.string() == "raw" break;
|| part.string() == "devraw")
continue;
} }
assetPath.append(part.string());
} }
const auto extension = GetExtensionForFormat(static_cast<snd_asset_format>(entry.format)); assetPath.append(outputFileName);
if (!extension.empty()) if (!extension.empty())
assetPath.concat(extension); assetPath.concat(extension);
return assetPath.string(); return assetPath.string();
} }
_NODISCARD std::unique_ptr<std::ostream> OpenAssetOutputFile(const std::string& outputFileName, const SoundAssetBankEntry& entry) const _NODISCARD std::unique_ptr<std::ostream> OpenAssetOutputFile(const std::string& outputFileName, const std::string& extension) const
{ {
fs::path assetPath(GetAssetFilename(outputFileName, entry)); fs::path assetPath(GetAssetFilename(outputFileName, extension));
auto assetDir(assetPath); auto assetDir(assetPath);
assetDir.remove_filename(); assetDir.remove_filename();
@ -156,7 +131,7 @@ class AssetDumperSndBank::Internal
return nullptr; return nullptr;
} }
std::unique_ptr<std::ostream> OpenAliasOutputFile(const SndBank* sndBank) const static std::unique_ptr<std::ostream> OpenAliasOutputFile(const SndBank* sndBank)
{ {
return nullptr; return nullptr;
} }
@ -171,7 +146,7 @@ class AssetDumperSndBank::Internal
stream.NextRow(); stream.NextRow();
} }
void WriteAliasToFile(CsvOutputStream& stream, const SndAlias* alias) static void WriteAliasToFile(CsvOutputStream& stream, const SndAlias* alias)
{ {
// name // name
stream.WriteColumn(alias->name); stream.WriteColumn(alias->name);
@ -247,7 +222,7 @@ class AssetDumperSndBank::Internal
// "# snapshot", // "# snapshot",
} }
void DumpSndBankAliases(const SndBank* sndBank, std::unordered_map<unsigned, std::string>& aliasFiles) static void DumpSndBankAliases(const SndBank* sndBank)
{ {
const auto outputFile = OpenAliasOutputFile(sndBank); const auto outputFile = OpenAliasOutputFile(sndBank);
@ -267,57 +242,106 @@ class AssetDumperSndBank::Internal
{ {
const auto& alias = aliasList.head[j]; const auto& alias = aliasList.head[j];
WriteAliasToFile(csvStream, &alias); WriteAliasToFile(csvStream, &alias);
if (alias.assetId && alias.assetFileName)
aliasFiles[alias.assetId] = alias.assetFileName;
} }
} }
} }
void DumpSoundData(std::unordered_map<unsigned, std::string>& aliasFiles) const static SoundBankEntryInputStream FindSoundDataInSoundBanks(const unsigned assetId)
{ {
for (const auto& [id, filename] : aliasFiles) for (const auto* soundBank : SoundBank::Repository)
{ {
auto foundEntry = false; auto soundFile = soundBank->GetEntryStream(assetId);
if (soundFile.IsOpen())
return soundFile;
}
for (const auto* soundBank : SoundBank::Repository) return {};
}
void DumpSoundFilePassthrough(const char* assetFileName, const SoundBankEntryInputStream& soundFile, const std::string& extension) const
{
const auto outFile = OpenAssetOutputFile(assetFileName, extension);
if (!outFile)
{
std::cerr << "Failed to open sound output file: \"" << assetFileName << "\"\n";
return;
}
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 DumpSndAlias(const SndAlias& alias) const
{
const auto soundFile = FindSoundDataInSoundBanks(alias.assetId);
if (soundFile.IsOpen())
{
const auto format = static_cast<snd_asset_format>(soundFile.m_entry.format);
switch (format)
{ {
auto soundFile = soundBank->GetEntryStream(id); case SND_ASSET_FORMAT_MP3:
if (soundFile.IsOpen()) DumpSoundFilePassthrough(alias.assetFileName, soundFile, ".mp3");
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:
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::cerr << "Cannot dump sound (Unsupported sound format " << format << "): \"" << alias.assetFileName << "\"\n";
break;
default:
assert(false);
std::cerr << "Cannot dump sound (Unknown sound format " << format << "): \"" << alias.assetFileName << "\"\n";
break;
}
}
else
{
std::cerr << "Could not find data for sound \"" << alias.assetFileName << "\"\n";
}
}
void DumpSoundData(const SndBank* sndBank) const
{
std::unordered_set<unsigned> dumpedAssets;
for (auto i = 0u; i < sndBank->aliasCount; i++)
{
const auto& aliasList = sndBank->alias[i];
for (auto j = 0; j < aliasList.count; j++)
{
const auto& alias = aliasList.head[j];
if (alias.assetId && alias.assetFileName && dumpedAssets.find(alias.assetId) == dumpedAssets.end())
{ {
auto outFile = OpenAssetOutputFile(filename, soundFile.m_entry); DumpSndAlias(alias);
if (!outFile) dumpedAssets.emplace(alias.assetId);
{
std::cout << "Failed to open sound outputfile: \"" << filename << "\"" << std::endl;
break;
}
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);
}
foundEntry = true;
break;
} }
} }
if (!foundEntry)
{
std::cout << "Could not find data for sound \"" << filename << "\"" << std::endl;
}
} }
} }
void DumpSndBank(const XAssetInfo<SndBank>* sndBankInfo) void DumpSndBank(const XAssetInfo<SndBank>* sndBankInfo) const
{ {
const auto* sndBank = sndBankInfo->Asset(); const auto* sndBank = sndBankInfo->Asset();
std::unordered_map<unsigned int, std::string> aliasMappings; DumpSndBankAliases(sndBank);
DumpSndBankAliases(sndBank, aliasMappings); DumpSoundData(sndBank);
DumpSoundData(aliasMappings);
} }
public: public:
@ -326,7 +350,7 @@ public:
{ {
} }
void DumpPool(AssetPool<SndBank>* pool) void DumpPool(AssetPool<SndBank>* pool) const
{ {
for (const auto* assetInfo : *pool) for (const auto* assetInfo : *pool)
{ {
@ -340,6 +364,6 @@ public:
void AssetDumperSndBank::DumpPool(AssetDumpingContext& context, AssetPool<SndBank>* pool) void AssetDumperSndBank::DumpPool(AssetDumpingContext& context, AssetPool<SndBank>* pool)
{ {
Internal internal(context); const Internal internal(context);
internal.DumpPool(pool); internal.DumpPool(pool);
} }