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 prefetch heads of speech lines (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, Checkpoint.txt = progress marker. 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> |
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 = prefetch head of a speech line |
sound |
p rows: key of that speech line (e.g. INT:2B151272:0); each language has its own lines and heads |
A replacement is written into every m copy of a BANK sound; replacing a speech line also rewrites its p
heads (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
- Make sure the game files are original (
ackit status;ackit revert --all). - 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. - 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.csvandindex.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. - Run
ackit verify --catalog(no issues expected). New character labels need a display name inackit/classify.py: USER_LABELS(otherwise the file name is used).