D21: an E-mu record is closed by the channel it declares, and found by either one - #40
Merged
Conversation
`+34` is the right channel's end pointer, not the record's length. The walk took the extent from it unconditionally, which is right only where the right-hand set describes the record -- and on 10 274 of the 15 272 EIII/ESI records here the left-hand set does. Closes #39. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
Issue #39 reported three EIIIX/ESI discs each claiming a bank, returning no files and giving no reason — the ADR-0012 signature this project treats as a bug rather than a quirk. Twelve banks in all, ten of them on one disc.
None of them is the case ADR-0021 already explains. Every one declares a non-zero sample area, so
OFF_BANK_SAMPLE_BYTEShas nothing to say about any of them. The cause is one field read as something it is not, and it reaches a long way past those three discs.The finding
+34is the right channel's end pointer, not the record's length. It carried both names infs/emu3.py—OFF_SAMPLE_END_RandOFF_SAMPLE_RECORD_LEN— and the walk took the record's extent from it unconditionally. That is correct only where the right-hand pointer set is what describes this record's audio, and on 10 274 of the 15 272 EIII/ESI records across seven discs the left-hand set is.Four shapes the right-hand set takes when it is not describing the record it sits in:
+34as a length doesstart_R = 0,end_R = end_L − 92— the same channel counted from the payload's start instead of the record'sstart_R = end_R = 0start_R = 92 + F,end_R = 92 + 2F − 2for a constant allocation frameF— 1 MiB onE-mu Classics, 2 MiB onEIIIX Vol. 1start_R = 92with the left set not opening the audio (start_L = 0on 1 371 of them)The last one is the sharpest, because
docs/formats/emu3.mdalready recorded it: "Either set can be the single one — 542 records oneiv-studio… declare their one channel on the right", and "Read the set whose start is 92 and use it." That rule was applied to picking a loop and to nothing else. The EIII walk both located and sized a record from the left-hand pointer alone.The mirror-92 shape answers a question
docs/README.mdhad open since D17: "Either the reader is 90 bytes short on those samples or the extent field means something else." It was the reader, by 92 bytes.The decision
A record's extent is closed by the end pointer of the set that opens its audio, and a record is found by either set opening it (ADR-0029).
92at+22or at+26, deduplicated by address and yielded in address order, so which anchor found a record cannot change what is written.end + 2of the set whose start is 92 — the larger where both are.end_R + 2and covers both blocks. Stated from the pointers alone:start_L == 92,start_R == end_L + 2,end_R − start_R == end_L − start_L. That is ADR-0026's three conditions without reference to the payload size — which matters, because the payload size is what is being computed.What says it is right
Three things, none of them the pointer block agreeing with itself.
The stride to the next record.
end_L + 2equals the distance to the next record on 2 093 ofESI-32 General Midi's records;end_R + 2equals it on 30.The bank header's declared run — a different field, in a different structure. ADR-0021 measured a bank's last record ending exactly at
0x30 + 74 + 0x34on 72 banks and "exactly 92 bytes — one sample header — short of it" on 19 more, and recorded the second population as a loose fit. It is this bug, seen from the bank header:ESI-32 General MidiProtozoaEIIIX Vol. 1EIIIX Vol. 2E-mu ClassicsVintageDitto DrumsNo bank on any disc is left in the "92 bytes short" bucket. The reference bank says the same on its own:
8M GeneralMidi Xnow yields 531 records totalling 8 248 316 bytes, which is its declared run to the byte, where it previously yielded 452 records and 7 345 200 bytes inside a run nothing filled.The loops splice. The extent decides how much audio each sample is, so counts moving is not itself a reason to believe them. 838 of
ESI-32 General Midi's loops and 1 082 ofProtozoa's are newly admitted — exactly the loops ADR-0025 refused because the declared end ran past the payload, and with the corrected extent they fit without being clamped, which is the move that record showed destroys a loop. Scored by the format doc's own shape and join tests, with its controls:ESI-32 General MidiESI-32 General MidiProtozoaProtozoaProtozoaEIIIX Vol. 1EIIIX Vol. 1VintageThe record newly found rows are the right-declared and zeroed-right-set records, and they answer the obvious worry about widening a signature that scans through megabytes of audio. A false hit inside PCM does not carry a loop that splices at +0.9 against a control at zero.
What moves
ESI-32 General MidiProtozoaEIIIX Vol. 1EIIIX Vol. 2E-mu ClassicsVintageDitto DrumsThe collection goes from 104 921 samples to 109 554, and E-mu from 14 738 on seven discs to 19 371 on ten. All twelve banks of #39 yield files; the only volumes left empty on those discs are index banks and the sampler's own code banks, both of which already carry their note.
Anyone who extracted an EIII or ESI disc before this should do it again. On
ESI-32 General MidiandProtozoamost samples were 46 frames short at the end, and on every disc some samples were missing entirely.What does not move, and why that matters
The three E-IV discs are byte-identical — 449, 2 822 and 828 samples, same payload digests. They size a record from their own big-endian sample directory and never read
+34(ADR-0020), so they are the control that says nothing shared was disturbed.The stereo counts are unchanged on every disc that had them. Changing how long a record is did not change what shape it is.
Payload overlaps into the following record fall rather than rise — 439 to 238 on
EIIIX Vol. 1, 236 to 188 onEIIIX Vol. 2— and the newly found right-declared records land in the gaps between existing records rather than inside them: 0 of 353 onESI-32 General Midi, 0 of 607 onProtozoa, 1 of 18 onEIIIX Vol. 1.Every WAV still matches the disc it came from. 73 of 73 discs, 109 554 payloads, comparing multisets of SHA-256 over the PCM per disc; the ten E-mu discs were re-measured for this deliverable and match on all 19 371.
Protozoa's trombones resolveADR-0026 identified six records whose "first half is byte for byte the whole of a one-channel record of the same name in another bank" —
Trom B2, 16 756 bytes inside a 33 512-byte payload, with nothing on the disc matching the second half. There was no second half. Read at its declared length,Proteus1PresetsX'sTrom B2is 16 764 bytes and byte-identical toVintage PresetsX's andVintage InstrmtX's, as areTrom E3,Trom C5,Trom D4andTrom G4.That has a consequence for ADR-0026 worth stating plainly. Its gate's third condition caught 65 records that declared a two-channel shape and were not stereo; under the corrected extent that population is zero on all ten discs, because those records only ever looked like a split when sized at twice their length. The condition stays — it is what makes the two-channel test exact — but it is now an unexercised gate, and that is recorded rather than glossed.
What this deliberately does not claim
The whole-extent loop guard is not fixed here.
Ditto Drumswrites a loop spanning the entire sample on 934 of its 948 records, starting at frame 6 rather than frame 0, andsample/emu3.pyonly refuses a whole-extent loop that starts at exactly 0. The same pattern already ships onEIIIX Vol. 1(460) andEIIIX Vol. 2(320) and predates this deliverable. Folding it in would move the loop counts for two unrelated reasons at once and make neither attributable, so it is recorded indocs/formats/emu3.md,docs/README.mdand the README's "what doesn't work yet" instead.A fifth shape of right-hand set would still be silent. The rule refuses a record where neither set opens the audio at 92. That is a drop of exactly the kind this change exists to remove; it would present as a bank yielding fewer records than its run declares, and the new bank-run test is what would catch it.
Tests
The disc suite skips without
SAMPLERDISC_TEST_DISCS, so the mechanism is pinned in both places.tests/test_emu3.pygains synthetic coverage ofrecord_extent— all four right-hand-set shapes, the two-channel exception, and the two refusals — plus walk-level tests that a bank of right-declared records and a record with its unused side zeroed both read. These run in CI, where there are no discs.tests/test_discs.pyre-pins the four EIII/ESI discs and adds the three new ones; asserts the three E-IV rows unmoved; pins the twelve banks of emu3: three EIIIX volumes claim a bank and return no files with no note #39 by shape as well as by count, so the day one stops holding it says which of the three ways it stopped; and asserts the bank-run agreement above, since that is the independent evidence the decision rests on and is exactly what a later simplification would quietly break.One piece of shared test infrastructure changed.
_pinned_discfinds a disc by size, on the measured assumption that sizes are distinct across the collection. A whole publisher's series arriving at once is where that stops holding:E-mu Classicsshares 526 723 072 bytes withVol. 03 – Orchestral, andStudio Essentialsshares 399 077 376 withMore Studio Essentials. The pin now falls back to a digest of the image's first megabyte where two share a size — still a property of the disc rather than of its filename (ADR-0004) — and is consulted only on a collision, so every other pin is untouched.Closes #39.
🤖 Generated with Claude Code