re: the UI sound effects ARE extractable -- retracting "cannot be

extracted", and the tool was in the build all along

Two iterations ago I closed Q8 by declaring the SE audio undecodable:
Static.slb has no wave boundaries, there is no XACT container anywhere,
and I said the index "exists only at runtime" as though that put it out
of reach. The disc half of that stands. The conclusion did not.

This build of Canary carries a cvar called xma_param_probe, added by this
project, whose own comment says it logs each XMA stream's parameters and
head bytes so raw sound.pak entries can be matched to real decode params.
It has been sitting in the startup CONFIG DUMP of every log I have read
this session.

Run with it, driving the main menu: a d-pad move spawns a new mono 48 kHz
stream of 4 packets / 8192 bytes, and B spawns a different one of 2
packets / 4096 bytes. Searching their logged head bytes in Static.slb
finds each at exactly one offset -- 0x1ec0 and 0x0ec0 -- and the two are
contiguous, 0x0ec0 + 4096 = 0x1ec0. So the bank is a packed run of whole
2048-byte packets with no delimiters, which is precisely why the seek
scan found nothing: there is nothing to find. A wave is (offset, packet
count) and nothing else.

That splits Q8's binding cleanly. Event -> WAVE is now measured: the port
can have the audio. Event -> cue NAME is still a name match on the
authors' identifiers, and the page says so.

The same run settled something for Q10 too. Sitting on the main menu, TWO
stereo 48 kHz streams were decoding simultaneously. bgm-two-stems.md said
that observation was what it needed and that this container could not
make it; it can, and a music bank's two waves are now measured as
simultaneous rather than only inferred.

METHOD gets the general lesson, because it cost two iterations: check
what instrumentation the local build already has before declaring a
question blocked on tooling.
This commit is contained in:
Sylpheed RE agent
2026-08-28 19:30:03 +00:00
parent aea529e7dc
commit 0d7199bc22
6 changed files with 113 additions and 13 deletions

View File

@@ -163,15 +163,19 @@ authored version can be deleted.
🟡 **Which event fires which cue is a name match**, not a measurement — strong,
because these are the authors' own event names, but nobody has watched the game
emit cue 2 on a d-pad press. The port is authoring it.
❔ **The SE audio cannot be exported at all from the disc.** `Static.slb`'s
8 353 472 readable bytes contain **0 `RIFF`, 0 `seek`, 0 `WAVE`** — the boundary
marker that works for all 7 620 other banks is absent — and there is **no XACT
container anywhere**: 0 × `XGSF`/`SDBK`/`WBND` across all 1.08 GB of
`sound.pak`, and no `XACT`/`.xgs` string in the executable. The `.xgs`/`.slb`
names come from the authoring tool, not the shipped format. The bank is
certainly the right one — 8 353 472 B over 322 cues is 0.84–1.01 s each at the
disc's own bitrates — but the index into it exists only at runtime. **The UI
sound effects must be sourced or authored; they cannot be extracted.**
✅ **The SE audio IS extractable — by playing it.** (This corrects an earlier
"cannot be extracted" on this page.) The disc carries no index: `Static.slb` has
**0 `RIFF`/`seek`/`WAVE`** and there is **no XACT container anywhere** (0 ×
`XGSF`/`SDBK`/`WBND` in 1.08 GB of `sound.pak`; no `XACT` string in the
executable — those extensions are the authoring tool's). But Canary's
`--xma_param_probe=true` logs every stream's head bytes, and searching them in
`Static.slb` locates the wave exactly:
**d-pad move → `0x1ec0`, 4 packets / 8 192 B, mono 48 kHz; Ⓑ back → `0x0ec0`,
2 packets / 4 096 B.** Each matched at one offset only, and they are contiguous
(`0x0ec0 + 4096 = 0x1ec0`) — the bank is a packed run of whole 2 048-byte
packets with no delimiters, which is why nothing could be scanned for.
⚠️ The order is **not** cue-id order, so the index must be observed per cue, not
counted. ❔ Decoding a located slice to PCM has not been attempted.
* **The boot sequence is not data-driven — the port authors it.** ❔ Four places
were checked and the order is in none: `config.ini`'s `[SYSTEM]` is empty, the
@@ -251,15 +255,16 @@ here until 2026-08-28 and is now settled.)
| | what | why it is stuck |
|---|---|---|
| 🟡 | **cue → event binding as a measurement** (Q8) | nobody has watched the game emit `SE_UI_CURSOR` on a d-pad press. Needs the guest's cue call observed with its argument |
| ❔ | **the wave index into `Static.slb`** (Q8) | same instrumentation. This container runs `--mute=true` against an SDL dummy device, so it cannot watch the audio path at all |
| 🟡 | **cue NAME → event binding** (Q8) | the event→**wave** binding is now measured; that the cursor's wave is the cue *named* `SE_UI_CURSOR` is still read off the authors' identifiers |
| ❔ | **decoding a located `Static.slb` slice to PCM** (Q8) | offsets and packet counts are in hand; the XMA1 `RIFF` wrapper for a mono slice was not built |
| 🟡 | **the paint-order tie-break** (Q3) | eight candidates refuted; costs one element's blend on one screen |
| 🟡 | **GamePart ids behind the buttons** (Q4) | the *screens* are measured; the ids are a name match onto the executable's class names |
| ❔ | **the boot transitions in code** (Q6) | bounded as code-not-data, not proven. `sub_821C6458` — the substantial function in `GamePart_Title`'s neighbourhood — has **not been read** |
| ❔ | **builds 0/1 and 10/11**, the `DELTASABER` plates (Q2) | never seen anywhere in the boot path, the title-side screens or the attract loop. A mission load is the remaining candidate and this container kills runs before one completes |
The first two share one unblocker — an emulator build whose audio path can be
observed — and would be the only entries here that change a port decision.
(An earlier version of this table called the audio items blocked on "an emulator
whose audio path can be observed". That was wrong — this build already has
`--xma_param_probe`, and using it settled both.)
⚠️ **A container caveat that bounds all of the above:** the emulator has twice
been killed mid-run with no crash line in its own log (at ~50 s and ~145 s), on a