List and edit in-memory sounds in soundbanks

This commit is contained in:
2026-10-09 20:12:10 +02:00
parent 61bbf26f3b
commit 5d6c2447f7
36 changed files with 71568 additions and 54823 deletions

View File

@@ -55,8 +55,29 @@ loopback); it is a developer tool and not part of the editor.
Speech/ambience variations are addressed by offset+size from BKPK tables inside compressed `.upk` packages,
which ackit does not rewrite. Replacements are written in place and must not exceed the original WEM's size;
the encoder lowers quality, then sample rate, to fit, and refuses otherwise. Music stream packs have a loose
index (`SFX\*.bnk`) that ackit rewrites, so music can be any length. (Rewriting `.upk` packages would lift the
limit but means LZO recompression of large engine packages: out of scope, high risk.)
index (`SFX\*.bnk`) that ackit rewrites, so music can be any length. In-memory sounds follow the same rule
(below). Lifting the limit would mean re-laying out the uncompressed packages (export offsets, BKPK/DIDX
tables): high risk for little gain, not done.
## 4b. In-memory sounds (soundbanks in loose `.bnk` files and `.upk` packages)
- **Model:** one catalog row per Wwise media ID (archive `BANK`, target = media ID), not per bank: the same
media is stored in up to dozens of bank copies (banks are cooked into every package that uses them), and the
game may load any of them. A replacement is written into **every** copy (`BANK_locations.csv.gz`).
- **In place:** each copy keeps its size (zero-padded, like WAD speech); DIDX/HIRC offsets and the package
layout never change, so nothing else in the engine data has to be rewritten.
- **Packages:** ackit reads the LZO packages itself (pure Python, ~47 MB/s, block-level access) and writes
only the changed 128 KiB blocks, stored as a single LZO literal run (valid LZO1X without matches), then
fixes the chunk table. No compressor and no external tool are needed; untouched blocks stay byte-identical.
- **Revert:** before the first change to a bank file a verified full copy goes to the store (mandatory, not
optional like the WAD copies: the file is rebuilt from it). The file content is always "original copy +
replacements applied now", so reverting the last one restores the original bytes exactly, and an interrupted
operation is repaired by the next one. Conflicts: the whole-file SHA-1 must be the original's or the last one
ackit wrote.
- **Prefetch heads:** 396 speech lines (about 79 per language) have their first bytes copied into banks; a
replacement of such a line rewrites those heads too, otherwise the start would play the old line.
- **Names:** the hash list names none of these media. Names come from Wwise events whose names are in the
packages' name tables (FNV-1 of the name = event ID), following event -> action -> containers -> sounds
(6,416 sounds); the rest are numbered per bank. Categories use the bank name.
## 5. Catalog
- Shipped CSVs per archive (names, categories, characters, original size + checksum) make loading instant and