From 131cb84e9a2196767ea38b8dde614e777e73548a Mon Sep 17 00:00:00 2001 From: Julien Tregoat Date: Wed, 14 Oct 2020 00:25:58 -0400 Subject: [PATCH] fix tests leave unimplemented placeholder for examples --- examples/beep.rs | 1 + examples/record_wav.rs | 2 + src/lib.rs | 49 ++++++++++++++++++++--- src/samples_formats.rs | 89 ++++++++++++++++++++++++++++++++++++------ 4 files changed, 122 insertions(+), 19 deletions(-) diff --git a/examples/beep.rs b/examples/beep.rs index ceb6dd522..4f568e808 100644 --- a/examples/beep.rs +++ b/examples/beep.rs @@ -41,6 +41,7 @@ fn main() -> Result<(), anyhow::Error> { cpal::SampleFormat::I16 => run::(&device, &config.into())?, cpal::SampleFormat::I32 => run::(&device, &config.into())?, cpal::SampleFormat::U16 => run::(&device, &config.into())?, + cpal::SampleFormat::I24 => unimplemented!() } Ok(()) diff --git a/examples/record_wav.rs b/examples/record_wav.rs index dce46d92d..e372e3d49 100644 --- a/examples/record_wav.rs +++ b/examples/record_wav.rs @@ -51,6 +51,7 @@ fn main() -> Result<(), anyhow::Error> { move |data, _: &_| write_input_data::(data, &writer_2), err_fn, )?, + cpal::SampleFormat::I24 => unimplemented!(), cpal::SampleFormat::I32 => device.build_input_stream( &config.into(), move |data, _: &_| write_input_data::(data, &writer_2), @@ -79,6 +80,7 @@ fn sample_format(format: cpal::SampleFormat) -> hound::SampleFormat { hound::SampleFormat::Int } cpal::SampleFormat::F32 => hound::SampleFormat::Float, + cpal::SampleFormat::I24 => unimplemented!() } } diff --git a/src/lib.rs b/src/lib.rs index 6e4d9d5fc..a88066d32 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,6 +101,7 @@ //! SampleFormat::I16 => device.build_output_stream(&config, write_silence::, err_fn), //! SampleFormat::I32 => device.build_output_stream(&config, write_silence::, err_fn), //! SampleFormat::U16 => device.build_output_stream(&config, write_silence::, err_fn), +//! SampleFormat::I24 => unimplemented!(), //! }.unwrap(); //! //! fn write_silence(data: &mut [T], _: &cpal::OutputCallbackInfo) { @@ -603,6 +604,8 @@ impl SupportedStreamConfigRange { /// - f32 /// - i16 /// - u16 + /// - i32 + /// - i24 /// /// **Sample rate**: /// @@ -610,7 +613,7 @@ impl SupportedStreamConfigRange { /// - Max sample rate pub fn cmp_default_heuristics(&self, other: &Self) -> std::cmp::Ordering { use std::cmp::Ordering::Equal; - use SampleFormat::{F32, I16, I32, U16}; + use SampleFormat::{F32, I16, I32, U16, I24}; let cmp_stereo = (self.channels == 2).cmp(&(other.channels == 2)); if cmp_stereo != Equal { @@ -642,6 +645,16 @@ impl SupportedStreamConfigRange { return cmp_u16; } + let cmp_i32 = (self.sample_format == I32).cmp(&(other.sample_format == I32)); + if cmp_i32 != Equal { + return cmp_i32; + } + + let cmp_i24 = (self.sample_format == I24).cmp(&(other.sample_format == I24)); + if cmp_i24 != Equal { + return cmp_i24; + } + const HZ_44100: SampleRate = SampleRate(44_100); let r44100_in_self = self.min_sample_rate <= HZ_44100 && HZ_44100 <= self.max_sample_rate; let r44100_in_other = @@ -693,6 +706,20 @@ fn test_cmp_default_heuristics() { max_sample_rate: SampleRate(22050), sample_format: SampleFormat::F32, }, + SupportedStreamConfigRange { + buffer_size: SupportedBufferSize::Range { min: 256, max: 512 }, + channels: 2, + min_sample_rate: SampleRate(1), + max_sample_rate: SampleRate(96000), + sample_format: SampleFormat::I24, + }, + SupportedStreamConfigRange { + buffer_size: SupportedBufferSize::Range { min: 256, max: 512 }, + channels: 2, + min_sample_rate: SampleRate(1), + max_sample_rate: SampleRate(96000), + sample_format: SampleFormat::I32, + }, ]; formats.sort_by(|a, b| a.cmp_default_heuristics(b)); @@ -703,25 +730,35 @@ fn test_cmp_default_heuristics() { assert_eq!(formats[0].max_sample_rate(), SampleRate(96000)); assert_eq!(formats[0].channels(), 1); - assert_eq!(formats[1].sample_format(), SampleFormat::U16); + assert_eq!(formats[1].sample_format(), SampleFormat::I24); assert_eq!(formats[1].min_sample_rate(), SampleRate(1)); assert_eq!(formats[1].max_sample_rate(), SampleRate(96000)); assert_eq!(formats[1].channels(), 2); - assert_eq!(formats[2].sample_format(), SampleFormat::I16); + assert_eq!(formats[2].sample_format(), SampleFormat::I32); assert_eq!(formats[2].min_sample_rate(), SampleRate(1)); assert_eq!(formats[2].max_sample_rate(), SampleRate(96000)); assert_eq!(formats[2].channels(), 2); - assert_eq!(formats[3].sample_format(), SampleFormat::F32); + assert_eq!(formats[3].sample_format(), SampleFormat::U16); assert_eq!(formats[3].min_sample_rate(), SampleRate(1)); - assert_eq!(formats[3].max_sample_rate(), SampleRate(22050)); + assert_eq!(formats[3].max_sample_rate(), SampleRate(96000)); assert_eq!(formats[3].channels(), 2); - assert_eq!(formats[4].sample_format(), SampleFormat::F32); + assert_eq!(formats[4].sample_format(), SampleFormat::I16); assert_eq!(formats[4].min_sample_rate(), SampleRate(1)); assert_eq!(formats[4].max_sample_rate(), SampleRate(96000)); assert_eq!(formats[4].channels(), 2); + + assert_eq!(formats[5].sample_format(), SampleFormat::F32); + assert_eq!(formats[5].min_sample_rate(), SampleRate(1)); + assert_eq!(formats[5].max_sample_rate(), SampleRate(22050)); + assert_eq!(formats[5].channels(), 2); + + assert_eq!(formats[6].sample_format(), SampleFormat::F32); + assert_eq!(formats[6].min_sample_rate(), SampleRate(1)); + assert_eq!(formats[6].max_sample_rate(), SampleRate(96000)); + assert_eq!(formats[6].channels(), 2); } impl From for StreamConfig { diff --git a/src/samples_formats.rs b/src/samples_formats.rs index 47002a21a..12d19b3f9 100644 --- a/src/samples_formats.rs +++ b/src/samples_formats.rs @@ -54,7 +54,7 @@ unsafe impl Sample for u16 { #[inline] fn to_f32(&self) -> f32 { - *self as f32 / ::std::u16::MAX as f32 + self.to_i16().to_f32() } #[inline] @@ -142,11 +142,13 @@ unsafe impl Sample for f32 { *self } + /// This function inherently returns a lossy value due to scaling. #[inline] fn to_u16(&self) -> u16 { (((*self + 1.0) * 0.5) * ::std::u16::MAX as f32).round() as u16 } + /// This function inherently returns a lossy value due to scaling. #[inline] fn to_i16(&self) -> i16 { if *self >= 0.0 { @@ -156,6 +158,7 @@ unsafe impl Sample for f32 { } } + /// This function inherently returns a lossy value due to scaling. #[inline] fn to_i24(&self) -> Padded24 { let result: f32; @@ -169,7 +172,11 @@ unsafe impl Sample for f32 { #[inline] fn to_i32(&self) -> i32 { - (*self as f64 * std::i32::MAX as f64).round() as i32 + if self.is_sign_positive() { + (*self as f64 * std::i32::MAX as f64).round() as i32 + } else { + (*self as f64 * -(std::i32::MIN as f64)).round() as i32 + } } #[inline] @@ -250,11 +257,13 @@ unsafe impl Sample for Padded24 { } } + /// This function inherently returns a lossy value due to scaling. #[inline] fn to_i16(&self) -> i16 { self.to_f32().to_i16() } + /// This function inherently returns a lossy value due to scaling. #[inline] fn to_u16(&self) -> u16 { self.to_f32().to_u16() @@ -265,7 +274,6 @@ unsafe impl Sample for Padded24 { *self } - #[inline] fn to_i32(&self) -> i32 { self.to_f32().to_i32() @@ -283,6 +291,7 @@ unsafe impl Sample for Padded24 { unsafe impl Sample for i32 { const FORMAT: SampleFormat = SampleFormat::I32; + /// This function inherently returns a lossy value due to scaling. #[inline] fn to_f32(&self) -> f32 { if *self < 0 { @@ -292,16 +301,19 @@ unsafe impl Sample for i32 { } } + /// This function inherently returns a lossy value due to scaling. #[inline] fn to_i16(&self) -> i16 { self.to_f32().to_i16() } + /// This function inherently returns a lossy value due to scaling. #[inline] fn to_u16(&self) -> u16 { self.to_f32().to_u16() } + /// This function inherently returns a lossy value due to scaling. #[inline] fn to_i24(&self) -> Padded24 { self.to_f32().to_i24() @@ -321,10 +333,63 @@ unsafe impl Sample for i32 { } } +// TODO add _to_i24 tests #[cfg(test)] mod test { - use super::Sample; + use super::{Sample, Padded24}; + + #[test] + fn i24_to_i16() { + assert_eq!(Padded24::new(Padded24::MAX).to_i16(), std::i16::MAX); + assert_eq!(Padded24::new(Padded24::MIN / 2).to_i16(), std::i16::MIN / 2); + assert_eq!(Padded24::new(Padded24::MIN).to_i16(), std::i16::MIN); + assert_eq!(Padded24::new(0).to_i16(), 0); + } + + #[test] + fn i24_to_i24() { + // let max = Padded24::new(Padded24::MAX); + // let min = Padded24::new(Padded24::MIN); + + // assert_eq!(max.to_i16(), std::i16::MAX); + // assert_eq!((std::i32::MIN / 2).to_i16(), std::i16::MIN / 2); + // assert_eq!(std::i32::MIN.to_i16(), std::i16::MIN); + // assert_eq!(0i32.to_i16(), 0); + } + + + #[test] + fn i24_to_i32() { + assert_eq!(Padded24::new(Padded24::MAX).to_i32(), std::i32::MAX); + assert_eq!(Padded24::new(Padded24::MIN / 2).to_i32(), std::i32::MIN / 2); + assert_eq!(Padded24::new(Padded24::MIN).to_i32(), std::i32::MIN); + assert_eq!(Padded24::new(0).to_i32(), 0); + } + + #[test] + fn i24_to_u16() { + assert_eq!(Padded24::new(Padded24::MAX).to_u16(), std::u16::MAX); + // half of the int max will be 3/4 of the uint max + assert_eq!( + Padded24::new(Padded24::MAX / 2).to_u16(), + (std::u16::MAX as f32 / 4.0 * 3.0).round() as u16 + ); + assert_eq!(Padded24::new(Padded24::MIN).to_u16(), std::u16::MIN); + } + + #[test] + fn i24_to_f32() { + let max = Padded24::new(Padded24::MAX); + let min = Padded24::new(Padded24::MIN); + + assert_eq!(max.to_f32(), 1.0f32); + assert_eq!(max.to_f32() / 8.0, 0.125f32); + assert_eq!(max.to_f32() / -16.0, -0.0625f32); + assert_eq!(max.to_f32() / -4.0, -0.25f32); + assert_eq!(min.to_f32(), -1.0f32); + assert_eq!(Padded24::new(0).to_f32(), 0f32); + } #[test] fn i32_to_i16() { @@ -346,8 +411,8 @@ mod test { fn i32_to_u16() { assert_eq!(std::i32::MAX.to_u16(), std::u16::MAX); assert_eq!( - (std::i32::MIN / 2).to_u16(), - (std::u16::MAX as f32 / 4f32) as u16 + 0i32.to_u16(), + (std::u16::MAX as f32 / 2.0).round() as u16 ); assert_eq!(std::i32::MIN.to_u16(), std::u16::MIN); } @@ -373,9 +438,8 @@ mod test { #[test] fn i16_to_i32() { assert_eq!(0i16.to_i32(), 0); - assert_eq!((-467i16).to_i32(), -467); - assert_eq!(std::i16::MAX.to_i32(), std::i16::MAX as i32); - assert_eq!(std::i16::MIN.to_i32(), std::i16::MIN as i32); + assert_eq!(std::i16::MAX.to_i32(), std::i32::MAX); + assert_eq!(std::i16::MIN.to_i32(), std::i32::MIN); } #[test] @@ -405,10 +469,9 @@ mod test { #[test] fn u16_to_i32() { - assert_eq!(32768u16.to_i32(), 0); - assert_eq!(16384u16.to_i32(), -16384); - assert_eq!(65535u16.to_i32(), std::i16::MAX as i32); - assert_eq!(0u16.to_i32(), std::i16::MIN as i32); + assert_eq!(((std::u16::MAX as f32 / 2.0).round() as u16).to_i32(), 0); + assert_eq!(std::u16::MAX.to_i32(), std::i32::MAX); + assert_eq!(std::u16::MIN.to_i32(), std::i32::MIN); } #[test]