Merge pull request #58 from skiff/main

T6 SndBank & SndDriverGlobals Asset Dumping
This commit is contained in:
Jan 2024-01-01 16:54:16 +01:00 committed by GitHub
commit 383042046e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 1025 additions and 161 deletions

View File

@ -12,6 +12,26 @@ namespace T6
static int Com_HashString(const char* str, int len);
static uint32_t R_HashString(const char* str, uint32_t hash);
static constexpr uint32_t SND_HashName(const char* str)
{
if (!str || !*str)
return 0;
auto result = 0x1505;
auto offset = 0u;
while (str[offset])
{
const auto c = tolower(str[offset++]);
result = c + 0x1003F * result;
}
if (!result)
return 1;
return result;
}
static PackedTexCoords Vec2PackTexCoords(const vec2_t* in);
static PackedUnitVec Vec3PackUnitVec(const vec3_t* in);
static GfxColor Vec4PackGfxColor(const vec4_t* in);

View File

@ -5578,13 +5578,57 @@ namespace T6
MaterialArgumentDef u;
};
enum SndAliasType
enum SndAliasLoopType
{
SAT_UNKNOWN = 0x0,
SAT_LOADED = 0x1,
SAT_STREAMED = 0x2,
SAT_PRIMED = 0x3,
SAT_COUNT = 0x4,
SA_NON_LOOPING = 0x0,
SA_LOOPING = 0x1,
};
enum SndAliasPanType
{
SA_PAN_2D = 0x0,
SA_PAN_3D = 0x1,
};
enum SndAliasLoadType
{
SA_UNKNOWN = 0x0,
SA_LOADED = 0x1,
SA_STREAMED = 0x2,
SA_PRIMED = 0x3,
SA_COUNT = 0x4,
};
struct SndAliasFlags
{
// flags0
unsigned int looping : 1; // 0
unsigned int panType : 1; // 1
unsigned int distanceLpf : 1; // 2
unsigned int doppler : 1; // 3
unsigned int isBig : 1; // 4
unsigned int pauseable : 1; // 5
unsigned int isMusic : 1; // 6
unsigned int stopOnDeath : 1; // 7
unsigned int timescale : 1; // 8
unsigned int voiceLimit : 1; // 9
unsigned int ignoreMaxDist : 1; // 10
unsigned int busType : 4; // 11-14
unsigned int loadType : 2; // 15-16
unsigned int volumeGroup : 5; // 17-21
unsigned int fluxType : 3; // 22-24
unsigned int limitType : 2; // 25-26
unsigned int entityLimitType : 2; // 27-28
unsigned int randomizeType : 3; // 29-31
// flags1
unsigned int neverPlayTwice : 1; // 0
unsigned int unknown1_0 : 1; // 1
unsigned int volumeFalloffCurve : 6; // 2-7
unsigned int reverbFalloffCurve : 6; // 8-13
unsigned int volumeMinFalloffCurve : 6; // 14-19
unsigned int reverbMinFalloffCurve : 6; // 20-25
unsigned int unknown1_1 : 6; // 26-31
};
struct SndAlias
@ -5595,8 +5639,7 @@ namespace T6
const char* secondaryname;
unsigned int assetId;
const char* assetFileName;
unsigned int flags0; // Bits 15/16 are SndAliasType
unsigned int flags1;
SndAliasFlags flags;
unsigned int duck;
unsigned int contextType;
unsigned int contextValue;
@ -5631,6 +5674,10 @@ namespace T6
char duckGroup;
};
#ifndef __zonecodegenerator
static_assert(sizeof(SndAliasFlags) == 8);
#endif
struct type_align(4) pathlink_s
{
float fDist;

View File

@ -1,9 +1,10 @@
#include "AssetDumperSndBank.h"
#include "Csv/CsvStream.h"
#include "Game/T6/CommonT6.h"
#include "ObjContainer/SoundBank/SoundBank.h"
#include "Sound/WavWriter.h"
#include "Utils/ClassUtils.h"
#include "nlohmann/json.hpp"
#include <filesystem>
#include <fstream>
@ -15,69 +16,89 @@ namespace fs = std::filesystem;
namespace
{
const std::string ALIAS_HEADERS[]{
"# name",
"# file",
"# template",
"# loadspec",
"# secondary",
"# group",
"# vol_min",
"# vol_max",
"# team_vol_mod",
"# dist_min",
"# dist_max",
"# dist_reverb_max",
"# volume_falloff_curve",
"# reverb_falloff_curve",
"# volume_min_falloff_curve",
"# reverb_min_falloff_curve",
"# limit_count",
"# limit_type",
"# entity_limit_count",
"# entity_limit_type",
"# pitch_min",
"# pitch_max",
"# team_pitch_mod",
"# min_priority",
"# max_priority",
"# min_priority_threshold",
"# max_priority_threshold",
"# spatialized",
"# type",
"# loop",
"# randomize_type",
"# probability",
"# start_delay",
"# reverb_send",
"# duck",
"# pan",
"# center_send",
"# envelop_min",
"# envelop_max",
"# envelop_percentage",
"# occlusion_level",
"# occlusion_wet_dry",
"# is_big",
"# distance_lpf",
"# move_type",
"# move_time",
"# real_delay",
"# subtitle",
"# mature",
"# doppler",
"# futz",
"# context_type",
"# context_value",
"# compression",
"# timescale",
"# music",
"# fade_in",
"# fade_out",
"# pc_format",
"# pause",
"# stop_on_death",
"# bus",
"# snapshot",
"name",
"file",
"template",
"loadspec",
"secondary",
"group",
"vol_min",
"vol_max",
"team_vol_mod",
"dist_min",
"dist_max",
"dist_reverb_max",
"volume_falloff_curve",
"reverb_falloff_curve",
"volume_min_falloff_curve",
"reverb_min_falloff_curve",
"limit_count",
"limit_type",
"entity_limit_count",
"entity_limit_type",
"pitch_min",
"pitch_max",
"team_pitch_mod",
"min_priority",
"max_priority",
"min_priority_threshold",
"max_priority_threshold",
"spatialized",
"type",
"loop",
"randomize_type",
"probability",
"start_delay",
"reverb_send",
"duck",
"pan",
"center_send",
"envelop_min",
"envelop_max",
"envelop_percentage",
"occlusion_level",
"occlusion_wet_dry",
"is_big",
"distance_lpf",
"move_type",
"move_time",
"real_delay",
"subtitle",
"mature",
"doppler",
"futz",
"context_type",
"context_value",
"compression",
"timescale",
"music",
"fade_in",
"fade_out",
"pc_format",
"pause",
"stop_on_death",
"bus",
"snapshot",
};
const std::string REVERB_HEADERS[]{
"name",
"smoothing",
"earlyTime",
"lateTime",
"earlyGain",
"lateGain",
"returnGain",
"earlyLpf",
"lateLpf",
"inputLpf",
"dampLpf",
"wallReflect",
"dryGain",
"earlySize",
"lateSize",
"diffusion",
"returnHighpass",
};
const std::string PREFIXES_TO_DROP[]{
@ -96,6 +117,148 @@ namespace
96000,
192000,
};
const std::string GROUPS_ENUM[]{
"grp_reference",
"grp_master",
"grp_wpn_lfe",
"grp_lfe",
"grp_hdrfx",
"grp_music",
"grp_voice",
"grp_set_piece",
"grp_igc",
"grp_mp_game",
"grp_explosion",
"grp_player_impacts",
"grp_scripted_moment",
"grp_menu",
"grp_whizby",
"grp_weapon",
"grp_vehicle",
"grp_impacts",
"grp_foley",
"grp_destructible",
"grp_physics",
"grp_ambience",
"grp_alerts",
"grp_air",
"grp_bink",
"grp_announcer",
"",
};
const std::string CURVES_ENUM[]{
"default",
"defaultmin",
"allon",
"alloff",
"rcurve0",
"rcurve1",
"rcurve2",
"rcurve3",
"rcurve4",
"rcurve5",
"steep",
"sindelay",
"cosdelay",
"sin",
"cos",
"rev60",
"rev65",
"",
};
std::unordered_map<unsigned int, std::string> CreateCurvesMap()
{
std::unordered_map<unsigned int, std::string> result;
for (auto i = 0u; i < std::extent_v<decltype(CURVES_ENUM)>; i++)
result.emplace(T6::Common::SND_HashName(CURVES_ENUM[i].data()), CURVES_ENUM[i]);
return result;
}
const std::unordered_map<unsigned int, std::string> CURVES_MAP = CreateCurvesMap();
const std::string DUCK_GROUPS_ENUM[]{
"snp_alerts_gameplay",
"snp_ambience",
"snp_claw",
"snp_destructible",
"snp_dying",
"snp_dying_ice",
"snp_evt_2d",
"snp_explosion",
"snp_foley",
"snp_grenade",
"snp_hdrfx",
"snp_igc",
"snp_impacts",
"snp_menu",
"snp_movie",
"snp_music",
"snp_never_duck",
"snp_player_dead",
"snp_player_impacts",
"snp_scripted_moment",
"snp_set_piece",
"snp_special",
"snp_vehicle",
"snp_vehicle_interior",
"snp_voice",
"snp_weapon_decay_1p",
"snp_whizby",
"snp_wpn_1p",
"snp_wpn_3p",
"snp_wpn_turret",
"snp_x2",
"snp_x3",
};
const std::string LIMIT_TYPES_ENUM[]{
"none",
"oldest",
"reject",
"priority",
};
const std::string MOVE_TYPES_ENUM[]{
"none",
"left_player",
"center_player",
"right_player",
"random",
"left_shot",
"center_shot",
"right_shot",
};
const std::string LOAD_TYPES_ENUM[]{
"unknown",
"loaded",
"streamed",
"primed",
};
const std::string BUS_IDS_ENUM[]{
"bus_reverb",
"bus_fx",
"bus_voice",
"bus_pfutz",
"bus_hdrfx",
"bus_ui",
"bus_reference",
"bus_music",
"bus_movie",
"bus_reference",
"",
};
const std::string RANDOMIZE_TYPES_ENUM[]{
"volume",
"pitch",
"variant",
"",
};
} // namespace
class AssetDumperSndBank::Internal
@ -142,11 +305,6 @@ class AssetDumperSndBank::Internal
return nullptr;
}
static std::unique_ptr<std::ostream> OpenAliasOutputFile(const SndBank* sndBank)
{
return nullptr;
}
static void WriteAliasFileHeader(CsvOutputStream& stream)
{
for (const auto& headerField : ALIAS_HEADERS)
@ -157,7 +315,30 @@ class AssetDumperSndBank::Internal
stream.NextRow();
}
static void WriteAliasToFile(CsvOutputStream& stream, const SndAlias* alias)
static void WriteReverbFileHeader(CsvOutputStream& stream)
{
for (const auto& headerField : REVERB_HEADERS)
{
stream.WriteColumn(headerField);
}
stream.NextRow();
}
static const char* FindNameForDuck(unsigned int id, const SndBank* bank)
{
for (auto i = 0u; i < bank->duckCount; i++)
{
if (id == bank->ducks[i].id)
{
return bank->ducks[i].name;
}
}
return "";
}
static void WriteAliasToFile(CsvOutputStream& stream, const SndAlias* alias, const SndBank* bank)
{
// name
stream.WriteColumn(alias->name);
@ -165,96 +346,188 @@ class AssetDumperSndBank::Internal
// file
stream.WriteColumn(alias->assetFileName);
// "# template",
// template
stream.WriteColumn("");
// loadspec
stream.WriteColumn("");
// "# secondary",
// "# group",
// "# vol_min",
// "# vol_max",
// "# team_vol_mod",
// "# dist_min",
// "# dist_max",
// "# dist_reverb_max",
// "# volume_falloff_curve",
// "# reverb_falloff_curve",
// "# volume_min_falloff_curve",
// "# reverb_min_falloff_curve",
// "# limit_count",
// "# limit_type",
// "# entity_limit_count",
// "# entity_limit_type",
// "# pitch_min",
// "# pitch_max",
// "# team_pitch_mod",
// "# min_priority",
// "# max_priority",
// "# min_priority_threshold",
// "# max_priority_threshold",
// "# spatialized",
// "# type",
// "# loop",
// "# randomize_type",
// "# probability",
// "# start_delay",
// "# reverb_send",
// "# duck",
// "# pan",
// "# center_send",
// "# envelop_min",
// "# envelop_max",
// "# envelop_percentage",
// "# occlusion_level",
// "# occlusion_wet_dry",
// "# is_big",
// "# distance_lpf",
// "# move_type",
// "# move_time",
// "# real_delay",
// "# subtitle",
// "# mature",
// "# doppler",
// "# futz",
// "# context_type",
// "# context_value",
// "# compression",
// "# timescale",
// "# music",
// "# fade_in",
// "# fade_out",
// "# pc_format",
// "# pause",
// "# stop_on_death",
// "# bus",
// "# snapshot",
}
// secondary
stream.WriteColumn((alias->secondaryname && *alias->secondaryname) ? alias->secondaryname : "");
static void DumpSndBankAliases(const SndBank* sndBank)
{
const auto outputFile = OpenAliasOutputFile(sndBank);
// group
stream.WriteColumn(GROUPS_ENUM[alias->flags.volumeGroup]);
if (outputFile == nullptr)
{
std::cout << "Failed to open sound alias output file for: \"" << sndBank->name << "\"" << std::endl;
return;
}
// vol_min
stream.WriteColumn(std::to_string(alias->volMin));
CsvOutputStream csvStream(*outputFile);
WriteAliasFileHeader(csvStream);
// vol_max
stream.WriteColumn(std::to_string(alias->volMax));
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];
WriteAliasToFile(csvStream, &alias);
}
}
// team_vol_mod
stream.WriteColumn("");
// dist_min
stream.WriteColumn(std::to_string(alias->distMin));
// dist_max
stream.WriteColumn(std::to_string(alias->distMax));
// dist_reverb_max
stream.WriteColumn(std::to_string(alias->distReverbMax));
// volume_falloff_curve
stream.WriteColumn(CURVES_ENUM[alias->flags.volumeFalloffCurve]);
// reverb_falloff_curve
stream.WriteColumn(CURVES_ENUM[alias->flags.reverbFalloffCurve]);
// volume_min_falloff_curve
stream.WriteColumn(CURVES_ENUM[alias->flags.volumeMinFalloffCurve]);
// reverb_min_falloff_curve"
stream.WriteColumn(CURVES_ENUM[alias->flags.reverbMinFalloffCurve]);
// limit_count
stream.WriteColumn(std::to_string(alias->limitCount));
// limit_type
stream.WriteColumn(LIMIT_TYPES_ENUM[alias->flags.limitType]);
// entity_limit_count
stream.WriteColumn(std::to_string(alias->entityLimitCount));
// entity_limit_type
stream.WriteColumn(LIMIT_TYPES_ENUM[alias->flags.entityLimitType]);
// pitch_min
stream.WriteColumn(std::to_string(alias->pitchMin));
// pitch_max
stream.WriteColumn(std::to_string(alias->pitchMax));
// team_pitch_mod
stream.WriteColumn("");
// min_priority
stream.WriteColumn(std::to_string(alias->minPriority));
// max_priority
stream.WriteColumn(std::to_string(alias->maxPriority));
// min_priority_threshold
stream.WriteColumn(std::to_string(alias->minPriorityThreshold));
// max_priority_threshold
stream.WriteColumn(std::to_string(alias->maxPriorityThreshold));
// spatialized
stream.WriteColumn("");
// type
stream.WriteColumn(LOAD_TYPES_ENUM[alias->flags.loadType]);
// loop
stream.WriteColumn(alias->flags.looping == T6::SA_NON_LOOPING ? "nonlooping" : "looping");
// randomize_type
stream.WriteColumn(RANDOMIZE_TYPES_ENUM[alias->flags.randomizeType]);
// probability",
stream.WriteColumn(std::to_string(alias->probability));
// start_delay",
stream.WriteColumn(std::to_string(alias->startDelay));
// reverb_send",
stream.WriteColumn(std::to_string(alias->reverbSend));
// duck",
stream.WriteColumn(FindNameForDuck(alias->duck, bank));
// pan",
stream.WriteColumn(alias->flags.panType == SA_PAN_2D ? "2d" : "3d");
// center_send",
stream.WriteColumn(std::to_string(alias->centerSend));
// envelop_min",
stream.WriteColumn(std::to_string(alias->envelopMin));
// envelop_max",
stream.WriteColumn(std::to_string(alias->envelopMax));
// envelop_percentage",
stream.WriteColumn(std::to_string(alias->envelopPercentage));
// occlusion_level",
stream.WriteColumn(std::to_string(alias->occlusionLevel));
// occlusion_wet_dry",
stream.WriteColumn("");
// is_big",
stream.WriteColumn(alias->flags.isBig ? "yes" : "no");
// distance_lpf"
stream.WriteColumn(alias->flags.distanceLpf ? "yes" : "no");
// move_type",
stream.WriteColumn(MOVE_TYPES_ENUM[alias->flags.fluxType]);
// move_time",
stream.WriteColumn(std::to_string(alias->fluxTime));
// real_delay",
stream.WriteColumn("");
// subtitle",
stream.WriteColumn((alias->subtitle && *alias->subtitle) ? alias->subtitle : "");
// mature",
stream.WriteColumn("");
// doppler",
stream.WriteColumn(alias->flags.doppler ? "yes" : "no");
// futz",
stream.WriteColumn(std::to_string(alias->futzPatch));
// context_type",
stream.WriteColumn(std::to_string(alias->contextType));
// context_value",
stream.WriteColumn(std::to_string(alias->contextValue));
// compression",
stream.WriteColumn("");
// timescale",
stream.WriteColumn(alias->flags.timescale ? "yes" : "no");
// music",
stream.WriteColumn(alias->flags.isMusic ? "yes" : "no");
// fade_in",
stream.WriteColumn(std::to_string(alias->fadeIn));
// fade_out",
stream.WriteColumn(std::to_string(alias->fadeOut));
// pc_format",
stream.WriteColumn("");
// pause",
stream.WriteColumn(alias->flags.pauseable ? "yes" : "no");
// stop_on_death",
stream.WriteColumn(alias->flags.stopOnDeath ? "yes" : "no");
// bus",
stream.WriteColumn(BUS_IDS_ENUM[alias->flags.busType]);
// snapshot",
stream.WriteColumn("");
}
static SoundBankEntryInputStream FindSoundDataInSoundBanks(const unsigned assetId)
@ -353,10 +626,20 @@ class AssetDumperSndBank::Internal
}
}
void DumpSoundData(const SndBank* sndBank) const
void DumpSndBankAliases(const SndBank* sndBank) const
{
std::unordered_set<unsigned> dumpedAssets;
const auto outFile = OpenAssetOutputFile("soundbank/" + std::string(sndBank->name) + ".aliases", ".csv");
if (!outFile)
{
std::cerr << "Failed to open sound alias output file: \"" << sndBank->name << "\"\n";
return;
}
CsvOutputStream csvStream(*outFile);
WriteAliasFileHeader(csvStream);
for (auto i = 0u; i < sndBank->aliasCount; i++)
{
const auto& aliasList = sndBank->alias[i];
@ -368,17 +651,130 @@ class AssetDumperSndBank::Internal
{
DumpSndAlias(alias);
dumpedAssets.emplace(alias.assetId);
WriteAliasToFile(csvStream, &alias, sndBank);
csvStream.NextRow();
}
}
}
}
void DumpSoundRadverb(const SndBank* sndBank) const
{
if (sndBank->radverbCount <= 0)
{
return;
}
const auto outFile = OpenAssetOutputFile("soundbank/" + std::string(sndBank->name) + ".reverbs", ".csv");
if (!outFile)
{
std::cerr << "Failed to open sound reverb output file: \"" << sndBank->name << "\"\n";
return;
}
CsvOutputStream csvStream(*outFile);
WriteReverbFileHeader(csvStream);
for (auto i = 0u; i < sndBank->radverbCount; i++)
{
const auto& reverb = sndBank->radverbs[i];
csvStream.WriteColumn(reverb.name);
csvStream.WriteColumn(std::to_string(reverb.smoothing));
csvStream.WriteColumn(std::to_string(reverb.earlyTime));
csvStream.WriteColumn(std::to_string(reverb.lateTime));
csvStream.WriteColumn(std::to_string(reverb.earlyGain));
csvStream.WriteColumn(std::to_string(reverb.lateGain));
csvStream.WriteColumn(std::to_string(reverb.returnGain));
csvStream.WriteColumn(std::to_string(reverb.earlyLpf));
csvStream.WriteColumn(std::to_string(reverb.lateLpf));
csvStream.WriteColumn(std::to_string(reverb.inputLpf));
csvStream.WriteColumn(std::to_string(reverb.dampLpf));
csvStream.WriteColumn(std::to_string(reverb.wallReflect));
csvStream.WriteColumn(std::to_string(reverb.dryGain));
csvStream.WriteColumn(std::to_string(reverb.earlySize));
csvStream.WriteColumn(std::to_string(reverb.lateSize));
csvStream.WriteColumn(std::to_string(reverb.diffusion));
csvStream.WriteColumn(std::to_string(reverb.returnHighpass));
csvStream.NextRow();
}
}
void DumpSoundDucks(const SndBank* sndBank) const
{
if (sndBank->duckCount <= 0)
{
return;
}
const auto outFile = OpenAssetOutputFile("soundbank/" + std::string(sndBank->name) + ".ducklist", ".csv");
if (!outFile)
{
std::cerr << "Failed to open sound reverb output file: \"" << sndBank->name << "\"\n";
return;
}
CsvOutputStream csvStream(*outFile);
csvStream.WriteColumn("name");
csvStream.NextRow();
for (auto i = 0u; i < sndBank->duckCount; i++)
{
const auto& duck = sndBank->ducks[i];
csvStream.WriteColumn(duck.name);
csvStream.NextRow();
const auto duckFile = OpenAssetOutputFile("soundbank/ducks/" + std::string(duck.name), ".duk");
if (!outFile)
{
std::cerr << "Failed to open sound duck output file: \"" << duck.name << "\"\n";
return;
}
nlohmann::json duckObj{};
duckObj["fadeIn"] = duck.fadeIn;
duckObj["fadeOut"] = duck.fadeOut;
duckObj["startDelay"] = duck.startDelay;
duckObj["distance"] = duck.distance;
duckObj["length"] = duck.length;
duckObj["fadeInCurveId"] = duck.fadeInCurve;
duckObj["fadeOutCurveId"] = duck.fadeOutCurve;
duckObj["updateWhilePaused"] = duck.updateWhilePaused;
auto fadeInItr = CURVES_MAP.find(duck.fadeInCurve);
if (fadeInItr != CURVES_MAP.end())
{
duckObj["fadeInCurve"] = fadeInItr->second;
}
auto fadeOutItr = CURVES_MAP.find(duck.fadeOutCurve);
if (fadeOutItr != CURVES_MAP.end())
{
duckObj["fadeOutCurve"] = fadeOutItr->second;
}
auto values = std::vector<nlohmann::json>{};
for (auto i = 0u; i < 32u; i++)
{
values.push_back({
{"duckGroup", DUCK_GROUPS_ENUM[i]},
{"attenuation", duck.attenuation[i]},
{"filter", duck.filter[i] }
});
}
duckObj["values"] = values;
*duckFile << duckObj.dump(4) << std::endl;
}
}
void DumpSndBank(const XAssetInfo<SndBank>* sndBankInfo) const
{
const auto* sndBank = sndBankInfo->Asset();
DumpSndBankAliases(sndBank);
DumpSoundData(sndBank);
DumpSoundRadverb(sndBank);
DumpSoundDucks(sndBank);
}
public:

View File

@ -0,0 +1,385 @@
#include "AssetDumperSndDriverGlobals.h"
#include "Csv/CsvStream.h"
#include "ObjContainer/SoundBank/SoundBank.h"
using namespace T6;
class AssetDumperSndDriverGlobals::Internal
{
AssetDumpingContext& m_context;
inline static const std::string GROUPS_HEADERS[]{
"name",
"attenuationSp",
"attenuationMp",
"category",
"parent",
"id",
};
inline static const std::string GROUPS_CATEGORIES[]{
"sfx",
"music",
"void",
"ui",
"cinematic",
"id",
};
inline static const std::string CURVE_HEADERS[]{
"name",
"x0",
"y0",
"x1",
"y1",
"x2",
"y2",
"x3",
"y3",
"x4",
"y4",
"x5",
"y5",
"x6",
"y6",
"x7",
"y7",
"id",
};
inline static const std::string PAN_HEADERS[]{
"name",
"front",
"back",
"center",
"lfe",
"left",
"right",
"id",
};
inline static const std::string MASTER_HEADERS[]{
"name", "lowE", "lowG", "lowF", "lowQ", "peak1E", "peak1G", "peak1F", "peak1Q", "peak2E", "peak2G",
"peak2F", "peak2Q", "hiE", "hiG", "hiF", "hiQ", "eqG", "compE", "compPG", "compMG", "compT",
"compR", "compTA", "compTR", "limitE", "limitPG", "limitMG", "limitT", "limitR", "limitTA", "limitTR", "busReverbG",
"busFxG", "busVoiceG", "busPfutzG", "busHdrfxG", "busUiG", "busMusicG", "busMovieG", "busVcsG", "busReverbE", "busFxE", "busVoiceE",
"busPfutzE", "busHdrfxE", "busUiE", "busMusicE", "busMovieE", "hdrfxCompE", "voiceEqE", "voiceCompE", "id",
};
inline static const std::string SIDECHAIN_HEADERS[]{
"name",
"g",
"f",
"q",
"ta",
"tr",
"tf",
"id",
};
inline static const std::string FUTZ_HEADERS[]{
"name",
"bpfF",
"bpfQ",
"lsG",
"lsF",
"lsQ",
"dist",
"preG",
"postG",
"th",
"tg",
"clippre",
"clippost",
"blend",
"startAliasId",
"stopAliasId",
"loopAliasId",
"id",
};
std::unique_ptr<std::ostream> OpenAssetFile(const std::string& filename)
{
auto outputFile = this->m_context.OpenAssetFile(filename);
if (outputFile == nullptr)
{
std::cout << "Failed to open sound driver globals output file for: \"" << filename << "\"" << std::endl;
}
return outputFile;
}
static void WriteFileHeader(CsvOutputStream& stream, const std::string* headers, size_t count)
{
for (auto i = 0u; i < count; i++)
{
stream.WriteColumn(headers[i]);
}
stream.NextRow();
}
void DumpSndVolumesGroups(const SndVolumeGroup* groups, const size_t count)
{
const auto outputFile = this->OpenAssetFile("soundbank/globals/group.csv");
if (outputFile != nullptr)
{
CsvOutputStream csvStream(*outputFile);
WriteFileHeader(csvStream, GROUPS_HEADERS, std::extent_v<decltype(GROUPS_HEADERS)>);
for (auto i = 0u; i < count; i++)
{
const auto& group = groups[i];
csvStream.WriteColumn(group.name);
csvStream.WriteColumn(std::to_string(group.attenuationSp));
csvStream.WriteColumn(std::to_string(group.attenuationMp));
csvStream.WriteColumn(GROUPS_CATEGORIES[group.category]);
csvStream.WriteColumn(group.parentName);
csvStream.WriteColumn(std::to_string(group.id));
csvStream.NextRow();
}
}
}
void DumpSndCurves(const SndCurve* curves, const size_t count)
{
const auto outputFile = this->OpenAssetFile("soundbank/globals/curves.csv");
if (outputFile != nullptr)
{
CsvOutputStream csvStream(*outputFile);
WriteFileHeader(csvStream, CURVE_HEADERS, std::extent_v<decltype(CURVE_HEADERS)>);
for (auto i = 0u; i < count; i++)
{
const auto& curve = curves[i];
csvStream.WriteColumn(curve.name);
for (auto j = 0u; j < 8; j++)
{
csvStream.WriteColumn(std::to_string(curve.points[j].x));
csvStream.WriteColumn(std::to_string(curve.points[j].y));
}
csvStream.WriteColumn(std::to_string(curve.id));
csvStream.NextRow();
}
}
}
void DumpSndPans(const SndPan* pans, const size_t count)
{
const auto outputFile = this->OpenAssetFile("soundbank/globals/pan.csv");
if (outputFile != nullptr)
{
CsvOutputStream csvStream(*outputFile);
WriteFileHeader(csvStream, PAN_HEADERS, std::extent_v<decltype(PAN_HEADERS)>);
for (auto i = 0u; i < count; i++)
{
const auto& pan = pans[i];
csvStream.WriteColumn(pan.name);
csvStream.WriteColumn(std::to_string(pan.front));
csvStream.WriteColumn(std::to_string(pan.back));
csvStream.WriteColumn(std::to_string(pan.center));
csvStream.WriteColumn(std::to_string(pan.lfe));
csvStream.WriteColumn(std::to_string(pan.left));
csvStream.WriteColumn(std::to_string(pan.right));
csvStream.WriteColumn(std::to_string(pan.id));
csvStream.NextRow();
}
}
}
void DumpSndDuckGroups(const SndDuckGroup* duckGroups, const size_t count)
{
const auto outputFile = this->OpenAssetFile("soundbank/globals/duck_groups.csv");
if (outputFile != nullptr)
{
CsvOutputStream csvStream(*outputFile);
csvStream.WriteColumn("name");
csvStream.WriteColumn("id");
csvStream.NextRow();
for (auto i = 0u; i < count; i++)
{
const auto& duckGroup = duckGroups[i];
csvStream.WriteColumn(duckGroup.name);
csvStream.WriteColumn(std::to_string(duckGroup.id));
csvStream.NextRow();
}
}
}
void DumpSndMasters(const SndMaster* masters, const size_t count)
{
const auto outputFile = this->OpenAssetFile("soundbank/globals/master.csv");
if (outputFile != nullptr)
{
CsvOutputStream csvStream(*outputFile);
WriteFileHeader(csvStream, MASTER_HEADERS, std::extent_v<decltype(MASTER_HEADERS)>);
for (auto i = 0u; i < count; i++)
{
const auto& master = masters[i];
csvStream.WriteColumn(master.name);
csvStream.WriteColumn(std::to_string(master.lowE));
csvStream.WriteColumn(std::to_string(master.lowG));
csvStream.WriteColumn(std::to_string(master.lowF));
csvStream.WriteColumn(std::to_string(master.lowQ));
csvStream.WriteColumn(std::to_string(master.peak1E));
csvStream.WriteColumn(std::to_string(master.peak1G));
csvStream.WriteColumn(std::to_string(master.peak1F));
csvStream.WriteColumn(std::to_string(master.peak1Q));
csvStream.WriteColumn(std::to_string(master.peak2E));
csvStream.WriteColumn(std::to_string(master.peak2G));
csvStream.WriteColumn(std::to_string(master.peak2F));
csvStream.WriteColumn(std::to_string(master.peak2Q));
csvStream.WriteColumn(std::to_string(master.hiE));
csvStream.WriteColumn(std::to_string(master.hiG));
csvStream.WriteColumn(std::to_string(master.hiF));
csvStream.WriteColumn(std::to_string(master.hiQ));
csvStream.WriteColumn(std::to_string(master.eqG));
csvStream.WriteColumn(std::to_string(master.compE));
csvStream.WriteColumn(std::to_string(master.compPG));
csvStream.WriteColumn(std::to_string(master.compMG));
csvStream.WriteColumn(std::to_string(master.compT));
csvStream.WriteColumn(std::to_string(master.compR));
csvStream.WriteColumn(std::to_string(master.compTA));
csvStream.WriteColumn(std::to_string(master.compTR));
csvStream.WriteColumn(std::to_string(master.limitE));
csvStream.WriteColumn(std::to_string(master.limitPG));
csvStream.WriteColumn(std::to_string(master.limitMG));
csvStream.WriteColumn(std::to_string(master.limitT));
csvStream.WriteColumn(std::to_string(master.limitR));
csvStream.WriteColumn(std::to_string(master.limitTA));
csvStream.WriteColumn(std::to_string(master.limitTR));
csvStream.WriteColumn(std::to_string(master.busReverbG));
csvStream.WriteColumn(std::to_string(master.busFxG));
csvStream.WriteColumn(std::to_string(master.busVoiceG));
csvStream.WriteColumn(std::to_string(master.busPfutzG));
csvStream.WriteColumn(std::to_string(master.busHdrfxG));
csvStream.WriteColumn(std::to_string(master.busUiG));
csvStream.WriteColumn(std::to_string(master.busMusicG));
csvStream.WriteColumn(std::to_string(master.busMovieG));
csvStream.WriteColumn(std::to_string(master.busVcsG));
csvStream.WriteColumn(std::to_string(master.busReverbE));
csvStream.WriteColumn(std::to_string(master.busFxE));
csvStream.WriteColumn(std::to_string(master.busVoiceE));
csvStream.WriteColumn(std::to_string(master.busPfutzE));
csvStream.WriteColumn(std::to_string(master.busHdrfxE));
csvStream.WriteColumn(std::to_string(master.busUiE));
csvStream.WriteColumn(std::to_string(master.busMusicE));
csvStream.WriteColumn(std::to_string(master.busMovieE));
csvStream.WriteColumn(std::to_string(master.hdrfxCompE));
csvStream.WriteColumn(std::to_string(master.voiceEqE));
csvStream.WriteColumn(std::to_string(master.voiceCompE));
csvStream.WriteColumn(std::to_string(master.id));
csvStream.NextRow();
}
}
}
void DumpSndSidechainDucks(const SndSidechainDuck* sidechains, const size_t count)
{
const auto outputFile = this->OpenAssetFile("soundbank/globals/sidechain_duck.csv");
if (outputFile != nullptr)
{
CsvOutputStream csvStream(*outputFile);
WriteFileHeader(csvStream, SIDECHAIN_HEADERS, std::extent_v<decltype(SIDECHAIN_HEADERS)>);
for (auto i = 0u; i < count; i++)
{
const auto& sidechain = sidechains[i];
csvStream.WriteColumn(sidechain.name);
csvStream.WriteColumn(std::to_string(sidechain.g));
csvStream.WriteColumn(std::to_string(sidechain.f));
csvStream.WriteColumn(std::to_string(sidechain.q));
csvStream.WriteColumn(std::to_string(sidechain.ta));
csvStream.WriteColumn(std::to_string(sidechain.tr));
csvStream.WriteColumn(std::to_string(sidechain.tf));
csvStream.WriteColumn(std::to_string(sidechain.id));
csvStream.NextRow();
}
}
}
void DumpSndFutz(const SndFutz* futzes, const size_t count)
{
const auto outputFile = this->OpenAssetFile("soundbank/globals/futz.csv");
if (outputFile != nullptr)
{
CsvOutputStream csvStream(*outputFile);
WriteFileHeader(csvStream, FUTZ_HEADERS, std::extent_v<decltype(FUTZ_HEADERS)>);
for (auto i = 0u; i < count; i++)
{
const auto& futz = futzes[i];
csvStream.WriteColumn(futz.name);
csvStream.WriteColumn(std::to_string(futz.bpfF));
csvStream.WriteColumn(std::to_string(futz.bpfQ));
csvStream.WriteColumn(std::to_string(futz.lsG));
csvStream.WriteColumn(std::to_string(futz.lsF));
csvStream.WriteColumn(std::to_string(futz.lsQ));
csvStream.WriteColumn(std::to_string(futz.dist));
csvStream.WriteColumn(std::to_string(futz.preG));
csvStream.WriteColumn(std::to_string(futz.postG));
csvStream.WriteColumn(std::to_string(futz.th));
csvStream.WriteColumn(std::to_string(futz.tg));
csvStream.WriteColumn(std::to_string(futz.clippre));
csvStream.WriteColumn(std::to_string(futz.clippost));
csvStream.WriteColumn(std::to_string(futz.blend));
csvStream.WriteColumn(std::to_string(futz.startAliasId));
csvStream.WriteColumn(std::to_string(futz.stopAliasId));
csvStream.WriteColumn(std::to_string(futz.loopAliasId));
csvStream.WriteColumn(std::to_string(futz.id));
csvStream.NextRow();
}
}
}
void DumpSndDriverGlobals(const XAssetInfo<SndDriverGlobals>* sndDriverGlobalsInfo)
{
const auto* sndDriverGlobals = sndDriverGlobalsInfo->Asset();
DumpSndVolumesGroups(sndDriverGlobals->groups, sndDriverGlobals->groupCount);
DumpSndCurves(sndDriverGlobals->curves, sndDriverGlobals->curveCount);
DumpSndPans(sndDriverGlobals->pans, sndDriverGlobals->panCount);
DumpSndDuckGroups(sndDriverGlobals->duckGroups, sndDriverGlobals->duckGroupCount);
// DumpSndContexts(sndDriverGlobals->contexts, sndDriverGlobals->contextCount);
DumpSndMasters(sndDriverGlobals->masters, sndDriverGlobals->masterCount);
DumpSndSidechainDucks(sndDriverGlobals->voiceDucks, sndDriverGlobals->voiceDuckCount);
DumpSndFutz(sndDriverGlobals->futzes, sndDriverGlobals->futzCount);
}
public:
explicit Internal(AssetDumpingContext& context)
: m_context(context)
{
}
void DumpPool(AssetPool<SndDriverGlobals>* pool)
{
for (const auto* assetInfo : *pool)
{
if (!assetInfo->m_name.empty() && assetInfo->m_name[0] == ',')
continue;
DumpSndDriverGlobals(assetInfo);
}
}
};
void AssetDumperSndDriverGlobals::DumpPool(AssetDumpingContext& context, AssetPool<SndDriverGlobals>* pool)
{
Internal internal(context);
internal.DumpPool(pool);
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include "Game/T6/T6.h"
namespace T6
{
class AssetDumperSndDriverGlobals final : public IAssetDumper<SndDriverGlobals>
{
class Internal;
public:
void DumpPool(AssetDumpingContext& context, AssetPool<SndDriverGlobals>* pool) override;
};
} // namespace T6

View File

@ -10,6 +10,7 @@
#include "AssetDumpers/AssetDumperScriptParseTree.h"
#include "AssetDumpers/AssetDumperSlug.h"
#include "AssetDumpers/AssetDumperSndBank.h"
#include "AssetDumpers/AssetDumperSndDriverGlobals.h"
#include "AssetDumpers/AssetDumperStringTable.h"
#include "AssetDumpers/AssetDumperTracer.h"
#include "AssetDumpers/AssetDumperVehicle.h"
@ -66,7 +67,7 @@ bool ZoneDumper::DumpZone(AssetDumpingContext& context) const
DUMP_ASSET_POOL(AssetDumperWeaponAttachment, m_attachment, ASSET_TYPE_ATTACHMENT)
DUMP_ASSET_POOL(AssetDumperWeaponAttachmentUnique, m_attachment_unique, ASSET_TYPE_ATTACHMENT_UNIQUE)
// DUMP_ASSET_POOL(AssetDumperWeaponCamo, m_camo, ASSET_TYPE_WEAPON_CAMO)
// DUMP_ASSET_POOL(AssetDumperSndDriverGlobals, m_snd_driver_globals, ASSET_TYPE_SNDDRIVER_GLOBALS)
DUMP_ASSET_POOL(AssetDumperSndDriverGlobals, m_snd_driver_globals, ASSET_TYPE_SNDDRIVER_GLOBALS)
// DUMP_ASSET_POOL(AssetDumperFxEffectDef, m_fx, ASSET_TYPE_FX)
// DUMP_ASSET_POOL(AssetDumperFxImpactTable, m_fx_impact_table, ASSET_TYPE_IMPACT_FX)
DUMP_ASSET_POOL(AssetDumperRawFile, m_raw_file, ASSET_TYPE_RAWFILE)