1use super::{FRAMES_PER_SECTOR, Track};
2use cd_da_reader::{AudioSectorReader, CdReader, CdReaderError, ReadOptions, RetryConfig};
3pub(crate) struct NativeReader<'a>(pub &'a CdReader);
4impl AudioSectorReader for NativeReader<'_> {
5 type Error = CdReaderError;
6 fn read_audio_sectors(&self, start: u32, count: u32) -> Result<Vec<u8>, Self::Error> {
7 self.0.read_sector_range(
8 start,
9 count,
10 &ReadOptions::default().with_retry(RetryConfig::default().with_max_attempts(2)),
11 )
12 }
13}
14pub struct Chunk {
16 bytes: Vec<u8>,
17 skip: usize,
18}
19impl Chunk {
20 pub fn frames(&self) -> impl ExactSizeIterator<Item = [f32; 2]> + '_ {
22 self.bytes
23 .as_chunks::<4>()
24 .0
25 .iter()
26 .skip(self.skip)
27 .map(|b| {
28 [
29 f32::from(i16::from_le_bytes([b[0], b[1]])) / 32768.,
30 f32::from(i16::from_le_bytes([b[2], b[3]])) / 32768.,
31 ]
32 })
33 }
34}
35pub struct TrackReader<'a> {
37 reader: &'a dyn AudioSectorReader<Error = CdReaderError>,
38 track: &'a Track,
39 frame: u64,
40}
41impl<'a> TrackReader<'a> {
42 pub(crate) fn new(
43 reader: &'a dyn AudioSectorReader<Error = CdReaderError>,
44 track: &'a Track,
45 ) -> Self {
46 Self {
47 reader,
48 track,
49 frame: 0,
50 }
51 }
52 pub fn seek(&mut self, frame: u64) -> Result<(), String> {
54 if frame > self.track.frames {
55 return Err("Position hors du CD.".into());
56 }
57 self.frame = frame;
58 Ok(())
59 }
60 pub fn next_chunk(&mut self) -> Result<Option<Chunk>, String> {
62 if self.frame == self.track.frames {
63 return Ok(None);
64 }
65 let sector = self.frame / FRAMES_PER_SECTOR;
66 let count = (self.track.frames / FRAMES_PER_SECTOR - sector).min(27) as u32;
67 let bytes = self
68 .reader
69 .read_audio_sectors(self.track.start + sector as u32, count)
70 .map_err(
71 |_| "Lecture du CD impossible : disque retiré, illisible ou erreur du lecteur.",
72 )?;
73 if bytes.len() != count as usize * 2352 {
74 return Err("Le lecteur CD a renvoyé des données incomplètes.".into());
75 }
76 let skip = (self.frame % FRAMES_PER_SECTOR) as usize;
77 self.frame = (sector + u64::from(count)) * FRAMES_PER_SECTOR;
78 Ok(Some(Chunk { bytes, skip }))
79 }
80}
81#[cfg(test)]
82#[path = "stream_tests.rs"]
83mod tests;