1#![warn(rust_2018_idioms)]
2#![warn(rust_2021_compatibility)]
3#![warn(clippy::missing_panics_doc)]
4#![warn(clippy::clone_on_ref_ptr)]
5#![deny(trivial_numeric_casts)]
6#![forbid(unsafe_code)]
7
8use std::fs::File;
9use std::path::PathBuf;
10
11use symphonia::core::audio::AudioBuffer;
12use symphonia::core::codecs::{CodecParameters, Decoder as SymphDecoder, DecoderOptions};
13use symphonia::core::errors::Error;
14use symphonia::core::formats::{FormatOptions, FormatReader, SeekMode, SeekTo};
15use symphonia::core::io::MediaSourceStream;
16use symphonia::core::meta::{Metadata, MetadataOptions, MetadataRevision};
17use symphonia::core::probe::Hint;
18
19use creek_core::{DataBlock, Decoder, FileInfo};
20
21mod error;
22pub use error::OpenError;
23
24pub struct SymphoniaDecoder {
25 reader: Box<dyn FormatReader>,
26 decoder: Box<dyn SymphDecoder>,
27
28 decode_buffer: AudioBuffer<f32>,
29 decode_buffer_len: usize,
30 curr_decode_buffer_frame: usize,
31
32 num_frames: usize,
33 sample_rate: Option<u32>,
34 block_size: usize,
35
36 playhead_frame: usize,
37 reset_decode_buffer: bool,
38 seek_diff: usize,
39}
40
41impl Decoder for SymphoniaDecoder {
42 type T = f32;
43 type FileParams = SymphoniaDecoderInfo;
44 type OpenError = OpenError;
45 type FatalError = Error;
46 type AdditionalOpts = ();
47
48 const DEFAULT_BLOCK_SIZE: usize = 16384;
49 const DEFAULT_NUM_CACHE_BLOCKS: usize = 0;
50 const DEFAULT_NUM_LOOK_AHEAD_BLOCKS: usize = 8;
51
52 fn new(
53 file: PathBuf,
54 start_frame: usize,
55 block_size: usize,
56 _additional_opts: Self::AdditionalOpts,
57 ) -> Result<(Self, FileInfo<Self::FileParams>), Self::OpenError> {
58 let mut hint = Hint::new();
60
61 if let Some(extension) = file.extension() {
63 if let Some(extension_str) = extension.to_str() {
64 hint.with_extension(extension_str);
65 }
66 }
67
68 let source = Box::new(File::open(file)?);
69
70 let mss = MediaSourceStream::new(source, Default::default());
72
73 let format_opts: FormatOptions = Default::default();
75 let metadata_opts: MetadataOptions = Default::default();
76
77 let probed =
78 symphonia::default::get_probe().format(&hint, mss, &format_opts, &metadata_opts)?;
79
80 let mut reader = probed.format;
81
82 let decoder_opts = DecoderOptions {
83 ..Default::default()
84 };
85
86 let params = {
87 let stream = reader.default_track().ok_or(OpenError::NoDefaultTrack)?;
89
90 stream.codec_params.clone()
91 };
92 let num_frames = params.n_frames.ok_or(OpenError::NoNumFrames)? as usize;
93 let sample_rate = params.sample_rate;
94
95 if start_frame != 0 {
97 reader.seek(
98 SeekMode::Accurate,
99 SeekTo::Time {
100 time: frame_to_symphonia_time(start_frame as u64, sample_rate.unwrap_or(44100)),
101 track_id: None,
102 },
103 )?;
104 }
105
106 let mut decoder = symphonia::default::get_codecs().make(¶ms, &decoder_opts)?;
108 debug_assert_eq!(params.n_frames, decoder.codec_params().n_frames);
109 debug_assert_eq!(params.sample_rate, decoder.codec_params().sample_rate);
110 debug_assert_eq!(params.channels, decoder.codec_params().channels);
111
112 let mut channels = params.channels;
116
117 let (decode_buffer, decode_buffer_len) = loop {
119 match decoder.decode(&reader.next_packet()?) {
120 Ok(decoded) => {
121 let spec = *decoded.spec();
123 if let Some(channels) = channels {
124 assert_eq!(channels, spec.channels);
125 } else {
126 log::debug!(
127 "Assuming {num_channels} channel(s) according to the first decoded packet",
128 num_channels = spec.channels.count()
129 );
130 channels = Some(spec.channels);
131 }
132
133 let len = decoded.frames();
134 let capacity = decoded.capacity();
135
136 let mut decode_buffer: AudioBuffer<f32> =
137 AudioBuffer::new(capacity as u64, spec);
138
139 decoded.convert(&mut decode_buffer);
140
141 break (decode_buffer, len);
142 }
143 Err(Error::DecodeError(err)) => {
144 log::warn!("{err}");
146 continue;
148 }
149 Err(e) => {
150 return Err(e.into());
152 }
153 }
154 };
155
156 let metadata = reader.metadata().skip_to_latest().cloned();
157 let info = SymphoniaDecoderInfo {
158 codec_params: params,
159 metadata,
160 };
161 let num_channels = (channels.ok_or(OpenError::NoNumChannels)?).count();
162
163 let file_info = FileInfo {
164 params: info,
165 num_frames,
166 num_channels: num_channels as u16,
167 sample_rate,
168 };
169 Ok((
170 Self {
171 reader,
172 decoder,
173
174 decode_buffer,
175 decode_buffer_len,
176 curr_decode_buffer_frame: 0,
177
178 num_frames,
179 sample_rate,
180 block_size,
181
182 playhead_frame: start_frame,
183 reset_decode_buffer: false,
184 seek_diff: 0,
185 },
186 file_info,
187 ))
188 }
189
190 fn seek(&mut self, frame: usize) -> Result<(), Self::FatalError> {
191 if frame >= self.num_frames {
192 self.playhead_frame = self.num_frames;
194
195 return Ok(());
196 }
197
198 self.playhead_frame = frame;
199
200 match self.reader.seek(
201 SeekMode::Accurate,
202 SeekTo::Time {
203 time: frame_to_symphonia_time(
204 self.playhead_frame as u64,
205 self.sample_rate.unwrap_or(44100),
206 ),
207 track_id: None,
208 },
209 ) {
210 Ok(res) => {
211 debug_assert!(res.required_ts >= res.actual_ts);
213
214 self.seek_diff = (res.required_ts - res.actual_ts) as usize;
215 }
216 Err(e) => {
217 return Err(e);
218 }
219 }
220
221 self.reset_decode_buffer = true;
222 self.curr_decode_buffer_frame = 0;
223
224 Ok(())
236 }
237
238 fn decode(&mut self, data_block: &mut DataBlock<Self::T>) -> Result<(), Self::FatalError> {
239 if self.playhead_frame >= self.num_frames {
240 return Ok(());
242 }
243
244 let mut reached_end_of_file = false;
245
246 let mut block_start_frame = 0;
247 while block_start_frame < self.block_size {
248 let num_frames_to_cpy = if self.reset_decode_buffer {
249 self.reset_decode_buffer = false;
251 0
252 } else {
253 (self.block_size - block_start_frame)
255 .min(self.decode_buffer_len - self.curr_decode_buffer_frame)
256 };
257
258 if num_frames_to_cpy != 0 {
259 let src_planes = self.decode_buffer.planes();
260 let src_channels = src_planes.planes();
261
262 for (dst_ch, src_ch) in data_block.block.iter_mut().zip(src_channels) {
263 let src_ch_part = &src_ch[self.curr_decode_buffer_frame
264 ..self.curr_decode_buffer_frame + num_frames_to_cpy];
265 dst_ch.extend_from_slice(src_ch_part);
266 }
267
268 block_start_frame += num_frames_to_cpy;
269
270 self.curr_decode_buffer_frame += num_frames_to_cpy;
271 if self.curr_decode_buffer_frame >= self.decode_buffer_len {
272 self.reset_decode_buffer = true;
273 }
274 } else {
275 loop {
278 match self.reader.next_packet() {
279 Ok(packet) => {
280 match self.decoder.decode(&packet) {
281 Ok(decoded) => {
282 self.decode_buffer_len = decoded.frames();
283 if self.seek_diff < self.decode_buffer_len {
284 let capacity = decoded.capacity();
285 if self.decode_buffer.capacity() < capacity {
286 self.decode_buffer =
287 AudioBuffer::new(capacity as u64, *decoded.spec());
288 }
289 decoded.convert(&mut self.decode_buffer);
290 self.curr_decode_buffer_frame = self.seek_diff;
291 self.seek_diff = 0;
292 break;
293 } else {
294 self.seek_diff -= self.decode_buffer_len;
295 }
296 }
297 Err(Error::DecodeError(err)) => {
298 log::warn!("{err}");
300 continue;
302 }
303 Err(e) => {
304 return Err(e);
306 }
307 }
308 }
309 Err(e) => {
310 if let Error::IoError(io_error) = &e {
311 if io_error.kind() == std::io::ErrorKind::UnexpectedEof {
312 reached_end_of_file = true;
314 block_start_frame = self.block_size;
315 break;
316 } else {
317 return Err(e);
318 }
319 } else {
320 return Err(e);
321 }
322 }
323 }
324 }
325 }
326 }
327
328 if reached_end_of_file {
329 self.playhead_frame = self.num_frames;
330 } else {
331 self.playhead_frame += self.block_size;
332 }
333
334 Ok(())
335 }
336
337 fn current_frame(&self) -> usize {
338 self.playhead_frame
339 }
340}
341
342impl Drop for SymphoniaDecoder {
343 fn drop(&mut self) {
344 let _ = self.decoder.finalize();
345 }
346}
347
348impl SymphoniaDecoder {
349 pub fn get_metadata_raw(&mut self) -> Metadata<'_> {
353 self.reader.metadata()
354 }
355
356 pub fn get_metadata(&mut self) -> Option<MetadataRevision> {
358 let mut md = self.reader.metadata();
359 md.skip_to_latest().cloned()
360 }
361}
362
363#[derive(Debug, Clone)]
364pub struct SymphoniaDecoderInfo {
365 pub codec_params: CodecParameters,
366 pub metadata: Option<MetadataRevision>,
367}
368
369fn frame_to_symphonia_time(frame: u64, sample_rate: u32) -> symphonia::core::units::Time {
370 let seconds = frame / u64::from(sample_rate);
372 let fract_frames = frame % u64::from(sample_rate);
373 let frac = fract_frames as f64 / f64::from(sample_rate);
374
375 symphonia::core::units::Time { seconds, frac }
378}
379
380#[cfg(test)]
381mod tests {
382 use super::*;
383 use float_cmp::*;
384
385 #[test]
386 fn decoder_new() {
387 let files = vec![
388 ("../test_files/wav_u8_mono.wav", 1, 1323000, Some(44100)),
390 ("../test_files/wav_i16_mono.wav", 1, 1323000, Some(44100)),
391 ("../test_files/wav_i24_mono.wav", 1, 1323000, Some(44100)),
392 ("../test_files/wav_i32_mono.wav", 1, 1323000, Some(44100)),
393 ("../test_files/wav_f32_mono.wav", 1, 1323000, Some(44100)),
394 ("../test_files/wav_i24_stereo.wav", 2, 1323000, Some(44100)),
395 ];
402
403 for file in files {
404 dbg!(file.0);
405 let decoder =
406 SymphoniaDecoder::new(file.0.into(), 0, SymphoniaDecoder::DEFAULT_BLOCK_SIZE, ());
407 match decoder {
408 Ok((_, file_info)) => {
409 assert_eq!(file_info.num_channels, file.1);
410 assert_eq!(file_info.num_frames, file.2);
411 }
413 Err(e) => {
414 panic!("{}", e);
415 }
416 }
417 }
418 }
419
420 #[test]
421 fn decode_first_frame() {
422 let block_size = 10;
423
424 let decoder =
425 SymphoniaDecoder::new("../test_files/wav_u8_mono.wav".into(), 0, block_size, ());
426
427 let (mut decoder, file_info) = decoder.unwrap();
428
429 let mut data_block = DataBlock::new(1, block_size);
430 data_block.clear();
431 decoder.decode(&mut data_block).unwrap();
432
433 let samples = &mut data_block.block[0];
434 assert_eq!(samples.len(), block_size);
435
436 let first_frame = [
437 0.0, 0.046875, 0.09375, 0.1484375, 0.1953125, 0.2421875, 0.2890625, 0.3359375,
438 0.3828125, 0.421875,
439 ];
440
441 for i in 0..samples.len() {
442 assert!(approx_eq!(f32, first_frame[i], samples[i], ulps = 2));
443 }
444
445 let second_frame = [
446 0.46875, 0.5078125, 0.5390625, 0.578125, 0.609375, 0.640625, 0.671875, 0.6953125,
447 0.71875, 0.7421875,
448 ];
449
450 data_block.clear();
451 decoder.decode(&mut data_block).unwrap();
452
453 let samples = &mut data_block.block[0];
454 for i in 0..samples.len() {
455 assert_approx_eq!(f32, second_frame[i], samples[i], ulps = 2);
456 }
457
458 let last_frame = [
459 -0.0859375, -0.09375, -0.1015625, -0.1015625, -0.1015625, -0.09375, -0.0859375,
460 -0.078125, -0.0625, -0.046875,
461 ];
462
463 decoder.seek(file_info.num_frames - 1 - block_size).unwrap();
465
466 data_block.clear();
467 decoder.decode(&mut data_block).unwrap();
468
469 let samples = &mut data_block.block[0];
470 for i in 0..samples.len() {
471 assert_approx_eq!(f32, last_frame[i], samples[i], ulps = 2);
472 }
473
474 assert_eq!(decoder.playhead_frame, file_info.num_frames - 1);
475 }
476}