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?
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}