aede_core/playback/decoder/
integer.rs1use std::fs::File;
4use std::io::{Read, Seek, SeekFrom};
5use std::path::Path;
6
7use flaccompagnon_core::AnalysisError;
8
9use crate::playback::format::IntegerPcmFormat;
10
11use super::flac::IntegerFlacStream;
12use super::integer_wav::IntegerWavStream;
13use super::{Error, FlacMd5Status, SeekResult};
14
15pub struct IntegerFileDecoder {
22 source: Source,
23 format: IntegerPcmFormat,
24 pending: Vec<i32>,
25 pending_offset: usize,
26 finished: bool,
27}
28
29enum Source {
30 Flac(IntegerFlacStream),
31 Wav(IntegerWavStream),
32}
33
34impl IntegerFileDecoder {
35 pub fn open(path: &Path) -> Result<Self, Error> {
37 crate::copy::validate_source(path).map_err(decode_error)?;
40 let mut file = File::open(path).map_err(decode_error)?;
41 if !file.metadata().map_err(decode_error)?.is_file() {
42 return Err(Error::UnsupportedIntegerSource(
43 "integer playback requires a local regular file",
44 ));
45 }
46 let mut magic = [0; 4];
47 file.read_exact(&mut magic).map_err(decode_error)?;
48 file.seek(SeekFrom::Start(0)).map_err(decode_error)?;
49 let (source, format) = if &magic == b"RIFF" {
50 let wav = IntegerWavStream::open(file)?;
51 let format = IntegerPcmFormat::new(
52 wav.sample_rate(),
53 wav.channel_layout(),
54 wav.bits_per_sample(),
55 )
56 .map_err(|_| Error::InvalidFormat)?;
57 if format.channels() != wav.channels() {
58 return Err(Error::InvalidFormat);
59 }
60 (Source::Wav(wav), format)
61 } else if &magic == b"fLaC" || &magic[..3] == b"ID3" {
62 let flac = IntegerFlacStream::open_integer(file)?;
63 let format =
64 IntegerPcmFormat::new(flac.sample_rate, flac.layout, flac.bits_per_sample())
65 .map_err(|_| Error::InvalidFormat)?;
66 (Source::Flac(flac), format)
67 } else {
68 return Err(Error::UnsupportedIntegerSource(
69 "integer playback requires native 16/24-bit mono/stereo FLAC or PCM WAV",
70 ));
71 };
72 Ok(Self {
73 source,
74 format,
75 pending: Vec::new(),
76 pending_offset: 0,
77 finished: false,
78 })
79 }
80
81 pub fn format(&self) -> IntegerPcmFormat {
83 self.format
84 }
85
86 pub fn flac_md5_status(&self) -> Option<FlacMd5Status> {
88 match &self.source {
89 Source::Flac(flac) => Some(flac.md5_status()),
90 Source::Wav(_) => None,
91 }
92 }
93
94 pub fn read_frames(&mut self, output: &mut [i32]) -> Result<usize, Error> {
100 let channels = usize::from(self.format.channels());
101 if output.is_empty() || !output.len().is_multiple_of(channels) {
102 return Err(Error::InvalidBuffer);
103 }
104 if !self.fill_pending()? {
105 return Ok(0);
106 }
107 let count = output.len().min(self.pending.len() - self.pending_offset);
108 output[..count]
109 .copy_from_slice(&self.pending[self.pending_offset..self.pending_offset + count]);
110 self.pending_offset += count;
111 Ok(count / channels)
112 }
113
114 pub fn skip_frames(
123 &mut self,
124 frames: u64,
125 mut cancelled: impl FnMut() -> bool,
126 ) -> Result<SeekResult, Error> {
127 let channels = usize::from(self.format.channels());
128 let mut skipped = 0;
129 loop {
130 if cancelled() {
131 return Err(Error::SeekCancelled);
132 }
133 if skipped == frames {
134 return Ok(SeekResult {
135 frames: skipped,
136 reached_eof: false,
137 });
138 }
139 if !self.fill_pending()? {
140 return Ok(SeekResult {
141 frames: skipped,
142 reached_eof: true,
143 });
144 }
145 let available = (self.pending.len() - self.pending_offset) / channels;
146 let count = available.min((frames - skipped).min(4096) as usize);
147 self.pending_offset += count * channels;
148 skipped += count as u64;
149 }
150 }
151
152 fn fill_pending(&mut self) -> Result<bool, Error> {
153 if self.finished {
154 return Ok(false);
155 }
156 while self.pending_offset == self.pending.len() {
157 let chunk = match &mut self.source {
158 Source::Flac(flac) => {
159 let chunk = flac.next_chunk()?;
160 chunk.map(|mut samples| {
163 let shift = 32 - self.format.bits_per_sample();
164 for sample in &mut samples {
165 *sample >>= shift;
166 }
167 samples
168 })
169 }
170 Source::Wav(wav) => wav.next_chunk()?,
171 };
172 let Some(samples) = chunk else {
173 self.finished = true;
174 return Ok(false);
175 };
176 self.pending = samples;
177 self.pending_offset = 0;
178 }
179 Ok(true)
180 }
181}
182
183fn decode_error(error: impl std::fmt::Display) -> Error {
184 Error::Decode(AnalysisError::Decode(error.to_string()))
185}
186
187#[cfg(test)]
188#[path = "integer_tests.rs"]
189mod tests;