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:
- Get a CD drive’s handle
- Read the ToC (table of contents) of the audio CD
- 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_defaultoropenwith a known path instead oflist_driveson 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 audioThis 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/secondEach 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
Droptrait, so that the CD drive handle is properly closed. - Drive
Info - Information about all found drives. This info is not tested extensively, and in general it is encouraged to provide a disk drive directly.
- Retry
Config - Retry policy for idempotent read operations.
- Scsi
Error - 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
tracksvector, which allows you to read raw track data. - Track
- Representation of the track from TOC, purely in terms of data location on the CD.
- Track
Stream - 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.
- Track
Stream Config - Configuration for streamed track reads.
Enums§
- CdReader
Error - Top-level error type returned by
cd-da-reader. - ScsiOp
- SCSI command groups issued by this library.