This repository has been archived on 2026-09-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Syplheed-Reborn/docs/re/structures/slb-data-offset.md
Sylpheed RE agent d15b3d8d85 slb: derive the leading-stream data offset instead of assuming 1392
HEADERLESS_DATA_OFFSET is the value the offset takes in <lang>\etc\, not a
property of the format. The leading stream is a whole number of 2048-byte XMA1
packets ending at the first RIFF, so its start is first_riff % XMA1_PACKET.
Disc-wide that takes four values -- 1392, 1468, 1600, 1728 -- varying by
language and subdirectory.

Verified by decoding, not by arithmetic: on a random 140-bank sample with a
non-empty leading region, the derived offset yields more audio in 85, identical
in 54 (the eng\etc controls, where it must and does reproduce the old
behaviour) and less in 1. Median gain among the improved is 70x --
eng\Voice\VOICE_TCAF_592 goes 1506 -> 97152 bytes, jpn 2910 -> 127178.

This withdraws my own claim from earlier today that the Japanese banks were a
different undecoded layout. They are the same format with a different offset;
I had treated a constant derived from one subdirectory as a property of the
format. The same error was hiding the identical defect in 1873 eng\Voice banks.
2026-08-26 03:56:50 +00:00

88 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# `.slb` leading-stream data offset — 1392 was never a constant
**✅ Settled 2026-08-26, verified by decoding.** A bank's leading headerless
packet stream does not start at a fixed offset. It starts at
**`first_riff % 2048`**. `HEADERLESS_DATA_OFFSET = 1392` is the value that
offset happens to take in `<lang>\etc\`, and assuming it everywhere starts the
decode mid-packet and throws away almost all of the audio.
## The rule
XMA1 packets are 2048 bytes and the leading stream is a whole number of them
ending at the first `RIFF`. So its start is forced:
start = first_riff % 2048
Disc-wide that lands on exactly **four** values — 1392, 1468, 1600, 1728 — all
of the form `1392 + 4k`. Across the 3 965 Japanese and 3 393 English banks with
a non-empty leading region, no other value occurs:
| | 1392 | 1468 | 1600 | 1728 |
|---|---|---|---|---|
| `eng\etc`, `eng\Movie`, `eng\Briefing` | 1 520 | — | — | — |
| `eng\Voice` | 8 | 1 873 | — | — |
| `jpn\etc` | — | 1 402 | 303 | — |
| `jpn\Briefing` | — | 71 | — | — |
| `jpn\Movie` | — | — | 61 | — |
| `jpn\Voice` | — | — | 2 033 | 95 |
It varies by **language and subdirectory**, which is why a constant derived
from `eng\etc\` looked right for years' worth of the banks anyone had reason to
open.
## Verified by decoding, not by arithmetic
The alignment argument alone proves nothing — any offset can be made to "align"
by definition. The test is whether more audio comes out. Decoded through
FFmpeg's `xma1` at mono/48 kHz, on a random sample of **140** banks that have a
non-empty leading region:
| outcome | banks |
|---|---|
| more audio at `ri % 2048` | **85** |
| byte-identical | 54 |
| less audio | **1** |
Median gain among the improved: **70×**. The 54 identical ones are the control —
they are the `eng\etc`-style banks where `ri % 2048` *is* 1392, so the rule
must and does reproduce the old behaviour exactly. Individual cases:
eng\Voice\VOICE_TCAF_592.slb 1 506 -> 97 152 bytes (65x)
jpn\Voice\VOICE_TCAF_592.slb 2 910 -> 127 178 bytes (44x)
eng\etc\VOICE_D_452.slb 30 154 -> 30 154 bytes (unchanged, control)
## The one counterexample
`eng\Voice\VOICE_TCAF_608.slb` decodes 2 840 bytes at 1392 and 896 at 1468.
It is worth being precise about what that is and is not. It is **not** a bank
where the old constant works and the derived offset fails: its leading region is
38 988 bytes, and *both* offsets yield well under a tenth of a second, i.e. both
fail. 1392 merely produces marginally more garbage. Whatever is wrong with this
bank is a separate defect and is **not settled** here.
## ❌ This withdraws my own claim from earlier the same day
[`sound-pak-contents.md`](sound-pak-contents.md) reported that the leading
region rule holds for "0 of 5 100 Japanese banks" and filed a backlog item
saying the Japanese banks were a different, undecoded layout. **That was wrong.**
The Japanese banks are the same format; only the offset differs. The measurement
behind it was correct — zero of them satisfy `(riff 1392) % 2048 == 0` — but
the conclusion drawn from it was not, and the reason is instructive: I treated
`HEADERLESS_DATA_OFFSET` as a property of the format when it was a property of
the sample the format was derived from.
The same error was hiding a defect in the **English** set too: 1 873 `eng\Voice`
banks sit at 1468 and were being decoded mid-packet just as badly.
## What this does not settle
* **Why the offset takes those four values**, and what the bytes before it are.
There is no length field in the first 64 bytes — banks open on high-entropy
data — so the offset is derived, not read.
* **`eng\Voice\VOICE_TCAF_608.slb`**, above.
* **The 799 jpn / 696 eng banks with no `RIFF` at all** are untouched by this;
they go down the headerless path and were not re-examined.
* Nothing here was run **in the game** — this is a decoder-side result measured
with FFmpeg as the oracle.