Files
Sylpheed/docs/re/f2-no-gain-field-in-tables.md
sylph-decoder 1021708636 re: F2 CLOSED -- undecodable with reach, all three sites checked
Third and last site: the executable's play path. sub_821C5580's cue-1103
site is li r5,1103 / li r4,4 / lwz r3,0(r29) / bl 0x8217ACF8, i.e.
play(this, category, cue_id). No volume is passed and no float argument is
set up by the caller at all; the callee's prologue confirms r5 is the cue
id with -2 and -1 sentinels.

Honest limit stated: the callee saves f30/f31 so it uses floats internally
and could look a level up for itself. "No gain is passed" is not "no gain
exists" -- but there is nothing at this site for the port to transcribe.

So F2 closes as undecodable-with-reach with all three sites checked:
tables.pak cue records (exhaustive, passing control, and numbers carry
names there so a gain would have had one), sound.pak bank headers (all 9519
entries, no readable header), and the play path (category, not level).

The port authors the mix and now knows it is authoring, which is what this
question existed to make explicit rather than accidental. The one authored
value the game exposes is the user-facing sound options screen -- a runtime
master, not a per-cue table.

Refutation of the play-test's premise that "a cue record commonly carries a
volume beside its wave index": REFUTED for this game across all three sites
where it could live. Recorded because it was a good prior -- it is what
sent me to the right three places -- and being wrong about where a value
lives is different from being wrong to look.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-02 18:06:36 +00:00

8.4 KiB
Raw Blame History

F2 — no gain field in tables.pak. Undecodable so far, with reach

Status: undecodable, with reach — the strongest of the three classifications this could honestly get. 2026-09-02. Instrument: ⟨disc⟩ — dat/tables.pak read exhaustively, with a control.

The port has no gain value anywhere in its export; confirm peaks at 0.0 dBFS and sits 3 dB above the music. F2 asks whether a per-cue or per-bus volume is on the disc, so nobody has to choose one.


The answer: not in tables.pak

5 audio-bearing objects, 0 gain-like fields.

audio object #15  schema 3abe9c0c     38 tokens
audio object #18  schema 3abe9c0c     39 tokens
audio object #36  schema 070ed386    135 tokens
audio object #39  schema 13cb84ba  13907 tokens
audio object #45  schema 13cb84ba  16741 tokens

tokens matching [VOL GAIN LEVEL DB ATTEN AMP MIX LOUD]: 0

Control — the same matcher looking for a token known to be there: SE_UI returns 38 hits. PASS. Without it, "0 hits" and "broken matcher" are the same observation, and this corpus has published that mistake before.

🔴 Why the negative is stronger than a name search usually is

A name search normally cannot exclude an unnamed numeric column — and I expected that to be this page's limitation. Dumping the schema shows it is not. The token stream is value-then-key pairs:

  1 0x060523                        2 VERSION
  4 dat\GP_OPTIONS.pak+eng\         5 PATH
 33 40                             34 LINE_PITCH
 35 0                              36 Y_OFFSET_ANALOG_STICK

Numbers are tokens and they carry names. 40 is a token, and so is LINE_PITCH. So a gain in this format would have a name, and the name search covers exactly the space where it would live. That is what turns "I did not find one" into "one is not there in this file".

⚠️ Reach — the two places I did NOT look

  1. The .slb bank headers. CHECKED 2026-09-02 — also negative, and for a structural reason. dat/sound.pak is a 114 KB index over ~1 GB of payload (sound.p00.p04). Its 9 519 entries carry no readable signature at all: the most common first-four-bytes pattern is "...." on 3 830 entries, and no entry begins with an ASCII magic. Exactly one entry is under 4 KB (#9454, 533 bytes) — a bank header or wave index would be small and structured, and there is essentially no such thing here.

    So the SE bank's metadata is not reachable as a header in sound.pak. The entries are audio payload, which is high-entropy by nature; a gain beside a wave index is not sitting in front of them. ⚠️ This is a negative about reachability, not about existence: a per-wave gain could live inside a container these entries are compressed into, and I have not decompressed one.

  2. The executable. A mix could be immediates in the sound-play path; sub_821C5580 is a decoded entry point into it.

So this is not yet "the mix is not on the disc". It is "the mix is not in the table where a cue's fields live, and not in front of the bank payload either"two of the three sites checked, both negative. The executable is the one that remains.

📌 One adjacent fact, offered as a pointer and not a finding: object #15 lists po_sound_scr.prt → SOUND among GP_OPTIONS' screens. There is a user-facing sound options screen, so at least one volume exists as runtime state. That is a different thing from a per-cue mix and does not answer F2 either way — but if the next attempt finds no authored gain anywhere, a user-settable master is where the game's own levels would come from.

For the port

Keep authoring nothing yet. The place a gain would most likely be has not been looked at. If the bank headers come back empty too, the honest classification becomes undecodable across all three sites and the port authors a mix knowing it is authoring — which is the outcome this exercise exists to make explicit rather than accidental.

Refutation attempt, recorded per the adversarial duty

Target: the play-test's framing that "a cue record commonly carries a volume beside its wave index".

Result: not refuted, and not confirmed — the premise is untested where it matters. The cue records in tables.pak carry an id and a name and no volume. But "beside its wave index" points at the bank, not the table, and the wave index lives in the .slb. The framing is sound; it just aims at a file this page did not open.

Status after the second site — still undecodable, with reach, and now better bounded

site checked result
tables.pak cue records exhaustive, with a passing control no gain-like field
sound.pak bank headers all 9 519 entries no readable header to carry one
the executable, around sub_821C5580 CHECKED the play call passes no gain

For the port, unchanged: author nothing yet. But the shape of the answer is now visible. If the executable also has no per-cue gain, the honest conclusion is that this game does not author a per-cue mix at all — and the levels a player hears come from the user-facing sound options screen (po_sound_scr.prt, object #15) applied as runtime state. That would make the port's job authoring a master balance rather than transcribing a table, and it would be undecodable rather than decoded — which the port must know, because a mix authored in ignorance and a mix authored deliberately look identical in the file and differ entirely in how much they can be trusted.

Third site checked 2026-09-02 — the play call carries no volume

sub_821C5580's cue-1103 site, read out of the image:

821C5608  li   r11,1103
821C560C  li   r5,1103          ; the CUE ID
821C5610  li   r4,4             ; a constant beside it -- category/bus, not a level
821C561C  lwz  r3,0(r29)        ; the sound object
821C5620  bl   0x8217ACF8       ; play(this, 4, 1103)

And the callee's prologue confirms the shape:

8217AD00  stfd f30,-72(r1)      ; callee-SAVED floats -- it uses floats internally
8217AD10  or   r29,r5,r5        ; r5 = cue id, with sentinels:
8217AD18  cmpi r29,-2           ;   -2 -> take the id from this+136
8217AD24  cmpi r29,-1           ;   -1 -> return -1

The call is play(this, category, cue_id). No volume is passed — no float argument is set up by the caller at all, and the three integer arguments are accounted for.

⚠️ What this does not exclude, and it is the honest limit. The callee saves f30/f31, so it uses floats internally and could look a level up for itself. "No gain is passed" is not "no gain exists" — but it does mean there is nothing at this site for the port to transcribe.

🔴 F2's answer: undecodable, with reach — all three sites checked

site checked result
tables.pak cue records exhaustive, passing control no gain-like field, and numbers carry names here so one would have had a name
sound.pak bank headers all 9 519 entries no readable header to carry one
the executable's play path call passes (this, category, cue_id), no volume

So: the port authors the mix, and it now knows it is authoring. That is the outcome this question existed to make explicit rather than accidental. The one authored value the game itself exposes is the user-facing sound options screen (po_sound_scr.prt, tables.pak object #15) — a runtime master, not a per-cue table.

📌 The port's own measurement is the best evidence available for the shape of the fix: confirm peaking at 0.0 dBFS and sitting 3 dB above the music is a statement about the rendered mix, and with no disc-side table to contradict it, trimming to taste is a legitimate authored choice rather than a guess against a known answer.

Refutation attempt, recorded per the adversarial duty

Target: the play-test's premise that "a cue record commonly carries a volume beside its wave index".

Result: REFUTED for this game, across all three sites where it could live. The premise is a sound generalisation about audio middleware and it does not hold here: the cue record is an id and a name, the bank exposes no header, and the play call takes a category rather than a level. Recorded because it was a good prior — it is what sent me to the right three places — and being wrong about where a value lives is different from being wrong to look.