mod common;
use std::path::Path;
use cd_da_reader::{CdReader, ReadOptions, create_wav};
const SECTORS_PER_SECOND: u32 = 75;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let output_dir = common::fresh_output_dir("play_audio_track")?;
let seconds: u32 = match std::env::args().nth(1) {
Some(a) => a.parse()?,
None => 30,
};
let reader = CdReader::open_default()?;
let toc = reader.read_toc()?;
let track = toc
.tracks
.iter()
.find(|t| t.is_audio)
.ok_or("no audio tracks found on this disc")?;
let track_end = toc
.tracks
.iter()
.map(|t| t.start_lba)
.filter(|&lba| lba > track.start_lba)
.min()
.unwrap_or(toc.leadout_lba);
let track_sectors = track_end - track.start_lba;
let sectors = (seconds * SECTORS_PER_SECOND).min(track_sectors);
let actual_seconds = sectors / SECTORS_PER_SECOND;
println!(
"Reading first {actual_seconds}s ({sectors} sectors) of audio track #{}...",
track.number
);
let pcm = reader.read_sector_range(track.start_lba, sectors, &ReadOptions::default())?;
println!(
"Read {} bytes of PCM ({:.1} MiB)",
pcm.len(),
pcm.len() as f64 / (1024.0 * 1024.0)
);
let output_path = output_dir.join(format!("track{:02}_preview.wav", track.number));
std::fs::write(&output_path, create_wav(pcm))?;
println!("Saved {}", output_path.display());
play(&output_path)
}
#[cfg(target_os = "macos")]
fn play(path: &Path) -> Result<(), Box<dyn std::error::Error>> {
println!("Playing (Ctrl+C to stop)...");
let status = std::process::Command::new("afplay").arg(path).status()?;
if !status.success() {
return Err("afplay exited with an error".into());
}
Ok(())
}
#[cfg(target_os = "windows")]
fn play(path: &Path) -> Result<(), Box<dyn std::error::Error>> {
println!("Playing (this blocks until the preview ends)...");
let escaped_path = path.display().to_string().replace('\'', "''");
let script = format!("(New-Object Media.SoundPlayer '{escaped_path}').PlaySync()");
let status = std::process::Command::new("powershell")
.args(["-NoProfile", "-Command", &script])
.status()?;
if !status.success() {
return Err("powershell SoundPlayer exited with an error".into());
}
Ok(())
}
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
fn play(path: &Path) -> Result<(), Box<dyn std::error::Error>> {
println!(
"Saved the WAV — play it with your audio player, e.g. `aplay {}`.",
path.display()
);
Ok(())
}