re: the seek table's sample total is not the wave length -- durations corrected
Chasing w0 I decoded leading waves and the output matched neither trailer word. Following that into RIFF waves, where the extent is certain, the decoded sample count exceeds the seek table's last cumulative sample by a median 9.7%. The tiebreak is the bank's own PsuedoBytesPerSec: over 14 banks it agrees with an actual FFmpeg decode to a mean of 0.007 s and with the seek-table duration only to 0.287 s. Two independent quantities agree with each other and both disagree with the seek total, so that last entry is the last SEEK POINT, not the sample count. Both artifacts regenerated with data_bytes / PsuedoBytesPerSec. Total audio is 408.3 minutes, not the 390.9 I published -- 4.3% in aggregate. Dialogue timings all rise, e.g. 'They got Leader!' from 1.78/2.46 s to 2.25/2.93 s. What made this hard to catch is worth recording: the seek total gave BGM of 2.4 minutes, chatter of 2.8 seconds and cutscenes of 11 minutes, and I cited that as the chain validating itself. It validated the structure, not the scale -- a uniform 10% error preserves every ratio I checked.
This commit is contained in:
@@ -95,7 +95,7 @@ files, which is how the same ground got covered twice.
|
||||
| [`structures/idxd-container.md`](structures/idxd-container.md) | The IDXD/IXUD container — record/field table, and the two beliefs it withdraws | ✅ CONFIRMED disc-wide, 7 750/7 750 objects and 1 271 462/1 271 462 named fields, zero failures |
|
||||
| [`structures/hud-glyph-quad.md`](structures/hud-glyph-quad.md) | The HUD's glyph quad — vtable `0x820B2A64` | ✅ CONFIRMED for the object layout and the atlas size, read live off |
|
||||
| [`structures/slb-data-offset.md`](structures/slb-data-offset.md) | `.slb` leading-stream offset is `first_riff % 2048`, not the constant 1392 | ✅ CONFIRMED by decoding — 85 of 140 sampled banks yield more audio (median 70×), 54 identical controls. ⚠️ The *cause* is a segment-packing phase, not a header: `X = (cumulative .pNN start) mod 2048`. Wave boundaries are exact — `seek` magic at `data_at + declared_size`, **7 620/7 620** — and `Channels` must be read from `RIFF+49` (2.12 % are stereo) |
|
||||
| [`structures/sound-pak-contents.md`](structures/sound-pak-contents.md) | Census of `sound.pak`, and the limit of the leading-region rule | ✅ CONFIRMED, 5 135/5 135 names hash into the TOC, **9 519/9 519** entries accounted for, and a full 4 114-bank manifest (390.9 min of audio) computed from the seek tables without decoding; ⚠️ leading-region rule holds for 1 571/4 382 eng and 0/5 100 jpn |
|
||||
| [`structures/sound-pak-contents.md`](structures/sound-pak-contents.md) | Census of `sound.pak`, and the limit of the leading-region rule | ✅ CONFIRMED, 5 135/5 135 names hash into the TOC, **9 519/9 519** entries accounted for, and a full 4 114-bank manifest (408.3 min of audio) computed from PsuedoBytesPerSec without decoding; ⚠️ leading-region rule holds for 1 571/4 382 eng and 0/5 100 jpn |
|
||||
| [`structures/sound-cue-table.md`](structures/sound-cue-table.md) | The cue index in `tables.pak` — message id -> cue -> sound id -> `.slb` bank | ✅ CONFIRMED, 1 326/1 338 script message ids bind to a bank; SOUNDS and FILES agree on the same 12 absentees, 0 orphan files |
|
||||
| [`structures/cutscene-message-table.md`](structures/cutscene-message-table.md) | Cutscene dialogue — speaker, portrait, on-screen seconds, audio cue per page | ✅ CONFIRMED, field count = 9·PageCount+2 for all 7 PageCounts, 1 252/1 252 caption keys match, 138 ids close both ways |
|
||||
| [`structures/isl-message-dialogue-link.md`](structures/isl-message-dialogue-link.md) | Mission scripts as dialogue — built-in 64 -> message id -> caption text | ✅ CONFIRMED total, 2 683/2 683 call sites across all 28 stages resolve, no residue |
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -601,3 +601,48 @@ That is the shape of a sparse table, and it is unidentified.
|
||||
**A correction to how I described this block**: I called the region "zero
|
||||
padding" after the seek chunk. It is not padding — it is a sparse structure that
|
||||
is *mostly* zero. The distinction matters for anyone who tries to skip it.
|
||||
|
||||
|
||||
## ❌ The `seek` table's sample total is NOT the wave's length — my durations were low
|
||||
|
||||
**2026-08-26.** I published two artifacts using `last cumulative sample ÷ sample
|
||||
rate` as the duration. That is wrong, and this is the measurement that shows it.
|
||||
|
||||
Trying to pin down `w0`, I decoded leading waves and found the output matched
|
||||
**neither** trailer word. Following that into the `RIFF` waves, where the extent
|
||||
is certain, the decoded sample count exceeds the `seek` table's last cumulative
|
||||
sample by a **median 9.7 %** — far too much to be rounding.
|
||||
|
||||
The tiebreak is the bank's own **`PsuedoBytesPerSec`** field, which gives a
|
||||
duration as `data_bytes / PBPS` and is read, not decoded. Over 14 banks:
|
||||
|
||||
| comparison | mean absolute difference |
|
||||
|---|---|
|
||||
| `PBPS` vs the **seek-table** duration | **0.287 s** |
|
||||
| `PBPS` vs the **decoded** duration | **0.007 s** |
|
||||
|
||||
Two independent quantities — the bank's declared byte rate and an actual FFmpeg
|
||||
decode — agree with each other to seven milliseconds and both disagree with the
|
||||
`seek` total. The `seek` table's last entry is therefore **not** the wave's
|
||||
sample count; it is the last *seek point*, which stops short of the end.
|
||||
|
||||
**Corrected**, and both artifacts regenerated with `data_bytes / PsuedoBytesPerSec`:
|
||||
|
||||
* [`../data/voice-bank-manifest.txt`](../data/voice-bank-manifest.txt) — total
|
||||
audio **408.3 minutes**, not the 390.9 I reported. A **4.3 %** understatement
|
||||
in aggregate; the per-bank median error was 9.7 %, but long banks dominate the
|
||||
total and are proportionally more accurate.
|
||||
* [`../data/stage-dialogue-with-durations.txt`](../data/stage-dialogue-with-durations.txt)
|
||||
— every line's timing rises, e.g. *"They got Leader!"* from 1.78/2.46 s to
|
||||
**2.25/2.93 s**.
|
||||
|
||||
⚠️ **What made this hard to catch**: the `seek` total *looked* right. It gave
|
||||
BGM tracks of 2.4 minutes, radio chatter of 2.8 seconds, cutscenes of 11
|
||||
minutes — a set of numbers that sorted themselves into exactly the right shapes,
|
||||
which I cited as the chain validating itself. It was validating the *structure*
|
||||
and not the *scale*: a uniform 10 % error preserves every ratio I checked. A
|
||||
self-consistency check cannot catch a systematic factor, and I should not have
|
||||
read it as confirmation of the value.
|
||||
|
||||
🟡 `w0` remains unidentified. Neither trailer word matches the decoded length,
|
||||
so the "usable length" reading of `w0` is now less likely, not more.
|
||||
@@ -128,7 +128,7 @@ those are the headerless banks.) Duration comes from the **last cumulative
|
||||
sample** in the `seek` table divided by the sample rate — arithmetic, no
|
||||
decoding.
|
||||
|
||||
**Total: 390.9 minutes — about 6½ hours of audio.**
|
||||
**Total: 408.3 minutes — about 6¾ hours of audio.** ⚠️ An earlier version of this page said 390.9 minutes, computed from the `seek` table's sample total; that understates the true length by a median 9.7 % per bank. See [slb-data-offset.md](slb-data-offset.md).
|
||||
|
||||
The reason this is worth more than a listing is that nothing in it was fitted to
|
||||
an expectation, yet every category lands where its content says it should:
|
||||
|
||||
Reference in New Issue
Block a user