1#![cfg_attr(not(test), no_std)]
34
35use heapless::Vec;
36use num_traits::float::Float;
37use winnow::binary::{
38 be_f32, be_f64, be_i16, be_i24, be_i32, le_f32, le_f64, le_i16, le_i24, le_i32,
39};
40use winnow::{ModalResult, Parser};
41
42mod aiff;
43pub mod imaadpcm;
44mod wav;
45
46const MAX_NUM_CHUNKS: usize = 16;
47
48#[derive(Debug, thiserror::Error)]
50pub enum PcmReaderError {
51 #[error("Unsupported bit-depth")]
52 UnsupportedBitDepth,
53 #[error("Unsupported audio format")]
54 UnsupportedAudioFormat,
55 #[error("Invalid channel")]
56 InvalidChannel,
57 #[error("Invalid sample")]
58 InvalidSample,
59 #[error("RIFF or AIFF header size mismatch")]
60 HeaderSizeMismatch,
61 #[error("fmt parse error")]
62 FmtParseError,
63 #[error("Header parse error")]
64 HeaderParseError,
65}
66
67#[derive(Debug, Default, PartialEq, Eq, Clone)]
69pub enum AudioFormat {
70 #[default]
72 Unknown,
73 LinearPcmLe,
75 LinearPcmBe,
77 IeeeFloatLe,
79 IeeeFloatBe,
81 ImaAdpcmLe,
83}
84
85#[derive(Default, Debug, Clone)]
87pub struct PcmSpecs {
88 pub audio_format: AudioFormat,
90 pub num_channels: u16,
92 pub sample_rate: u32,
94 pub bit_depth: u16,
96 pub num_samples: u32,
98 pub(crate) ima_adpcm_num_block_align: Option<u16>,
100 pub(crate) ima_adpcm_num_samples_per_block: Option<u16>,
102}
103
104#[derive(Default)]
133pub struct PcmReader<'a> {
134 pub(crate) specs: PcmSpecs,
135 pub(crate) data: &'a [u8],
136}
137
138impl<'a> PcmReader<'a> {
139 pub fn new(input: &mut &'a [u8]) -> Result<Self, PcmReaderError> {
149 let mut reader = PcmReader {
150 data: &[],
151 specs: PcmSpecs::default(),
152 };
153 reader.reload(input)?;
154 Ok(reader)
155 }
156
157 pub fn reload(&mut self, input: &mut &'a [u8]) -> Result<(), PcmReaderError> {
167 let file_length = input.len();
168 self.data = &[];
169 self.specs = PcmSpecs::default();
170
171 if let Ok((_, riff)) = wav::parse_riff_header.parse_peek(input) {
174 if file_length - 8 != riff.size as usize {
175 return Err(PcmReaderError::HeaderSizeMismatch);
176 }
177
178 return self.parse_wav(input);
179 };
180
181 if let Ok((_, aiff)) = aiff::parse_aiff_header.parse_peek(input) {
184 if (file_length - 8) != aiff.size as usize {
185 return Err(PcmReaderError::HeaderSizeMismatch);
186 }
187
188 return self.parse_aiff(input);
189 };
190
191 Err(PcmReaderError::UnsupportedAudioFormat)
192 }
193
194 fn parse_aiff(&mut self, input: &mut &'a [u8]) -> Result<(), PcmReaderError> {
200 let Ok(_) = aiff::parse_aiff_header.parse_next(input) else {
202 return Err(PcmReaderError::HeaderParseError);
203 };
204
205 let mut chunk_vec = Vec::<aiff::Chunk, MAX_NUM_CHUNKS>::new();
206
207 while let Ok(chunk) = aiff::parse_chunk.parse_next(input) {
209 chunk_vec.push(chunk).unwrap();
210 }
211
212 for mut chunk in chunk_vec {
213 match chunk.id {
214 aiff::ChunkId::Common => {
215 let Ok(spec) = aiff::parse_comm.parse_next(&mut chunk.data) else {
216 return Err(PcmReaderError::UnsupportedAudioFormat);
217 };
218 self.specs = spec;
219 }
220 aiff::ChunkId::SoundData => {
221 let Ok(_ssnd_block_info) = aiff::parse_ssnd.parse_next(&mut chunk.data) else {
222 return Err(PcmReaderError::UnsupportedAudioFormat);
223 };
224 self.data = chunk.data;
225 }
226 aiff::ChunkId::FormatVersion => {}
227 aiff::ChunkId::Marker => {}
228 aiff::ChunkId::Instrument => {}
229 aiff::ChunkId::Midi => {}
230 aiff::ChunkId::AudioRecording => {}
231 aiff::ChunkId::ApplicationSpecific => {}
232 aiff::ChunkId::Comment => {}
233 aiff::ChunkId::Name => {}
234 aiff::ChunkId::Author => {}
235 aiff::ChunkId::Copyright => {}
236 aiff::ChunkId::Annotation => {}
237 aiff::ChunkId::Unknown => {}
238 }
239 }
240 Ok(())
241 }
242
243 fn parse_wav(&mut self, input: &mut &'a [u8]) -> Result<(), PcmReaderError> {
249 let Ok(_) = wav::parse_riff_header.parse_next(input) else {
251 return Err(PcmReaderError::HeaderParseError);
252 };
253
254 let mut chunk_vec = Vec::<wav::Chunk, MAX_NUM_CHUNKS>::new();
255
256 while let Ok(chunk) = wav::parse_chunk.parse_next(input) {
258 chunk_vec.push(chunk).unwrap();
259 }
260
261 for mut chunk in chunk_vec {
262 match chunk.id {
263 wav::ChunkId::Fmt => {
264 let Ok(spec) = wav::parse_fmt.parse_next(&mut chunk.data) else {
265 return Err(PcmReaderError::FmtParseError);
266 };
267 self.specs.num_channels = spec.num_channels;
268 self.specs.sample_rate = spec.sample_rate;
269 self.specs.audio_format = spec.audio_format;
270 self.specs.bit_depth = spec.bit_depth;
271 if self.specs.audio_format == AudioFormat::ImaAdpcmLe {
272 self.specs.ima_adpcm_num_block_align = spec.ima_adpcm_num_block_align;
273 self.specs.ima_adpcm_num_samples_per_block =
274 spec.ima_adpcm_num_samples_per_block;
275 }
276 }
277 wav::ChunkId::Data => {
278 self.data = chunk.data;
279 }
280 wav::ChunkId::Fact => {}
281 wav::ChunkId::IDv3 => {}
282 wav::ChunkId::Junk => {}
283 wav::ChunkId::List => {}
284 wav::ChunkId::Peak => {}
285 wav::ChunkId::Unknown => {}
286 }
287 }
288
289 match self.specs.audio_format {
290 AudioFormat::ImaAdpcmLe => {
291 self.specs.num_samples =
292 imaadpcm::calc_num_samples_per_channel(self.data.len() as u32, &self.specs)
293 .unwrap();
294 }
295 AudioFormat::LinearPcmLe | AudioFormat::IeeeFloatLe => {
296 self.specs.num_samples =
297 wav::calc_num_samples_per_channel(self.data.len() as u32, &self.specs).unwrap();
298 }
299 _ => {
300 unreachable!();
301 }
302 }
303 Ok(())
304 }
305
306 #[must_use]
308 pub fn get_pcm_specs(&self) -> PcmSpecs {
309 self.specs.clone()
310 }
311
312 pub fn read_sample<T: Float>(&self, channel: u16, sample: u32) -> Result<T, PcmReaderError> {
323 let num_channels = self.specs.num_channels;
324 if channel >= num_channels {
325 return Err(PcmReaderError::InvalidChannel);
326 }
327
328 if sample >= self.specs.num_samples {
329 return Err(PcmReaderError::InvalidSample);
330 }
331
332 let byte_depth = self.specs.bit_depth / 8u16;
333 let byte_offset = ((byte_depth as u32 * sample * num_channels as u32)
334 + (byte_depth * channel) as u32) as usize;
335 let mut data = &self.data[byte_offset..];
336 decode_sample(&self.specs, &mut data)
337 }
338}
339
340fn decode_sample<T: Float>(specs: &PcmSpecs, data: &mut &[u8]) -> Result<T, PcmReaderError> {
351 match specs.audio_format {
352 AudioFormat::Unknown => Err(PcmReaderError::UnsupportedAudioFormat),
353 AudioFormat::LinearPcmLe => match specs.bit_depth {
354 16 => {
355 const MAX: u32 = 2u32.pow(15);
356 let res: ModalResult<i16> = le_i16.parse_next(data);
357 let Ok(sample) = res else {
358 return Err(PcmReaderError::InvalidSample);
359 };
360 Ok(T::from(sample).unwrap() / T::from(MAX).unwrap())
361 }
362 24 => {
363 const MAX: u32 = 2u32.pow(23);
364 let res: ModalResult<i32> = le_i24.parse_next(data);
365 let Ok(sample) = res else {
366 return Err(PcmReaderError::InvalidSample);
367 };
368 Ok(T::from(sample).unwrap() / T::from(MAX).unwrap())
369 }
370 32 => {
371 const MAX: u32 = 2u32.pow(31);
372 let res: ModalResult<i32> = le_i32.parse_next(data);
373 let Ok(sample) = res else {
374 return Err(PcmReaderError::InvalidSample);
375 };
376 Ok(T::from(sample).unwrap() / T::from(MAX).unwrap())
377 }
378 _ => Err(PcmReaderError::UnsupportedBitDepth),
379 },
380 AudioFormat::LinearPcmBe => match specs.bit_depth {
381 16 => {
382 const MAX: u32 = 2u32.pow(15);
383 let res: ModalResult<i16> = be_i16.parse_next(data);
384 let Ok(sample) = res else {
385 return Err(PcmReaderError::InvalidSample);
386 };
387 Ok(T::from(sample).unwrap() / T::from(MAX).unwrap())
388 }
389 24 => {
390 const MAX: u32 = 2u32.pow(23);
391 let res: ModalResult<i32> = be_i24.parse_next(data);
392 let Ok(sample) = res else {
393 return Err(PcmReaderError::InvalidSample);
394 };
395 Ok(T::from(sample).unwrap() / T::from(MAX).unwrap())
396 }
397 32 => {
398 const MAX: u32 = 2u32.pow(31);
399 let res: ModalResult<i32> = be_i32.parse_next(data);
400 let Ok(sample) = res else {
401 return Err(PcmReaderError::InvalidSample);
402 };
403 Ok(T::from(sample).unwrap() / T::from(MAX).unwrap())
404 }
405 _ => Err(PcmReaderError::UnsupportedBitDepth),
406 },
407 AudioFormat::IeeeFloatLe => match specs.bit_depth {
408 32 => {
409 let res: ModalResult<f32> = le_f32.parse_next(data);
410 let Ok(sample) = res else {
411 return Err(PcmReaderError::InvalidSample);
412 };
413 Ok(T::from(sample).unwrap())
414 }
415 64 => {
416 let res: ModalResult<f64> = le_f64.parse_next(data);
417 let Ok(sample) = res else {
418 return Err(PcmReaderError::InvalidSample);
419 };
420 Ok(T::from(sample).unwrap())
421 }
422 _ => Err(PcmReaderError::UnsupportedBitDepth),
423 },
424 AudioFormat::IeeeFloatBe => match specs.bit_depth {
425 32 => {
426 let res: ModalResult<f32> = be_f32.parse_next(data);
427 let Ok(sample) = res else {
428 return Err(PcmReaderError::InvalidSample);
429 };
430 Ok(T::from(sample).unwrap())
431 }
432 64 => {
433 let res: ModalResult<f64> = be_f64.parse_next(data);
434 let Ok(sample) = res else {
435 return Err(PcmReaderError::InvalidSample);
436 };
437 Ok(T::from(sample).unwrap())
438 }
439 _ => Err(PcmReaderError::UnsupportedBitDepth),
440 },
441 AudioFormat::ImaAdpcmLe => Err(PcmReaderError::UnsupportedAudioFormat),
442 }
443}
444
445#[derive(Debug, thiserror::Error)]
447pub enum PcmPlayerError {
448 #[error("Output buffer too short")]
449 OutputBufferTooShort,
450 #[error("Invalid position")]
451 InvalidPosition,
452 #[error("Finish playing")]
453 FinishPlaying,
454}
455
456#[derive(Default)]
483pub struct PcmPlayer<'a> {
484 pub reader: PcmReader<'a>,
486 playback_position: u32,
487 loop_playing: bool,
488}
489
490impl<'a> PcmPlayer<'a> {
491 pub fn new(reader: PcmReader<'a>) -> Self {
493 PcmPlayer {
494 reader,
495 playback_position: 0,
496 loop_playing: false,
497 }
498 }
499
500 pub fn set_position(&mut self, sample: u32) -> Result<(), PcmPlayerError> {
503 if self.reader.specs.num_samples <= sample {
504 return Err(PcmPlayerError::InvalidPosition);
505 }
506 self.playback_position = sample;
507 Ok(())
508 }
509
510 pub fn set_loop_playing(&mut self, en: bool) {
515 self.loop_playing = en;
516 }
517
518 pub fn get_next_frame<T: Float>(&mut self, out: &mut [T]) -> Result<(), PcmPlayerError> {
529 if out.len() < self.reader.specs.num_channels as usize {
530 return Err(PcmPlayerError::OutputBufferTooShort);
531 }
532
533 let num_samples = self.reader.specs.num_samples;
534 if self.playback_position >= num_samples {
535 if self.loop_playing {
536 self.set_position(0)?;
537 } else {
538 return Err(PcmPlayerError::FinishPlaying);
539 }
540 }
541
542 let num_chennels = self.reader.specs.num_channels;
543 for ch in 0..num_chennels {
544 let Ok(sample) = self.reader.read_sample(ch, self.playback_position) else {
545 return Err(PcmPlayerError::InvalidPosition);
546 };
547 out[ch as usize] = sample;
548 }
549
550 self.playback_position += 1;
552
553 Ok(())
554 }
555}