Put sound in the packed container, and find the padding is a rate error
ROADMAP P6b, FINDINGS 67. DLXP2: a 64-byte header and then groups -- one audio lump of A sectors, then F records -- so record i is at off_frm + i*rec + (i//F)*A*512 and lump k at off_aud + k*(F*rec + A*512). Still no index and still none needed, which is the packed branch's whole claim surviving the one change that could have ended it. The player carries the third term in six instructions once a frame and zero parsing, and 120 of 120 records are still pixel-exact off a real MB89352 volume with the interleave in, against a silent control that says no picture byte moved. The finding is what 65.3 called padding. A lump is 7,168 B of SPACE; eleven frames of audio is 7,161.4583... B, so the payload alternates 7,161 and 7,162 and the rest is zero. A player that fed the chip the whole lump -- which is what "14 sectors every 11 frames" invites -- runs 0.09% fast, and that is not waste, it is drift: 0.84 ms a group, 1.25 s of lip-sync over the game's 22.8 minutes. What a player carries is one accumulator, acc += 11*15625; n = acc//24; acc %= 24, which is clock.i's shape for clock.i's reason and the third time this tree has met the pattern. The four ADPCM axes ride in the header as fields rather than a version number, and the gate flips each one to prove they earn it: nibble order -31.99 dB, delta formula -24.86, clamp 0.00, accumulator -0.49. Nothing parses a packed container, so the gate partitions the whole file -- 131 spans, no overlap, no gap -- and asserts what a cadence-blind player would read: exactly records 11..119 wrong, and frames 0..10 identical either way, which is how an off-by-one like that survives a rig that checks frame 0. Wire 582.0 + 7.64 = 589.6 KB/s, 65.3's prediction to the tenth. Green light ALL GREEN before (tmp/check_s35_start.log) and after (tmp/check_s35_end.log), with the new stage in it. Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
This commit is contained in:
@@ -395,6 +395,37 @@ the obvious one-lump-per-record cadence wastes **57.3%** of every audio sector.
|
||||
The wire goes **582.0 → 589.6 KB/s**. The codec container, which already has the
|
||||
index the packed one deleted, pays **zero**.
|
||||
|
||||
**And the packed container has sound in it now — its padding turned out to be
|
||||
drift.** DLXP2 is a 64-byte header and then *groups*: one audio lump of 14
|
||||
sectors, then 11 records, so `record i = off_frm + i*rec + (i//11)*7,168`. **Still
|
||||
no index and still none needed** — the packed branch's whole claim survives the
|
||||
one change that could have ended it — and on the 68000 the third term is **six
|
||||
instructions once a frame** and zero parsing, because the cadence is two numbers
|
||||
in the header rather than a table in the stream. `src/player/packed.s` fetches
|
||||
records out of the interleaved container off a real MB89352 volume and **120 of
|
||||
120 are still pixel-exact**, against a **silent control** built from the same
|
||||
frames that says no picture byte moved.
|
||||
|
||||
The finding is what 65.3 called padding. A lump is **7,168 bytes of space** and
|
||||
eleven frames of audio is **7,161.4583… bytes**, so the *payload* alternates
|
||||
7,161 and 7,162 and the rest is zero. A player that fed the chip the whole lump
|
||||
— which is what "14 sectors every 11 frames" invites — runs **0.09% fast**, and
|
||||
that is not waste, it is **drift: 1.25 seconds of lip-sync over the game's 22.8
|
||||
minutes**. What a player carries is one accumulator, `acc += 11*15625;
|
||||
n = acc//24; acc %= 24`, which is the frame clock's shape for the frame clock's
|
||||
reason. **Third time this tree has met a ratio with a remainder**, and the rule
|
||||
it keeps writing is that rounding one *once* is an error and rounding it *every
|
||||
period* is a rate.
|
||||
|
||||
The four ADPCM axes ride in the header as fields rather than a version number,
|
||||
and the gate flips each one to show they earn it: **nibble order −31.99 dB,
|
||||
delta formula −24.86, clamp 0.00, accumulator −0.49**. Nothing parses a packed
|
||||
container, so the gate **partitions the whole file** — 131 spans, no overlap, no
|
||||
gap — and asserts what a cadence-blind player would read: exactly records
|
||||
11..119 wrong, **and frames 0..10 identical either way**, which is how an
|
||||
off-by-one like that survives a rig that checks frame 0. The wire is **582.0 +
|
||||
7.64 = 589.6 KB/s**, which is 65.3's prediction to the tenth (FINDINGS 67).
|
||||
|
||||
**The scene graph is in, and the worst gap between two decision points is
|
||||
zero.** `tools/import/scenegraph.py` imports the arcade scene graph — 40 scenes,
|
||||
516 sequences, 906 input windows — and 5.4% of the game's 612 branch transitions
|
||||
@@ -425,11 +456,13 @@ mounted) re-runs both display regression tests, the rate-control drift gate, the
|
||||
display-path coherency counterexample, a 120-frame 68000 decode on two CPU
|
||||
cores, the ring and paced-ring passes, the DMAC configuration gate and the
|
||||
load-time transforms on both cores, then imports and gates the scene graph
|
||||
when a DirkSimple checkout is present, then builds the packed container and
|
||||
renders it through px68k's own GVRAM model, then **runs the packed player for
|
||||
120 frames off a real volume and compares every one of them**, then encodes the
|
||||
same window's audio and gates it against ffmpeg's decoder, then prints
|
||||
`ALL GREEN`.
|
||||
when a DirkSimple checkout is present, then builds the packed container --
|
||||
with audio in it, and a silent control beside it -- and renders it through
|
||||
px68k's own GVRAM model, then **runs the packed player for 120 frames off a real
|
||||
volume and compares every one of them**, then encodes the same window's audio
|
||||
and gates it against ffmpeg's decoder, then asks the emulated MSM6258 which of
|
||||
sixteen decoders it is, then gates the DLXP2 container and every one of its
|
||||
axes, then prints `ALL GREEN`.
|
||||
|
||||
## Reproducing this
|
||||
|
||||
@@ -631,6 +664,11 @@ tools/import/ the ONLY code in this tree coupled to somebody else's source.
|
||||
project's own DLXSCENE1 schema, with the sources' licences and
|
||||
attribution inside it. Nothing is vendored and the output is
|
||||
gitignored derived data.
|
||||
34 is DLXP2's gate: the file partitioned into spans, the
|
||||
records checked against a SILENT control, the lumps checked
|
||||
byte-exact against the encoder, and one negative control per
|
||||
ADPCM axis. Nothing parses a packed container, so a lump one
|
||||
sector out does not fail -- it paints.
|
||||
30 is the PACKED container's gate: the format's invariants
|
||||
(round-trip, sectors, the transparency key, the palette word),
|
||||
and the quality re-derivation 61.9 asked for, in both the RGB888
|
||||
@@ -649,12 +687,19 @@ tools/encoder/ hybrid VQ encoder and DLX3 container writer.
|
||||
record as whole sectors straight into the ring with no window
|
||||
and no bounce copy; dlx.record_lengths() is the one place that
|
||||
rule is applied.
|
||||
dlxp.py and pack.py are the OTHER container -- DLXP1, the
|
||||
decoder-free packed one (FINDINGS 63). Nothing is shared with
|
||||
the codec's writer on purpose: a packed record is a palette and
|
||||
a picture, both geometry, and dlxp.py is the one place the
|
||||
interleave and the 97-sector record are stated. There is no
|
||||
rate control in pack.py because there is no rate lever.
|
||||
dlxp.py and pack.py are the OTHER container -- DLXP2, the
|
||||
decoder-free packed one (FINDINGS 63, 67). Nothing is shared
|
||||
with the codec's writer on purpose: a packed record is a
|
||||
palette and a picture, both geometry, and dlxp.py is the one
|
||||
place the interleave, the 97-sector record, the audio cadence
|
||||
and the lump PAYLOAD are stated. There is no rate control in
|
||||
pack.py because there is no rate lever.
|
||||
adpcm.py is the MSM6258 codec and it carries TWO decoders on
|
||||
purpose: the module defaults are ffmpeg's, so that
|
||||
tools/bench/verify_adpcm.py stays a check against an
|
||||
independent implementation, and adpcm.CHIP is the set measured
|
||||
out of the machine's own chip (66). Anything that encodes FOR
|
||||
the machine passes CHIP explicitly.
|
||||
dlx.py is the reference DECODER, ground truth for the 68000.
|
||||
24 models the ring with the 68000 owning it: the request
|
||||
queue, the poll-only-when-not-decoding rule and 54.4's frame
|
||||
|
||||
Reference in New Issue
Block a user