Skip to content

EMU3: decode the loop from the record's pointer block - #31

Merged
bmxcode merged 2 commits into
mainfrom
d17-emu3-loops
Aug 21, 2026
Merged

EMU3: decode the loop from the record's pointer block#31
bmxcode merged 2 commits into
mainfrom
d17-emu3-loops

Conversation

@bmxcode

@bmxcode bmxcode commented Aug 21, 2026

Copy link
Copy Markdown
Owner

What this does

Every other backend carries what its disc knows about a sample into the WAV's own smpl chunk — AKAI since D7, Roland since D13, AIFF since D16. The E-mu path carried none, so 14 738 samples across seven discs shipped as plain WAV and their loop points were lost the moment the disc was. ADR-0011 calls dropping that data loss, not neutrality.

8 039 of the 14 738 now carry their loop points.

Disc Samples With a loop
esi32-gm 2 265 107 5%
eiiix-1 1 189 1 157 97%
eiiix-2 1 333 1 260 95%
protozoa 5 852 1 689 29%
eiv-analogia 449 449 100%
eiv-studio 2 822 2 551 90%
eiv-vitous 828 826 100%

The eight fields were never eight fields

docs/README.md listed the record's undecoded middle as +18, +24, +28, +32, +36, +40, +44, +48. That is a four-byte stride begun in the wrong place: a u32 read at +28 straddles two real fields, which is why those columns dump as nine-digit noise and why nothing was ever made of them.

The record carries an eight-pointer block at +22, +26, +30, +34, +38, +42, +46, +50 — a start, an end, a loop start and a loop end, per channel, each a byte offset from the record's own start naming the first byte of a 16-bit word.

The strongest argument that this reading is right is how much of the existing doc it explains for free:

  • OFF_SAMPLE_HEADER_LEN was never a header length. It is start_L, reading 92 because the header is 92 bytes and the audio begins immediately after it — which is also why it works as the record signature. docs/formats/emu3.md recorded that this field "reads 92 on most E-IV records and 0 on 547 of eiv-studio's — those carry 92 at +26 instead" and left it as an oddity. Those records declare no left channel. Not a broken field: a different value of a working one.
  • RECORD_LEN_BIAS = 2 stops being a bias. +34 is end_R, which addresses the last word rather than one past it.
  • +34 == 2 × (+30) − 90, reported in the "Everything is mono" section without an explanation, is end_R = end_L + P/2.

How the loop was established

The oracle is the one formats/roland-s7xx.md used for the S-7xx sustain loop, guards included — a minimum loop length and a minimum amplitude at both ends, because that record says in as many words that a metric that rewards silence will find plenty of it. Two tests on different evidence. The join is |x[E−1] − x[L]| over the mean step measured in a window at each end; the shape test correlates the waveform at L against the waveform at E, and is the stronger instrument here.

The control is the same loop end with the start put somewhere else, which is the only thing that isolates the field in question.

Disc Publisher scored shape r control join seamless
eiiix-1 E-mu 512 +0.70 +0.02 0.66 91%
eiiix-2 E-mu 526 +0.73 −0.01 1.12 81%
protozoa E-mu 723 +0.83 −0.01 1.22 83%
esi32-gm E-mu 16 +0.64 +0.17 0.32 81%
eiv-studio Producer Series 1 051 +0.86 −0.02 1.49 79%
eiv-vitous Miroslav Vitous 144 +0.68 −0.06 2.30 64%
eiv-analogia Producer Series 34 −0.00 +0.02 2.44 53%

Six of seven discs, both E-mu generations, three publishers. ADR-0020's independence requirement is met and then some.

What the end field is not. +46 and +30 sit six frames apart on most records, so no test separates them. The start is what is established, along with the fact that the pair splices.

A loop end past the audio is refused, not clamped

This is the finding that made the measurement work, and the one place this format parts company with the rest of the project. AKAI and Roland both clamp a declared end back to the audio actually present, because these rips run a little short of their directories. Doing that here destroys the loop, and protozoa shows it on a single disc within a single record shape:

protozoa, one-channel records count shape r control
loop end already inside the payload 689 +0.86 −0.04
loop end past the payload, clamped back 525 −0.10 +0.01

Same disc, same shape, separated only by whether the end fits. A clamped end is a loop point the disc did not state.

That is most of why esi32-gm — the format doc's own reference disc, whose 8M GeneralMidi X is its worked example — yields loops on 5% of its samples. It declares an extent about 45 frames past the payload on nearly every record.

What this deliberately does not claim

There is no root key, and none is invented. No byte of the 92 tracks the note written in the sample's own name: over 1 741 named records on esi32-gm the best byte matches at any constant offset on 8%, and 917 on eiiix-1 on 6% — chance, on constant-zero bytes. +58 is the field that looks most like it and turns out to be the sample rate (64 096 ↔ 12 000, 64 184 ↔ 13 000, 64 388 ↔ 15 625). The E3 keeps root key in its preset and presets are not read.

Deriving one from the sample name — Piano E0 → 28 — would have covered 1 741 records of one disc and is rejected, as the most important rejection in ADR-0025. A name is a label someone typed; the output would be indistinguishable from a value the disc actually stated, which is the failure ADR-0012 exists to prevent. The WAV carries its loop with MIDIUnityNote 60, the RIFF neutral value, and every document says plainly that 60 is a placeholder.

eiv-analogia does not confirm on its own evidence, and is reported that way. 441 of its 449 records pass every structural gate but only 34 carry audio loud enough at both ends to score, and those 34 show nothing. That is a lack of power rather than a refutation; its loops rest on the rule the other six discs establish. It is stated rather than smoothed over.

Which of esi32-gm's two lengths is right is open. Either the reader is 90 bytes short on ~2 200 records or the extent field means something else. Scanning candidate ends across ±96 frames and taking the shape peak does not settle it: within ±2 frames of the declared end on 10% of esi32-gm's records and 20% of protozoa's, against ~3% for chance. Better than chance, nowhere near an answer, so nothing is changed on it.

This overturns a rejected alternative in ADR-0020

ADR-0020 rejected "treat the paired length fields as a channel count" on a measurement, and that measurement tested the wrong hypothesis. It de-interleaved payloads as LRLR and found the roughness roughly doubled — a sound refutation of interleaved stereo. The pointer block says the layout is a block split, all left then all right, which de-interleaving cannot detect: read as mono it is one continuous waveform with a single join in the middle.

Measured directly, on records whose own pointers declare two channels, the halves are the same performance — median RMS-envelope correlation:

esi32-gm eiiix-1 eiiix-2 protozoa analogia studio vitous
two channels declared 0.99 0.71 0.95 0.55 0.91 0.96 0.82
one channel declared 0.13 0.16 0.59 0.26 0.21 0.22

So roughly 2 700 of the 14 738 E-mu samples are stereo and are currently written as double-length mono. That is the largest known defect in the E-mu path and it is not fixed here: correcting it moves audio, and this deliverable was scoped to add metadata without touching a byte of payload. ADR-0020 is annotated rather than edited, docs/README.md lists it under what is not done, and it has an issue.

The loop points survive that fix unchanged: (pointer − start) / 2 is a per-channel frame index either way.

Additive, and asserted rather than claimed

Nothing here touches read_file or the offset arithmetic. Saying so is not enough — a table of sample counts cannot see a payload that shifted by a byte while staying the same length — so tests/test_discs.py now pins the SHA-256 of every sample payload per disc beside the counts. All seven digests are identical to the release before this branch, verified by running the same walk on main.

The per-disc loop counts are pinned as tightly as the sample counts, for the reason the AKAI table pins its noted-volume counts: a loop appearing where none was measured is a gate come loose, and one disappearing is the decode silently failing on a disc nobody looked at.

Verification

  • uv run ruff check . · uv run ruff format --check . · uv run pytest -q — clean.
  • SAMPLERDISC_TEST_DISCS=~/repo/projects/sample-images uv run pytest -q — clean across the whole shelf, not only the E-mu discs.
  • uv tool install --editable . && samplerdisc --version — 0.3.0.
  • End to end: extracting eiiix-1's Full Arco String gives 14 WAVs whose data chunks are byte-identical to the disc and all 14 carry an smpl chunk — e.g. Arco Violin F#2, loop (23 455, 63 893) in 127 798 frames.

🤖 Generated with Claude Code

The 92-byte sample record's undecoded middle is an eight-pointer block --
a start, an end, a loop start and a loop end per channel, as byte offsets
from the record's own start. 8 039 of the 14 738 E-mu samples now carry
their loop points in the WAV smpl chunk.

Established from the audio: the waveform at the loop start correlates with
the waveform at the loop end at +0.64 to +0.86 on six of seven discs,
against a control of about zero. A loop end past the audio is refused
rather than clamped, which is where this format parts company with AKAI
and Roland -- clamping turns +0.86 into -0.10 on protozoa's own records.

No root key ships: the record does not carry one, measured against the
notes in the sample names over 2 658 records.

Additive by construction, and asserted -- the disc-backed suite now pins
the SHA-256 of every sample payload per disc, and all seven are unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@bmxcode
bmxcode merged commit 12052a4 into main Aug 21, 2026
1 check passed
@bmxcode
bmxcode deleted the d17-emu3-loops branch August 21, 2026 11:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant