diff --git a/docs/port/HANDOFF.md b/docs/port/HANDOFF.md index 062eafe6..931aa1bf 100644 --- a/docs/port/HANDOFF.md +++ b/docs/port/HANDOFF.md @@ -283,9 +283,12 @@ authored version can be deleted. ❔ **And it is not a seamless loop**: `BGM_001` fades out at 167.663 s and is followed by 6.15 s of silence, with no loop-point field identified. A menu loop is authored. - ❔ **Which bank is the menu's music is not on the disc** — all 32 BGM cues are - named `BGM_001`…`BGM_109`, no semantic name in `SOUNDS`, `FILES` or the bank - headers. The port is choosing a track. + ✅ **The menu's music is `BGM_103`.** The cue *table* cannot say — its BGM + entries are numeric — but `GamePart_Title`'s `sub_821C5580` plays **cue 1103**, + and `BGM_103.slb`'s two declared waves (3 876 864 / 3 930 112 B) are + byte-for-byte the two streams the XMA probe saw decoding at the main menu. + Static code, disc census and runtime all agree. The port does **not** have to + choose a track. * **`JNGL_001.slb` does not decode.** One bank in 9 519; its payload is not a whole number of XMA1 packets from any known data offset. diff --git a/docs/re/METHOD.md b/docs/re/METHOD.md index d2701923..6371582d 100644 --- a/docs/re/METHOD.md +++ b/docs/re/METHOD.md @@ -220,3 +220,9 @@ agent's loop prompt, i.e. nowhere durable. See [`README.md`](README.md) for the into place later (`addi r27, r11, X` … `mr r5, r27`). A backward search for the destination register alone found 7 of 48 sites and missed the two known-good ones. Simulate forward over a window instead, tracking `lis`/`addi`/`mr`. +* **Check a measurement against the WHOLE reference set, not the part you were + reading.** Two observed BGM stream sizes were recorded as matching "no bank's + declared waves", which spawned a wrong theory that the decoder gets a window + rather than a whole wave. They match `BGM_103` exactly — the check had covered + only the `BGM_0xx` rows of the census, because that is the block that had been + on screen. diff --git a/docs/re/REFUTED.md b/docs/re/REFUTED.md index a9ca0f06..93e3b536 100644 --- a/docs/re/REFUTED.md +++ b/docs/re/REFUTED.md @@ -174,6 +174,14 @@ neighbourhood, not just the line. ## Audio +* "which bank the menu plays is not on the disc" → the **cue table** cannot say + (all BGM cues are numeric), but the **code** can: `sub_821C5580` plays cue + **1103 = `BGM_103`**, and its two declared waves match the two streams the XMA + probe saw byte-for-byte. +* "the observed BGM stream sizes match no bank's declared waves, so the game hands + the decoder a window" → **mine, and wrong** — I checked only the `BGM_0xx` rows. + They are `BGM_103`'s two waves exactly; the game hands over the whole wave. + * "an individual SE cue's audio cannot be extracted" → **mine, and wrong.** `--xma_param_probe=true` logs each stream's head bytes; searching them in `Static.slb` locates the wave exactly. [`menu-audio-cues.md`](menu-audio-cues.md) diff --git a/docs/re/boot-config-and-gamepart-registry.md b/docs/re/boot-config-and-gamepart-registry.md index 7d127f96..81303c4f 100644 --- a/docs/re/boot-config-and-gamepart-registry.md +++ b/docs/re/boot-config-and-gamepart-registry.md @@ -441,3 +441,45 @@ arguments, and `r28` is `sub_821C7850`'s own third argument, passed through untouched. So the event vocabulary is defined **at least one level above** this function. Finding what `3`, `5`, `8`, `10`, `25` mean means going up again, and that was not done. + + +## Going up one more level — three of four callers pass a constant event + +`sub_821C7850` has **four** direct callers. Recovering the `r5` argument at each: + +| caller | event passed | +|---|---| +| `sub_821C7CB8` | **0** (→ back to the title) | +| `sub_821C7BA0` | **0** | +| `sub_821C47A0` | **5** (→ `LOADING`) | +| `sub_821C5580` | **not constant** — `lwz r5, 4(r27)`, read out of a structure | + +So the vocabulary is still not enumerable from here: the interesting caller reads +its event from a field. ❔ What `3`, `8`, `10` and `25` mean remains open. + +**`sub_821C5580` is also where the outer gate is set:** + +``` +821c5640 li r11, 3 +821c5644 stw r11, 16(r28) ; this+16 = 3 — the exact value sub_821C7850 tests +821c5650 lwz r5, 4(r27) ; event from a struct field +821c5658 bl 0x821C7850 +``` + +That answers the "what does `this+16 == 3` gate on" question from the previous +section: this function arms it. + +### 🎁 And it names the title's music + +The same function, a few instructions earlier: + +``` +821c560c li r5, 1103 +821c5610 li r4, 4 +821c561c lwz r3, 0(r29) +821c5620 bl 0x8217ACF8 ; a sound-play call +``` + +**1103 is a BGM cue id** — `BGM_103`. That closes an open residual from Q8/Q10 +("which bank is the menu's music is not on the disc"), and it checks out three +ways; see [`structures/bgm-two-stems.md`](structures/bgm-two-stems.md). diff --git a/docs/re/menu-audio-cues.md b/docs/re/menu-audio-cues.md index 3f4651f7..c124d650 100644 --- a/docs/re/menu-audio-cues.md +++ b/docs/re/menu-audio-cues.md @@ -63,12 +63,20 @@ same instrumentation Q4's residual wants, and not something this container can d today (it runs `--mute=true` against an SDL dummy device, so there is no audio path to watch either). -## ❔ Which BGM per screen — undecodable, reach already recorded +## ✅ Which BGM per screen — the TABLE cannot say, but the CODE can -All 32 BGM cues are named `BGM_001`…`BGM_109`. Nothing in `SOUNDS`, `FILES` or the -bank headers names a screen — see -[`structures/bgm-two-stems.md`](structures/bgm-two-stems.md). Unchanged by this -iteration. +All 32 BGM cues are named `BGM_001`…`BGM_109`, and nothing in `SOUNDS`, `FILES` or +the bank headers names a screen. That negative stands **for the tables**. + +It does not stand for the executable. `GamePart_Title`'s phase handler +`sub_821C5580` contains `li r5, 1103` feeding a sound call — **cue 1103 = +`BGM_103`** — and `BGM_103.slb`'s two declared waves (3 876 864 / 3 930 112 bytes) +are byte-for-byte the two streams the XMA probe saw decoding at the main menu. +Three routes, one answer; see +[`structures/bgm-two-stems.md`](structures/bgm-two-stems.md). + +So the per-screen BGM binding is recoverable **per screen, from the code that +plays it** — not from any table. ## ❔ And a new negative: an individual SE's audio is not extractable yet diff --git a/docs/re/structures/bgm-two-stems.md b/docs/re/structures/bgm-two-stems.md index 1eedfcde..4197d7b2 100644 --- a/docs/re/structures/bgm-two-stems.md +++ b/docs/re/structures/bgm-two-stems.md @@ -129,8 +129,25 @@ bank's two waves are simultaneous, not sequential.** Concatenating them is wrong now measured as well as inferred. 🟡 It still does **not** separate the two readings — surround-rear pair versus a -second intensity layer — because both predict simultaneity. And the two byte -sizes do not match any bank's declared wave sizes in -[`../data/bgm-wave-census.txt`](../data/bgm-wave-census.txt), so *which* bank the -menu plays is still not established; the game hands the decoder a window, not the -whole declared wave. +second intensity layer — because both predict simultaneity. + +## ✅ The menu's music is `BGM_103` — three independent routes agree + +An earlier version of this section said the two observed byte sizes "do not match +any bank's declared wave sizes". **That was wrong** — I had checked only the +`BGM_0xx` rows. They match `BGM_103` exactly, and the code names it: + +| route | evidence | +|---|---| +| **static, code** | `GamePart_Title`'s phase handler `sub_821C5580` does `li r5, 1103` into a sound call (`sub_8217ACF8`, with `r4 = 4`) — **cue 1103 = `BGM_103`** | +| **static, disc** | [`../data/bgm-wave-census.txt`](../data/bgm-wave-census.txt): `BGM_103.slb` = two waves of **3 876 864** and **3 930 112** bytes, 87.75 s each | +| **runtime** | the XMA probe at the **main menu** saw two stereo 48 kHz streams decoding simultaneously, of **3 876 864** and **3 930 112** bytes | + +Byte-for-byte on both waves. So: + +* **which bank the menu plays is decoded** — `BGM_103`, from the executable, since + the cue *table*'s BGM entries are numeric and name no screen; +* and the two-stems-play-together finding is now confirmed **on a named bank**, + with the runtime stream sizes equal to the bank's declared wave sizes — so the + game hands the decoder the whole wave, not a window, which is the opposite of + what the earlier note guessed.