Skip to content

AKAI: read every partition, from the table the disk declares - #26

Merged
bmxcode merged 1 commit into
mainfrom
d22-akai-partitions
Aug 21, 2026
Merged

AKAI: read every partition, from the table the disk declares#26
bmxcode merged 1 commit into
mainfrom
d22-akai-partitions

Conversation

@bmxcode

@bmxcode bmxcode commented Aug 21, 2026

Copy link
Copy Markdown
Owner

Closes #22.

An AKAI disc is a disk image: the sampler wrote a hard disk of several partitions and the CD is a copy of it. AkaiBackend.volumes() walked the partition the origin resolved to and stopped, so across the 44 AKAI discs on the shelf it listed 448 volumes and 14 670 files of the 2 154 volumes and 68 997 files they hold. Loop Soup reported 7 volumes; it has 60.

The partition table exists, and this reads it

#22 recorded partitions as tiling at multiples of the size declared at 0x00 — an observation across 44 discs, not a field anyone had read — and asked, before anything was built on it, whether the disc declares a table anywhere. It does.

At 0x4500 of the first partition, past the largest allocation map that fits in front of it:

Offset Contents
+0x00 u8, the number of partitions
+0x01 u8, 0 on 37 discs and 1 on the other 7. Unexplained
+0x02 that many u16 LE partition sizes, in blocks, in order
+2n+2 u16 LE, the total blocks on the disk

All 44 AKAI discs carry one, and on all 44 the sizes sum to the total. Loop Soup declares nine partitions — eight of 7680 blocks and a last of 4095, totalling 65 535, which is the ceiling u16 block numbers imply.

That last entry is what tiling could not have got right. The sizes are not all equal: the final partition is a remainder. Tiling places the same partitions everywhere both rules can be applied, and then invents a fourteenth on AKAI.S3000.Sound.Library.1 at block 65 535 that the disk does not declare. This is the register ADR-0021 settled one deliverable ago: a field the disc states beats a bound inferred between structures.

The other candidate #22 named — the 100 u16 at 0x02 that ramp by 3333 on every disc — declares nothing. Its 196 bytes are byte-identical on every disc and every partition, so nothing in it varies with anything. What does vary is the pair after it: the u16 at 0xC6 is the block count plus 47573 and the u16 at 0xC8 is 47, on all 276 partitions measured. That is the header restating its own size, and it is what confirms a partition is where the table says without trusting the arithmetic that placed it.

What it costs to get wrong, and how this is checked

Block numbers are relative to the partition, so the same number means a different place in each one, and a read with the partition term dropped returns another partition's audio rather than an error. Three independent checks say it is right:

  • Partition 1 does not move on any disc. 448 volumes and 14 670 files before and after, pinned per disc in tests/test_discs.py (_AKAI_FIRST_PARTITION) precisely because the failure mode here is plausible output rather than an exception.
  • The new files verify against a structure that did not place them. Of 44 174 samples past the first partition, 44 101 — 99.83 % — carry a payload header whose id, valid byte and 12-character name match the directory entry. That is the same rate as the partitions already being read (19 mismatches in 12 316, nine of them A sample payload whose header disagrees with its directory entry is extracted silently #23's). On Loop Soup all 3 200 agree exactly, and a disc test asserts it.
  • The allocation map agrees with every file's size, per partition. Extended from 14 607 of 14 607 in the first partitions to 68 267 of 68 284 across all 276. All seventeen exceptions are one thing: a MULTI FILE — type m, all on Library.1 — whose chain runs exactly one block past what its size needs. Named in the test rather than tolerated, so a second kind of disagreement fails.

The content is plainly the disc's own: Loop Soup's partition 1 ends at SOUP 115-117 and its partition 2 opens at SOUP 120.

The three discs #22 could not explain

AKAI.S3000.Sound.Library.6, .7 and Elektra Vox are not laid out differently. They are short images. Where a declared partition has no header at its position, one turns up earlier — and every displacement is a whole number of 32 KB MDX blocks, accumulating down the disc (Library.6 by 60 then 68; Elektra Vox from 424 to 2888 over nine partitions). All are .mdx. That is the finding #17 reached from inside partition 1, now measurable from outside it.

Those partitions are not recovered here, and #25 records why with the numbers: the header's constant field is a sawtooth as PCM so audio matches it (374 blocks of free space on one disc), filtering those by "does a volume yield a file" loses real partitions elsewhere, and 7 723 of the ~15 000 files a search would gain are on Kickin' Lunatic Beats 2 CD1, whose partition 1 already extracts nine samples that are not their own (#23).

What changes for a user

Extraction paths. AKAI samples now land in out/partition-1/VOLUME 001/… where they landed in out/VOLUME 001/…, on every AKAI disc including single-partition ones. Nearly every partition of a disc has a VOLUME 001, so a flat layout put two libraries' audio in one directory under unique_path suffixes with nothing saying which was which — not a lost file, an unusable one. The batch manifest keys volumes by partition and name for the same reason. Making the layout conditional on a disc having several partitions was considered and rejected: a layout that varies by disc is worse than one that moved once.

list reports the table: 9 partitions declared, 9 present in this image, then volumes under their partition. Kickin' Lunatic Beats 2 CD1 prints eleven declared and one present — its missing ten used to be an absence with nothing to see.

What this does not claim

  • The flag byte at +0x01, the 196-byte constant and the 0xC8 tail are unread. They are recorded as unread.
  • 512 MB is corrected in the format doc from a cap on a partition to the ceiling on a disk: block numbers are u16, no disc declares a total above 65 535, and a partition runs 3840–7680 blocks.
  • Nothing is recovered from a short image, and nothing here detects displaced audio — that is A sample payload whose header disagrees with its directory entry is extracted silently #23, still open.
  • The table has only been found in the first partition. A disc whose first partition is damaged falls back to reading one partition, quietly, because that is also the honest answer for a disc that declares no table.

Also here

  • allocation_map takes its block count from a header that restates it, rather than from what the image can hold. A partition the image ends inside now gets the map for the blocks present, which is what stopped two volumes on ProSamples vol.17 being empty and silent — the ADR-0012 signature raised by a short image rather than by a disc declaring nonsense. ADR-0022's "no map, no note" is narrowed to a count that is absent or unvouched for, and amended in place to say so.
  • A file's block bound is now its partition rather than the image. No volume or file on the 44 discs points past its own partition, so nothing is rejected that was read before.

Verification

ruff check, ruff format --check, pytest -q and the installed entrypoint all pass. SAMPLERDISC_TEST_DISCS against the 38-image regression set: 433 passed, no skips (170 before this branch, on the disc module alone; 181 after, plus the new synthetic tests). Collection-wide, by listing: 71 of 79 images claimed, 2 578 volumes and 110 989 files, from 872 and 56 662.

🤖 Generated with Claude Code

An AKAI disc is a disk image and the walk stopped at the partition the
origin resolved to, so 44 discs listed 448 volumes and 14 670 files of
the 2 154 and 68 997 they hold (#22).

The disk declares its partitions: a table at 0x4500 of the first one,
carrying a count, that many sizes in blocks and the disk's total. All 44
discs have one and on all 44 the sizes sum to the total. A partition is
read only where a header sits at the position the table gives and
restates the size it was given, and a declared position with no header
is skipped rather than searched for.

Block numbers count from the partition they are in, so a Volume and a
File now carry the offset theirs count from and read_file adds it.
Extraction nests under the partition, since volume names repeat.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@bmxcode
bmxcode merged commit 0a2b6f3 into main Aug 21, 2026
1 check passed
@bmxcode
bmxcode deleted the d22-akai-partitions branch August 21, 2026 06:51
bmxcode added a commit that referenced this pull request Aug 21, 2026
)

The "Only the first partition of an AKAI disc is read" entry under
Unreleased / Known limits contradicted the Added bullet in the same
section: PR #26 read every partition from the table at 0x4500 and closed
issue #22, and this entry should have gone with it. Its own explanation
was also superseded — partitions come from the table, not from tiling at
multiples of the size at 0x00, and their sizes are not all equal
(ADR-0023).

What survives is the narrower limit ADR-0023 states plainly: a declared
partition with no header at its declared position is skipped rather than
searched for, leaving roughly fifteen thousand readable files unread on
the nine short images, which is issue #25. That is what the bullet now
says.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.

AKAI: only the first partition of a multi-partition disc is read

1 participant