viewer: open the whole sound bank, not just the voice half

The library enumerator kept only names containing VOICE or \Briefing\, and read
eng\sounds.tbl unconditionally. So the Explorer could reach 4382 of the 9519
banks in sound.pak: no music, no jingles, no sound effects, and no Japanese
voice at all -- roughly half the disc's audio had no route to the UI.

`slb::list_audio_entries` now returns every named bank with the category its
path implies (Music / Jingles / Sound effects / Radio / Dialogue / Movie voice /
Briefing). `list_voice_clips` is that, restricted to the spoken categories, so
its existing test still guards the old behaviour. The 36 root banks carry no
language component and appear whichever table is read; the window gets an
English/Japanese switch that re-reads the other sounds.tbl, since the table name
IS the selector.

Two defects the decode found, both recorded in
docs/re/structures/sound-pak-contents.md:

* `Static.slb` -- the SFX bank -- declares 616768 bytes more than sound.p04
  holds. Not our extraction: p04 matches the ISO's own directory record, and a
  sweep of every pak on the disc finds this one entry over-running and no other.
  It is the highest-offset entry, so its comp_size is an allocation size. A
  short read is now allowed for the tail entry ONLY; any other overrun stays an
  error, because clamping it would hide real damage behind a half-decoded asset.
  The bank went from unreadable to 514 s of audio.

* the left-channel downmix was applied to everything. Right for voice (mono
  content however stored), wrong for music (a real stereo mix, half of it
  discarded). The caller now decides from the category.

35 of the 36 shared banks decode; JNGL_001 does not, and says so in the player
instead of the panel silently closing. Its payload is not a whole number of XMA1
packets from any known data offset, so it is likely not a plain headerless
stream -- written up rather than papered over.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Sylpheed RE agent
2026-08-28 16:28:20 +02:00
parent fb70511242
commit 306a8a5661
5 changed files with 492 additions and 141 deletions

View File

@@ -149,3 +149,63 @@ into those five shapes.
Two incidental facts fall out: **4 banks run at 44 100 Hz** where everything else
is 48 000, and the `BGM_*` tracks are the stereo ones.
## The 36 shared banks, decoded end-to-end (2026-08-28)
The census above is arithmetic — durations from the `seek` table, no decoding.
This section is the decode itself, for the 36 language-independent banks
(32 `BGM_*` + 3 `JNGL_*` + `Static.slb`), because they were the ones no viewer
had ever played: the library enumerator kept only names containing `VOICE` or
`\Briefing\`, so every one of them was filtered out before it could be tried.
**35 of 36 decode to plausible audio**, and the shapes agree with the census:
the 32 `BGM_*` come out 75555 s and **stereo**, matching "the `BGM_*` tracks
are the stereo ones"; `JNGL_002` decodes to 33.89 s against the manifest's
predicted 33.97 s.
Two things the census could not have caught, both found by decoding:
### `Static.slb`'s TOC entry over-declares its size
The SFX bank sits at the **highest offset in the archive** and claims
8 970 240 bytes — **616 768 past the end of `sound.p04`**. It is not our
extraction: `sound.p04` is byte-for-byte the size the ISO's own directory record
gives. A sweep of **every `.pak` on the disc** finds this one entry over-running
and no other, so the last entry's `comp_size` is an allocation size rather than a
stored size.
`PakArchive::stored_bytes` therefore allows a short read **only** for the
highest-offset entry. Any other overrun is still an error — that would be real
damage, and clamping it would hide the damage behind a half-decoded asset. With
the short read, `Static.slb` decodes to **514 s of mono**; before it, the SFX
bank could not be read at all.
### `JNGL_001.slb` does not decode — and that is a real gap, not a filter
It is one of the headerless banks (no `RIFF`), so it was already outside the
4 114-bank manifest above. Decoding it yields **0.01 s** — one frame, the
signature this corpus already records for a wrong channel count. But the usual
fixes do not apply:
* it is not a channel-count error the `RIFF+49` rule can repair, because there is
no `RIFF` to read the count from;
* its payload is **not a whole number of 2048-byte XMA1 packets** from any of the
four `DATA_OFFSET_CANDIDATES`, which a headerless XMA1 stream must be.
So `JNGL_001` is probably not a plain headerless XMA1 stream at all. The other
headerless root bank, `Static.slb`, decodes fine at 514 s, so the headerless path
is not broken in general — this is one bank in 9 519. It is listed in the viewer
and reports that it did not decode, rather than being hidden.
⚠️ Note on the offsets: `to_xma_riffs` still *scans* for the headerless data
offset, while [slb-data-offset.md](slb-data-offset.md) establishes the exact rule
(the cumulative `.pNN` segment start mod 2048, 8 783/8 783). Wiring the exact
rule into the decoder is open, and is the first thing to try on `JNGL_001`.
### Downmix is a per-category decision, not a constant
The decoder took the left channel unconditionally. That is right for **voice**,
whose content is mono however it is stored (some clips put the signal in the left
channel alone, others duplicate L=R) — and wrong for **music**, where the two
channels are a real stereo mix and taking one throws half of it away. The caller
now decides from the bank's category.