re: the voice region s leading chunk is the movie s OWN dialogue, and a guard puts it there

My own leading hypothesis -- that the leading chunk is an in-mission VOICE_D_*
line -- is refuted, on the route the port suggested: widen the enumeration past
the 95 manifest-bound movies and the byte-span test settles it without anyone
listening.

Scanning the stream for every trailer descriptor (the (id, 0x11) pair whose id
repeats at +0x800) gives the complete cue partition, mission lines included:
287 descriptors in a 116.2 MB window, all 287 carrying an id the 4280-name
registry names. Every one of the 17 leading spans is bracketed by
desc(N-1)..desc(N) where desc(N) is that movie s OWN cue id. Zero mission lines.

The mechanism is a guard in our own resolver. resolve_movie_voice_region takes
the predecessor trailer as the region start, guards it with
end - start < 1_500_000, and falls back to the .slb TOC anchor when that fails.
Cues with a true span over the guard: 17, of which 17 are stream-opening. Cues
under it: 78, of which 0. Perfect discrimination both ways. The anchor sits a
constant 504464 B after the true predecessor trailer on all 17, which is
unexplained.

Not established, and stated as such: this does NOT mean the export truncates N
seconds. The port s decode already has ADV s region at 359 s against a 137 s
movie, so it over-covers and the byte-to-time mapping is not linear. No XMA1
decoder in this container to check.

Also withdraws a claim this page had adopted from the port -- that chunks 1 and
2 are two stems of one performance. The port refuted its own claim by decoding:
S00A chunk 2 is digital silence, ADV chunk 2 is 0.60x chunk 1 with the residual
26.8 dB down. Equal duration was a shape match and Q10 s music census should not
have been carried across to voice on it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
This commit is contained in:
sylph-decoder
2026-08-29 15:03:58 +00:00
parent de2fe4a110
commit 432fb7450b
4 changed files with 361 additions and 39 deletions

View File

@@ -0,0 +1,50 @@
registry: 4280 cue names, 4280 distinct ids
scanning dat/sound 421739888..537953648 (116.2 MB)
287 trailer descriptors found
of those, 287 carry an id the registry names, 0 do not
leading span -> owning cue
ADV lead 808304 B bracketed by desc@Some((433425776, 1528)) .. desc@Some((437044592, 1600)) owner VOICE_ADV [movie cue]
S00A lead 1324400 B bracketed by desc@Some((452294000, 1500)) .. desc@Some((455499120, 1501)) owner VOICE_S00A [movie cue]
S01A lead 1154416 B bracketed by desc@Some((455499120, 1501)) .. desc@Some((460117360, 1502)) owner VOICE_S01A [movie cue]
S02B lead 431472 B bracketed by desc@Some((461518192, 1503)) .. desc@Some((463838576, 1504)) owner VOICE_S02B [movie cue]
S02C lead 1869168 B bracketed by desc@Some((463838576, 1504)) .. desc@Some((469970288, 1506)) owner VOICE_S02C [movie cue]
S03A lead 253296 B bracketed by desc@Some((469970288, 1506)) .. desc@Some((472020336, 1507)) owner VOICE_S03A [movie cue]
S04B lead 556400 B bracketed by desc@Some((480003440, 1508)) .. desc@Some((482938224, 1509)) owner VOICE_S04B [movie cue]
S06A lead 351600 B bracketed by desc@Some((483433840, 1510)) .. desc@Some((485457264, 1511)) owner VOICE_S06A [movie cue]
S06B lead 607600 B bracketed by desc@Some((485457264, 1511)) .. desc@Some((488908144, 1512)) owner VOICE_S06B [movie cue]
S07A lead 505200 B bracketed by desc@Some((488908144, 1512)) .. desc@Some((491443568, 1513)) owner VOICE_S07A [movie cue]
S09B lead 177520 B bracketed by desc@Some((491634032, 1514)) .. desc@Some((493743472, 1515)) owner VOICE_S09B [movie cue]
S11C lead 742768 B bracketed by desc@Some((502173040, 1517)) .. desc@Some((505619824, 1518)) owner VOICE_S11C [movie cue]
S12C lead 1844592 B bracketed by desc@Some((506262896, 1520)) .. desc@Some((512406896, 1521)) owner VOICE_S12C [movie cue]
S13A lead 402800 B bracketed by desc@Some((512406896, 1521)) .. desc@Some((514874736, 1522)) owner VOICE_S13A [movie cue]
S14A lead 1817968 B bracketed by desc@Some((515278192, 1523)) .. desc@Some((521794928, 1524)) owner VOICE_S14A [movie cue]
S15A lead 255344 B bracketed by desc@Some((521794928, 1524)) .. desc@Some((524309872, 1525)) owner VOICE_S15A [movie cue]
S15C lead 931184 B bracketed by desc@Some((525626736, 1526)) .. desc@Some((529565040, 1527)) owner VOICE_S15C [movie cue]
verdicts: {"movie cue": 17}
cue span vs the 1.5 MB guard, and what the region actually starts at:
ADV true cue span 3618816 B (> guard: true) region starts at 433930240, true start 433425776 -> 504464 B of the cue's own audio is OUTSIDE the region
S00A true cue span 3205120 B (> guard: true) region starts at 452798464, true start 452294000 -> 504464 B of the cue's own audio is OUTSIDE the region
S01A true cue span 4618240 B (> guard: true) region starts at 456003584, true start 455499120 -> 504464 B of the cue's own audio is OUTSIDE the region
S02B true cue span 2320384 B (> guard: true) region starts at 462022656, true start 461518192 -> 504464 B of the cue's own audio is OUTSIDE the region
S02C true cue span 6131712 B (> guard: true) region starts at 464343040, true start 463838576 -> 504464 B of the cue's own audio is OUTSIDE the region
S03A true cue span 2050048 B (> guard: true) region starts at 470474752, true start 469970288 -> 504464 B of the cue's own audio is OUTSIDE the region
S04B true cue span 2934784 B (> guard: true) region starts at 480507904, true start 480003440 -> 504464 B of the cue's own audio is OUTSIDE the region
S06A true cue span 2023424 B (> guard: true) region starts at 483938304, true start 483433840 -> 504464 B of the cue's own audio is OUTSIDE the region
S06B true cue span 3450880 B (> guard: true) region starts at 485961728, true start 485457264 -> 504464 B of the cue's own audio is OUTSIDE the region
S07A true cue span 2535424 B (> guard: true) region starts at 489412608, true start 488908144 -> 504464 B of the cue's own audio is OUTSIDE the region
S09B true cue span 2109440 B (> guard: true) region starts at 492138496, true start 491634032 -> 504464 B of the cue's own audio is OUTSIDE the region
S11C true cue span 3446784 B (> guard: true) region starts at 502677504, true start 502173040 -> 504464 B of the cue's own audio is OUTSIDE the region
S12C true cue span 6144000 B (> guard: true) region starts at 506767360, true start 506262896 -> 504464 B of the cue's own audio is OUTSIDE the region
S13A true cue span 2467840 B (> guard: true) region starts at 512911360, true start 512406896 -> 504464 B of the cue's own audio is OUTSIDE the region
S14A true cue span 6516736 B (> guard: true) region starts at 515782656, true start 515278192 -> 504464 B of the cue's own audio is OUTSIDE the region
S15A true cue span 2514944 B (> guard: true) region starts at 522299392, true start 521794928 -> 504464 B of the cue's own audio is OUTSIDE the region
S15C true cue span 3938304 B (> guard: true) region starts at 526131200, true start 525626736 -> 504464 B of the cue's own audio is OUTSIDE the region
cues over the 1.5 MB guard: 17, of which stream-opening: 17
cues under the guard: 78, of which stream-opening: 0

View File

@@ -2,7 +2,9 @@
**Status:** ✅ the *structure* is decoded, disc-wide, 95/95 regions. 🟡 what the
leading chunk **contains** is open, and this page states the reach of that
negative rather than guessing.
negative rather than guessing. 🔴 One claim this page carried — that chunks 1 and
2 are two stems of one performance — is **withdrawn**; see
[the bottom of the page](#what-a-consumer-should-do-meanwhile).
Raised by the port: `media::sound_bank_riffs("BGM_103.slb")` used to return three
sub-waves where [`bgm-two-stems`](bgm-two-stems.md) says two, and
@@ -75,36 +77,107 @@ where another region ends; **0 of 17** leading-stream regions do.
So the leading chunk is not another *movie's* voice.
## 🟡 What it is, is open — and here is the reach
## ✅ RESOLVED 2026-08-29 — the leading chunk is the MOVIE'S OWN cue, and the mechanism is a guard
What is established: the leading chunk is a whole number of XMA1 packets at the
disc's own derived data offset, inside this movie's region, claimed by no other
movie-voice region. What is **not** established is what it sounds like.
The section that stood here left this open and named an in-mission `VOICE_D_*`
line as the leading hypothesis. **That hypothesis is refuted.** The port pointed
out that the byte-span test already built settles it without anyone listening, if
the enumeration is widened past the 95 manifest-bound movies — and it does.
The reach of the negative, stated plainly:
Rather than resolving cues one at a time, scan the stream for **every** trailer
descriptor: the `(id: u32be, 0x11, …)` pair whose id repeats at `+0x800`, which
[`movie_voice`](../../crates/sylpheed-formats/src/movie_voice.rs) documents as
the end of a cue's audio, with a false-match probability of ~2⁻⁶⁴. The full
descriptor list **is** the stream's complete cue partition, movie and mission
alike. Over a 116.2 MB window covering every region: **287 descriptors, and all
287 carry an id the registry names** (4 280 cue names).
* The census enumerates the **95 movie-voice regions the manifest binds in
English**. The same stream also carries the in-mission voice cues
(`VOICE_D_*`), which are *not* enumerated here. The leading bytes could belong
to one of those, and this test would not see it. **That is the leading
hypothesis and it is untested.**
* 🔴 **It could not be settled by listening in this container.** There is no XMA1
decoder here — `sylpheed-cli audio info` reports `decode not supported (needs
an XMA2 decoder + the sound-bank descriptor)`, and its header read of these
chunks is visibly wrong (16 channels, 4310 Hz, 2-bit depth), so it cannot even
be used for durations. Settling this needs a decoder run, which the port has
and this container does not.
Tool: `cargo run -p sylpheed-formats --example voice_stream_cue_map -- $SYLPHEED_DISC`,
output at [`data/voice-stream-cue-map.txt`](../data/voice-stream-cue-map.txt).
### The leading span belongs to the movie itself — 17 of 17
Each leading span is bracketed by `desc(N-1) .. desc(N)`, and in every case
`desc(N)` is **that movie's own cue id**:
| movie | leading span ends at descriptor | |
|---|---|---|
| `ADV` | id 1600 = `VOICE_ADV` | movie cue |
| `S00A` | 1501 = `VOICE_S00A` | movie cue |
| `S14A` | 1524 = `VOICE_S14A` | movie cue |
| …all 17 | | **movie cue, 0 mission lines** |
By the stream's own rule — cue N's audio is `[desc(N-1) .. desc(N)]` — those
bytes are **this movie's dialogue**. 🔴 So "it is an in-mission `VOICE_D_*` line"
is dead, and so is any reading in which the leading chunk is foreign audio.
### ✅ And the mechanism is `resolve_movie_voice_region`'s own guard
`resolve_movie_voice_region` takes the predecessor trailer as the region start,
but guards it with `end - start < 1_500_000` and falls back to the `.slb` TOC
**anchor** when that fails. If the guard is the cause, the stream-opening regions
should be exactly the cues whose true span exceeds it:
| | cues | of which stream-opening |
|---|---|---|
| true cue span **≥ 1.5 MB** | **17** | **17** |
| true cue span **< 1.5 MB** | **78** | **0** |
**Perfect discrimination, both ways.** A long cue's region does not start at its
cue boundary; it starts at the anchor, mid-cue, and everything from the anchor to
the next `.slb` `RIFF` becomes the leading chunk. That is the whole phenomenon.
⚠️ **The anchor sits a constant `504 464 B` after the true predecessor trailer on
all 17** — not an approximate constant, the same number every time. That
regularity is unexplained and is worth someone's attention; it says the `.slb`
chunk boundary is placed at a fixed distance from a trailer.
### ⚠️ What this does NOT establish — do not convert bytes into missing seconds
It is tempting to read "504 464 B of the cue's own audio lies outside the region"
as *the export truncates 246 packets of dialogue*. **Do not.** The port's decode
of `ADV`'s region already yields **359 s against a 137 s movie**, so the region
over-covers rather than under-covers, and the byte↔time mapping is plainly not
linear — consistent with more than one sub-stream being interleaved. Bytes are
what was measured here; seconds are not, and this container has no XMA1 decoder
to get them.
**So what remains open is narrower and better posed than before:** not *whose
audio is this* (answered: the movie's own), but *why one cue's byte span decodes
to ~2.6× the movie's duration*, and what `ADV` chunk 2 — a 0.60 × scaled copy of
chunk 1 — is doing in it.
## What a consumer should do meanwhile
🟡 Dropping the leading chunk is **defensible and should stay labelled**, which is
what the port already does. It is not junk and it is not a header — it is
undecoded audio — so the manifest note must not harden into "the bank had a
spurious chunk". If it turns out to be an in-mission line, dropping it is
correct; if it turns out to be part of the cutscene, it is a truncation.
🔴 **Dropping the leading chunk is dropping the cutscene's own dialogue** — that
is now measured, not suspected, and the manifest note must not say or imply that
the bank had a spurious chunk. ⚠️ It does **not** follow that simply including it
is right: the region already decodes to ~2.6× the movie's length, so inclusion is
a decoding question that is still open, and this page has moved it rather than
closed it. What is settled is the *provenance* of those bytes.
⚠️ **Do not "fix" it by concatenating.** The port measured a concatenated region
at 359 s against a 137 s movie, and chunks 1 and 2 are the two-stem pattern
[`bgm-two-stems`](bgm-two-stems.md) documents for music — equal duration, played
together, not in sequence. Concatenation is wrong here for the same reason it is
wrong there.
at 359 s against a 137 s movie.
🔴 **But the REASON this page gave was wrong, and is withdrawn (2026-08-29).**
It said chunks 1 and 2 are "the two-stem pattern [`bgm-two-stems`](bgm-two-stems.md)
documents for music — equal duration, played together". That claim originated
with the port, I adopted it here on the strength of equal duration, and the port
then refuted its own claim by decoding the content:
* **`S00A` chunk 2 is digital silence** — 4 497 300 samples, peak −∞. Not a quiet
stem. Nothing at all.
* **`ADV` chunk 2 is `0.60 ×` chunk 1** — best-fit scalar, residual **26.8 dB
below** the target. ~95 % of its energy is a 4.4 dB copy of chunk 1, not an
independent performance.
Equal duration was a *shape* match and Q10's music census should not have been
carried across to voice on it. ⚠️ **This is how a wrong belief hardens**: it was
asserted in one place, adopted in a second, and the second citing the first would
have made it look corroborated. It was caught because the port measured its own
claim rather than the other agent's.
**What `ADV`'s near-duplicate chunk 2 is remains open** — a decoding question,
not a port one. What is *not* open is that summing a digitally silent chunk at
`1/n` costs 6.02 dB for nothing; the port drops silent chunks before summing,
which is arithmetic rather than a content judgement.