From 653baac38d147f746821984dde4c40ddb08e9cc0 Mon Sep 17 00:00:00 2001 From: AkiyukiOkayasu Date: Fri, 16 Aug 2024 22:24:34 +0900 Subject: [PATCH 01/12] Replace `anyhow` with `thiserror-core` --- Cargo.toml | 2 +- src/aiff.rs | 4 ++-- src/imaadpcm.rs | 44 ++++++++++++++++++++++-------------- src/lib.rs | 59 +++++++++++++++++++++++++++++++------------------ src/wav.rs | 14 ++++++------ 5 files changed, 75 insertions(+), 48 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6be2dfe..8c7614e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,11 +12,11 @@ edition = "2021" rust-version = "1.79.0" [dependencies] -anyhow = { version = "1.0.86", default-features = false } arbitrary-int = { version = "1.2.7", default-features = false } fixed = "1.28.0" heapless = "0.8.0" nom = { version = "7.1.3", default-features = false } +thiserror = { version = "1.0", package = "thiserror-core", default-features = false } [dev-dependencies] cpal = "0.15.3" diff --git a/src/aiff.rs b/src/aiff.rs index 9b18181..cedb195 100644 --- a/src/aiff.rs +++ b/src/aiff.rs @@ -89,7 +89,7 @@ pub(super) struct Chunk<'a> { /// AIFFチャンクの情報 /// * 'size' - ファイルサイズ(byte) - 8 pub(super) struct AiffHeader { - pub _size: u32, + pub size: u32, } /// SSNDチャンクのOffset, BlockSize @@ -108,7 +108,7 @@ pub(super) fn parse_aiff_header(input: &[u8]) -> IResult<&[u8], AiffHeader> { let (input, _) = tag(b"FORM")(input)?; let (input, size) = be_u32(input)?; let (input, _id) = alt((tag(b"AIFF"), tag(b"AIFC")))(input)?; - Ok((input, AiffHeader { _size: size })) + Ok((input, AiffHeader { size: size })) } /// 先頭のチャンクを取得する diff --git a/src/imaadpcm.rs b/src/imaadpcm.rs index 7f5afe7..485216e 100644 --- a/src/imaadpcm.rs +++ b/src/imaadpcm.rs @@ -17,7 +17,6 @@ //! ``` use crate::{AudioFormat, PcmReader, PcmSpecs}; -use anyhow::ensure; use arbitrary_int::u4; use heapless::spsc::Queue; use nom::bits::{bits, complete::take}; @@ -51,6 +50,19 @@ struct BlockHeader { b_step_table_index: i8, } +/// Error type for IMA-ADPCM. +#[derive(Debug, thiserror::Error)] +pub enum ImaAdpcmError { + #[error("IMA-ADPCM is not supported in decode_sample(). Use ImaAdpcmPlayer.")] + CantDecodeImaAdpcm, + #[error("The audio format is not IMA-ADPCM.")] + NotImaAdpcm, + #[error("The number of elements in the output buffer must be at least equal to the number of IMA-ADPCM channels.")] + InsufficientOutputBufferChannels, + #[error("Finish playing.")] + FinishPlaying, +} + /// IMA-ADPCMのHeader Wordをパースする /// Multimedia Data Standards Update April 15, 1994 Page 32 of 74 /// http://elm-chan.org/junk/adpcm/RIFF_NEW.pdf @@ -118,11 +130,11 @@ fn compute_step_size(nibble: u4, mut step_size_table_index: i8) -> i8 { pub(crate) fn calc_num_samples_per_channel( data_chunk_size_in_bytes: u32, spec: &PcmSpecs, -) -> anyhow::Result { - ensure!( - spec.audio_format == AudioFormat::ImaAdpcmLe, - "IMA-ADPCM only" - ); +) -> Result { + if spec.audio_format != AudioFormat::ImaAdpcmLe { + return Err(ImaAdpcmError::NotImaAdpcm); + } + let num_block_align = spec.ima_adpcm_num_block_align.unwrap() as u32; let num_samples_per_block = spec.ima_adpcm_num_samples_per_block.unwrap() as u32; let num_blocks = data_chunk_size_in_bytes / num_block_align; @@ -162,20 +174,18 @@ impl<'a> ImaAdpcmPlayer<'a> { /// Return samples value of the next frame. /// * 'out' - Output buffer which the sample values are written. Number of elements must be equal to or greater than the number of channels in the PCM file. - pub fn get_next_frame(&mut self, out: &mut [I1F15]) -> anyhow::Result<()> { + pub fn get_next_frame(&mut self, out: &mut [I1F15]) -> Result<(), ImaAdpcmError> { let num_channels = self.reader.specs.num_channels; - // outバッファーのチャンネル数が不足 - ensure!( - out.len() >= num_channels as usize, - "Number of elements in \"out\" must be greater than or equal to the number of IMA-ADPCM channels" - ); + // outバッファーのチャンネル数が不足している場合はエラーを返す + if out.len() < num_channels as usize { + return Err(ImaAdpcmError::InsufficientOutputBufferChannels); + } - // 再生終了 - ensure!( - self.frame_index < self.reader.specs.num_samples, - "Played to the end." - ); + // 再生終了している場合はエラーを返す + if self.frame_index >= self.reader.specs.num_samples { + return Err(ImaAdpcmError::FinishPlaying); + } //IMA-ADPCMのBlock切り替わりかどうか判定 if self.reading_block.is_empty() && self.nibble_queue[0].is_empty() { diff --git a/src/lib.rs b/src/lib.rs index 78ccb3e..00d9303 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,8 +25,8 @@ //! } //! ``` #![cfg_attr(not(test), no_std)] +#![feature(error_in_core)] -use anyhow::{bail, ensure}; use heapless::Vec; use nom::error::Error; use nom::number::complete::{ @@ -41,6 +41,23 @@ mod wav; const MAX_NUM_CHUNKS: usize = 16; +/// Error type for LinearPCM +#[derive(Debug, thiserror::Error)] +pub enum LinearPcmError { + #[error("Unsupported bit-depth")] + UnsupportedBitDepth, + #[error("Unsupported audio format")] + UnsupportedAudioFormat, + #[error("Invalid channel")] + InvalidChannel, + #[error("Invalid sample")] + InvalidSample, + #[error("Invalid output buffer length")] + InvalidOutputBufferLength, + #[error("Finished playing")] + FinishPlaying, +} + /// Audio format #[derive(Debug, Default, PartialEq, Eq, Clone)] pub enum AudioFormat { @@ -217,9 +234,14 @@ impl<'a> PcmReader<'a> { /// Returns the value of a sample at an arbitrary position. /// Returns a normalized value in the range +/-1.0 regardless of AudioFormat. - pub fn read_sample(&self, channel: u32, sample: u32) -> anyhow::Result { - ensure!(channel < self.specs.num_channels as u32, "Invalid channel"); - ensure!(sample < self.specs.num_samples, "Invalid sample"); + pub fn read_sample(&self, channel: u32, sample: u32) -> Result { + if channel >= self.specs.num_channels as u32 { + return Err(LinearPcmError::InvalidChannel); + } + + if sample >= self.specs.num_samples { + return Err(LinearPcmError::InvalidSample); + } let byte_depth = self.specs.bit_depth as u32 / 8u32; let byte_offset = ((byte_depth * sample * self.specs.num_channels as u32) @@ -234,11 +256,9 @@ impl<'a> PcmReader<'a> { /// TODO return not only f32 but also Q15, Q23, f64, etc. /// Or make it possible to select f32 or f64. /// It may be better to use a function like read_raw_sample() to get fixed-point numbers. -fn decode_sample(specs: &PcmSpecs, data: &[u8]) -> anyhow::Result { +fn decode_sample(specs: &PcmSpecs, data: &[u8]) -> Result { match specs.audio_format { - AudioFormat::Unknown => { - bail!("Unknown audio format"); - } + AudioFormat::Unknown => Err(LinearPcmError::UnsupportedAudioFormat), AudioFormat::LinearPcmLe => { match specs.bit_depth { 16 => { @@ -259,7 +279,7 @@ fn decode_sample(specs: &PcmSpecs, data: &[u8]) -> anyhow::Result { let sample = sample as f32 / MAX as f32; Ok(sample) } - _ => bail!("Unsupported bit-depth"), + _ => Err(LinearPcmError::UnsupportedBitDepth), } } AudioFormat::LinearPcmBe => { @@ -282,7 +302,7 @@ fn decode_sample(specs: &PcmSpecs, data: &[u8]) -> anyhow::Result { let sample = sample as f32 / MAX as f32; Ok(sample) } - _ => bail!("Unsupported bit-depth"), + _ => Err(LinearPcmError::UnsupportedBitDepth), } } AudioFormat::IeeeFloatLe => { @@ -297,7 +317,7 @@ fn decode_sample(specs: &PcmSpecs, data: &[u8]) -> anyhow::Result { let (_remains, sample) = le_f64::<_, Error<_>>(data).finish().unwrap(); Ok(sample as f32) // TODO f32にダウンキャストするべきなのか検討 } - _ => bail!("Unsupported bit-depth"), + _ => Err(LinearPcmError::UnsupportedBitDepth), } } AudioFormat::IeeeFloatBe => { @@ -312,12 +332,10 @@ fn decode_sample(specs: &PcmSpecs, data: &[u8]) -> anyhow::Result { let (_remains, sample) = be_f64::<_, Error<_>>(data).finish().unwrap(); Ok(sample as f32) // TODO f32にダウンキャストするべきなのか検討 } - _ => bail!("Unsupported bit-depth"), + _ => Err(LinearPcmError::UnsupportedBitDepth), } } - AudioFormat::ImaAdpcmLe => { - bail!("IMA-ADPCM is not supported in decode_sample(). Use ImaAdpcmPlayer.") - } + AudioFormat::ImaAdpcmLe => Err(LinearPcmError::UnsupportedAudioFormat), } } @@ -359,19 +377,18 @@ impl<'a> PcmPlayer<'a> { /// Return samples value of the next frame. /// * ‘out’ - Output buffer which the sample values are written. Number of elements must be equal to or greater than the number of channels in the PCM file. - pub fn get_next_frame(&mut self, out: &mut [f32]) -> anyhow::Result<()> { + pub fn get_next_frame(&mut self, out: &mut [f32]) -> Result<(), LinearPcmError> { let byte_depth = self.reader.specs.bit_depth / 8; - ensure!( - out.len() >= self.reader.specs.num_channels as usize, - "Invalid output buffer length" - ); + if out.len() < self.reader.specs.num_channels as usize { + return Err(LinearPcmError::InvalidOutputBufferLength); + } if self.reading_data.is_empty() { if self.loop_playing { self.set_position(0); } else { - bail!("Finished playing"); + return Err(LinearPcmError::FinishPlaying); } } diff --git a/src/wav.rs b/src/wav.rs index e92a3a6..7e27d6e 100644 --- a/src/wav.rs +++ b/src/wav.rs @@ -1,5 +1,4 @@ -use crate::{AudioFormat, PcmSpecs}; -use anyhow::ensure; +use crate::{AudioFormat, LinearPcmError, PcmSpecs}; use nom::bytes::complete::{tag, take}; use nom::number::complete::{le_u16, le_u32}; use nom::IResult; @@ -174,11 +173,12 @@ pub(super) fn parse_fmt(input: &[u8]) -> IResult<&[u8], WavFmtSpecs> { pub(super) fn calc_num_samples_per_channel( data_chunk_size_in_bytes: u32, spec: &PcmSpecs, -) -> anyhow::Result { - ensure!( - spec.audio_format != AudioFormat::ImaAdpcmLe, - "IMA-ADPCM is not supported in calc_num_samples_per_channel" - ); +) -> Result { + // IMA-ADPCMは非対応 + if spec.audio_format == AudioFormat::ImaAdpcmLe { + return Err(LinearPcmError::UnsupportedAudioFormat); + } + Ok(data_chunk_size_in_bytes / (spec.bit_depth / 8u16 * spec.num_channels) as u32) } From 14c28d8f1c5a6c4c8aea55611f9df215b7c7da8b Mon Sep 17 00:00:00 2001 From: AkiyukiOkayasu Date: Fri, 16 Aug 2024 23:09:37 +0900 Subject: [PATCH 02/12] Add error handling instead of assert! used in extended2double() --- src/aiff.rs | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/aiff.rs b/src/aiff.rs index cedb195..936d5b3 100644 --- a/src/aiff.rs +++ b/src/aiff.rs @@ -4,6 +4,20 @@ use nom::bytes::complete::{tag, take}; use nom::number::complete::{be_i16, be_i32, be_u32}; use nom::IResult; +#[derive(thiserror::Error, Debug)] +enum AiffError { + #[error("Buffer length must be exactly 10 bytes")] + InvalidBufferLength, +} + +/// AiffErrorをnom::Errに変換する +/// 変換時に情報が失われてしまう。とりあえずnom::error::ErrorKind::Failとしたが、IResultを使わずに実装できるか検討したい +impl<'a> From for nom::Err> { + fn from(_err: AiffError) -> Self { + nom::Err::Error(nom::error::Error::new(&[], nom::error::ErrorKind::Fail)) + } +} + /// ckID chunkの種類 #[derive(Debug, PartialEq, Default)] pub(super) enum ChunkId { @@ -131,7 +145,7 @@ pub(super) fn parse_comm(input: &[u8]) -> IResult<&[u8], PcmSpecs> { let (input, bit_depth) = be_i16(input)?; let bit_depth = bit_depth as u16; let (input, sample_rate) = take(10usize)(input)?; - let sample_rate = extended2double(sample_rate) as u32; + let sample_rate = extended2double(sample_rate).map_err(|e| nom::Err::from(e))? as u32; if input.len() >= 4 { //AIFF-C parameters @@ -168,8 +182,10 @@ pub(super) fn parse_ssnd(input: &[u8]) -> IResult<&[u8], SsndBlockInfo> { /// 80 bit floating point value according to the IEEE-754 specification and the Standard Apple Numeric Environment specification: /// 1 bit sign, 15 bit exponent, 1 bit normalization indication, 63 bit mantissa /// https://stackoverflow.com/a/3949358 -fn extended2double(buffer: &[u8]) -> f64 { - assert!(buffer.len() == 10); +fn extended2double(buffer: &[u8]) -> Result { + if buffer.len() != 10 { + return Err(AiffError::InvalidBufferLength); + } let sign = if (buffer[0] & 0x80) == 0x00 { 1f64 @@ -195,8 +211,9 @@ fn extended2double(buffer: &[u8]) -> f64 { mantissa &= 0x7FFFFFFFFFFFFFFF; //value = (-1) ^ s * (normalizeCorrection + m / 2 ^ 63) * 2 ^ (e - 16383) - sign * (normalize_correction + mantissa as f64 / (1u64 << 63) as f64) - * (1u64 << (exponent as i32 - 16383)) as f64 + Ok(sign + * (normalize_correction + mantissa as f64 / (1u64 << 63) as f64) + * (1u64 << (exponent as i32 - 16383)) as f64) } #[cfg(test)] From bd958cc31172554ec5d17ff94ca2a26bb4c2222f Mon Sep 17 00:00:00 2001 From: AkiyukiOkayasu Date: Fri, 16 Aug 2024 23:59:45 +0900 Subject: [PATCH 03/12] clippy --- examples/beep_imaadpcm.rs | 2 +- src/aiff.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/beep_imaadpcm.rs b/examples/beep_imaadpcm.rs index 2421a1e..08e3946 100644 --- a/examples/beep_imaadpcm.rs +++ b/examples/beep_imaadpcm.rs @@ -29,7 +29,7 @@ fn main() { let buf = buffer.as_mut_slice(); match player.get_next_frame(buf) { Ok(_) => { - for (_ch, sample) in frame.iter_mut().enumerate() { + for sample in frame.iter_mut() { *sample = buf[0].to_num::(); } } diff --git a/src/aiff.rs b/src/aiff.rs index 936d5b3..29ee53e 100644 --- a/src/aiff.rs +++ b/src/aiff.rs @@ -122,7 +122,7 @@ pub(super) fn parse_aiff_header(input: &[u8]) -> IResult<&[u8], AiffHeader> { let (input, _) = tag(b"FORM")(input)?; let (input, size) = be_u32(input)?; let (input, _id) = alt((tag(b"AIFF"), tag(b"AIFC")))(input)?; - Ok((input, AiffHeader { size: size })) + Ok((input, AiffHeader { size })) } /// 先頭のチャンクを取得する @@ -145,7 +145,7 @@ pub(super) fn parse_comm(input: &[u8]) -> IResult<&[u8], PcmSpecs> { let (input, bit_depth) = be_i16(input)?; let bit_depth = bit_depth as u16; let (input, sample_rate) = take(10usize)(input)?; - let sample_rate = extended2double(sample_rate).map_err(|e| nom::Err::from(e))? as u32; + let sample_rate = extended2double(sample_rate).map_err(nom::Err::from)? as u32; if input.len() >= 4 { //AIFF-C parameters @@ -226,7 +226,7 @@ mod tests { #[test] fn extended2double_test() { let array: [u8; 10] = [64, 14, 187, 128, 0, 0, 0, 0, 0, 0]; - assert_relative_eq!(extended2double(&array), 48000.0f64); + assert_relative_eq!(extended2double(&array).unwrap(), 48000.0f64); } #[test] From 4979d2eb50a72f518a480183243c1458edfe5f19 Mon Sep 17 00:00:00 2001 From: AkiyukiOkayasu Date: Mon, 19 Aug 2024 23:57:39 +0900 Subject: [PATCH 04/12] =?UTF-8?q?feature(error=5Fin=5Fcore)=E3=81=8C1.81?= =?UTF-8?q?=E4=BB=A5=E9=99=8D=E3=81=AFstable=E3=81=AB=E7=A7=BB=E8=A1=8C?= =?UTF-8?q?=E3=81=99=E3=82=8B=E3=81=BE=E3=81=A7clippy=E3=82=92=E9=BB=99?= =?UTF-8?q?=E3=82=89=E3=81=9B=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 00d9303..257ca7b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,6 +25,7 @@ //! } //! ``` #![cfg_attr(not(test), no_std)] +#![allow(stable_features)] #![feature(error_in_core)] use heapless::Vec; From 984d27fed545e2b47d637491ad118a17dee9c257 Mon Sep 17 00:00:00 2001 From: AkiyukiOkayasu Date: Mon, 19 Aug 2024 23:59:03 +0900 Subject: [PATCH 05/12] =?UTF-8?q?AIFF=20header=E3=81=AEassert=E3=82=92?= =?UTF-8?q?=E5=BE=A9=E6=B4=BB=E3=81=95=E3=81=9B=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 257ca7b..9b29666 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -215,8 +215,8 @@ impl<'a> PcmReader<'a> { }; //AIFF - if let Ok((input, _aiff)) = aiff::parse_aiff_header(input) { - // assert_eq!((file_length - 8) as u32, aiff.size); + if let Ok((input, aiff)) = aiff::parse_aiff_header(input) { + assert_eq!((file_length - 8) as u32, aiff.size); if let Ok((_, _)) = reader.parse_aiff(input) { return reader; } From 5e8cbdd294371244fdf3ee0705b769d783b8f01f Mon Sep 17 00:00:00 2001 From: AkiyukiOkayasu Date: Tue, 20 Aug 2024 00:00:25 +0900 Subject: [PATCH 06/12] TODO --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 9b29666..33f4eb0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -223,7 +223,7 @@ impl<'a> PcmReader<'a> { }; //WAVでもAIFFでもなかった場合 - + //TODO panicせずにエラーを返す panic!(); } From 22cf2ec4ab2f93a40dacccc73df905795d5e3d05 Mon Sep 17 00:00:00 2001 From: AkiyukiOkayasu Date: Tue, 20 Aug 2024 00:04:19 +0900 Subject: [PATCH 07/12] =?UTF-8?q?=E7=8F=BE=E6=99=82=E7=82=B9=E3=81=A7?= =?UTF-8?q?=E3=81=AERust=20nightly=E3=81=A7=E3=81=AFerror=5Fin=5Fcore=20fe?= =?UTF-8?q?ature=E3=81=AF=E5=AE=89=E5=AE=9A=E5=8C=96=E3=81=97=E3=81=A6?= =?UTF-8?q?=E3=81=84=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 33f4eb0..c6a3d19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,8 +25,6 @@ //! } //! ``` #![cfg_attr(not(test), no_std)] -#![allow(stable_features)] -#![feature(error_in_core)] use heapless::Vec; use nom::error::Error; From 6c01796984f5371188af07da1f78d5a8e5c85a6b Mon Sep 17 00:00:00 2001 From: AkiyukiOkayasu Date: Tue, 20 Aug 2024 00:20:29 +0900 Subject: [PATCH 08/12] Use thiserror fork from https://github.com/quartiq/thiserror.git --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8c7614e..4966eb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ arbitrary-int = { version = "1.2.7", default-features = false } fixed = "1.28.0" heapless = "0.8.0" nom = { version = "7.1.3", default-features = false } -thiserror = { version = "1.0", package = "thiserror-core", default-features = false } +thiserror = { version = "1.0", git = "https://github.com/quartiq/thiserror.git", default-features = false, branch = "no-std" } [dev-dependencies] cpal = "0.15.3" From 688f282382e98073e9d491685bf22cdd187d755c Mon Sep 17 00:00:00 2001 From: AkiyukiOkayasu Date: Tue, 20 Aug 2024 00:35:41 +0900 Subject: [PATCH 09/12] =?UTF-8?q?use=20nom::error::Error=E3=82=92=E5=89=8A?= =?UTF-8?q?=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/imaadpcm.rs | 3 +-- src/lib.rs | 31 ++++++++++++++++++++----------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/imaadpcm.rs b/src/imaadpcm.rs index 485216e..7a18b60 100644 --- a/src/imaadpcm.rs +++ b/src/imaadpcm.rs @@ -20,7 +20,6 @@ use crate::{AudioFormat, PcmReader, PcmSpecs}; use arbitrary_int::u4; use heapless::spsc::Queue; use nom::bits::{bits, complete::take}; -use nom::error::Error; use nom::number::complete::{le_i16, le_i8, le_u8}; use nom::sequence::tuple; use nom::IResult; @@ -266,7 +265,7 @@ type DataWordNibbles = (u8, u8, u8, u8, u8, u8, u8, u8); /// IMA-ADPCMのBlockのData word(32bit長)を8つのnibble(4bit長)にパースする. fn parse_data_word(input: &[u8]) -> IResult<&[u8], DataWordNibbles> { - bits::<_, _, Error<(&[u8], usize)>, _, _>(tuple(( + bits::<_, _, nom::error::Error<(&[u8], usize)>, _, _>(tuple(( take(4usize), take(4usize), take(4usize), diff --git a/src/lib.rs b/src/lib.rs index c6a3d19..5076579 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,6 @@ #![cfg_attr(not(test), no_std)] use heapless::Vec; -use nom::error::Error; use nom::number::complete::{ be_f32, be_f64, be_i16, be_i24, be_i32, le_f32, le_f64, le_i16, le_i24, le_i32, }; @@ -262,19 +261,22 @@ fn decode_sample(specs: &PcmSpecs, data: &[u8]) -> Result { match specs.bit_depth { 16 => { const MAX: u32 = 2u32.pow(15); //normalize factor: 2^(BitDepth-1) - let (_remains, sample) = le_i16::<_, Error<_>>(data).finish().unwrap(); + let (_remains, sample) = + le_i16::<_, nom::error::Error<_>>(data).finish().unwrap(); let sample = sample as f32 / MAX as f32; Ok(sample) } 24 => { const MAX: u32 = 2u32.pow(23); //normalize factor: 2^(BitDepth-1) - let (_remains, sample) = le_i24::<_, Error<_>>(data).finish().unwrap(); + let (_remains, sample) = + le_i24::<_, nom::error::Error<_>>(data).finish().unwrap(); let sample = sample as f32 / MAX as f32; Ok(sample) } 32 => { const MAX: u32 = 2u32.pow(31); //normalize factor: 2^(BitDepth-1) - let (_remains, sample) = le_i32::<_, Error<_>>(data).finish().unwrap(); + let (_remains, sample) = + le_i32::<_, nom::error::Error<_>>(data).finish().unwrap(); let sample = sample as f32 / MAX as f32; Ok(sample) } @@ -285,19 +287,22 @@ fn decode_sample(specs: &PcmSpecs, data: &[u8]) -> Result { match specs.bit_depth { 16 => { const MAX: u32 = 2u32.pow(15); //normalize factor: 2^(BitDepth-1) - let (_remains, sample) = be_i16::<_, Error<_>>(data).finish().unwrap(); + let (_remains, sample) = + be_i16::<_, nom::error::Error<_>>(data).finish().unwrap(); let sample = sample as f32 / MAX as f32; Ok(sample) } 24 => { const MAX: u32 = 2u32.pow(23); //normalize factor: 2^(BitDepth-1) - let (_remains, sample) = be_i24::<_, Error<_>>(data).finish().unwrap(); + let (_remains, sample) = + be_i24::<_, nom::error::Error<_>>(data).finish().unwrap(); let sample = sample as f32 / MAX as f32; Ok(sample) } 32 => { const MAX: u32 = 2u32.pow(31); //normalize factor: 2^(BitDepth-1) - let (_remains, sample) = be_i32::<_, Error<_>>(data).finish().unwrap(); + let (_remains, sample) = + be_i32::<_, nom::error::Error<_>>(data).finish().unwrap(); let sample = sample as f32 / MAX as f32; Ok(sample) } @@ -308,12 +313,14 @@ fn decode_sample(specs: &PcmSpecs, data: &[u8]) -> Result { match specs.bit_depth { 32 => { //32bit float - let (_remains, sample) = le_f32::<_, Error<_>>(data).finish().unwrap(); + let (_remains, sample) = + le_f32::<_, nom::error::Error<_>>(data).finish().unwrap(); Ok(sample) } 64 => { //64bit float - let (_remains, sample) = le_f64::<_, Error<_>>(data).finish().unwrap(); + let (_remains, sample) = + le_f64::<_, nom::error::Error<_>>(data).finish().unwrap(); Ok(sample as f32) // TODO f32にダウンキャストするべきなのか検討 } _ => Err(LinearPcmError::UnsupportedBitDepth), @@ -323,12 +330,14 @@ fn decode_sample(specs: &PcmSpecs, data: &[u8]) -> Result { match specs.bit_depth { 32 => { //32bit float - let (_remains, sample) = be_f32::<_, Error<_>>(data).finish().unwrap(); + let (_remains, sample) = + be_f32::<_, nom::error::Error<_>>(data).finish().unwrap(); Ok(sample) } 64 => { //64bit float - let (_remains, sample) = be_f64::<_, Error<_>>(data).finish().unwrap(); + let (_remains, sample) = + be_f64::<_, nom::error::Error<_>>(data).finish().unwrap(); Ok(sample as f32) // TODO f32にダウンキャストするべきなのか検討 } _ => Err(LinearPcmError::UnsupportedBitDepth), From 32ed49abf215557e5266636c2a73e0c21058ca32 Mon Sep 17 00:00:00 2001 From: AkiyukiOkayasu Date: Tue, 20 Aug 2024 17:17:23 +0900 Subject: [PATCH 10/12] Do not use assert! in library --- examples/beep.rs | 2 +- examples/print_sample_values.rs | 2 +- examples/read_wav_no_std.rs | 2 +- src/imaadpcm.rs | 14 +++++-- src/lib.rs | 69 ++++++++++++++++++++++----------- src/wav.rs | 37 ++++++++++++++---- tests/integration_test.rs | 28 ++++++------- 7 files changed, 103 insertions(+), 51 deletions(-) diff --git a/examples/beep.rs b/examples/beep.rs index 051a638..4132616 100644 --- a/examples/beep.rs +++ b/examples/beep.rs @@ -15,7 +15,7 @@ fn main() { println!("Default output config: {config:?}"); let channels = config.channels() as usize; - let reader = PcmReader::new(wav); + let reader = PcmReader::new(wav).unwrap(); let mut sample_index = 0; println!("PCM spec: {:?}", reader.get_pcm_specs()); diff --git a/examples/print_sample_values.rs b/examples/print_sample_values.rs index c264b9a..2b4846d 100644 --- a/examples/print_sample_values.rs +++ b/examples/print_sample_values.rs @@ -4,7 +4,7 @@ use std::{fs, io::Write}; fn main() { let wav = include_bytes!("../tests/resources/Sine440Hz_1ch_48000Hz_64FP.wav"); println!("Wave length in bytes: {}", wav.len()); - let reader = PcmReader::new(wav); + let reader = PcmReader::new(wav).unwrap(); println!("PCM spec: {:?}", reader.get_pcm_specs()); let mut file = fs::File::create("sinewave.txt").unwrap(); diff --git a/examples/read_wav_no_std.rs b/examples/read_wav_no_std.rs index 68de8f1..c5bc4cc 100644 --- a/examples/read_wav_no_std.rs +++ b/examples/read_wav_no_std.rs @@ -6,7 +6,7 @@ use pacmog::PcmReader; fn main() { let wav = include_bytes!("../tests/resources/Sine440Hz_1ch_48000Hz_16.wav"); - let reader = PcmReader::new(wav); + let reader = PcmReader::new(wav).unwrap(); for sample in 0..48000 { let _s = reader.read_sample(0, sample); } diff --git a/src/imaadpcm.rs b/src/imaadpcm.rs index 7a18b60..8da1cdd 100644 --- a/src/imaadpcm.rs +++ b/src/imaadpcm.rs @@ -60,6 +60,8 @@ pub enum ImaAdpcmError { InsufficientOutputBufferChannels, #[error("Finish playing.")] FinishPlaying, + #[error("Block length does not match block align")] + BlockLengthMismatch, } /// IMA-ADPCMのHeader Wordをパースする @@ -162,7 +164,8 @@ pub struct ImaAdpcmPlayer<'a> { impl<'a> ImaAdpcmPlayer<'a> { /// * 'input' - PCM data byte array. pub fn new(input: &'a [u8]) -> Self { - let reader = PcmReader::new(input); + //TODO unwrapではなくきちんとエラーハンドリングする + let reader = PcmReader::new(input).unwrap(); ImaAdpcmPlayer { reader, @@ -188,7 +191,7 @@ impl<'a> ImaAdpcmPlayer<'a> { //IMA-ADPCMのBlock切り替わりかどうか判定 if self.reading_block.is_empty() && self.nibble_queue[0].is_empty() { - self.update_block(); + self.update_block()?; out[..(num_channels as usize)] .copy_from_slice(&self.last_predicted_sample[..(num_channels as usize)]); self.frame_index += 1; //Blockの最初のサンプルはHeaderに記録されている @@ -229,13 +232,15 @@ impl<'a> ImaAdpcmPlayer<'a> { } /// IMA-ADPCMのブロック更新. - fn update_block(&mut self) { + fn update_block(&mut self) -> Result<(), ImaAdpcmError> { let samples_per_block = self.reader.specs.ima_adpcm_num_samples_per_block.unwrap() as u32; let block_align = self.reader.specs.ima_adpcm_num_block_align.unwrap() as u32; let offset = (self.frame_index / samples_per_block) * block_align; self.reading_block = &self.reader.data[offset as usize..(offset + block_align) as usize]; //新しいBlockをreading_blockへ更新 - assert_eq!(self.reading_block.len(), block_align as usize); + if self.reading_block.len() != block_align as usize { + return Err(ImaAdpcmError::BlockLengthMismatch); + } for ch in 0..self.reader.specs.num_channels as usize { // BlockのHeader wordを読み出す @@ -244,6 +249,7 @@ impl<'a> ImaAdpcmPlayer<'a> { self.step_size_table_index[ch] = block_header.b_step_table_index; self.reading_block = block; } + Ok(()) } /// Move the playback position back to the beginning. diff --git a/src/lib.rs b/src/lib.rs index 5076579..05ae76b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ //! use pacmog::PcmReader; //! //! let wav = include_bytes!("../tests/resources/Sine440Hz_1ch_48000Hz_16.wav"); -//! let reader = PcmReader::new(wav); +//! let reader = PcmReader::new(wav).unwrap(); //! let specs = reader.get_pcm_specs(); //! let num_samples = specs.num_samples; //! let num_channels = specs.num_channels as u32; @@ -54,6 +54,8 @@ pub enum LinearPcmError { InvalidOutputBufferLength, #[error("Finished playing")] FinishPlaying, + #[error("RIFF or AIFF header size mismatch")] + HeaderSizeMismatch, } /// Audio format @@ -111,17 +113,28 @@ impl<'a> PcmReader<'a> { }, )(input)?; - for e in v { - assert_ne!(e.size, 0); - match e.id { + for chunk in v { + if chunk.size < 0 { + return Err(nom::Err::Error(nom::error::Error::new( + input, + nom::error::ErrorKind::LengthValue, + ))); + } + + match chunk.id { aiff::ChunkId::Common => { - let (_, spec) = aiff::parse_comm(e.data)?; + let (_, spec) = aiff::parse_comm(chunk.data)?; self.specs = spec; } aiff::ChunkId::SoundData => { - let (data, ssnd_block_info) = aiff::parse_ssnd(e.data)?; - assert_eq!(ssnd_block_info.offset, 0); //offsetとblock_sizeはほとんどの場合で0固定。したがって0で指定されたファイルにのみ対応する。 - assert_eq!(ssnd_block_info.block_size, 0); + let (data, ssnd_block_info) = aiff::parse_ssnd(chunk.data)?; + // offset and block_size are typically 0. Therefore, this only supports files where they are set to 0. + if ssnd_block_info.offset != 0 || ssnd_block_info.block_size != 0 { + return Err(nom::Err::Error(nom::error::Error::new( + input, + nom::error::ErrorKind::Verify, + ))); + } self.data = data; } aiff::ChunkId::FormatVersion => {} @@ -151,11 +164,17 @@ impl<'a> PcmReader<'a> { }, )(input)?; - for e in v { - assert_ne!(e.size, 0); - match e.id { + for chunk in v { + if chunk.size < 0 { + return Err(nom::Err::Error(nom::error::Error::new( + input, + nom::error::ErrorKind::LengthValue, + ))); + } + + match chunk.id { wav::ChunkId::Fmt => { - let (_, spec) = wav::parse_fmt(e.data)?; + let (_, spec) = wav::parse_fmt(chunk.data)?; self.specs.num_channels = spec.num_channels; self.specs.sample_rate = spec.sample_rate; self.specs.audio_format = spec.audio_format; @@ -167,7 +186,7 @@ impl<'a> PcmReader<'a> { } } wav::ChunkId::Data => { - self.data = e.data; + self.data = chunk.data; } wav::ChunkId::Fact => {} wav::ChunkId::IDv3 => {} @@ -196,32 +215,36 @@ impl<'a> PcmReader<'a> { } /// PCMReader is a struct that reads PCM data from a byte array. - /// It supports Linear PCM and IEEE Float. /// * 'input' - PCM data byte array - pub fn new(input: &'a [u8]) -> Self { + pub fn new(input: &'a [u8]) -> Result { let file_length = input.len(); - let mut reader: PcmReader = Default::default(); //WAVE if let Ok((input, riff)) = wav::parse_riff_header(input) { - assert_eq!((file_length - 8) as u32, riff.size); + if (file_length - 8) != riff.size as usize { + return Err(LinearPcmError::HeaderSizeMismatch); + } + if let Ok((_, _)) = reader.parse_wav(input) { - return reader; + return Ok(reader); } }; //AIFF if let Ok((input, aiff)) = aiff::parse_aiff_header(input) { assert_eq!((file_length - 8) as u32, aiff.size); + if (file_length - 8) != aiff.size as usize { + return Err(LinearPcmError::HeaderSizeMismatch); + } + if let Ok((_, _)) = reader.parse_aiff(input) { - return reader; + return Ok(reader); } }; //WAVでもAIFFでもなかった場合 - //TODO panicせずにエラーを返す - panic!(); + Err(LinearPcmError::UnsupportedAudioFormat) } /// Returns basic information about the PCM file. @@ -359,7 +382,9 @@ pub struct PcmPlayer<'a> { impl<'a> PcmPlayer<'a> { /// * 'input' - PCM data byte array pub fn new(input: &'a [u8]) -> Self { - let reader = PcmReader::new(input); + //TODO error handling + let reader = PcmReader::new(input).unwrap(); + let mut player = PcmPlayer { reader, reading_data: &[], diff --git a/src/wav.rs b/src/wav.rs index 7e27d6e..4a4a512 100644 --- a/src/wav.rs +++ b/src/wav.rs @@ -129,16 +129,37 @@ pub(super) fn parse_fmt(input: &[u8]) -> IResult<&[u8], WavFmtSpecs> { if audio_format == AudioFormat::ImaAdpcmLe { //IMA-ADPCMの拡張属性の取得 let num_block_align = block_size; - assert!(block_size % 4 == 0); - assert!(input.len() >= 4); - let (input, cb_size) = le_u16(input)?; //2 - assert_eq!(cb_size, 2); + + if block_size % 4 != 0 { + return Err(nom::Err::Error(nom::error::Error::new( + input, + nom::error::ErrorKind::LengthValue, + ))); + } + if input.len() < 4 { + return Err(nom::Err::Error(nom::error::Error::new( + input, + nom::error::ErrorKind::Eof, + ))); + } + let (input, cb_size) = le_u16(input)?; + if cb_size != 2 { + return Err(nom::Err::Error(nom::error::Error::new( + input, + nom::error::ErrorKind::Verify, + ))); + } + //wSamplesPerBlock = (((nBlockAlign - (4*nChannels))) * 8) / (wBitPerSample * nChannels) + 1 let (input, num_samples_per_block) = le_u16(input)?; //2041 - assert_eq!( - num_samples_per_block, - ((block_size - (4 * num_channels)) * 8) / (bit_depth * num_channels) + 1 - ); + if num_samples_per_block + != ((block_size - (4 * num_channels)) * 8) / (bit_depth * num_channels) + 1 + { + return Err(nom::Err::Error(nom::error::Error::new( + input, + nom::error::ErrorKind::Verify, + ))); + } return Ok(( input, diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 85ac6bb..41976f7 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -3028,7 +3028,7 @@ fn fixed_test() { #[test] fn wav_linearpcm_specs() { let wav = include_bytes!("./resources/Sine440Hz_1ch_48000Hz_16.wav"); - let reader = PcmReader::new(wav); + let reader = PcmReader::new(wav).unwrap(); let spec = reader.get_pcm_specs(); assert_eq!(spec.bit_depth, 16); assert_eq!(spec.audio_format, AudioFormat::LinearPcmLe); @@ -3040,7 +3040,7 @@ fn wav_linearpcm_specs() { #[test] fn aiff_linearpcm_specs() { let data = include_bytes!("./resources/Sine440Hz_1ch_48000Hz_16.aif"); - let reader = PcmReader::new(data); + let reader = PcmReader::new(data).unwrap(); let spec = reader.get_pcm_specs(); assert_eq!(spec.bit_depth, 16); assert_eq!(spec.audio_format, AudioFormat::LinearPcmBe); //Big endian @@ -3052,7 +3052,7 @@ fn aiff_linearpcm_specs() { #[test] fn wav_float32_specs() { let wav = include_bytes!("./resources/Sine440Hz_1ch_48000Hz_32FP.wav"); - let reader = PcmReader::new(wav); + let reader = PcmReader::new(wav).unwrap(); let spec = reader.get_pcm_specs(); assert_eq!(spec.bit_depth, 32); assert_eq!(spec.audio_format, AudioFormat::IeeeFloatLe); //Little endian @@ -3064,7 +3064,7 @@ fn wav_float32_specs() { #[test] fn aiff_float32_specs() { let data = include_bytes!("./resources/Sine440Hz_1ch_48000Hz_32FP.aif"); - let reader = PcmReader::new(data); + let reader = PcmReader::new(data).unwrap(); let spec = reader.get_pcm_specs(); assert_eq!(spec.bit_depth, 32); assert_eq!(spec.audio_format, AudioFormat::IeeeFloatBe); //Big endian @@ -3076,7 +3076,7 @@ fn aiff_float32_specs() { #[test] fn wav_16bit() { let wav = include_bytes!("./resources/Sine440Hz_1ch_48000Hz_16.wav"); - let reader = PcmReader::new(wav); + let reader = PcmReader::new(wav).unwrap(); let spec = reader.get_pcm_specs(); assert_eq!(spec.num_samples, 240000); assert_eq!(spec.sample_rate, 48000); @@ -3097,7 +3097,7 @@ fn wav_16bit() { #[test] fn wav_24bit() { let wav = include_bytes!("./resources/Sine440Hz_1ch_48000Hz_24.wav"); - let reader = PcmReader::new(wav); + let reader = PcmReader::new(wav).unwrap(); let spec = reader.get_pcm_specs(); assert_eq!(spec.num_samples, 240000); assert_eq!(spec.sample_rate, 48000); @@ -3114,7 +3114,7 @@ fn wav_24bit() { #[test] fn wav_32bit() { let wav = include_bytes!("./resources/Sine440Hz_1ch_48000Hz_32.wav"); - let reader = PcmReader::new(wav); + let reader = PcmReader::new(wav).unwrap(); let spec = reader.get_pcm_specs(); assert_eq!(spec.num_samples, 240000); assert_eq!(spec.sample_rate, 48000); @@ -3186,7 +3186,7 @@ fn wav_player_32bit() { #[test] fn wav_32bit_float() { let wav = include_bytes!("./resources/Sine440Hz_1ch_48000Hz_32FP.wav"); - let reader = PcmReader::new(wav); + let reader = PcmReader::new(wav).unwrap(); let spec = reader.get_pcm_specs(); assert_eq!(spec.num_samples, 240000); assert_eq!(spec.sample_rate, 48000); @@ -3203,7 +3203,7 @@ fn wav_32bit_float() { #[test] fn wav_64bit_float() { let wav = include_bytes!("./resources/Sine440Hz_1ch_48000Hz_64FP.wav"); - let reader = PcmReader::new(wav); + let reader = PcmReader::new(wav).unwrap(); let spec = reader.get_pcm_specs(); assert_eq!(spec.num_samples, 240000); assert_eq!(spec.sample_rate, 48000); @@ -3220,7 +3220,7 @@ fn wav_64bit_float() { #[test] fn aiff_16bit() { let aiff = include_bytes!("./resources/Sine440Hz_1ch_48000Hz_16.aif"); - let reader = PcmReader::new(aiff); + let reader = PcmReader::new(aiff).unwrap(); let spec = reader.get_pcm_specs(); assert_eq!(spec.num_samples, 240000); assert_eq!(spec.sample_rate, 48000); @@ -3241,7 +3241,7 @@ fn aiff_16bit() { #[test] fn aiff_24bit() { let aiff = include_bytes!("./resources/Sine440Hz_1ch_48000Hz_24.aif"); - let reader = PcmReader::new(aiff); + let reader = PcmReader::new(aiff).unwrap(); let spec = reader.get_pcm_specs(); assert_eq!(spec.num_samples, 240000); assert_eq!(spec.sample_rate, 48000); @@ -3258,7 +3258,7 @@ fn aiff_24bit() { #[test] fn aiff_32bit() { let aiff = include_bytes!("./resources/Sine440Hz_1ch_48000Hz_32.aif"); - let reader = PcmReader::new(aiff); + let reader = PcmReader::new(aiff).unwrap(); let spec = reader.get_pcm_specs(); assert_eq!(spec.num_samples, 240000); assert_eq!(spec.sample_rate, 48000); @@ -3275,7 +3275,7 @@ fn aiff_32bit() { #[test] fn aiff_32bit_float() { let aiff = include_bytes!("./resources/Sine440Hz_1ch_48000Hz_32FP.aif"); - let reader = PcmReader::new(aiff); + let reader = PcmReader::new(aiff).unwrap(); let spec = reader.get_pcm_specs(); assert_eq!(spec.num_samples, 240000); assert_eq!(spec.sample_rate, 48000); @@ -3292,7 +3292,7 @@ fn aiff_32bit_float() { #[test] fn aiff_64bit_float() { let aiff = include_bytes!("./resources/Sine440Hz_1ch_48000Hz_64FP.aif"); - let reader = PcmReader::new(aiff); + let reader = PcmReader::new(aiff).unwrap(); let spec = reader.get_pcm_specs(); assert_eq!(spec.num_samples, 240000); assert_eq!(spec.sample_rate, 48000); From 8ea68633f856ba3d3bb2503b8c38a00e7241004e Mon Sep 17 00:00:00 2001 From: AkiyukiOkayasu Date: Tue, 20 Aug 2024 17:20:56 +0900 Subject: [PATCH 11/12] Remove unnecessary checks --- src/aiff.rs | 1 + src/lib.rs | 14 -------------- src/wav.rs | 1 + 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/aiff.rs b/src/aiff.rs index 29ee53e..21c270b 100644 --- a/src/aiff.rs +++ b/src/aiff.rs @@ -96,6 +96,7 @@ impl TryFrom<&[u8]> for CompressionTypeId { #[derive(Debug, Default)] pub(super) struct Chunk<'a> { pub id: ChunkId, + #[allow(dead_code)] pub size: u32, pub data: &'a [u8], } diff --git a/src/lib.rs b/src/lib.rs index 05ae76b..739eda8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,13 +114,6 @@ impl<'a> PcmReader<'a> { )(input)?; for chunk in v { - if chunk.size < 0 { - return Err(nom::Err::Error(nom::error::Error::new( - input, - nom::error::ErrorKind::LengthValue, - ))); - } - match chunk.id { aiff::ChunkId::Common => { let (_, spec) = aiff::parse_comm(chunk.data)?; @@ -165,13 +158,6 @@ impl<'a> PcmReader<'a> { )(input)?; for chunk in v { - if chunk.size < 0 { - return Err(nom::Err::Error(nom::error::Error::new( - input, - nom::error::ErrorKind::LengthValue, - ))); - } - match chunk.id { wav::ChunkId::Fmt => { let (_, spec) = wav::parse_fmt(chunk.data)?; diff --git a/src/wav.rs b/src/wav.rs index 4a4a512..4c5b6fd 100644 --- a/src/wav.rs +++ b/src/wav.rs @@ -42,6 +42,7 @@ impl TryFrom<&[u8]> for ChunkId { #[derive(Debug, Default)] pub(super) struct Chunk<'a> { pub id: ChunkId, + #[allow(dead_code)] pub size: u32, pub data: &'a [u8], } From a60b5cc4c243915a1179cbce880fc3a82dd40cfb Mon Sep 17 00:00:00 2001 From: AkiyukiOkayasu Date: Tue, 20 Aug 2024 17:25:26 +0900 Subject: [PATCH 12/12] fix bench code --- benches/bench.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index 8f38b7c..8b84395 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -6,14 +6,14 @@ fn parse_wav(c: &mut Criterion) { let wav = include_bytes!("../tests/resources/Sine440Hz_1ch_48000Hz_16.wav"); c.bench_function("Parse WAV 16bit", |b| { b.iter(|| { - let _reader = PcmReader::new(black_box(wav)); + let _reader = PcmReader::new(black_box(wav)).unwrap(); }) }); } fn read_sample(c: &mut Criterion) { let wav = include_bytes!("../tests/resources/Sine440Hz_1ch_48000Hz_16.wav"); - let reader = PcmReader::new(wav); + let reader = PcmReader::new(wav).unwrap(); let pcm_specs = reader.get_pcm_specs(); c.bench_function("Read a sample 16bit", |b| { b.iter(|| {