diff --git a/src/Common/Game/T6/CommonT6.h b/src/Common/Game/T6/CommonT6.h index 78ac76f6d..6580ccdf3 100644 --- a/src/Common/Game/T6/CommonT6.h +++ b/src/Common/Game/T6/CommonT6.h @@ -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); diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 410d12d2c..76948153a 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -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; diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp index b72dabfa8..b36a4f3c9 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndBank.cpp @@ -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 #include @@ -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 CreateCurvesMap() + { + std::unordered_map result; + for (auto i = 0u; i < std::extent_v; i++) + result.emplace(T6::Common::SND_HashName(CURVES_ENUM[i].data()), CURVES_ENUM[i]); + return result; + } + + const std::unordered_map 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,14 +305,19 @@ class AssetDumperSndBank::Internal return nullptr; } - static std::unique_ptr OpenAliasOutputFile(const SndBank* sndBank) + static void WriteAliasFileHeader(CsvOutputStream& stream) { - return nullptr; + for (const auto& headerField : ALIAS_HEADERS) + { + stream.WriteColumn(headerField); + } + + stream.NextRow(); } - static void WriteAliasFileHeader(CsvOutputStream& stream) + static void WriteReverbFileHeader(CsvOutputStream& stream) { - for (const auto& headerField : ALIAS_HEADERS) + for (const auto& headerField : REVERB_HEADERS) { stream.WriteColumn(headerField); } @@ -157,7 +325,20 @@ class AssetDumperSndBank::Internal stream.NextRow(); } - static void WriteAliasToFile(CsvOutputStream& stream, const SndAlias* alias) + 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 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{}; + 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* sndBankInfo) const { const auto* sndBank = sndBankInfo->Asset(); DumpSndBankAliases(sndBank); - DumpSoundData(sndBank); + DumpSoundRadverb(sndBank); + DumpSoundDucks(sndBank); } public: diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndDriverGlobals.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndDriverGlobals.cpp new file mode 100644 index 000000000..828854b76 --- /dev/null +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndDriverGlobals.cpp @@ -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 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); + + 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); + + 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); + + 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); + + 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); + + 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); + + 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* 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* pool) + { + for (const auto* assetInfo : *pool) + { + if (!assetInfo->m_name.empty() && assetInfo->m_name[0] == ',') + continue; + + DumpSndDriverGlobals(assetInfo); + } + } +}; + +void AssetDumperSndDriverGlobals::DumpPool(AssetDumpingContext& context, AssetPool* pool) +{ + Internal internal(context); + internal.DumpPool(pool); +} diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndDriverGlobals.h b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndDriverGlobals.h new file mode 100644 index 000000000..18f0cf896 --- /dev/null +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperSndDriverGlobals.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/T6/T6.h" + +namespace T6 +{ + class AssetDumperSndDriverGlobals final : public IAssetDumper + { + class Internal; + + public: + void DumpPool(AssetDumpingContext& context, AssetPool* pool) override; + }; +} // namespace T6 diff --git a/src/ObjWriting/Game/T6/ZoneDumperT6.cpp b/src/ObjWriting/Game/T6/ZoneDumperT6.cpp index c01fe85b5..ffb4113fd 100644 --- a/src/ObjWriting/Game/T6/ZoneDumperT6.cpp +++ b/src/ObjWriting/Game/T6/ZoneDumperT6.cpp @@ -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)