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:
prosolis
2026-08-25 11:22:38 -07:00
parent 6dd3fb3597
commit e3778f62b0
13 changed files with 1001 additions and 51 deletions
+32 -3
View File
@@ -667,10 +667,22 @@ echo "--- session 31: the PACKED container, and the picture re-derived (FINDINGS
# present, the way the codec's gate container is: a packed encode is 3 seconds
# because there is no k-means in it, so there is no reason to let a stale file
# stand between the encoder and the gate.
# The window's audio has to exist before the container can carry it, so the
# extraction that used to live in session 33's stage moves up here. Same seconds
# as the frames, and that is not a convenience: an audio stream that is not the
# same seconds as the picture is not this project's audio.
[ -f tmp/au_singe.raw ] || python3 tools/encoder/extract_audio.py 00223 tmp/au_singe.raw 15625 539.4 10.0
python3 tools/encoder/pack.py tmp/fr_singe tmp/packed_singe.dlxp \
--nframes "$NF" > tmp/pack_encode.log 2>&1 \
--nframes "$NF" --audio tmp/au_singe.raw > tmp/pack_encode.log 2>&1 \
|| { cat tmp/pack_encode.log; exit 1; }
grep -aE "^ (record|wire)" tmp/pack_encode.log
grep -aE "^ (record|wire|DLXP2|the four axes|lump payload)" tmp/pack_encode.log
# ...and the SILENT control beside it, which is what says the interleave moved no
# picture byte. It is the same encode with one flag off, and a packed encode is
# four seconds because there is no k-means in it, so the control is cheap enough
# to build every run rather than reason about.
python3 tools/encoder/pack.py tmp/fr_singe tmp/packed_singe_silent.dlxp \
--nframes "$NF" > tmp/pack_encode_silent.log 2>&1 \
|| { cat tmp/pack_encode_silent.log; exit 1; }
# WHAT IS GATED. Four format invariants that a DMA channel cannot check for
# itself -- it copies bytes and has no opinion about them (FINDINGS 62) -- and
# the three quality claims FINDINGS 61.9 rests the whole packed branch on:
@@ -740,7 +752,8 @@ echo "--- session 33: AUDIO -- the encoder, and what it does to the wire (FINDIN
# is the SAME WINDOW as the frames -- 00223 from 539.4 s for 10 s -- because an
# audio stream that is not the same seconds as the picture is not this project's
# audio, and a gate that lets the two drift apart would never say so.
[ -f tmp/au_singe.raw ] || python3 tools/encoder/extract_audio.py 00223 tmp/au_singe.raw 15625 539.4 10.0
# tmp/au_singe.raw was extracted by session 31's stage, which needs it to build
# the container.
# There is NO ffmpeg encoder for this format -- adpcm_ima_oki is decode-only --
# so the encoder cannot be checked against a reference. What is checked is that
# the decoder our encoder runs in its own loop IS ffmpeg's, sample for sample.
@@ -770,4 +783,20 @@ python3 tools/analysis/33_adpcm_model.py tmp/au_singe.raw > tmp/adpcm_model.log
grep -aE "wrong only here|played on the chip|decoded on the encoder|headroom left" \
tmp/adpcm_model.log
echo "--- session 35: DLXP2 -- a packed container with sound in it (FINDINGS 67) ---"
# ROADMAP P6b. 65.3 did the arithmetic and wrote no byte; 66 measured which of
# sixteen decoder models the chip runs. This is the container both produce, and
# it needs a gate of its own because NOTHING PARSES A PACKED CONTAINER: a lump
# one sector out does not fail, it paints 512 B of audio and plays 512 B of
# picture, and a gate that only looked for errors would pass it.
#
# The picture side of it is gated twice over: here against a SILENT control
# built from the same frames, and above by the packed player itself, which now
# carries the `(i//F)*A` term and still gets all 120 frames pixel-exact off a
# real volume.
python3 tools/analysis/34_packed_audio.py tmp/packed_singe.dlxp \
> tmp/packed_audio.log 2>&1 || { cat tmp/packed_audio.log; exit 1; }
grep -aE "^ (OK|FAIL) |^ (order|variant|bits|init) |min of play ->" \
tmp/packed_audio.log
echo "ALL GREEN"