Skip to content

Add pluggable AudioSectorReader file backing (1.0)#58

Open
danifunker wants to merge 5 commits into
Bloomca:mainfrom
danifunker:file-backend-on-1.0
Open

Add pluggable AudioSectorReader file backing (1.0)#58
danifunker wants to merge 5 commits into
Bloomca:mainfrom
danifunker:file-backend-on-1.0

Conversation

@danifunker

Copy link
Copy Markdown
Contributor

Summary

Adds a hardware-independent seam for reading CD-DA tracks from a file/image
(CHD, BIN/CUE, in-memory, network, …) reusing the crate's existing TOC/track
machinery, with no image-format dependencies pulled into the crate. Also bumps
to 1.0.0, the first release carrying the breaking 1.0 API already on main.

This is the file-based-backend work rebuilt on top of the 1.0 API rather than
git-rebased: main and that branch had independently built data-track support, so
a literal rebase would have collided and dragged back the older implementation.
Only the genuinely-unique file backing is ported here.

Public API additions

  • AudioSectorReader trait — implement read_audio_sectors(start_lba, count) for
    any backing that yields raw CD-DA sectors (2352 B, 16-bit signed LE, stereo).
  • read_track(&src, &toc, n) -> Result<Vec<u8>, TrackReadError<E>> — the
    file/image counterpart to CdReader::read_track; TrackReadError keeps a bad
    track request (Toc) separate from a backing failure (Backend(E)).
  • Free create_wav(Vec<u8>) and public lba_to_msf(u32) — the support surface a
    backing needs (WAV wrapping without naming CdReader; building a Toc from
    image metadata).
  • CdReader itself implements AudioSectorReadeked code share the generic read_track` path.

No changes to existing drive behavior.

Examples

  • examples/file_backend.rs — dependency-free ihe seam
    without a decoder).
  • examples/save_data_track.rs — detect a data it
    cooked to a mountable .iso (bounded memory),t command;
    Mode 2 falls back to saving complete raw secto

Docs

  • docs/consuming-cd-da-reader.md — downstream-del,
    sector formats, detect_track_format, the dats Mode 2,
    file backing, and a pre-1.0 → 1.0 migration ta
  • README: "Reading data tracks" and "Reading from a file image" sections.

Verification

cargo fmt --check, cargo clippy --all-targets -- -D warnings, and
cargo test (49 unit + 6 doctests) all pass. fnd (valid RIFF…WAVE, correct sizes). The drive-dependent examples (save_data_track, read_data_track`) are compit path
needs a physical mixed-mode disc.

Note for reviewers

The 1.0.0 bump rides along with this feature. If you'd rather tag the release
independently, land the version commit (`885335ed keep
this PR purely additive — or just squash-merge.

danifunker and others added 3 commits July 12, 2026 18:44
Reconstructs the pluggable file/image backing from the pre-1.0
`file-based-backend` branch on top of main's unified read API, since a
literal rebase would collide with main's independently-built data-track
support.

- backend.rs: AudioSectorReader trait, `read_track` free fn, and
  TrackReadError, with the CdReader impl now reading via
  `read_sector_range(.., &ReadOptions::default())`.
- Expose the support surface the seam needs: free `create_wav` and a
  public `lba_to_msf` (for building a Toc from image metadata).
- examples: file_backend (dependency-free backing) and save_data_track
  (detect -> read cooked -> save .iso -> mount).
- docs/consuming-cd-da-reader.md: downstream-consumer guide covering the
  options model, sector formats, detection, the data-track workflow,
  Mode 1 vs Mode 2, file backing, and a pre-1.0 -> 1.0 migration table.
- README: data-track and file-image sections.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The data-track example read the entire track into a Vec before writing —
a full data track can be hundreds of MB. Switch it to the streaming API
(open_track_stream_with_options) so cooked/raw chunks are written as they
arrive and peak memory is one ~64 KB chunk regardless of track size.

Both the ISO (Mode1Cooked) and Mode 2 branches now share one
stream_track_to_file helper with a progress line, which also showcases
that reading and streaming run over the same options/read path. Docs
updated to recommend streaming for large images.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
First release carrying the breaking 1.0 API (SectorReadFormat, per-read
ReadOptions, detect_track_format) plus the AudioSectorReader file backing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Bloomca

Bloomca commented Jul 14, 2026

Copy link
Copy Markdown
Owner

@danifunker hey, thanks for the PR.

I looked over it but I am a bit confused on how is it supposed to be used. In the description you mentioned the BIN/CUE and network. So is it intended to turn CUE + PCM data into individual files? But if you have that, wouldn't you have tracks as actual tracks and not just PCM data? And if you have a CD image, wouldn't it be easier to mount it into a virtual drive?

@danifunker

Copy link
Copy Markdown
Contributor Author

Thanks for review it so quickly! I may read like a format-conversion feature, but it's really just an abstraction seam - it parses/converts nothing and pulls in no image-format deps. I am hoping for a native rust-only solution for my projects.

AudioSectorReader is a one-method trait: read_audio_sectors(start_lba, count) -> Vec of raw 2352-byte sectors. BIN/CUE, CHD, and "network" were just examples of backings a user could implement - not formats the crate reads. The value is reusing everything above the raw read (track-boundary math incl. the CD-Extra trailing-gap rule, plus create_wav), which is currently welded to the SCSI path. CdReader now implements the trait too, so drive- and file-backed code share one read_track.

To answer your questions:

  • "wouldn't you have tracks as actual tracks, not just PCM?" Answer: Usually no. A CHD, or .bin+.cue, or a raw dump is one contiguous run of sectors + a TOC of offsets (same shape a physical disc presents), not per-track files. Computing where a track really ends; especially the CD-Extra gap, is the non-trivial bit this crate already gets right; the seam lets image-backed code reuse it instead of re-deriving it wrong.
  • "wouldn't mounting a virtual drive be easier?" Answer: Mounting needs OS privileges, is platform-specific, and getting bin/cue audio tracks mounted can be quite the headache, especially in MacOS. This keeps it a pure bytes in → PCM out computation with no drive at all — see examples/file_backend.rs: an in-memory backing, no drive, no deps.

I've already implemented this in one of my cross-platform projects which helps users identify what discs they may be looking at, and provides a way to "listen to the track" in the case users are familiar with the music (think vintage video-game CDs, or older OSTs/Anime CDs).

@Bloomca

Bloomca commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Alright, I am going to review it properly tomorrow! We definitely don't want to bundle the 1.0 update with this PR, I update all releases as a separate PR/commit

@danifunker

Copy link
Copy Markdown
Contributor Author

Sounds fair! I thought you may have overlooked that a bit. Do you want me to revert that part of the PR?

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.

2 participants