pub struct TrackStream<'a> { /* private fields */ }Expand description
Track-scoped streaming reader for audio or data sectors.
You can pull sector-aligned chunks incrementally and seek to track-relative
sector or time positions. Create a stream with CdReader::open_track_stream.
Implementations§
Source§impl<'a> TrackStream<'a>
impl<'a> TrackStream<'a>
Sourcepub fn with_sectors_per_chunk(self, sectors: u32) -> Self
pub fn with_sectors_per_chunk(self, sectors: u32) -> Self
Set the target chunk size in sectors (default 27).
The byte size of a chunk also depends on the
SectorReadFormat selected in ReadOptions.
A value of zero is normalized to one sector.
Sourcepub fn next_chunk(&mut self) -> Result<Option<Vec<u8>>, CdReaderError>
pub fn next_chunk(&mut self) -> Result<Option<Vec<u8>>, CdReaderError>
Read the next chunk of sector data.
Returns Ok(None) when end-of-track is reached. The bytes per sector
depend on the SectorReadFormat selected in
ReadOptions.
§Errors
Returns CdReaderError::Io or CdReaderError::Scsi if the drive
read fails. The stream position does not advance on error.
Examples found in repository?
6fn main() -> Result<(), Box<dyn std::error::Error>> {
7 let output_dir = common::fresh_output_dir("stream_last_track")?;
8 let reader = CdReader::open_default()?;
9 let toc = reader.read_toc()?;
10
11 let last_audio = toc
12 .tracks
13 .iter()
14 .rev()
15 .find(|t| t.is_audio)
16 .ok_or("no audio tracks found")?;
17
18 println!("Streaming track {}...", last_audio.number);
19 let mut stream = reader.open_track_stream(&toc, last_audio.number)?;
20
21 let mut pcm = Vec::new();
22 while let Some(chunk) = stream.next_chunk()? {
23 pcm.extend_from_slice(&chunk);
24 }
25
26 let wav = create_wav(pcm);
27 let output_path = output_dir.join(format!("track{:02}.wav", last_audio.number));
28 std::fs::write(&output_path, wav)?;
29 println!("Saved {}", output_path.display());
30
31 Ok(())
32}More examples
92fn stream_track_to_file(
93 reader: &CdReader,
94 toc: &Toc,
95 track_no: u8,
96 format: SectorReadFormat,
97 path: &Path,
98) -> Result<u64, Box<dyn std::error::Error>> {
99 let options = ReadOptions::default().with_format(format);
100 let mut stream = reader.open_track_stream_with_options(toc, track_no, &options)?;
101
102 let total_sectors = stream.total_sectors();
103 let mut writer = BufWriter::new(File::create(path)?);
104 let mut written = 0u64;
105
106 while let Some(chunk) = stream.next_chunk()? {
107 writer.write_all(&chunk)?;
108 written += chunk.len() as u64;
109
110 let done = stream.current_sector();
111 let pct = done as f32 / total_sectors as f32 * 100.0;
112 eprint!("\r {done}/{total_sectors} sectors ({pct:5.1}%)");
113 }
114 eprintln!("\r {total_sectors}/{total_sectors} sectors (100.0%)");
115
116 writer.flush()?;
117 Ok(written)
118}6fn main() -> Result<(), Box<dyn std::error::Error>> {
7 let output_dir = common::fresh_output_dir("stream_with_progress")?;
8 let reader = CdReader::open_default()?;
9 let toc = reader.read_toc()?;
10
11 let first_audio = toc
12 .tracks
13 .iter()
14 .find(|t| t.is_audio)
15 .ok_or("no audio tracks found")?;
16
17 let mut stream = reader.open_track_stream(&toc, first_audio.number)?;
18
19 let total_secs = stream.total_seconds();
20 println!(
21 "Track {} — {} sectors ({:.0}s)\n",
22 first_audio.number,
23 stream.total_sectors(),
24 total_secs,
25 );
26
27 let mut pcm = Vec::new();
28 while let Some(chunk) = stream.next_chunk()? {
29 pcm.extend_from_slice(&chunk);
30
31 let cur = stream.current_seconds();
32 let pct = cur / total_secs * 100.0;
33 eprint!("\r [{:>5.1}s / {:.1}s] {:5.1}%", cur, total_secs, pct,);
34 }
35 eprintln!("\r [{:.1}s / {:.1}s] 100.0%", total_secs, total_secs);
36
37 let wav = create_wav(pcm);
38 let output_path = output_dir.join(format!("track{:02}.wav", first_audio.number));
39 std::fs::write(&output_path, wav)?;
40 println!("\nSaved {}", output_path.display());
41
42 Ok(())
43}Sourcepub fn total_sectors(&self) -> u32
pub fn total_sectors(&self) -> u32
Total number of sectors in this track stream.
Examples found in repository?
92fn stream_track_to_file(
93 reader: &CdReader,
94 toc: &Toc,
95 track_no: u8,
96 format: SectorReadFormat,
97 path: &Path,
98) -> Result<u64, Box<dyn std::error::Error>> {
99 let options = ReadOptions::default().with_format(format);
100 let mut stream = reader.open_track_stream_with_options(toc, track_no, &options)?;
101
102 let total_sectors = stream.total_sectors();
103 let mut writer = BufWriter::new(File::create(path)?);
104 let mut written = 0u64;
105
106 while let Some(chunk) = stream.next_chunk()? {
107 writer.write_all(&chunk)?;
108 written += chunk.len() as u64;
109
110 let done = stream.current_sector();
111 let pct = done as f32 / total_sectors as f32 * 100.0;
112 eprint!("\r {done}/{total_sectors} sectors ({pct:5.1}%)");
113 }
114 eprintln!("\r {total_sectors}/{total_sectors} sectors (100.0%)");
115
116 writer.flush()?;
117 Ok(written)
118}More examples
6fn main() -> Result<(), Box<dyn std::error::Error>> {
7 let output_dir = common::fresh_output_dir("stream_with_progress")?;
8 let reader = CdReader::open_default()?;
9 let toc = reader.read_toc()?;
10
11 let first_audio = toc
12 .tracks
13 .iter()
14 .find(|t| t.is_audio)
15 .ok_or("no audio tracks found")?;
16
17 let mut stream = reader.open_track_stream(&toc, first_audio.number)?;
18
19 let total_secs = stream.total_seconds();
20 println!(
21 "Track {} — {} sectors ({:.0}s)\n",
22 first_audio.number,
23 stream.total_sectors(),
24 total_secs,
25 );
26
27 let mut pcm = Vec::new();
28 while let Some(chunk) = stream.next_chunk()? {
29 pcm.extend_from_slice(&chunk);
30
31 let cur = stream.current_seconds();
32 let pct = cur / total_secs * 100.0;
33 eprint!("\r [{:>5.1}s / {:.1}s] {:5.1}%", cur, total_secs, pct,);
34 }
35 eprintln!("\r [{:.1}s / {:.1}s] 100.0%", total_secs, total_secs);
36
37 let wav = create_wav(pcm);
38 let output_path = output_dir.join(format!("track{:02}.wav", first_audio.number));
39 std::fs::write(&output_path, wav)?;
40 println!("\nSaved {}", output_path.display());
41
42 Ok(())
43}Sourcepub fn current_sector(&self) -> u32
pub fn current_sector(&self) -> u32
Current stream position as a track-relative sector index. Keep in mind that if you are playing the sound directly, this is likely not the track’s current position because you probably keep some of the data in your buffer.
Examples found in repository?
92fn stream_track_to_file(
93 reader: &CdReader,
94 toc: &Toc,
95 track_no: u8,
96 format: SectorReadFormat,
97 path: &Path,
98) -> Result<u64, Box<dyn std::error::Error>> {
99 let options = ReadOptions::default().with_format(format);
100 let mut stream = reader.open_track_stream_with_options(toc, track_no, &options)?;
101
102 let total_sectors = stream.total_sectors();
103 let mut writer = BufWriter::new(File::create(path)?);
104 let mut written = 0u64;
105
106 while let Some(chunk) = stream.next_chunk()? {
107 writer.write_all(&chunk)?;
108 written += chunk.len() as u64;
109
110 let done = stream.current_sector();
111 let pct = done as f32 / total_sectors as f32 * 100.0;
112 eprint!("\r {done}/{total_sectors} sectors ({pct:5.1}%)");
113 }
114 eprintln!("\r {total_sectors}/{total_sectors} sectors (100.0%)");
115
116 writer.flush()?;
117 Ok(written)
118}Sourcepub fn seek_to_sector(&mut self, sector: u32) -> Result<(), CdReaderError>
pub fn seek_to_sector(&mut self, sector: u32) -> Result<(), CdReaderError>
Seek to a sector position relative to the start of the track.
Valid range is 0..=total_sectors().
§Errors
Returns CdReaderError::Io containing
std::io::ErrorKind::InvalidInput if sector exceeds the track
length.
Sourcepub fn current_seconds(&self) -> f32
pub fn current_seconds(&self) -> f32
Current stream position in seconds. Functionally equivalent to “current_sector”, but converted to seconds.
CD addresses advance at 75 sectors = 1 second.
Examples found in repository?
6fn main() -> Result<(), Box<dyn std::error::Error>> {
7 let output_dir = common::fresh_output_dir("stream_with_progress")?;
8 let reader = CdReader::open_default()?;
9 let toc = reader.read_toc()?;
10
11 let first_audio = toc
12 .tracks
13 .iter()
14 .find(|t| t.is_audio)
15 .ok_or("no audio tracks found")?;
16
17 let mut stream = reader.open_track_stream(&toc, first_audio.number)?;
18
19 let total_secs = stream.total_seconds();
20 println!(
21 "Track {} — {} sectors ({:.0}s)\n",
22 first_audio.number,
23 stream.total_sectors(),
24 total_secs,
25 );
26
27 let mut pcm = Vec::new();
28 while let Some(chunk) = stream.next_chunk()? {
29 pcm.extend_from_slice(&chunk);
30
31 let cur = stream.current_seconds();
32 let pct = cur / total_secs * 100.0;
33 eprint!("\r [{:>5.1}s / {:.1}s] {:5.1}%", cur, total_secs, pct,);
34 }
35 eprintln!("\r [{:.1}s / {:.1}s] 100.0%", total_secs, total_secs);
36
37 let wav = create_wav(pcm);
38 let output_path = output_dir.join(format!("track{:02}.wav", first_audio.number));
39 std::fs::write(&output_path, wav)?;
40 println!("\nSaved {}", output_path.display());
41
42 Ok(())
43}Sourcepub fn total_seconds(&self) -> f32
pub fn total_seconds(&self) -> f32
Total stream duration in seconds. Functionally equivalent to “total_sectors”, but converted to seconds.
CD addresses advance at 75 sectors = 1 second.
Examples found in repository?
6fn main() -> Result<(), Box<dyn std::error::Error>> {
7 let output_dir = common::fresh_output_dir("stream_with_progress")?;
8 let reader = CdReader::open_default()?;
9 let toc = reader.read_toc()?;
10
11 let first_audio = toc
12 .tracks
13 .iter()
14 .find(|t| t.is_audio)
15 .ok_or("no audio tracks found")?;
16
17 let mut stream = reader.open_track_stream(&toc, first_audio.number)?;
18
19 let total_secs = stream.total_seconds();
20 println!(
21 "Track {} — {} sectors ({:.0}s)\n",
22 first_audio.number,
23 stream.total_sectors(),
24 total_secs,
25 );
26
27 let mut pcm = Vec::new();
28 while let Some(chunk) = stream.next_chunk()? {
29 pcm.extend_from_slice(&chunk);
30
31 let cur = stream.current_seconds();
32 let pct = cur / total_secs * 100.0;
33 eprint!("\r [{:>5.1}s / {:.1}s] {:5.1}%", cur, total_secs, pct,);
34 }
35 eprintln!("\r [{:.1}s / {:.1}s] 100.0%", total_secs, total_secs);
36
37 let wav = create_wav(pcm);
38 let output_path = output_dir.join(format!("track{:02}.wav", first_audio.number));
39 std::fs::write(&output_path, wav)?;
40 println!("\nSaved {}", output_path.display());
41
42 Ok(())
43}Sourcepub fn seek_to_seconds(&mut self, seconds: f32) -> Result<(), CdReaderError>
pub fn seek_to_seconds(&mut self, seconds: f32) -> Result<(), CdReaderError>
Seek to a time position relative to the start of the track in seconds.
Input is converted to sector offset and clamped to track bounds.
§Errors
Returns CdReaderError::Io containing
std::io::ErrorKind::InvalidInput if seconds is negative or not
finite.