Files
qbz/crates/qbz-disc/examples/cd_probe.rs
T
vicrodh db0999bf6f feat(disc): read CD-DA off a real drive, measured before it was written
New crate `qbz-disc`: table of contents and raw audio sectors through the
kernel's own cdrom ioctls. No libcdio — not because libcdio is worse (it is
better at RIPPING than this will ever be) but because this path PLAYS a clean
disc, and for that the kernel interface is enough while a native library would
have to be built into Flatpak, Snap and AppImage. Both need the same --device
permission in a sandbox; only one needs the library shipped.

Every claim below was measured on the owner's USB drive with Tool — Fear
Inoculum BEFORE a line of this crate existed, so the design answers evidence
rather than the other way round:

  - the TOC reads back 7 audio tracks, lead-out at LSN 356568, and the track
    lengths match the record exactly (10:21, 11:52, 12:44, 13:37, 10:05, 4:48,
    15:44 — 79:11 total);
  - CDROMREADAUDIO over 20 frames from LSN 4000 returned 47 040 bytes, 99 %
    non-zero samples, peak 14559: real audio, not silence;
  - the drive hands back LITTLE-endian samples. Neighbouring-sample deltas
    average 73.5 read as LE against 20 971 read as BE, a 285x margin, so the
    bytes go straight into a little-endian WAV with no swap. That is one
    drive, so `looks_byte_swapped` keeps the test available as a diagnostic
    instead of an article of faith;
  - the disc's MCN is all zeros, which is why identity is a digest over the
    track table and not the catalogue number.

What this is NOT is accurate extraction: no overlap synchronisation, no cache
modelling, no jitter verification. On a clean disc that is fine for playback,
and an unreadable sector surfaces as an ERROR rather than a hole full of
zeros — silence that pretends to be audio is the one outcome a bit-perfect
player must never produce.

`/dev/sr0` is nowhere in the code: drives are enumerated, because a box can
have several and /dev/cdrom is a symlink that may point at any of them. Data
tracks of a mixed-mode disc are skipped by their control bits.

`CdRef` is the typed reference (`cdda:/dev/sr0#285735+70833`) with ONE parser,
not prefix tests copied around — the scattered version is a known failure mode
here and cost a whole session on 2026-08-20.

11 tests, several asserting against that real table of contents.

cc
2026-08-20 23:28:28 -06:00

69 lines
2.1 KiB
Rust

//! Read the disc in the drive and prove the crate agrees with reality.
//! `cargo run -p qbz-disc --example cd_probe`
fn main() {
let devs = qbz_disc::list_devices();
println!("devices: {devs:?}");
let Some(dev) = devs.first() else {
println!("no drive");
return;
};
let toc = match qbz_disc::read_toc(dev) {
Ok(t) => t,
Err(e) => {
println!("toc failed: {e}");
return;
}
};
println!("fingerprint: {}", toc.fingerprint());
println!("leadout LSN: {}", toc.leadout_lsn);
let mut total = 0u64;
for t in &toc.tracks {
let d = t.duration_secs();
total += d;
println!(
" track {:2} lsn {:>7} {:>6} sectors {:>2}:{:02} {}",
t.number,
t.start_lsn,
t.sectors,
d / 60,
d % 60,
if t.is_audio { "audio" } else { "DATA (skipped)" }
);
}
println!("total {}:{:02}", total / 60, total % 60);
// Read the first audio track's opening chunk and prove it is music.
let Some(first) = toc.audio_tracks().next() else {
return;
};
let mut r = match qbz_disc::cdda::TrackReader::open(dev, first) {
Ok(r) => r,
Err(e) => {
println!("open failed: {e}");
return;
}
};
let mut buf = Vec::new();
// Skip the first second — track 1 often opens on silence.
for _ in 0..2 {
if let Err(e) = r.next_chunk(&mut buf) {
println!("read failed: {e}");
return;
}
}
let samples: Vec<i16> = buf
.chunks_exact(2)
.map(|b| i16::from_le_bytes([b[0], b[1]]))
.collect();
let peak = samples.iter().map(|s| s.unsigned_abs()).max().unwrap_or(0);
let nz = samples.iter().filter(|s| **s != 0).count();
println!(
"read {} bytes | {} samples | non-zero {}% | peak {} | byte-swapped? {}",
buf.len(),
samples.len(),
100 * nz / samples.len().max(1),
peak,
qbz_disc::cdda::looks_byte_swapped(&buf)
);
}