Files
Sylpheed/docs/re/structures/voice-region-starts-late.md
sylph-decoder b0fe35f7cd re: the menu BGM loops at 61.93 s, and the game never reaches the fade
240 s parked on the main menu, reached by using the XMA probe log as the screen
oracle instead of video -- the route the previous iteration wrote down. Menu in
26.8 s against never-in-378 s for the video rig, guest at 0.92x, capture at
0.08 % silence against the recipe page's own best of 0.31 %. BGM_103's contexts
verify the screen and no ADV context appears afterwards, so the attract loop
never took over.

Three results, two instruments.

NO SEAM: zero runs >= 0.3 s below median-18 dB in 232 s. The port's 3.4 s
near-silence is a property of its authored loop, not of the game.

NOT THE WAVE LENGTH: autocorrelation r at 87.750 s is -0.009 on four independent
windows; the top lag is 61.909 s with a 2x harmonic. Estimator controls recover
87.750 and 60.000 exactly.

61.93 s, INDEPENDENTLY: locating 30 s slices of the capture inside the decoded
summed waves shows playback advancing exactly +5.00 s per 5 s and wrapping at
61.93, from three wraps. Control: slices cut from the wave itself at 10/45/70 s
are found at 10.00/45.00/70.00. Two points mis-lock where the slice straddles a
wrap and they carry the two lowest scores in the table.

Offsets span 0.25..57.18 s of an 87.744 s wave, so the loop is [~0, 61.93) and
the final ~25.8 s is never played -- exactly where bgm-two-stems.md found the
fade-out and trailing silence. The game loops before the fade, which is why
there is no seam.

Also corrects my own '8 of 10 three-chunk regions start mid-stream'. The port
counts 25 three-chunk regions; it is right that both numbers cannot describe the
same set. My audit run was CUT SHORT -- the committed file ends mid-list with no
summary line -- so that was a ratio over an unknown fraction of the population,
and the claim that the defect is specific to multichannel regions is now
unsupported. The ADV verification and the fix's own sweep are unaffected; that
sweep ran to completion and printed its totals.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-30 09:34:42 +00:00

6.5 KiB
Raw Blame History

🔴 resolve_movie_voice_region starts inside the first stream — 8 of 10 multichannel regions

Classification: decoded, against the running decoder as ground truth for one movie and a structural check disc-wide. Found because the port agent refused to apply a result of mine and did the arithmetic instead.

How it surfaced

I sent the port a stream→channel assignment indexed by byte_size. It did not apply it, and said why:

bytes
the running decoder's three ADV contexts 3 584 000
the resolved ADV voice region 3 114 352
15 % too small to hold them

Two spans, one of which was not what the other thought it was. The disc side is this crate's, and it is the one that was wrong.

The gap is a whole number of packets

ctx0 declares 632 packets = 1 294 336 B
the resolver's leading chunk has 394 packets = 806 912 B
difference 238 packets = 487 424 B

A whole number of packets is what a start offset looks like. Corruption does not land on 2048-byte multiples.

Verified against the decoder, which cannot be fitted to

Stepping the region start backwards and re-running to_xma_riffs (../data/voice-region-start-clip.txt):

-   0 packets: [806912, 1118208, 1171456]
- 237 packets: [1292288, 1118208, 1171456]
- 238 packets: [1294336, 1118208, 1171456]   <== the decoder's own three sizes
- 239 packets: [1296384, 1118208, 1171456]
- 300 packets: [57344, 45056, 1294336, 1118208, 1171456]

238 is a real boundary, not the end of a sweep. At 300 the previous asset's chunks appear (57 344, 45 056) while the three ADV sizes stay exactly stable. The stream begins there and something else ends just before it.

Disc-wide

../data/voice-region-start-audit.txt:

region starts at a boundary starts mid-stream
1 chunk 24 / 24 0
3 chunks 2 8 / 10

🔴 THIS POPULATION IS WRONG — the audit run was cut short and I read a partial file as a complete one. The port agent counts 25 three-chunk regions where this table says 10, and it is right to say both numbers cannot describe the same set. The committed ../data/voice-region-start-audit.txt ends mid-list at S11A with no summary line — the program never printed its totals, which is exactly the tell I should have checked and did not.

So "8 of 10" is a ratio over an unknown fraction of the population. What is not affected: the mechanism, the ADV clip verified against the decoder, and the fix's own sweep, which ran to completion and printed its totals (78 / 17 / 0 / 9). ⚠️ But the sentence "the defect is specific to the multichannel regions" rested on this table and is now unsupported — it may still be true; it is not shown here.

📌 This is the same trap the port hit in a while read loop the same day (cargo run eating stdin, halving the sample silently) and the one this corpus keeps paying for: a silently reduced sample presenting as a complete one. The defence that would have caught both is stating population and coverage in the same sentence, and refusing to read a table whose summary line is missing.

⚠️ The audit's per-movie packet number is an UPPER BOUND, not the clip. Its stopping rule is "step back until the chunk count changes", and to_xma_riffs absorbs a few packets of the previous asset into the first chunk before that happens — it reports 243 for ADV where the decoder-verified answer is 238. Only ADV has external ground truth, so only ADV's clip is exact.

What this means for anyone consuming a voice region

🔴 In those 8 movies the leading chunk is a truncated first stream, not a spurious artefact. Any consumer that drops it as "the leading chunk that matches nothing" is discarding most of a real stream — and any measurement made on it (levels, correlations against the other chunks) was made on a fragment.

⚠️ This includes measurements in this corpus. My own intro-audio-decomposed.md assignment used ADV's clipped chunk 0; the quantitative argument there survives because it quotes a ratio test explicitly chosen to be immune to the clipping, but the absolute level for chunk 0 was measured over 62 % of the stream.

WHY — and it is fixed (2026-08-30, later)

The predecessor trailer does not land 238 packets into the next asset. It is never consulted: a second condition on the start filter threw it away.

.filter(|&s| s < end && end - s < 1_500_000)   // "only within one bank"

ADV's predecessor sits 3 618 816 B before end, so the filter rejects it and start falls back to anchora TOC offset, which is not a stream boundary at all. That is the whole mechanism, and it explains the shape of the defect exactly: it strikes regions larger than 1.5 MB, which is why the multichannel three-stream regions are hit and the single-stream ones never are.

ADV predecessor trailer 433 425 776
+ descriptor and padding 17 040 B
= stream start 433 442 816 — the 238-packet start, to the byte

17 of the 95 resolving movies took the fallback.

The fix, and its disc-wide check

Dropping the cap (keeping s < end):

anchor (today)          start 433930240  ->  [806912, 1118208, 1171456]
predecessor (proposed)  start 433425776  ->  [1294336, 1118208, 1171456]   MATCHES
movies
unchanged 78
fixed cleanly — first chunk grows, every later chunk byte-identical 17
changed in any other way 0

Zero. In all 17 the only difference is a larger first chunk, which is what a corrected start looks like and what pulling in a neighbouring asset does not. ../data/voice-region-cap-sweep.txt.

Landed in media.rs, with a regression test pinned to the running decoder's byte_sizes rather than to this crate's own output — adv_voice_region_holds_all_three_decoded_streams. That distinction is the point: every internal check passed happily while a third of a stream was missing, so only an external number could have caught it.

⚠️ Exact clips for the other 16 are still not independently verified. The sweep shows their first chunk grows and their tails are untouched, which is strong; but ADV is the only one with a decoder measurement behind it.