Files
Sylpheed/docs/re/structures/menu-bgm-loop-fields-conflict.md
sylph-decoder cf6be709ab re: the loop IS a runtime XMA field -- and reading it contradicts my audio measurement
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
2026-08-30 09:52:13 +00:00

81 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🟡 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`](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`](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.