feat(pipeline): add WSND (Wowee Sound Catalog) format

Novel open replacement for Blizzard's SoundEntries.dbc +
SoundEntriesAdvanced.dbc. The 10th open format added to the
editor — covers the audio-metadata gap (the previous 9 cover
geometry, terrain, atmosphere, and world manifests, but no
sound metadata).

Format:
  • magic "WSND", version 1, little-endian
  • catalogName + entry count
  • per entry: soundId / kind / flags / volume /
    minDistance / maxDistance / filePath / label

Kind enum (7 categories):
  sfx, music, ambient, ui, voice, spell, combat

Flags packed (3 bits used, rest reserved):
  loop (0x01), 3d (0x02), stream (0x04)

API: WoweeSoundLoader::save / load / exists; presets
makeStarter (one entry per kind), makeAmbient (wilderness
loops + footsteps), makeTavern (fire + crowd + drink + door
+ lute).

CLI added (5 flags, 465 documented total now):
  --gen-sound-catalog <base> [name]
  --gen-sound-catalog-ambient <base> [name]
  --gen-sound-catalog-tavern <base> [name]
  --info-wsnd <base> [--json]
  --validate-wsnd <base> [--json]

Validator catches: out-of-range kind, NaN/inf volume or
distances, 3D sounds with bad min/max, duplicate sound IDs,
empty filePaths.

All 3 presets verified: save / load / validate clean
on first run. Variable-length string fields use length-
prefixed encoding with a 1 MiB sanity cap on read to
prevent corrupted-file allocation blowups.
This commit is contained in:
Kelsi 2026-05-09 14:47:16 -07:00
parent 13312096ea
commit 36d63d8dd0
8 changed files with 566 additions and 0 deletions

View file

@ -835,6 +835,16 @@ void printUsage(const char* argv0) {
std::printf(" Export binary .womx to a human-editable JSON sidecar (rows of '1'/'0' strings, easy to hand-edit)\n");
std::printf(" --import-womx-json <json-path> [out-base]\n");
std::printf(" Import a .womx.json sidecar back into binary .womx (round-trip with --export-womx-json)\n");
std::printf(" --gen-sound-catalog <wsnd-base> [name]\n");
std::printf(" Emit .wsnd starter catalog (one entry per kind: sfx/music/ambient/ui/voice/spell/combat)\n");
std::printf(" --gen-sound-catalog-ambient <wsnd-base> [name]\n");
std::printf(" Emit .wsnd wilderness catalog: looped birds + wind + 3 footstep variants\n");
std::printf(" --gen-sound-catalog-tavern <wsnd-base> [name]\n");
std::printf(" Emit .wsnd tavern catalog: fire-crackle + crowd murmur + drink-clink + door-creak + lute music\n");
std::printf(" --info-wsnd <wsnd-base> [--json]\n");
std::printf(" Print WSND catalog entries (id / kind / flags / volume / 3D distances / file path / label)\n");
std::printf(" --validate-wsnd <wsnd-base> [--json]\n");
std::printf(" Static checks: kind in 0..6, finite distances, 3D needs max>min>=0, no duplicate sound IDs\n");
std::printf(" --gen-weather-temperate <wow-base> [zoneName]\n");
std::printf(" Emit .wow weather schedule: clear-dominant + occasional rain + fog (forest / grassland)\n");
std::printf(" --gen-weather-arctic <wow-base> [zoneName]\n");