Version 3.2.1: whole bank copies of voice lines, unique names, docs figures checked by tools/check_docs.py
This commit is contained in:
@@ -4,8 +4,9 @@ Implemented in `ackit/classify.py`; used both when building the shipped catalog
|
||||
and when a game build is not in the catalog (runtime scan), so every language/build gets the same scheme.
|
||||
|
||||
## Groups and categories
|
||||
Every sound has a **group** and a finer **category**, derived from its Wwise name (from the community hash
|
||||
list; unnamed IDs show as hex). First matching rule wins:
|
||||
Every sound has a **group** and a finer **category**, derived from its name (taken from the game files: the
|
||||
soundbank names in `CookedBanks.txt` and the Wwise event names; the 3 SFX entries no name reaches show as hex).
|
||||
First matching rule wins:
|
||||
|
||||
| name starts with | group | category |
|
||||
|------------------|-------|----------|
|
||||
@@ -78,9 +79,10 @@ alternates speakers between `NAME_1`, `NAME_2`, ...):
|
||||
identified). A line in two lists gets both ("A; B").
|
||||
- **characters_inferred** - characters and roles *mentioned by the name* (token rules in `classify._TOKENS`,
|
||||
e.g. `BM`/`BATMAN` -> Batman, `PENG` -> Penguin, `TF` -> Two-Face, `THUG*`/`GENTHUG*` -> Thug, `TYGER` ->
|
||||
TYGER guard; interview tapes add Hugo Strange). A hint for the ~7,500 lines without a verified speaker,
|
||||
TYGER guard; interview tapes add Hugo Strange). A hint for the ~7,400 lines without a verified speaker,
|
||||
never shown as the speaker. In the editor the character filter matches verified speakers, and optionally
|
||||
inferred ones.
|
||||
|
||||
Coverage (every voice language, the same lines): 3,366 with a verified speaker, 6,263 more with inferred
|
||||
characters, 1,186 with neither (mostly predator chatter and efforts of unnamed thugs).
|
||||
Coverage of the 10,811 WAD voice lines (every voice language, the same lines): 3,366 with a verified speaker,
|
||||
6,258 more with inferred characters, 1,187 with neither (combat barks 407, story missions 267, open-world
|
||||
chatter 228, radio & TV 122, ...).
|
||||
|
||||
@@ -75,11 +75,13 @@ tables): high risk for little gain, not done.
|
||||
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.
|
||||
- **Prefetch heads and whole copies:** 396 voice recordings (81 lines, 78-80 recordings per language) have
|
||||
their first bytes copied into banks, and 49 more are stored whole in banks (same media ID, identical bytes);
|
||||
a replacement of such a recording rewrites those copies too, otherwise the game could play the old line.
|
||||
They are not listed as sounds of their own.
|
||||
- **Names:** no list names these media. Names come from Wwise events whose names are in the
|
||||
packages' name and export tables (FNV-1 of the name = event ID), following event -> action -> containers ->
|
||||
sounds (6,456 sounds); the rest are numbered per bank. Categories use the bank name. A localized speech line
|
||||
sounds (13,501 of 15,355, voice lines included); the other 1,854 are numbered per bank. Categories use the bank name. A localized speech line
|
||||
has the same name in every language (its line, section 5).
|
||||
- **Localized speech:** speech banks hold one copy per voice language (4d); every media is labelled with the
|
||||
language(s) whose banks hold it (a few recordings are shared by several languages) and the catalog shows
|
||||
@@ -119,11 +121,11 @@ copy per voice language) is filtered the same way, so the sound list never mixes
|
||||
*Lines*): the recordings that are sources of the same Wwise Sound objects are one line, with exactly one
|
||||
recording per language (12,434 lines, all 5 languages). The catalog stores that identity (`line`), and
|
||||
speaker labels, mod packages (another language: the same `line`) and subtitles follow it. Positions are
|
||||
useless across languages (WEMs are stored in media-ID order; position i is another line in 75 % of the
|
||||
multi-variation entries).
|
||||
- A line has one name in every language: the most specific speech event that plays it (10,156 of 10,815 voice
|
||||
lines), numbered `NAME#2` in the event's own order when it plays two versions; the other 659 keep the name of
|
||||
their English (INT) recording's position. The position in each language stays an alias (`NAME#i`).
|
||||
useless across languages (WEMs are stored in media-ID order; 81.2-81.6 % of the WEMs in multi-variation entries
|
||||
are at another position than in INT).
|
||||
- A line has one name in every language: the most specific speech event that plays it (10,174 of the 10,811
|
||||
WAD voice lines), numbered `NAME#2` in the event's own order when it plays two versions; the other 637 keep
|
||||
the name of their English (INT) recording's position. The position in each language stays an alias (`NAME#i`).
|
||||
- A recording stored twice in a WAD (5 per language) is written and reverted in both places.
|
||||
- The catalog records the ORIGINAL bytes: `tools/build_catalog.py` stops before writing anything if a sound
|
||||
differs from the current catalog (a modified game), unless `--accept-changes` (a game update).
|
||||
@@ -174,14 +176,18 @@ copy per voice language) is filtered the same way, so the sound list never mixes
|
||||
## 8. Verification
|
||||
- `pytest`: unit tests, a synthetic game (WADs, packs, packages with banks, localized banks, dialogue and subtitle
|
||||
objects, localization files), a two-language game built like the real one (per-language BKPK tables, a media
|
||||
ID shared by both languages, a recording stored twice), offscreen GUI tests, and read-only real-game tests
|
||||
when the game is installed.
|
||||
ID shared by both languages, a recording stored twice, one also stored whole in a bank), offscreen GUI
|
||||
tests, and read-only real-game tests when the game is installed.
|
||||
- `ackit verify` (WEMs rebuilt byte-for-byte, encode/decode), `ackit verify --catalog` (catalog vs game files,
|
||||
and every relation re-derived from the game files with independent checks; it prints them as facts).
|
||||
- Real-game write round trips without launching the game: `tools/e2e_features.py [--lang all]` (every copy of
|
||||
an in-memory sound, localized line, prefetch heads, subtitles incl. RSubtitle, menu text, sound + subtitle in
|
||||
an in-memory sound, localized line, prefetch heads and whole bank copies of a line, subtitles incl. RSubtitle, menu text, sound + subtitle in
|
||||
one package, a mod moved to another voice language; `all` = each of the 11 languages) and
|
||||
`tools/e2e_editor.py` (through the editor's code path).
|
||||
- Documentation: `tools/check_docs.py [--scan] [--wems]` recomputes every figure the documents state (from the
|
||||
catalog, the build's `index.json`, the menu files; with `--scan` from a fresh package scan and the catalog
|
||||
check's facts; with `--wems` from rebuilding every WAD WEM) and fails on any difference, so figures are never
|
||||
copied by hand.
|
||||
- In the running game: `ackit verify --ingame` (music heard), `--banks` (patched packages loaded, probe data in
|
||||
memory), `--texts` (menu texts and Startup subtitles found in memory). Every tool reverts in a `finally` block
|
||||
and checks that every touched file is byte-identical afterwards.
|
||||
|
||||
@@ -10,29 +10,31 @@ Survey of the installed game (buildid 3718300), 2026-10-09.
|
||||
| where | banks | unique in-memory WEMs |
|
||||
|-------|-------|-----------------------|
|
||||
| loose `SFX\*.bnk` (Batman/Catwoman footsteps, 32 surfaces each, + `TST_Prep_Media`) | 65 | 1,117 |
|
||||
| banks embedded in `.upk` packages (in 1,432 of the 2,650 packages) | 3,340 | 15,641 (~276 MB) |
|
||||
| banks embedded in `.upk` packages (in 1,432 of the 2,650 packages) | 3,340 | 14,802 |
|
||||
|
||||
All of them are in the catalog (archive `BANK`).
|
||||
|
||||
The two sets share 119 media IDs: 15,800 unique media IDs in 96,011 places (bank copies). 396 of them are
|
||||
**prefetch heads** of streamed WAD sounds (below), so there are **15,404 in-memory sounds**. All copies of a
|
||||
**prefetch heads** of streamed WAD sounds and 49 are **whole copies** of WAD recordings (below), so there are
|
||||
**15,355 in-memory sounds**. All copies of a
|
||||
media ID are byte-identical except `1C898731` (two variants). The WADs, by comparison, are fully covered: the
|
||||
BKPK tables in the packages reference 2,543 WAD entries, all of them in the catalog.
|
||||
|
||||
Embedded WEMs by bank name prefix: `Speech` 7,872, `CHR` (character foley, combat, bosses) 3,896, `PSO` 781,
|
||||
`WPN` 664, `NPC` 475, `OBJ` 439, `SEQ` 265, `GUI` 208, `PSA` 203, `MTN` 196, `PX` 195, `DVC` 100, `GEN` 80,
|
||||
`PHY` 73, `AMB` 65, `SBJ` 50, others < 30. The `Speech_` banks (e.g. `Speech_EMOTE_Batman`, `..._GRUNT`) hold
|
||||
speech: grunts and efforts (language-neutral, 165) and **localized lines** (about 1,460 per language, see
|
||||
*Localized banks*).
|
||||
All WEMs seen are Vorbis (format tag 0xFFFF), the same codec as the WADs: the footsteps are mono (4 stereo),
|
||||
the embedded ones mono or stereo (~22 % stereo in a 2,533-WEM sample).
|
||||
Embedded WEMs by bank name prefix (a media held by banks of two prefixes counts for both): `Speech` 7,827, `CHR`
|
||||
(character foley, combat, bosses) 3,624, `PSO` 737, `WPN` 577, `NPC` 471, `OBJ` 411, `SEQ` 253, `PSA` 203,
|
||||
`PX` 195, `MTN` 191, `GUI` 155, `DVC` 100, `GEN` 80, `PHY` 73, `AMB` 61, `SBJ` 50, others < 30. The `Speech_` banks (e.g. `Speech_EMOTE_Batman`, `..._GRUNT`) hold
|
||||
speech: efforts, grunts and a few other lines stored once for every language (119 sounds) and **localized
|
||||
lines** (about 1,450 per language, see *Localized banks*).
|
||||
All WEMs seen are Vorbis (format tag 0xFFFF), the same codec as the WADs: the loose footsteps are mono (4
|
||||
stereo); of all 15,355 in-memory sounds 13,982 are mono, 1,196 stereo, 177 have 3-6 channels.
|
||||
|
||||
## Names
|
||||
- No list names these media IDs (the community hash list names only WAD entries and banks).
|
||||
- Media IDs have no names of their own: a sound is named after the Wwise event that plays it (event names
|
||||
are in the packages' name and export tables, event ID = FNV-1 of the name), else after its bank.
|
||||
- `CookedPCConsole\CookedBanks.txt` lists all 3,345 cooked bank names. Bank ID = FNV-1 32 of the lowercased
|
||||
name (the same hash Wwise uses for every name). 3,338 of them are embedded in packages, 4 are loose `.bnk`
|
||||
files (`Init`, `Global`, `Music`, `Music_PDLC`); `AMB_OW_A6`, `AMB_OW_C1`, `AMB_OW_E1`,
|
||||
`Speech_EMOTE_Thug_Muffled_Stop` and `Speech_GFxUI_ArkhamCityStories` were found nowhere.
|
||||
name (the same hash Wwise uses for every name). 3,338 of them are embedded in packages (`Music`, `Music_PDLC`
|
||||
also as loose `.bnk` files), 2 are only loose `.bnk` files (`Global`, `Init`); `AMB_OW_A6`, `AMB_OW_C1`,
|
||||
`AMB_OW_E1`, `Speech_EMOTE_Thug_Muffled_Stop` and `Speech_GFxUI_ArkhamCityStories` were found nowhere.
|
||||
- Loose footstep banks are named in their STID chunk (`CHR_BatmanFootsteps_Concrete_Media`, ...).
|
||||
|
||||
## Bank layout (version 56, Wwise 2011.1)
|
||||
@@ -51,6 +53,12 @@ with bank id 0 whose media is not in the same bank (loaded by another bank); 133
|
||||
(`wad.md`). A prefetch source's media is also in the bank's DIDX: that in-memory copy is the **head** of the
|
||||
streamed WEM (its size = the source's size), which the game plays while the rest is read from the WAD. 396
|
||||
WAD sounds have such heads (2,101 copies); replacing one of them must rewrite the heads too.
|
||||
49 more WAD recordings (9-11 per language: game-over taunts, an encryption-card line, a cutscene line, scripted
|
||||
story lines) are
|
||||
also stored **whole** in banks: an in-memory source with the WAD recording's own media ID, byte-identical to
|
||||
the WAD WEM (84 copies). They are handled like heads: part of the WAD line, written and reverted with it, not
|
||||
sounds of their own (`catalog._whole_recordings`). Heads and whole copies together: 445 recordings, 2,185
|
||||
copies (`BANK_locations.csv.gz` kind `p`).
|
||||
|
||||
## Localized banks
|
||||
Speech banks are localized inside the (language-neutral) packages: one `AkBank` export starts with a language
|
||||
@@ -58,9 +66,10 @@ list (FStrings `INT FRA ITA DEU ESN`) and then holds one block per language, in
|
||||
of the speech WAD entry for that language (`wad.md`) and a complete bank, with the same bank ID in every
|
||||
language. ackit gives each bank and each BKPK table the language of its position in that list (an export
|
||||
whose block count differs from its language count would be reported; none does). Each in-memory media gets
|
||||
the languages of the banks that hold it (`BANK.csv` column `language`): 8,098 sounds are language-neutral,
|
||||
~1,460 belong to one voice language, 6 to several (a DLC intro line shared by INT/FRA/ITA/ESN while DEU has
|
||||
its own); a media stored in the banks of every language is listed as `''` (the same recording everywhere).
|
||||
the languages of the banks that hold it (`BANK.csv` column `language`): 8,092 sounds are language-neutral,
|
||||
1,450-1,456 belong to one voice language, 6 to several (5 shared by INT/FRA/ITA/ESN while DEU has its own, 1
|
||||
by INT/FRA/ITA); a media stored in the banks of every language is listed as `''` (the same recording
|
||||
everywhere; 167 of these are voice lines, e.g. efforts and radio chatter).
|
||||
A catalog shows the neutral sounds plus the loaded language's lines; names are unique per language.
|
||||
|
||||
## Lines: one recording per language
|
||||
@@ -73,17 +82,18 @@ and the game ties the recordings together itself:
|
||||
- Every recording, streamed, prefetched or in memory, is the source of a Wwise Sound object; Sound objects,
|
||||
events, actions and containers have the same IDs in every language, only the media differ. A *line* = the
|
||||
recordings that are sources of the same Sound objects: 12,434 lines (WAD and in-memory), each with exactly
|
||||
one recording in each of the 5 voice languages (61,510 recordings), no Sound object with two recordings in
|
||||
one recording in each of the 5 voice languages (61,485 recordings), no Sound object with two recordings in
|
||||
one language. Line identity (`line` column) = the smallest Sound object ID.
|
||||
- Prefetched sources count too: the 396 lines with a prefetch head (mostly the game-over taunts) are linked
|
||||
only through them.
|
||||
- Prefetched sources count too: the 81 lines with a prefetch head (396 recordings over the 5 languages; mostly
|
||||
the game-over taunts) are linked only through them. A WAD recording that a bank also stores whole (49) is
|
||||
the same recording (same media ID), so its line is unchanged and the bank copies are written with it.
|
||||
- 5 recordings per language are stored twice in that language's WAD (same media ID in two entries, byte-
|
||||
identical, e.g. `Speech_STEEL_A1_CH2_Thug_behinddoormuffled` and `DIA_SteelA1Muffled`): the second place
|
||||
is a copy of the line (same `line`, keeps its position name) and is written and reverted with it, because
|
||||
the game plays whichever place the loaded package's table names.
|
||||
- Independent checks (no BKPK involved): every WAD recording is named as a source by a Sound object of a bank
|
||||
of its own language (54,055 of 54,055); every stored prefetch head equals the start of the recording its
|
||||
line gives it (2,101 of 2,101); a line's recordings have similar lengths across languages (11,761 of 12,434
|
||||
of its own language (54,055 of 54,055); every stored head or whole copy equals the start of the recording
|
||||
its line gives it (2,185 of 2,185); a line's recordings have similar lengths across languages (11,761 of 12,434
|
||||
within a factor 1.5; the others are different edits, e.g. a 0.55 s ESN line vs 5.46 s elsewhere).
|
||||
|
||||
## Banks inside packages
|
||||
@@ -99,10 +109,12 @@ and the game ties the recordings together itself:
|
||||
|
||||
## How ackit edits them
|
||||
- Catalog archive `BANK` (one row per media ID) + `data/catalog/BANK_locations.csv.gz` (every copy, and the
|
||||
prefetch heads of speech lines); built by `tools/build_catalog.py`, checked by `ackit verify --catalog`.
|
||||
heads and whole copies of WAD speech recordings); built by `tools/build_catalog.py`, checked by `ackit verify
|
||||
--catalog`.
|
||||
- A replacement is written **in place into every copy** (no larger than the smallest copy, zero-padded), so
|
||||
DIDX/HIRC offsets and sizes and the package layout never change. Loose banks are patched directly; in
|
||||
packages only the touched blocks are re-encoded (`upk.md`). A sound left in one package only would let the
|
||||
game load the original from another one.
|
||||
- Replacing a speech line that has prefetch heads rewrites the heads (first bytes of the new, zero-padded line).
|
||||
- Replacing a speech line that has prefetch heads or whole copies rewrites them (the first bytes of the new,
|
||||
zero-padded line; for a whole copy, all of it).
|
||||
- Design and revert rules: `docs/decisions.md` (4b). The same WEM rules apply (`wem.md`).
|
||||
|
||||
@@ -5,14 +5,15 @@ the UE3 packages (`upk.md`), holding the subtitle text of all 11 languages. acki
|
||||
`ackit/subtitles.py` and writes them through `Workspace.texts` (`ackit/texts.py`).
|
||||
|
||||
## Inventory (buildid 3718300)
|
||||
- 14,743 dialogue objects in the packages for 9,016 speech lines (a line's object is copied into every package
|
||||
- 14,744 dialogue objects in the packages for 9,032 speech lines (a line's object is copied into every package
|
||||
that uses it; all copies are identical), plus 41 scripted subtitles (below): ~9,400 subtitle strings and
|
||||
168,688 stored copies.
|
||||
- 11 languages: INT, FRA, ITA, DEU, ESN, ESM, POL, POR, RUS, JPN, KOR (the speech WADs exist only for INT, FRA,
|
||||
ITA, DEU, ESN; the other languages play the INT voices with their own subtitles).
|
||||
- ~9,400 subtitle strings per language: 94 % of the subtitles have one line, the rest up to 5 lines.
|
||||
- Strings are stored as cp1252 (positive FString length) or UTF-16 (negative length): RUS, POL, JPN, KOR
|
||||
and some INT/ESN/FRA/DEU strings are UTF-16.
|
||||
- 9,035-9,667 subtitle strings per language: 94-98 % of the subtitles have one line (JPN: all), the rest up
|
||||
to 5 lines.
|
||||
- Strings are stored as cp1252 (positive FString length) or UTF-16 (negative length): almost all RUS, JPN and
|
||||
KOR strings and 85 % of POL are UTF-16; the other languages have 17-56 UTF-16 strings each.
|
||||
|
||||
## Scripted subtitles (`RSubtitle`)
|
||||
41 more subtitles (radio and encryption-card lines) are `RSubtitle` objects in `Startup.upk`: the same layout,
|
||||
@@ -34,7 +35,7 @@ or property name from the name table, i32 byte size, i32 array index, then `size
|
||||
| `0x09 LocalizedSubtitles` | u32 count, then per language: `0D 00 00 00` FString language code, `09 00 0C 00 Subtitles` struct, `00 00` |
|
||||
| `Subtitles` | u32 line count, then per line: `0D 00 00 00` FString text, `04 00 0C 00` 4-byte value, `00 00` |
|
||||
|
||||
The sizes add up exactly in all 14,743 objects (checked by the parser: `SubtitleError` otherwise).
|
||||
The sizes add up exactly in all 14,744 objects (checked by the parser: `SubtitleError` otherwise).
|
||||
|
||||
## Link to the speech sound
|
||||
The speech event name is hashed (FNV-1) to the Wwise event ID and followed through the soundbanks (event ->
|
||||
@@ -46,7 +47,7 @@ export names) and from the subtitle objects themselves: some events are listed i
|
||||
dialogue / RSubtitle object names them (Vicki Vale's radio reports, the Hush tape reveal).
|
||||
An event that plays two versions of a line (105 subtitled events, e.g. Mr. Freeze's lines) links its subtitle
|
||||
to both (`sound` = `key1;key2`). Linked: 103,304 of 103,658 strings in the 11 languages (INT 9,373 / 9,404),
|
||||
each to the same line in every language. The rest (29 speech names, ~32 strings per language: Riddler trophy
|
||||
each to the same line in every language. The rest (24 speech names, 24-36 strings per language: Riddler trophy
|
||||
texts, Arkham City Stories, radio reports and tapes the game does not ship audio events for) have no event in
|
||||
any bank and stay editable without a sound link.
|
||||
|
||||
|
||||
@@ -29,8 +29,9 @@ Payload kinds:
|
||||
- **LOC WADs**: each entry is a group of WEMs, the variations of one line (every language: 10,816 WEMs in
|
||||
2,464 entries; e.g. `CHR_RadioScanner` holds 91). Each WEM starts at the next 0x800 boundary after
|
||||
the previous one (zero padding); 3 entries pack two WEMs back to back. Addressed `HASH:i`. The WEMs of an
|
||||
entry are stored in media-ID order and the languages have different media IDs, so variation `i` is a
|
||||
different line in each language (75 % of the lines). Which recording is which line comes from the banks
|
||||
entry are stored in media-ID order and the languages have different media IDs, so variation `i` is
|
||||
usually a different line in each language (81.2-81.6 % of the WEMs in multi-variation entries, compared with
|
||||
INT; e.g. `Speech_TAPE_JOKER_1_04` is variation 1 in INT and ITA, 8 in FRA, 6 in DEU, 5 in ESN). Which recording is which line comes from the banks
|
||||
(`banks.md`, *Lines*), not from positions.
|
||||
- **SFX WAD**: 79 grouped ambience/effect entries (260 WEMs) plus 4 **stream packs** (below).
|
||||
|
||||
|
||||
@@ -3,10 +3,14 @@
|
||||
Derived from the game's WEMs; `ackit verify` / `tests/test_realgame.py` rebuild them byte-for-byte from these rules
|
||||
alone. Checked on every WEM of the 5 speech WADs: 54,079 of 54,080 are identical; the exception (INT
|
||||
`FE9963E8:74`) differs only in the informational avg-bytes/s field (one lower than the formula below). In SFX
|
||||
only the 4 looping music tracks with loop points differ.
|
||||
626 of 651 are identical; the others are 14 music tracks whose seek table follows another placement (one entry per
|
||||
1,024-1,103 samples), 5 music tracks whose sample count exceeds what their packets hold, and 6 4-channel
|
||||
ambience WEMs with a `smpl` (loop) chunk. These rules are not needed to write sounds the game plays (replaced
|
||||
music, built with the rules here, is heard in game: `ackit verify --ingame`), only to reproduce those originals.
|
||||
|
||||
## RIFF layout
|
||||
`RIFF` size `WAVE`, then `fmt ` (0x42 bytes), optional `cue `/`LIST` (37 files), `data`.
|
||||
`RIFF` size `WAVE`, then `fmt ` (0x42 bytes), optional `LIST` + `cue ` (659 WEMs), `LIST` + `cue ` + `smpl` (1 WEM),
|
||||
`cue ` (18 WEMs), `cue ` + `smpl` (3 WEMs), `smpl` (41 WEMs), `data`.
|
||||
Odd-sized `data` chunks are **not** padded.
|
||||
|
||||
### `fmt ` (0x42)
|
||||
|
||||
@@ -70,7 +70,7 @@ Conclusion: approach A works end-to-end in-game. Use >= 30 s probes for the intr
|
||||
expects WAVEFORMATEX order (FL FR FC LFE BL BR) is unverified (identical-channel probes were used).
|
||||
16. (2026-10-09) The WADs hold only streamed audio. About 15,800 more sounds (footsteps, foley, combat, weapons,
|
||||
UI, grunts) are in-memory WEMs inside soundbanks: 65 loose `SFX\*.bnk` (1,117) and 3,340 banks embedded in
|
||||
the `.upk` packages (15,641; many banks copied into several packages). None were in the catalog then (they
|
||||
the `.upk` packages (14,802; many banks copied into several packages). None were in the catalog then (they
|
||||
are now: archive BANK); the WAD side was complete. Inventory and layout: `docs/formats/banks.md`.
|
||||
17. (2026-10-09) Speech lines have **per-language media IDs**: every package carries one BKPK table per language
|
||||
for the same WAD entry. 396 lines (78-80 per language) have a prefetch head (first N bytes) in banks; each
|
||||
@@ -95,12 +95,14 @@ Conclusion: approach A works end-to-end in-game. Use >= 30 s probes for the intr
|
||||
Position names (NAME_i, wemscan) therefore mean different lines per language. Speech sounds are now named
|
||||
after their speech event (same in every language); the curated ITA lists are mapped through it. Independent
|
||||
check: the speaker field of the dialogue objects agrees with the mapped labels for 955 / 955 lines.
|
||||
(Superseded by 22: the identity of a line now comes from the Sound objects, for every recording.)
|
||||
(Superseded by 22: the identity of a line now comes from the Sound objects, for every recording; measured
|
||||
that way, 81.2-81.6 % of the WEMs in multi-variation entries are at another position than in INT.)
|
||||
21. (2026-10-10) In-memory speech banks are localized (language list + one bank per language in one AkBank
|
||||
export, checked on 215 banks against the WAD languages of their streamed lines); 41 more subtitles are
|
||||
RSubtitle objects linked through RSubtitleLookup (key = FNV-1 of the line name without `Speech_`). Subtitle
|
||||
coverage by category is uneven in the game itself: efforts 0 %, combat barks 11 %, cinematics 10 % (cutscene
|
||||
lines are mostly not reached by speech events and have no dialogue object), story/predator/open world ~90 %+.
|
||||
(With every version of a line linked, item 22: combat barks 9 %, cinematics 23 %; REPORT.md.)
|
||||
|
||||
22. (2026-10-10) **One recording per language, from the game data alone** (`docs/formats/banks.md`, *Lines*).
|
||||
The BKPK tables of a speech entry sit inside the localized AkBank export, one per declared language; they
|
||||
@@ -113,6 +115,16 @@ Conclusion: approach A works end-to-end in-game. Use >= 30 s probes for the intr
|
||||
recording in each of the 5 languages, no conflict; independent checks: 54,055 / 54,055 WAD recordings are
|
||||
sources in a bank of their own language, 2,101 / 2,101 prefetch heads equal the start of their recording,
|
||||
every linked subtitle is on the same line in all 11 languages.
|
||||
23. (2026-10-10, final check) **Whole WAD recordings in banks.** 49 in-memory media (9-11 per language) have the
|
||||
media ID of a WAD recording of their bank's language and are byte-identical to it (game-over taunts,
|
||||
`Speech_CH_ZERO_CH0_ENCRYPTION_CARD3_01`, `Speech_SEQUENCE_CH2_RESCUE_DOC_01`, ...): the line's Sound
|
||||
object names that media, and some bank also stores the whole WEM in memory. They were listed as separate BANK sounds (with the
|
||||
line's name: the CLI called the name ambiguous), so a replacement of the line left the in-memory copies
|
||||
old. Now they are bank copies of the WAD recording like prefetch heads (84 copies; 445 recordings with
|
||||
heads or whole copies, 2,185 copies), written and reverted with the line. Also: 8 in-memory sounds per
|
||||
catalog had the same `<Bank>_<n>` name as an SFX WAD sound of the same bank (`CHR_RasBossFight_1`,
|
||||
`SEQ_DemonTrials_1`); they now take `<Bank>_<MEDIA>`, and a line's own name wins over another recording's
|
||||
position alias (`CHR_RadioScanner#1` in FRA). Every name of every catalog resolves to its own sound.
|
||||
|
||||
## Old path -> new path
|
||||
`scripts/harness.py` -> `ackit verify --ingame` (ackit/verify/ingame.py); `scripts/validate_builder.py` ->
|
||||
|
||||
@@ -48,7 +48,7 @@ the same line and are changed and reverted together.
|
||||
- Click a column header to sort (length, size, status, ...). Ctrl/Shift-click selects several rows.
|
||||
- Archive **BANK** holds the short sounds stored inside soundbanks (footsteps, foley, combat,
|
||||
weapons, menu sounds, grunts). Many are named after the game event that plays them (`Play_...`), the
|
||||
rest after their bank (`CHR_Bane_3`). The editor shows the bank and how many copies the game keeps of
|
||||
rest after their bank (`CHR_BatclawGrapple_3`). The editor shows the bank and how many copies the game keeps of
|
||||
the sound; a replacement is written into every copy.
|
||||
|
||||

|
||||
@@ -92,8 +92,10 @@ The **Subtitles** tab lists the subtitle of every speech line in the selected la
|
||||
- Search by text or line name, filter by **Character** and **Category** (taken from the linked speech sound),
|
||||
or show **Modified only**. Select a row to edit its text below and press **Apply** (or Enter).
|
||||
- Each subtitle replaces the original *in place*, so it can be at most as long as the original (the counter
|
||||
shows *used / room* characters). Latin-1 subtitles accept Latin-1 characters only (accents are fine);
|
||||
Russian, Polish, Japanese and Korean subtitles accept any character.
|
||||
shows *used / room* characters). Most subtitles are stored in the Western European character set
|
||||
(Windows-1252: accents are fine, other scripts are not); those stored as Unicode (almost all Russian,
|
||||
Japanese and Korean ones, most Polish ones) accept any character. The editor says so when a character does
|
||||
not fit.
|
||||
- **Go to the sound** opens the speech line in the Sounds tab. In the Sounds tab, the editor of a speech line
|
||||
shows its subtitle in the **Subtitle** column next to the audio: edit both side by side, **Apply** /
|
||||
**Revert** the subtitle there, or **Show in list** to jump back to the Subtitles tab.
|
||||
|
||||
Reference in New Issue
Block a user