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
This commit is contained in:
@@ -2529,6 +2529,39 @@ whatever it returns — the same reason a truncated log and a t=0 render both lo
|
||||
fine from inside. Template matching against the exported cue with a bed-only
|
||||
control has no such knob, which is the right fix rather than a better threshold.
|
||||
|
||||
## 🟡 2026-08-30 (later) — the loop IS a runtime field. **Change nothing yet.**
|
||||
|
||||
`loop_start` / `loop_end` live in the **XMA decoder context**, set by
|
||||
`XMASetLoopData`, and Xenia already logs them — no patch needed. Read from the menu:
|
||||
|
||||
| ctx | wave | loop_start | loop_end | loop_count |
|
||||
|---|---|---|---|---|
|
||||
| 0 | 3 876 864 B | 3 605 682 | 25 640 423 | 255 |
|
||||
| 1 | 3 930 112 B | 3 539 158 | 26 216 351 | 255 |
|
||||
|
||||
✅ Also decoded: the stream plays from offset **32**, and `loop_start` is where it
|
||||
returns *after* `loop_end` — so the first pass is longer than later cycles. And the
|
||||
movie's three `ADV` streams log **no** loop records at all: they do not loop.
|
||||
|
||||
🔴 **But two of my predictions are refuted and there is a conflict I cannot
|
||||
resolve**, so **do not re-author `loop_end_s` from this**:
|
||||
|
||||
* `loop_start` is **not ~0** — it is 11.6 % into the stream.
|
||||
* A linear bits→seconds conversion gives **62.34 s** and **63.29 s** for two stems
|
||||
that must stay sample-synchronous. 0.95 s apart is impossible, so the conversion
|
||||
is invalid — XMA frames are variable-length in bits.
|
||||
* That implies a cycle of roughly **[10 s, 72 s]**, against the **0.25 … 57.18 s**
|
||||
my audio tracking reported. Both cannot be right.
|
||||
|
||||
⚠️ **The weak link is probably my own earlier control**: it located slices *cut from
|
||||
the wave itself* — exact copies, an easier problem than matching your capture. A
|
||||
control easier than the measurement does not bound its error.
|
||||
|
||||
**The 61.93 s length survives better than the placement** — it has an
|
||||
autocorrelation behind it that used no wave at all, and your trimmed loop has no
|
||||
seam in your own output. Keep what you shipped.
|
||||
[`menu-bgm-loop-fields-conflict.md`](../re/structures/menu-bgm-loop-fields-conflict.md)
|
||||
|
||||
## ✅ 2026-08-30 — the menu BGM loops at **61.93 s**, and there is **no seam**
|
||||
|
||||
**Measured, 240 s parked on the menu.** Your authored loop is wrong in both
|
||||
|
||||
40
docs/re/data/menu-bgm-xma-loop-fields.txt
Normal file
40
docs/re/data/menu-bgm-xma-loop-fields.txt
Normal file
@@ -0,0 +1,40 @@
|
||||
# The XMA context's loop fields for the menu bed, read from the running game.
|
||||
#
|
||||
# 2026-08-30. run-canary --gpu=null --xma_param_probe=true --log_mask=13
|
||||
# --log_level=3 (log_mask DISABLES categories: 13 = Kernel+Cpu+Gpu off, APU ON,
|
||||
# and XELOGAPU is debug level, hence level 3). No Canary patch was needed --
|
||||
# UpdateLoopStatus already logs these.
|
||||
#
|
||||
# Menu reached by the log oracle in 26.8 s; 45 s hold; 8 734 'Looped Data'
|
||||
# lines, ALL of them after BGM_103's contexts appear. The movie's three ADV
|
||||
# streams produce NONE, i.e. loop_count = 0 on them.
|
||||
#
|
||||
# ctx -> wave, from the probe's own byte_size:
|
||||
# ctx0 packets=1893 byte_size=3876864 (wave 0)
|
||||
# ctx1 packets=1919 byte_size=3930112 (wave 1)
|
||||
#
|
||||
# LOOP FIELDS (bit offsets; loop_count 255 = infinite):
|
||||
# ctx0 loop_start = 3 605 682 loop_end = 25 640 423 len = 22 034 741
|
||||
# ctx1 loop_start = 3 539 158 loop_end = 26 216 351 len = 22 677 193
|
||||
#
|
||||
# READ-OFFSET TRAJECTORY over the 45 s hold:
|
||||
# ctx0 min 32 max 16 944 845 ctx1 min 32 max 17 165 054
|
||||
# 20.0 % of samples are BELOW loop_start in both.
|
||||
# Neither reaches loop_end, so NO WRAP was observed in this run.
|
||||
#
|
||||
# => playback starts at offset 32 (the first packet header) and runs forward;
|
||||
# loop_start is where it returns AFTER loop_end. The first pass is longer
|
||||
# than the cycles that follow.
|
||||
#
|
||||
# 🔴 A LINEAR bits->seconds conversion is INVALID. Applied to each stem with
|
||||
# its own byte_size it gives:
|
||||
# ctx0 62.34 s ctx1 63.29 s
|
||||
# Two stems that play sample-synchronously cannot have loop durations 0.95 s
|
||||
# apart, so the linearity assumption is refuted by the data itself. XMA frames
|
||||
# are variable-length in bits.
|
||||
#
|
||||
# 🔴 AND IT CONFLICTS with the audio measurement. loop_start at 3.6 M of
|
||||
# 31.0 M bits is 11.6 % in; linearly that is ~10 s, so the cycle would be
|
||||
# roughly [10 s, 72 s] of the wave. The audio wave-offset tracking
|
||||
# (menu-bgm-loop-measured.txt) put the observed offsets at 0.25 .. 57.18 s.
|
||||
# Both cannot be right. Unresolved.
|
||||
80
docs/re/structures/menu-bgm-loop-fields-conflict.md
Normal file
80
docs/re/structures/menu-bgm-loop-fields-conflict.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# 🟡 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.
|
||||
@@ -83,6 +83,24 @@ nothing every cycle". **The game never reaches the fade.** It loops before it.
|
||||
* **Expect no silence at the seam.** If your loop has one, that is your loop.
|
||||
* Play **both waves summed**, aligned at 0, unchanged.
|
||||
|
||||
## 🔴 Contested (2026-08-30, later) — read the XMA context page before using the offsets
|
||||
|
||||
Reading `loop_start` / `loop_end` out of the running decoder
|
||||
([`menu-bgm-loop-fields-conflict.md`](menu-bgm-loop-fields-conflict.md)) puts the
|
||||
cycle's **start** at ~11.6 % into the wave, where this page's locator put the
|
||||
observed offsets at 0.25 s. **Both cannot be right.**
|
||||
|
||||
⚠️ **And the weak link is likely this page's control.** It located slices **cut from
|
||||
the wave itself** — exact copies, a far easier problem than matching a real capture
|
||||
that differs by decoder, gain and mix. A control easier than the measurement does not
|
||||
bound the measurement's error. The clean +5.00 s stepping shows the locator is
|
||||
*self-consistent*; it does not show it locked to the right phrase, and music with
|
||||
repeated sections is where a locator aliases.
|
||||
|
||||
**The 61.93 s period survives better than the placement**: it is corroborated by an
|
||||
autocorrelation that used no wave at all, and the port's trimmed loop plays without
|
||||
a seam. Treat the *length* as measured and the *start* as open.
|
||||
|
||||
## Reach
|
||||
|
||||
⚠️ **One boot, one screen, one bank.** `BGM_103` on the main menu.
|
||||
|
||||
Reference in New Issue
Block a user