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:
+112
-1
@@ -1,4 +1,115 @@
|
||||
# Status & next-session handoff — end of session 34 (2026-08-25)
|
||||
# Status & next-session handoff — end of session 35 (2026-08-25)
|
||||
|
||||
## Session 35: the packed container gets sound, and the padding is drift
|
||||
|
||||
**Green light first and last: `./tools/bench/check.sh` was ALL GREEN before any
|
||||
of this (`tmp/check_s35_start.log`) and ALL GREEN after
|
||||
(`tmp/check_s35_end.log`)** — the same stages, plus one new one.
|
||||
|
||||
**FINDINGS 67. ROADMAP P6b is DONE.** `tools/encoder/dlxp.py` (DLXP2),
|
||||
`tools/encoder/pack.py --audio`, `tools/analysis/34_packed_audio.py`,
|
||||
`src/player/packed.s`, `tools/bench/prep_packed.py`, `tools/bench/packed.lua`,
|
||||
`tools/analysis/30_packed_container.py`, `tools/bench/check.sh`.
|
||||
|
||||
**NAME THE LAYER.** The container is **host arithmetic**. What ran on the
|
||||
emulated 68000 is its *video* consequence: `packed.s` now carries the third LBA
|
||||
term and fetches 120 records out of an interleaved container off a real MB89352
|
||||
volume, all 120 pixel-exact. **No audio byte has been played out of this
|
||||
container on any layer.**
|
||||
|
||||
**1. THE FORMAT.** 64-byte header; from sector 1, groups of one `A`-sector audio
|
||||
lump then `F` records. `record i = off_frm + i*rec + (i//F)*A*512`,
|
||||
`lump k = off_aud + k*(F*rec + A*512)`. **Still no index and still none needed**,
|
||||
which was the packed branch's whole claim and is the thing a second stream could
|
||||
have ended. The lump goes **before** the group it feeds; 65.3's formula put it
|
||||
after, and a stream is read forwards. On the 68000 it costs **six instructions
|
||||
once a frame** and zero parsing. The four ADPCM axes ride in the header as
|
||||
fields, not a version number.
|
||||
|
||||
**2. THE HEADLINE, AND 65.3 CALLED IT THE WRONG THING.** A lump is 7,168 B of
|
||||
*space*; eleven frames of audio is **7,161.4583… B**, so the payload alternates
|
||||
**7,161 / 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` — the same shape as `clock.i` and for
|
||||
the same reason. **Third time this tree has met it** (54, 65.3, now).
|
||||
|
||||
**3. THE GATE, AND ITS THREE NEGATIVE CONTROLS.** Nothing parses a packed
|
||||
container, so a lump one sector out does not fail, it paints. `34_packed_audio.py`
|
||||
therefore (a) **partitions the whole file** — 131 spans, no overlap, no gap,
|
||||
ending on the last byte — because a per-record read cannot see an off-by-one
|
||||
that shifts everything after it; (b) asserts a **cadence-blind player** gets
|
||||
exactly records 11..119 wrong, **109 of 120, and frames 0..10 identical either
|
||||
way**, which is how such a bug survives a rig that checks frame 0; (c) **flips
|
||||
each of the four ADPCM axes one at a time** — nibble order **−31.99 dB**, delta
|
||||
formula **−24.86 dB**, clamp 0.00, accumulator −0.49 — so the header fields are
|
||||
load-bearing rather than documentation. And the picture is gated against a
|
||||
**silent control** built from the same frames: all 120 records byte-identical.
|
||||
|
||||
**4. THE WIRE IS THE PREDICTION.** 582.0 + 7.64 = **589.6 KB/s**, which is
|
||||
65.3's figure to the tenth, because none of 66's four axes changes a byte count.
|
||||
|
||||
**RISKS IN THIS SESSION'S RESULT:**
|
||||
|
||||
- **Nothing has been heard.** The container has audio in it; no transport has
|
||||
fed it to a chip, on any layer.
|
||||
- **The lump buffer is not allocated anywhere.** 65.3 charges 14,336 B for
|
||||
double-buffering the cadence and no player holds it.
|
||||
- **Two channels have never run at once.** The audio DMA is 1.25%..1.48% of a
|
||||
frame *in isolation* (52); the video channel holds the bus (64.2/64.3).
|
||||
- **The level is still open downward** (66.3) and the loudest passage on the
|
||||
disc is still unmeasured.
|
||||
|
||||
## HANDOFF — start here
|
||||
|
||||
**THE TREE IS ALL GREEN**, session 35's stage included.
|
||||
|
||||
### The work, in the order it should be done
|
||||
|
||||
**1. THE LAST QUARTER OF P6 — audio out of the container, on the machine.**
|
||||
Everything it needs now exists and none of it has been joined up: the container
|
||||
carries the bytes (67), the transport is `adpcm.i`'s channel-3 configuration
|
||||
which worked first time (66.1), and the missing piece is **the lump buffer and
|
||||
the remainder accumulator in a player**. Do the accumulator as 67.2 states it or
|
||||
the run drifts 1.25 s over a game.
|
||||
|
||||
**2. AND THEN THE THING NEITHER HALF HAS MET: TWO CHANNELS AT ONCE.** The video
|
||||
channel holds the bus and halts the 68000 (64.3 — it costs the frame clock half
|
||||
its ticks *without the clock being able to tell*). An audio channel that has to
|
||||
be serviced during that hold has never been run. This is the interaction 52
|
||||
could not have had, and `32_audio_wire.py` names it: audio does not merely cost
|
||||
clocks, it costs **darkness**.
|
||||
|
||||
**3. THE REFILL CLIMB WITH A SECOND CONSUMER** through a real branch point
|
||||
(51.3, 55.4). The slack table is in `32_audio_wire.py`; nothing has been run.
|
||||
|
||||
**4. THE AUDIO LEVEL, which 66.3 reopened.** Measure the loudest passage on the
|
||||
disc before choosing a level.
|
||||
|
||||
### What is still BLOCKED, so it is not picked up by mistake
|
||||
|
||||
**K4 — the packed player that is on screen — is conditional on B2**, a board
|
||||
question. **E7, E4 and C1** are parked (61.8), and **P4a's wiring** is parked
|
||||
with the ring K3 deleted.
|
||||
|
||||
**The hardware list is unchanged and is the user's**: B1 (sustained AND the
|
||||
data-phase BURST rate, 64.2 — and the acceptance figure is now **589.6 KB/s**,
|
||||
not 582.0), B2 (blanking), B3 (`#EXREQ`), B4 (a byte write to a palette
|
||||
register), and session 34's fifth: play a known nibble stream on a real
|
||||
MSM6258V and record the line out.
|
||||
|
||||
### Reproducing this session
|
||||
|
||||
./tools/bench/check.sh # ALL GREEN
|
||||
python3 tools/encoder/pack.py tmp/fr_singe tmp/packed_singe.dlxp \
|
||||
--nframes 120 --audio tmp/au_singe.raw
|
||||
python3 tools/analysis/34_packed_audio.py # the DLXP2 gate on its own
|
||||
|
||||
**WHAT IS NEXT.** P6's last quarter: the container's own audio, out of a
|
||||
channel, beside the video channel that holds the bus.
|
||||
|
||||
---
|
||||
|
||||
## Session 34: the chip is asked, and the encoder was wrong on four axes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user