12 KiB
12 KiB
Report — full-game audio, subtitles and menu text (mission 3), Edit tab and effects (mission 4)
Briefs: docs/history/mission3_audio_text_prompt.md, docs/history/mission4_dubbing_plan.md (plan, the effects
found in the game, the user's decisions). Earlier missions: the WAD/WEM toolkit (mission 1) and the editor Unheard
City (mission 2).
What works (verified)
- Every sound of the game is cataloged and editable: the speech WADs (5 languages x 10,816), the SFX WAD (651)
and, new, the 15,355 in-memory sounds stored inside soundbanks (archive
BANK: footsteps, foley, combat, weapons, UI, efforts; 8,092 shared by all languages, ~1,450 localized speech lines per voice language, 6 shared by several) in 65 loose.bnkfiles and 974.upkpackages. ackit reads and patches the LZO-compressed UE3 packages itself (ackit/upk.py,lzo.py; no external tools). A replacement goes into every copy (93,702 copies). 445 WAD voice recordings (89 lines) also have bank copies (396 prefetch heads, 49 whole copies; 2,185 copies), which are rewritten with them. Names: 13,501 BANK sounds are named after the Wwise event that plays them (Play_...,Speech_...), the other 1,854 after their bank. - Catalog check:
ackit verify --catalogcompares the catalog with a fresh scan of the game (missing, extra, duplicate, size/checksum, category, character, language, bank copies, subtitle copies/texts) and re-derives every relation from the game files (lines, names, subtitle links, prefetch heads, copies): catalog OK on the full game. - Subtitles: found in
RDialogueEventobjects inside the packages (9,032 speech lines x 11 languages) and in 41 scriptedRSubtitleobjects (radio, encryption cards, Riddler; linked throughRSubtitleLookup), parsed, cataloged (SUB_<LANG>.csv) and linked to their voice recordings through the soundbanks: 103,304 of 103,658 strings in 11 languages (INT 9,373 of 9,404), each on the same line in every language; an event that plays two versions of a line links both. Edited in place in every copy (168,688 copies). - One recording per language, from the game data alone (
docs/formats/banks.md, Lines): every voice recording is tied to its line by the game's Wwise Sound objects (same IDs in every language), and each WAD recording to its media by its own language's BKPK table (10,816 / 10,816 in each language). Result: 12,434 lines (WAD + in-memory) with exactly one recording in each of the 5 voice languages, no gap and no conflict; recordings stored twice (5 per language) are written together. Independent checks: every WAD recording is a source in a bank of its own language (54,055 / 54,055), every prefetch head or whole bank copy is the start of its recording (2,185 / 2,185). Each line has one name in every language and carries its identity (line): speaker labels (3,366 in every language), subtitles and mod packages (another language: the same line) follow it. Speaker labels vs the game's dialogue speaker field: 2,766 agree, 19 differ (categories.md). - Menu text: the localization files (
BmGame\Localization\<LANG>\*.int, ~7,000 strings per language), edited value by value; everything else in the files stays byte-identical. - Editor: one Language setting (default: the game's language) for voices, subtitles and menu text (languages without voices use the INT ones, like the game); tabs Sounds / Edit / Subtitles / Menu text. Sounds only browses (filters, list, a player with Play original / Play installed / Stop, Edit / Add to edit list). Edit is where every kind of sound is replaced: an edit list (Previous / Next) whose sounds keep their replacement audio, trim/level values and effects in the user data folder until applied; the subtitle shown large with the original (and English) line; original / installed / replacement waveforms; record or load; the effects. No scrolling at 1400 x 900 or 1280 x 800. The subtitle list links back to the sound. Search, filters (character, category, file, modified), room counter, apply/revert/revert all, find & replace on the filtered rows, mod export/import with texts, changed-outside banner for sounds and texts.
- Effects (mission 4,
ackit/fx.py, pedalboard + numpy): the effects found in the game's sounds (metadata survey of every bank + signal analysis of every INT speech recording + the user listening to sample groups): pitch / formant / pitch drift, octave layers, ring modulator and comb, glitch repeats, band-pass EQ, distortion and phone codec, noise, echo, reverb (a generated room response) with reverse swells, and the channel layout of 2-5 channel sounds (WAVE mask order; the PA lines' dry centre and delayed surrounds). Presets per effect and whole presets (Radio, Phone, PA announcement, Mr. Freeze, ...); set by hand in the Edit tab, orackit replace --fxon the command line. Effects the game adds while it plays (the McDSP FutzBox radio sound of many thug and street lines, room reverbs) are not in the files and must not be added again. - Safety: every changed file (WAD, bank, package, localization file) is rebuilt from a verified original copy
in the store + the edits applied now; reverting the last edit restores it byte-for-byte; files changed by
another tool or Steam are detected (whole-file SHA-1) and not overwritten without confirmation (also when
installing a mod in the editor). The original copy is taken only from a file that matches the catalog
(another tool's or another originals store's change is a conflict; checked on all 1,446 files with sounds or
subtitles: no false alarm), and the editor does not switch stores while changes are applied. Writes are
serialized, so a sound and its subtitle applied at the same time both reach the package. Revert all
(editor and
ackit revert --all) reverts sounds and texts;ackit restore-backupis the last resort for a damaged store. - Tests: 177 automated tests (unit, synthetic game with packages/banks/dialogues/localization, a
two-language game for the lines (incl. a recording also stored whole in a bank), the shipped catalog's cross-references, real-game read-only (every
name of every language's catalog resolves to its own sound), offscreen GUI incl. list order, selection,
loading overlays and the Edit tab (edit list, saved replacements, effects panel, no scrolling), every effect
measured back on synthetic signals) pass.
ackit verifyPASS (incl. 300/300 in-memory WEMs rebuilt byte-identically). - Real game (2026-10-10), all reverting and checking byte-identity themselves:
tools/e2e_features.py --lang all89/89 PASS in all 11 languages (every copy of an in-memory sound, each language's localized line, prefetch heads, a line also stored whole in banks, a multi-copy subtitle, a scripted subtitle, a menu text, sound + subtitle in one package, a mod moved to another voice language and matched to the same line at another position);ackit verify --ingamePASS (music heard, ncc 1.0);--banksPASS (77 in-memory sounds of the front-end packages replaced in 54 files: the game loads them, 71 probes found in its memory, no crash);--textsPASS (12/12 menu texts and 23/23 subtitles of Startup.upk found in the game's memory, no crash);tools/e2e_editor.pyPASS. 2026-10-27 (Linux, the game's Flatpak install):tools/e2e_features.py --lang INT10/10 PASS, incl. a 5-channel line replaced with effects (EQ, echo, PA layout), decoded back from the game file (dry centre, surround echo 0.160 s later) and reverted byte-identically. Game files original at the end (ackit status). The catalog builder refuses to run on a modified game, so the catalog always describes the original files. - Package:
dist/UnheardCity-3.3.0-windows-amd64.zip(86 MB, catalogs included; built 2026-10-13). WithPATHreduced to the Windows folders the packaged exe passes its smoke test (in the game's language - Italian on the test PC: 21,015 sounds loaded, encode + inject, 9,377 subtitles and 7,020 menu texts loaded, an in-memory sound decoded from a package) and the GUI starts and quits cleanly. The installer is unchanged since mission 2 (install/upgrade/uninstall verified then); the uninstaller now also counts text edits before offering to delete the user data (2026-10-13; that count was tested, the full uninstall cycle was not run again). Version 3.4.0: the Linux package (dist/UnheardCity-3.4.0-linux-x86_64.tar.gz, built 2026-10-27, the first Linux build) passes the same smoke test (incl. the effects) withPATH=/usr/bin:/bin, and the GUI starts.
Unresolved / limitations
- Checked by a person in game (2026-10-10), not automatically (nothing of this plays or shows on the title screen without input, findings 18): replaced voice lines and edited subtitles are heard and shown; replaced footsteps play on every step. That test found the one defect the automatic checks could not: in-memory replacements followed by zero padding in their slot played as silence (fixed in 3.2.2, findings 24).
- Size limits: in-memory sounds and speech must fit their original size; subtitles must fit the original text's length ("room"); cp1252 subtitles accept cp1252 characters only. Lifting these limits means moving objects inside the packages (new export offsets/sizes, added chunks): designed but not done, because it could not be verified automatically in the game (decisions 4c).
- Unlinked subtitles: 24 speech names (24-36 strings per language, INT 31: Riddler trophy texts, Arkham City Stories, radio reports and tapes) have no event in any bank; they are listed and editable but not linked.
- Subtitle coverage is uneven in the game itself (INT voice lines with a subtitle): none for efforts/grunts, few for combat barks (9 %), cinematics and boss fights (23 %; most cutscene lines are not played through speech events and have no dialogue object), 89-97 % for story, predator, character and open-world lines. No other subtitle storage was found in the packages (all classes with subtitle data checked).
- 637 voice lines are played by no event whose name the game stores; they are named after their English recording's position (the same name in every language). Mod packages from versions before 3.1 carry no line identity: their voice lines are not moved to another language (listed instead of guessed).
- Speaker labels: 2 names of the curated lists match two recordings each (wemscan name collision), both are labelled; 19 labels differ from the game's dialogue speaker field (to be checked by listening).
- Unnamed sounds: 1,854 BANK sounds are reached by no event whose name the game stores and are named
<Bank>_<n>. - 25 SFX originals (music seek tables and sample counts, looping ambience) are not reproduced byte-for-byte by
the WEM rules (
docs/formats/wem.md); writing is not affected (replaced music plays in game). - Two copies of media
1C898731differ; its checksum is left empty. Channel order of 3-6 channel sounds: the WEMs carry WAVE channel masks and ackit keeps that order (mission 4). M4A/AAC/WMA input needs an ffmpeg on the system. - Effects are approximations set by ear; the presets are starting points. The Edit tab does not mark the lines the game itself adds an effect to (known from the bank survey, not in the catalog).
- Another game build is scanned at first start (WADs: seconds; banks, lines and subtitles: a few minutes, cached); it gets the same line identities, but no original checksums.
Next steps
- Optional: lift the subtitle length limit by relocating dialogue objects (checked in game by a person).
- Listen to the 19 lines whose speaker label differs from the game's dialogue speaker field
(
docs/categories.md) and fix the curated lists if needed; extend them (data/catalog/source/<lang>/*.txt) and rebuild the catalog.