No Canary patch was needed: UpdateLoopStatus already logs loop_start/loop_end, they just need the Apu category (--log_mask=13 --log_level=3). Decoded, from the menu, 8734 records all after BGM_103's contexts appear: ctx0 (wave 3876864) loop_start 3605682 loop_end 25640423 loop_count 255 ctx1 (wave 3930112) loop_start 3539158 loop_end 26216351 loop_count 255 The movie's three ADV streams log NO loop records -- they do not loop. Semantics visible in the trajectory: read_offset runs from 32 upward and 20 % of samples sit below loop_start, so the stream plays from the beginning and loop_start is where it returns AFTER loop_end. No wrap was observed -- the 45 s hold ended with read_offset at 17 M against a loop_end of 25.6 M. Two registered predictions REFUTED. loop_start is not ~0 but 11.6 % in. And a linear bits-to-seconds conversion is invalid: it gives 62.34 s and 63.29 s for two stems that must play sample-synchronously, which is impossible, so the data refutes the assumption on its own. That leaves a conflict I am not resolving: the field implies a cycle of roughly [10 s, 72 s]; my audio tracking reported offsets 0.25..57.18 s. Recorded as contested, with the likely weak link named as mine -- that locator's control used slices cut from the wave itself, exact copies, which is an easier problem than matching a real capture, and a control easier than the measurement does not bound its error. The port is told to change nothing: its trimmed 61.93 s loop is verified in its own output, and the length survives better than the placement. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
3.8 KiB
🟡 The loop point IS a runtime field — and reading it contradicts the audio measurement
Classification: decoded (the fields and their values) plus an unresolved conflict (what they mean in seconds). Xenia Canary, 2026-08-30, one boot, 45 s on the menu. The port should change nothing on the strength of this page.
✅ The loop point is not absent from the format
bgm-two-stems.md says "no loop-point field has been
identified in the XMA header, so a menu loop is authored". That is true of the
file header and it left the wrong impression. The loop lives in the XMA
decoder context, set at runtime by XMASetLoopData, and Xenia's
UpdateLoopStatus already logs it — no patch was needed, only the Apu log
category (--log_mask=13 --log_level=3).
| ctx | wave | loop_start |
loop_end |
loop_count |
|---|---|---|---|---|
| 0 | 3 876 864 B | 3 605 682 | 25 640 423 | 255 (infinite) |
| 1 | 3 930 112 B | 3 539 158 | 26 216 351 | 255 |
Bit offsets. 8 734 records, every one after BGM_103's contexts appear — the
movie's three ADV streams log none at all, i.e. they do not loop.
✅ And the semantics are visible in the trajectory. input_buffer_read_offset
runs from 32 (the first packet header) upward, and 20 % of samples sit below
loop_start — so the stream plays from the beginning, and loop_start is where
it returns after loop_end. The first pass is longer than the cycles after it.
⚠️ No wrap was observed. Max read offset was 16.9 M / 17.2 M against a
loop_end of 25.6 M / 26.2 M — the 45 s hold was too short. The jump itself is
inferred from the field semantics, not watched.
🔴 Two things I predicted are refuted
1. "loop_start ≈ 0" — no. It is ~3.5–3.6 M bits, 11.4–11.6 % into the stream.
I registered that prediction before the run and it is wrong.
2. A linear bits→seconds conversion — invalid, and the data proves it. Applied
to each stem with its own byte_size:
| linear loop duration | |
|---|---|
| ctx0 | 62.34 s |
| ctx1 | 63.29 s |
Two stems that play sample-synchronously cannot have loop durations 0.95 s apart — they would drift a second per cycle. So the assumption fails on its own output. XMA frames are variable-length in bits, which is exactly why.
🔴 The conflict, stated rather than resolved
loop_start at 11.6 % of the stream implies a cycle of roughly [10 s, 72 s] of
the 87.744 s wave. But
menu-bgm-loop-measured.md put the observed wave
offsets at 0.25 … 57.18 s. Both cannot be true.
⚠️ And the weakness is probably mine. That page's locator control used slices cut from the wave itself, which are exact copies — a far easier matching problem than a real capture, which differs by decoder, gain and mix. A control that is easier than the measurement does not bound the measurement's error, and music with repeated phrases is exactly where a locator aliases. The clean +5.00 s stepping shows the locator is self-consistent; it does not show it locked to the right phrase.
So the honest position is:
| claim | status |
|---|---|
| the loop is a runtime field, with these values | ✅ decoded |
| the movie streams do not loop | ✅ decoded |
| the cycle is 61.93 s | 🟡 measured from audio, and its control was too easy |
| where the cycle starts in the wave | 🔴 contested — 0.25 s from audio, ~10 s from the field |
| bits → seconds | ❔ needs an XMA frame walk; not done |
What the port should do: nothing yet
Its shipped loop — trim to 61.930 s — is verified in its own output and has no seam.
Do not re-author it from this page. What would settle it is walking the XMA
frame headers to convert loop_start/loop_end honestly, and a hold long enough to
watch a wrap rather than infer it. Neither is done.