My sound-cue write-up said the table 'does not explain' the VOICE_D_452 rejection and implied it was still open. It is not: voice-bank-leading-region.md settled it earlier -- the bank holds one generic line reused across four stages, so the binding is correct and the expectation was wrong. The narrower true statement, which is what the cue table actually adds, is that the reuse is a movie-slot -> bank relation and not a cue-level one.
100 lines
4.5 KiB
Markdown
100 lines
4.5 KiB
Markdown
# The sound-cue table, and how dialogue binds to a recording
|
||
|
||
**✅ Settled 2026-08-26.** `dat/tables.pak` carries the game's cue index. It
|
||
closes the join from a message id to the `.slb` bank that voices it — the
|
||
missing link between the script/caption side and the audio side.
|
||
|
||
## The table
|
||
|
||
One IDXD object in `dat/tables.pak` (373 680 bytes, 5 records, 10 937 fields)
|
||
holds:
|
||
|
||
| record | shape | content |
|
||
|---|---|---|
|
||
| `SETTINGS` | 3 fields | `PATH` = `game:\dat\sound.pak+`, `PARAM` = `Pj_Silph.xgs`, and a positional `BANK_SE` |
|
||
| `BANK_SE` | 1 positional | `Static.slb` |
|
||
| `FILES` | 5 135 positional | bank paths — `jpn\Voice\VOICE_TCAF_592.slb`, `BGM_001.slb`, … |
|
||
| `STAGES` | **0 fields** | present but empty |
|
||
| `SOUNDS` | 5 798 **named** | cue name → numeric sound id |
|
||
|
||
`SOUNDS` is the only record on the disc found so far that is entirely named
|
||
fields, and the names are the join key.
|
||
|
||
Cue families and their id ranges — the id space is partitioned by family, with
|
||
no overlap:
|
||
|
||
VOICE n=5044 1500 .. 7331
|
||
SE n= 322 1 .. 901
|
||
DEMO n= 295 8000 .. 8408
|
||
BR n= 101 8500 .. 8600
|
||
BGM n= 32 1001 .. 1109
|
||
JNGL n= 3 1201 .. 1203
|
||
|
||
5 797 of the 5 798 values are numeric and **all 5 797 are distinct** — the ids
|
||
are unique, so the id is not how banks get shared. One cue's value is
|
||
non-numeric.
|
||
|
||
The id is **not** an index into `FILES`: ids run to 8 600 and `FILES` has only
|
||
5 135 entries. `FILES` is reached by *name*, not by id.
|
||
|
||
## The join: a message id to a recording
|
||
|
||
MSG_VOICE_D_257 (built-in 64's operand, see isl-message-dialogue-link.md)
|
||
-> cue VOICE_D_257 `MSG_` becomes `VOICE_`
|
||
-> id 6945 SOUNDS
|
||
-> bank jpn\etc\VOICE_D_257.slb FILES, matched on stem
|
||
|
||
The prefix rule has one wrinkle, and getting it wrong is easy:
|
||
|
||
* **`MSG_` is replaced by `VOICE_`** — it is not simply stripped.
|
||
* A name that already carries `VOICE_` keeps the one it has rather than
|
||
doubling it: `MSG_VOICE_D_257` → `VOICE_D_257`, but `MSG_TCAF_592` →
|
||
`VOICE_TCAF_592` (not `TCAF_592`).
|
||
|
||
**I got this wrong first.** Stripping `MSG_` resolved 1 250 of 1 338 script
|
||
message names and left 88 unresolved, and the 88 were exactly the four-letter
|
||
ship families (`ADAN` 32, `ADPL` 27, `TCAF` 12, `ACRO` 3, `RHIN` 2) — which I
|
||
was ready to write up as "text-only announcements with no recording". Seeing
|
||
`jpn\Voice\VOICE_TCAF_592.slb` in `FILES` refuted that: the recordings exist,
|
||
my rule was wrong. Under the corrected rule the count is **1 326 of 1 338**.
|
||
|
||
`SOUNDS` and `FILES` agree exactly — the same 12 names are absent from both,
|
||
and **every one of the 5 135 bank files has a cue** (zero orphans). 663 cues
|
||
have no bank file; those are `SE`/`BGM`-family cues living in other banks.
|
||
|
||
## The 12 script lines with no recording
|
||
|
||
MSG_VOICE_A_273 MSG_VOICE_D_183
|
||
MSG_VOICE_D_600 … MSG_VOICE_D_608 MSG_VOICE_D_611
|
||
|
||
All twelve are in the `VOICE` family, have caption text, are called from the
|
||
stage scripts, and have neither a cue nor a bank. Ten of them form the near
|
||
contiguous block `D_600`–`D_611`. Whether they are subtitle-only by design or
|
||
a late cut is **not settled** — the shape (a contiguous high block) suggests
|
||
lines added after the recording sessions, but that is a guess, not a
|
||
measurement.
|
||
|
||
## What this does *not* settle
|
||
|
||
* **The wrong-recording case was already explained, and I overstated it as
|
||
open.** On first writing this page I said the cue table "does not explain"
|
||
the `hokyu_DS_s13A → VOICE_D_452` rejection and that the sharing must
|
||
therefore live deeper. That was careless:
|
||
[voice-bank-leading-region.md](../voice-bank-leading-region.md) settled it
|
||
earlier — the bank holds one **generic** line ("Resupply complete. You are
|
||
cleared for take-off!") reused across four stages, so the binding is right
|
||
and only the expectation was wrong. What this table adds is narrower and
|
||
worth stating precisely: the reuse is a **movie-slot → bank** relation, not a
|
||
cue-level one, because all 5 797 numeric cue ids are distinct and no two cues
|
||
name the same bank file.
|
||
* **`STAGES` is empty**, and what would have populated it is unknown.
|
||
* **`SOUNDS`' one non-numeric value** was not chased down.
|
||
* Only the English pack and the `jpn\` bank paths were examined. Every path in
|
||
`FILES` begins with `jpn\`, which is consistent with the already-recorded
|
||
finding that the voice set is Japanese, but the other language packs'
|
||
tables were not diffed against this one.
|
||
|
||
## Tool
|
||
|
||
tools/re-capture/sound_cues.py summary | resolve <MSG_id> | demo | unbound
|