Skip to main content

Crate cd_da_reader

Crate cd_da_reader 

Source
Expand description

§CD-DA (audio CD) reading library

This library provides cross-platform audio CD reading capabilities (tested on Windows, macOS and Linux). It was written to enable CD ripping, but you can also implement a live audio CD player with its help. The library works by issuing direct SCSI commands and abstracts both access to the CD drive and reading the actual data from it, so you don’t deal with the hardware directly.

All operations happen in this order:

  1. Get a CD drive’s handle
  2. Read the ToC (table of contents) of the audio CD
  3. Read track data using ranges from the ToC

§CD access

The easiest way to open a drive is to use CdReader::open_default, which scans all drives and opens the first one that contains an audio CD:

use cd_da_reader::CdReader;

let reader = CdReader::open_default()?;

If you need to pick a specific drive, use CdReader::list_drives followed by calling CdReader::open with the specific drive:

use cd_da_reader::CdReader;

// Windows / Linux: enumerate drives and inspect the has_audio_cd field
let drives = CdReader::list_drives()?;

// Any platform: open a known path directly
// Windows:  r"\\.\E:"
// macOS:    "disk6"
// Linux:    "/dev/sr0"
let reader = CdReader::open("disk6")?;

macOS note: querying drives requires claiming exclusive access, which unmounts the disc. Releasing it triggers a remount that hands control to the default app (usually Apple Music). Use open_default or open with a known path instead of list_drives on macOS.

§Reading ToC

Each audio CD carries a Table of Contents with the block address of every track. You need to read it first before issuing any track read commands:

use cd_da_reader::CdReader;

let reader = CdReader::open_default()?;
let toc = reader.read_toc()?;

The returned Toc contains a Vec<Track> where each entry has two equivalent address fields:

  • start_lba – Logical Block Address, which is a sector index. LBA 0 is the first readable sector after the 2-second lead-in pre-gap. This is the format used internally for read commands.
  • start_msf — Minutes/Seconds/Frames, a time-based address inherited from the physical disc layout. A “frame” is one sector; the spec defines 75 frames per second. MSF includes a fixed 2-second (150-frame) lead-in offset, so (0, 2, 0) corresponds to LBA 0. You can convert between them easily: LBA + 150 = total frames, then divide by 75 and 60 for M/S/F.

§Reading tracks

Pass the Toc and a track number to CdReader::read_track. The library calculates the sector boundaries automatically:

use cd_da_reader::CdReader;

let reader = CdReader::open_default()?;
let toc = reader.read_toc()?;
let data = reader.read_track(&toc, 1)?; // we assume track #1 exists and is audio

This is a blocking call. For a live-playback or progress-reporting use case, use the streaming API instead:

use cd_da_reader::{CdReader, RetryConfig, TrackStreamConfig};

let reader = CdReader::open_default()?;
let toc = reader.read_toc()?;

let cfg = TrackStreamConfig {
    sectors_per_chunk: 27, // ~64 KB per chunk
    retry: RetryConfig::default(),
};

let mut stream = reader.open_track_stream(&toc, 1, cfg)?;
while let Some(chunk) = stream.next_chunk()? {
    // process chunk — raw PCM, 2 352 bytes per sector
}

§Track format

Track data is raw PCM, the same format used inside WAV files. Audio CDs use 16-bit stereo PCM sampled at 44 100 Hz:

44 100 samples * 2 channels * 2 bytes = 176 400 bytes/second

Each sector holds exactly 2 352 bytes (176 400 ÷ 75 = 2 352), that’s where 75 sectors per second comes from. A typical 3-minute track is ~31 MB; a full 74-minute CD is ~650 MB.

Converting raw PCM to a playable WAV file only requires prepending a 44-byte RIFF header — CdReader::create_wav does exactly that:

use cd_da_reader::CdReader;

let reader = CdReader::open_default()?;
let toc = reader.read_toc()?;
let data = reader.read_track(&toc, 1)?;
let wav = CdReader::create_wav(data);
std::fs::write("track01.wav", wav)?;

§Metadata

Audio CDs carry almost no semantic metadata. CD-TEXT exists but is unreliable and because of that is not provided by this lbirary. The practical approach is to calculate a Disc ID from the ToC and look it up on a service such as MusicBrainz. The Toc struct exposes everything required for the MusicBrainz disc ID algorithm.

Structs§

CdReader
Helper struct to interact with the audio CD. While it doesn’t hold any internal data directly, it implements Drop trait, so that the CD drive handle is properly closed.
DriveInfo
Information about all found drives. This info is not tested extensively, and in general it is encouraged to provide a disk drive directly.
RetryConfig
Retry policy for idempotent read operations.
ScsiError
Structured SCSI failure context captured at the call site.
Toc
Table of Contents, read directly from the Audio CD. The most important part is the tracks vector, which allows you to read raw track data.
Track
Representation of the track from TOC, purely in terms of data location on the CD.
TrackStream
Track-scoped streaming reader for CD-DA PCM data. You can iterate through the data manually; this allows to receive initial data much faster and also allows you to navigate to specific points.
TrackStreamConfig
Configuration for streamed track reads.

Enums§

CdReaderError
Top-level error type returned by cd-da-reader.
ScsiOp
SCSI command groups issued by this library.