Skip to main content

read_track_with_bounds

Function read_track_with_bounds 

Source
pub fn read_track_with_bounds<R: AudioSectorReader>(
    src: &R,
    toc: &Toc,
    track_no: u8,
    bounds: TrackBounds,
) -> Result<Vec<u8>, CdReaderError>
Expand description

Reads one complete audio track into memory using an explicit TrackBounds policy.

This is the configurable form of read_track, which always uses TrackBounds::SessionGap. The bounds argument controls how the track’s end LBA is calculated from the Toc, specifically whether the CD-Extra inter-session gap is present in the source’s address space.

Use TrackBounds::SessionGap for a physical disc or geometry-preserving image. Use TrackBounds::Gapless for a contiguous, gap-stripped source.

The source and Toc must use the same LBA address space. All other behavior, including the returned PCM format and whole-track buffering, is identical to read_track. Use open_track_stream_with_bounds to process the track incrementally with an explicit bounds policy.

§Errors

Returns CdReaderError::Io if the track is absent from the Toc or its calculated sector bounds are invalid.

Returns CdReaderError::Backend if the source cannot read the requested sectors. The source’s original error is preserved as the error’s source.

Examples found in repository?
examples/bin_cue_backend.rs (line 135)
105fn main() -> Result<(), Box<dyn Error>> {
106    let output_dir = common::fresh_output_dir("bin_cue_backend")?;
107
108    let cue_path = match std::env::args().nth(1) {
109        Some(path) => PathBuf::from(path),
110        None => {
111            println!("No .cue argument given — writing a demo image to work against.\n");
112            write_demo_image(&output_dir)?
113        }
114    };
115
116    let (bin_path, toc) = parse_cue(&cue_path)?;
117    println!("Cue:   {}", cue_path.display());
118    println!("Bin:   {}", bin_path.display());
119    println!(
120        "Toc:   {} tracks, leadout at LBA {}\n",
121        toc.tracks.len(),
122        toc.leadout_lba
123    );
124
125    let image = BinImage {
126        bin: File::open(&bin_path)?,
127    };
128
129    // A single-FILE cue is a contiguous run of sectors, so the CD-Extra
130    // inter-session gap is not part of the addressing. See `explain_bounds`.
131    let bounds = TrackBounds::Gapless;
132    explain_bounds(&image, &toc)?;
133
134    for track in toc.tracks.iter().filter(|track| track.is_audio) {
135        let pcm = read_track_with_bounds(&image, &toc, track.number, bounds)?;
136        let wav_path = output_dir.join(format!("track{:02}.wav", track.number));
137        std::fs::write(&wav_path, create_wav(pcm))?;
138
139        println!("track {:02}: wrote {}", track.number, wav_path.display());
140    }
141
142    // The same backing streams instead of buffering — for a 74-minute image
143    // that is the difference between one chunk and ~650 MB resident.
144    if let Some(first_audio) = toc.tracks.iter().find(|track| track.is_audio) {
145        let mut stream = open_track_stream_with_bounds(&image, &toc, first_audio.number, bounds)?;
146        let (mut chunks, mut bytes) = (0u32, 0usize);
147        while let Some(chunk) = stream.next_chunk()? {
148            chunks += 1;
149            bytes += chunk.len();
150        }
151        println!(
152            "\nstreamed track {:02}: {bytes} bytes in {chunks} chunks ({:.1}s)",
153            first_audio.number,
154            stream.total_seconds()
155        );
156    }
157
158    Ok(())
159}