diff --git a/adv-game-output-6ch-v3.wav b/adv-game-output-6ch-v3.wav new file mode 100644 index 00000000..88aa79fe Binary files /dev/null and b/adv-game-output-6ch-v3.wav differ diff --git a/docs/port/BLOCKED.md b/docs/port/BLOCKED.md index 07a298f4..22a6e17e 100644 --- a/docs/port/BLOCKED.md +++ b/docs/port/BLOCKED.md @@ -114,7 +114,7 @@ HANDOFF. | ~~P6 BGM — the sub-wave count~~ | ~~is a music bank's LEADING REGION a stem, or a decoder artefact?~~ | Q10 | ✅ **CLOSED 2026-08-29 — the census was right and the port was summing a bank header into the music.** Decoded and timed, sub-wave 0 of `BGM_103`, `BGM_102` and `BGM_001` is identical: **10 300 B → 0.009 s, peak −inf**, i.e. digitally silent. 10 300 B is the 10 240-byte bank header (the Decoder's disc-wide census) plus a 60-byte RIFF wrapper. So it is not a stem, and `export_bgm` had been counting it in the divisor — putting every real stem at 1/3 instead of 1/2, **3.52 dB of attenuation on all menu music shipped since P6**. Dropping a *silent* input is arithmetic, not a decoding decision, so this closed on the port's side; measured after the fix, `main_menu.ogg` goes −7.69 → **−4.20 dBFS**, +3.49 dB against 3.52 predicted. Corroborates the Decoder's `c1f3608` from the other direction. The export now reports 2 sub-waves and the manifest warning is gone. | | ~~P3 — the plate's ONSET~~ | ~~visible 2.13 s after settle, or group starts then?~~ | Q2 | ✅ **resolved 2026-08-29, and the answer is AUTHOR NOTHING.** The port's refutation held and produced a better answer than either option it offered. Correction at `5b0a6e6` on `auto/no-disc-and-menu-captures`: **both builds run on one clock, started together**, and the plate arrives at its own declared `t=238`. Checked against this export rather than taken on trust — build 4's visible build-in ends at `t=118` (`pteff01`, `pteff02`, `ptlogoall_eff` finish together), `ptbtn00` reaches alpha 255 at `t=238`, difference **120 units = 2.000 s**, against a measured 2.138 / 2.132 s at an emulator presenting 28.1 fps rather than 30. The 2.13 s constant is **deleted**. | | ~~P3/P5 — `settle_time()`~~ | ~~`rest.t` is not when a screen settles, and the port's sequencer uses it~~ | — | ✅ **MEASURED 2026-08-29 and the row was HALF WRONG — mine.** The Decoder took it on a cold profile with no shader cache (`auto/no-disc-and-menu-captures` at `4bd4779`, `docs/re/boot-settle-times-measured.md`). The principle holds: the title's `rest.t` is 251 units = **4.183 s** where its art finishes at ~2 s. **But "everything the sequencer paces off that landmark is therefore late" does not.** Measured the port the way the game was measured — visible span, `--film` at 4 fps — the publisher wordmark runs **4.25 s** against the game's 4.297/4.604/4.370 and the developer logos **3.50 s** against 3.508/3.503/3.366. Dead on. My earlier reading compared the port's *arrival-to-arrival* timestamps against the game's *visible spans*, which differ by the exit ramp plus the black hold — the whole of the discrepancy I was about to chase. `rest.t` is still the wrong landmark; its blast radius is `_script_settled` waiting longer than it needs to, which is a slow test and not a wrong frame. `dwell_seconds` stays `null`, now for a measured reason. 🔴 **Do not author an Ⓐ→menu dwell**: it measures 3.763 s and contains a 1.53 s guest load stall, third independent reproduction. 🟡 Menu build-in 0.531 s and Ⓑ→title 0.482 s rest on one run and are not authored; the port is within ~0.1 s of both from the disc. | -| P4/P7 — the voice export is INCOMPLETE | **what are the three concurrent streams, and how do they combine?** | — | 🔴 **the premise of every earlier row here was refuted by the RUNNING GAME, 2026-08-29.** Canary's `--xma_param_probe` shows the game decoding **all three streams concurrently** in three XMA contexts, byte sizes matching the disc payloads exactly (1 294 336 / 1 118 208 / 1 171 456 against 1 294 396 / 1 118 268 / 1 171 516). So they are **not** three presentations of one take, there is no "which one" to answer, and the export — which ships one — is **missing two streams the game plays**. ⚠️ **The failure sounds like success**: one stream is clean audible dialogue. Stated as a top-level manifest warning per movie, on the console, and in `authored/audio.json`. **Behaviour deliberately unchanged**: an equal-gain `1/n` sum of channel pairs is not a downmix either (MISSION §6 pins an explicit matrix for exactly this reason) and summing cost `S00A` 6.02 dB when one stream was silence — swapping one guess for another is what produced this row twice. 🟡 "They are 5.1" is the Decoder's **hypothesis**: three stereo streams is six channels and N stereo streams is how XMA carries multichannel on the 360, but all three declare `ChannelMask = 0x0002` identically, which argues against distinct roles. 🔴 **NOT OBTAINABLE THIS SESSION — both capture routes are closed, and this is now the blocker.** Take 1 (`1788018994-16f9d19d90b8`) was corrupted by a **channel-map remap**: PulseAudio remapping between mismatched maps silently drops and duplicates, proved by a tone control (six tones in, `400 / 3200 / 200 / 800 / 800 / 200` out, two source channels gone). Take 2 (`1788019777-43f27c791bef`) is **starved** — verified here independently: **35.6 % of frames silent on all six channels, 10 482 alternating runs, median burst 13.5 ms / gap 3.9 ms, a 17.4 ms period at 57 Hz.** That destroys envelope correlation by construction, so the negative it produced said nothing about the game. ⚠️ **Withdrawn with it: the reading that the game may not play the `.wmv`'s WMA track** — neither supported nor refuted by a starved file, and nothing changed on account of it. **The monitor-sink route cannot be fixed by configuration**: it advances at wall-clock rate and substitutes silence, so every moment the emulator runs slow is a hole and deleting them warps the timebase non-uniformly. The route that works is an internal tap at `SDLAudioDriver::SubmitFrame`, needing a **Canary rebuild the Decoder has costed at a whole session** — the build root `build-canary` targets does not exist in that container, the warm tree is configured against the same missing path, ~700 MB free, with prior parallel builds OOM-killing the host. **That is the human's call, not an agent's.** `tools/port/check-capture` now catches both failure modes, so no future capture costs an analysis to discover it is unusable. | +| P4/P7 — the voice export | ~~what are the three concurrent streams~~ **what do streams 1 and 3 contribute?** | — | 🟡 **HALF ANSWERED BY THE ORACLE, 2026-08-29.** A faithful capture finally exists (`1788022539-4529c72ed7fb`, ALSA tee + `--gpu=null`, 0.35 % silence, passes `check-capture`, header verified here). Fitted with the calibrated correlator against its own controls (present +0.248 / absent +0.005): **the exported voice matches the game's CENTRE channel at r = 0.989, margin +0.305**, while the movie bed matches FL/FR/RL/RR and *not* FC. So the dialogue is in FC, the bed is in the corners, and **the port's exported file is the material the game plays there** — measured, where the header (`ChannelMask = 0x0002` on all three) could never have said it. ⚠️ Streams 2 and 3 are indistinguishable to this instrument, as expected from stream 3 being 0.60× stream 2 with 26.8 dB residual; stream 1 is undetectable in a 59.7 s window, consistent with being stream 2's tail. 🔴 **The `1 of 3` warning stays** — nothing here says what the other two contribute. Reach: 59.7 s of a 137 s movie, one run, no screen provenance (the `--gpu=null` route costs video; provenance is the XMA probe). OLD ROW BELOW. 🔴 **the premise of every earlier row here was refuted by the RUNNING GAME, 2026-08-29.** Canary's `--xma_param_probe` shows the game decoding **all three streams concurrently** in three XMA contexts, byte sizes matching the disc payloads exactly (1 294 336 / 1 118 208 / 1 171 456 against 1 294 396 / 1 118 268 / 1 171 516). So they are **not** three presentations of one take, there is no "which one" to answer, and the export — which ships one — is **missing two streams the game plays**. ⚠️ **The failure sounds like success**: one stream is clean audible dialogue. Stated as a top-level manifest warning per movie, on the console, and in `authored/audio.json`. **Behaviour deliberately unchanged**: an equal-gain `1/n` sum of channel pairs is not a downmix either (MISSION §6 pins an explicit matrix for exactly this reason) and summing cost `S00A` 6.02 dB when one stream was silence — swapping one guess for another is what produced this row twice. 🟡 "They are 5.1" is the Decoder's **hypothesis**: three stereo streams is six channels and N stereo streams is how XMA carries multichannel on the 360, but all three declare `ChannelMask = 0x0002` identically, which argues against distinct roles. 🔴 **NOT OBTAINABLE THIS SESSION — both capture routes are closed, and this is now the blocker.** Take 1 (`1788018994-16f9d19d90b8`) was corrupted by a **channel-map remap**: PulseAudio remapping between mismatched maps silently drops and duplicates, proved by a tone control (six tones in, `400 / 3200 / 200 / 800 / 800 / 200` out, two source channels gone). Take 2 (`1788019777-43f27c791bef`) is **starved** — verified here independently: **35.6 % of frames silent on all six channels, 10 482 alternating runs, median burst 13.5 ms / gap 3.9 ms, a 17.4 ms period at 57 Hz.** That destroys envelope correlation by construction, so the negative it produced said nothing about the game. ⚠️ **Withdrawn with it: the reading that the game may not play the `.wmv`'s WMA track** — neither supported nor refuted by a starved file, and nothing changed on account of it. **The monitor-sink route cannot be fixed by configuration**: it advances at wall-clock rate and substitutes silence, so every moment the emulator runs slow is a hole and deleting them warps the timebase non-uniformly. The route that works is an internal tap at `SDLAudioDriver::SubmitFrame`, needing a **Canary rebuild the Decoder has costed at a whole session** — the build root `build-canary` targets does not exist in that container, the warm tree is configured against the same missing path, ~700 MB free, with prior parallel builds OOM-killing the host. **That is the human's call, not an agent's.** `tools/port/check-capture` now catches both failure modes, so no future capture costs an analysis to discover it is unusable. | | ~~P3/P5 — the title plate~~ | ~~does the idle title show `PRESS Ⓐ`~~ | Q2 | ✅ **answered and TAKEN at this iteration.** `auto/no-disc-and-menu-captures` at `fb536df`, `docs/re/title-plate-delay-measured.md`, traces in `docs/re/data/plate-timing-run{1,2}.tsv`. It is the third case: build 4 alone, then the plate composited over it. ⚠️ The delay is timed from where build 4 **stops animating**, not from where it first appears — measured the other way the two runs differ by 0.48 s against 6 ms. `ScreenView` now draws two builds at once, as a second `ScreenView` in the same `SubViewport` rather than a subordinate screen inside one. The onset question above is what is left. | | P3 — the plate's PULSE | **does the plate's focus record loop, and with what period?** | Q2 | ❔ **open, and the port's earlier reading of it was wrong.** The port had looked for the pulse in `ptbtn00`'s own group; `5b0a6e6` identifies it as the plate's **focus record** `ptbtn00f` — a glow ramping alpha `0x00`→`0x50` and back, t=6…105. Measured on the running game at 2.12 / 2.19 / 2.34 / 2.31 s, mean **2.24 s**. 🟡 **The port has not taken it.** Looping that record needs a period, and its group is 105 timed units plus the **authored** 24-unit exit ramp = 129 units = 2.15 s — composing an authored constant with a loop assumption to land on a measured number is tuning, not measuring. Separately: the port draws no focus record on `press_start` at all, because the screen has no `buttons` and nothing is focused, so *whether the game always draws it* is its own question. | diff --git a/docs/port/DECISIONS.md b/docs/port/DECISIONS.md index 6be3229f..1cb4dbd2 100644 --- a/docs/port/DECISIONS.md +++ b/docs/port/DECISIONS.md @@ -3561,3 +3561,66 @@ frames N and N+172 must be the same frame: The control is what makes the rest mean anything: a quarter-second off the period differs by 58.7, on the period by 0–1. Measured on the held boot title, where the glow-box mean swings **26.0 ↔ 37.7** — a real pulse, not a static glow. + +## ✅ The oracle finally speaks: the exported voice IS the game's centre channel + +The Decoder's fourth capture is the first faithful one — `--gpu=null` takes the +guest from 0.70× to 0.96× real time so Xenia stops padding, an ALSA `file` tee in +front of a paced slave removes PulseAudio's wall clock entirely. **59.7 s, 0.35 % +silence, one gap in the whole file, six distinct channel hashes.** Checked here +independently: it passes `check-capture`, and its header sizes verify exactly +(RIFF 34 369 572 / data 34 369 536 against 34 369 580 actual). + +The correlator was already calibrated, so the fit was a re-run rather than a +rebuild. **Controls first, on this instrument: known-present margin +0.248, +known-absent +0.005.** + +### Speech band, 300–3000 Hz + +| | FL | FR | **FC** | LFE | RL | RR | +|---|---|---|---|---|---|---| +| stream 1 (leading) | +0.013 | +0.006 | +0.012 | +0.009 | +0.012 | +0.005 | +| **stream 2 — the one exported** | +0.238 | +0.171 | **+0.305** | +0.011 | +0.035 | +0.006 | +| stream 3 | +0.240 | +0.173 | **+0.307** | +0.009 | +0.054 | +0.006 | + +**`r = 0.989` on FC, margin +0.305 — above the known-present control.** And the +bed, in the low band, is the mirror image: FL 0.763 / FR 0.838 / RL 0.805 / RR +0.817, all agreeing on the same lag, and **FC 0.317**. + +### What is established, and what is not + +✅ **The capture contains `ADV`'s audio**, at lag ≈ +6.6–6.7 s — agreed by two +independent bands and by six channels. + +✅ **The dialogue is in the centre channel and the bed is in the four corners.** +FC carries the voice and not the bed; FL/FR/RL/RR carry the bed and not the +voice. That is a textbook film mix, and it is measured rather than inferred from +a header — which matters, because the header says `ChannelMask = 0x0002` on all +three streams and would never have told us. + +✅ **The port's exported voice file is the material the game plays in FC.** The +`loudest` choice in `authored/audio.json` — which I recorded as an unjustified +选 choice — selects the dialogue. A mono voice file played into the mix is the +right approximation of a centre channel. + +⚠️ **Streams 2 and 3 are indistinguishable to this instrument**, and that is +expected: I measured months-of-iterations ago that stream 3 is 0.60 × stream 2 +with the residual 26.8 dB down. They are the same take at two levels, so they +correlate identically with everything. **This does not say `loudest` picked the +*right* one of the two — only that whichever it picked is the dialogue.** + +⚠️ **Stream 1 is not detectable in this window**, margins +0.005…+0.013. Consistent +with it being the tail of stream 2 (measured earlier at r = 0.998) and with a +59.7 s window that starts before the tail. + +🔴 **The `1 of 3 streams` warning stays.** Nothing here explains what the other +two contribute to the game's output, and the export still ships one. What changed +is its character: it is no longer *"one of three, contents unknown"* but *"the +centre-channel dialogue, plus two streams whose relationship to it is measured +and whose role is not."* + +⚠️ **And the reach: 59.7 s of a 137 s movie**, one run, at 0.96× real time. The +`--gpu=null` route costs video, so this capture has no screen provenance — its +provenance is the XMA probe showing `ADV`'s three streams decoding during the +run, which for an audio question evidences the thing recorded rather than what +was on screen.