75 lines
6.6 KiB
Markdown
75 lines
6.6 KiB
Markdown
# Sound catalog
|
|
|
|
| file | content |
|
|
|------|---------|
|
|
| `<ARCHIVE>.csv` | every sound of one audio archive: `INT`, `FRA`, `ITA`, `DEU`, `ESN` (speech WADs, one per language), `SFX` (music, ambience and effects streamed from the SFX WAD) and `BANK` (in-memory sounds stored inside soundbanks: footsteps, foley, combat, weapons, UI, efforts; `docs/formats/banks.md`) |
|
|
| `BANK_locations.csv.gz` | every stored copy of the `BANK` sounds, and the bank copies of WAD speech recordings (prefetch heads, whole copies; below) |
|
|
| `SUB_<LANG>.csv` | subtitles of the speech lines, one file per language (11 languages; `docs/formats/subtitles.md`) |
|
|
| `SUB_locations.csv.gz` | every stored copy of each subtitle string (dialogue objects in the packages) |
|
|
| `characters.csv` | `name,character,language`: verified speaker per line name (empty `language`: every language, the same line everywhere; a language code would label a sound of that language only - none needs it now) |
|
|
| `index.json` | per archive: fingerprint of the game files the CSV was built from (`ackit/game.py: wad_fingerprint`, `ackit/banks.py: game_fingerprint`) and counts |
|
|
| `source/<lang>/*.txt` | **the curated original lists** (one file per character, one wemscan-style file name per line, e.g. `Speech_TAPE_JOKER_1_4.wem`). `Files.txt` = all files, `Stats.txt` = counts. Never edited by tools. |
|
|
|
|
All CSVs are UTF-8 with a header row. They contain only names and metadata (no game audio).
|
|
|
|
## `<ARCHIVE>.csv` columns
|
|
| column | meaning |
|
|
|--------|---------|
|
|
| `archive` | `INT`, `FRA`, ..., `SFX` or `BANK` |
|
|
| `target` | location: `HASH` (WAD entry with one WEM), `HASH:i` (i-th variation, 0-based), `PACK/MEDIA` (music stream pack), `MEDIA` (BANK: Wwise media ID) |
|
|
| `name` | display name. Speech: the line's name, the same in every language (`docs/decisions.md` 5): its speech event (e.g. `Speech_TAPE_JOKER_1_04`, `NAME#2` = second version an event plays) or, for lines no named event plays, the INT recording's position name. A recording stored twice keeps its position name in the second place. SFX: `NAME`, `NAME_1..n`. BANK: the Wwise event that plays it (`Play_..._i`) or `<Bank>_<n>` (`<Bank>_<MEDIA>` where that name is taken, e.g. by the SFX WAD's position names) |
|
|
| `aliases` | other accepted names, `\|`-separated: `NAME#i` = i-th WEM of the entry in this language's WAD (positions differ between languages), the entry name for single entries, `<Bank>/<MEDIA>` for BANK |
|
|
| `group` | Speech, Music, Ambience, SFX, Unknown (`docs/categories.md`) |
|
|
| `category` | finer category (`docs/categories.md`) |
|
|
| `bank` | BANK: the soundbank holding the sound (first by name if several do); empty for WAD sounds |
|
|
| `language` | BANK: language(s) of a localized speech line, `;`-separated (`INT`, or `ESN;FRA;INT;ITA` for one recording shared by those); empty = the same sound in every language. The editor shows the sounds of the selected language; names are unique per language |
|
|
| `line` | speech (WAD and BANK): the line's identity, the same in every language (smallest Wwise Sound object ID of the line; `ackit/lines.py`). Two rows of one archive with the same `line` are one recording stored twice (written together). Empty for non-speech sounds |
|
|
| `character` | verified speaker(s) from `characters.csv`, `; `-separated, empty if unknown |
|
|
| `characters_inferred` | characters/roles mentioned by the name (and bank) (hint only) |
|
|
| `seconds`, `rate`, `channels` | of the original sound |
|
|
| `size` | size of the original WEM in bytes = maximum size of a replacement (except music packs: any size) |
|
|
| `sha1` | first 16 hex digits of the original WEM's SHA-1 (detects files changed outside the tool; empty when the copies of a BANK sound differ) |
|
|
| `notes` | free text (empty; for future curation, e.g. transcripts) |
|
|
|
|
## `BANK_locations.csv.gz` columns (gzip-compressed CSV)
|
|
| column | meaning |
|
|
|--------|---------|
|
|
| `media` | Wwise media ID (hex) |
|
|
| `file` | file under `BmGame/CookedPCConsole`, `/`-separated (`SFX/xxxxxxxx.bnk` or `Name.upk`) |
|
|
| `offset` | position of the WEM in the *uncompressed* file (hex; `docs/formats/upk.md`) |
|
|
| `size` | bytes reserved for it there |
|
|
| `kind` | `m` = copy of a BANK sound, `p` = copy of (the start of) a WAD speech recording: a prefetch head, or a whole copy with the same media ID |
|
|
| `sound` | `p` rows: key of that speech recording (e.g. `INT:2B151272:0`); each language has its own recordings and heads |
|
|
|
|
A replacement is written into every `m` copy of a BANK sound; replacing a speech line also rewrites its `p`
|
|
copies (`docs/formats/banks.md`).
|
|
|
|
## `SUB_<LANG>.csv` columns
|
|
| column | meaning |
|
|
|--------|---------|
|
|
| `speech` | the speech event of the line (e.g. `Speech_CHURCH_B1_Ch2_POST_Explosion_BM_Cash_04`) |
|
|
| `line` | 0-based line of a multi-line subtitle |
|
|
| `text` | original subtitle text |
|
|
| `room` | maximum length of a replacement in characters (it is written in place) |
|
|
| `enc` | `a` = cp1252 string, `w` = UTF-16 string |
|
|
| `sound` | key(s) of the linked voice recording(s), `;`-separated when the event plays two versions: this language's WAD line or in-memory `BANK:` line (the INT ones for languages without voices); empty when no event reaches a sound |
|
|
|
|
`SUB_locations.csv.gz`: `lang, speech, line, file, pos` (hex, uncompressed offset of the FString), `size`, `enc`.
|
|
Menu text has no catalog: the localization files are read directly (`docs/formats/text.md`).
|
|
|
|
The editor uses these files directly when the installed game matches `index.json`; for another game build it
|
|
scans the game itself and applies the same rules (no checksums then; the bank scan takes a few minutes).
|
|
`ackit verify --catalog` cross-checks the catalog in use against the game files (`--quick` samples packages).
|
|
|
|
## Rebuilding / adding a language
|
|
1. Make sure the game files are original (`ackit status`; `ackit revert --all`).
|
|
2. Optional: add listening-based lists for another language in `source/<lang>/<Character>.txt` (same format:
|
|
wemscan names of THAT language's WAD). Each list is resolved against its own language's positions and moved
|
|
to the lines, so a label then applies to the same recording in every language.
|
|
3. Run `python tools/build_catalog.py` - it scans every archive and all soundbanks of the installed game (all
|
|
languages present; ~5 minutes) and rewrites the CSVs, the location indexes, `characters.csv` and `index.json`.
|
|
It stops before writing anything if a sound differs from the current catalog (a modified game); after a game
|
|
update run it with `--accept-changes`.
|
|
4. Run `ackit verify --catalog` (no issues expected).
|
|
New character labels need a display name in `ackit/classify.py: USER_LABELS` (otherwise the file name is used).
|