From 1f7b8cb1fd349089315db29634ea14649843b18d Mon Sep 17 00:00:00 2001 From: Julien Tregoat Date: Tue, 26 May 2020 21:17:56 -0400 Subject: [PATCH 1/6] 32 bit sample format support --- examples/beep.rs | 1 + examples/record_wav.rs | 10 ++- examples/wasm-beep/src/lib.rs | 1 + src/host/alsa/mod.rs | 10 ++- src/host/asio/device.rs | 9 +-- src/host/asio/stream.rs | 12 +-- src/host/oboe/mod.rs | 4 + src/host/wasapi/device.rs | 2 +- src/lib.rs | 32 ++++++-- src/samples_formats.rs | 148 +++++++++++++++++++++++++++++++--- 10 files changed, 190 insertions(+), 39 deletions(-) diff --git a/examples/beep.rs b/examples/beep.rs index ed15204a4..9dd1c0666 100644 --- a/examples/beep.rs +++ b/examples/beep.rs @@ -85,6 +85,7 @@ fn main() -> anyhow::Result<()> { match config.sample_format() { cpal::SampleFormat::F32 => run::(&device, &config.into()), cpal::SampleFormat::I16 => run::(&device, &config.into()), + cpal::SampleFormat::I32 => run::(&device, &config.into()), cpal::SampleFormat::U16 => run::(&device, &config.into()), } } diff --git a/examples/record_wav.rs b/examples/record_wav.rs index 7746f568f..53ce08a57 100644 --- a/examples/record_wav.rs +++ b/examples/record_wav.rs @@ -121,6 +121,11 @@ fn main() -> Result<(), anyhow::Error> { move |data, _: &_| write_input_data::(data, &writer_2), err_fn, )?, + cpal::SampleFormat::I32 => device.build_input_stream( + &config.into(), + move |data, _: &_| write_input_data::(data, &writer_2), + err_fn, + )?, cpal::SampleFormat::U16 => device.build_input_stream( &config.into(), move |data, _: &_| write_input_data::(data, &writer_2), @@ -140,8 +145,9 @@ fn main() -> Result<(), anyhow::Error> { fn sample_format(format: cpal::SampleFormat) -> hound::SampleFormat { match format { - cpal::SampleFormat::U16 => hound::SampleFormat::Int, - cpal::SampleFormat::I16 => hound::SampleFormat::Int, + cpal::SampleFormat::U16 | cpal::SampleFormat::I16 | cpal::SampleFormat::I32 => { + hound::SampleFormat::Int + } cpal::SampleFormat::F32 => hound::SampleFormat::Float, } } diff --git a/examples/wasm-beep/src/lib.rs b/examples/wasm-beep/src/lib.rs index 72dc81cc0..576dce1a4 100644 --- a/examples/wasm-beep/src/lib.rs +++ b/examples/wasm-beep/src/lib.rs @@ -36,6 +36,7 @@ pub fn beep() -> Handle { Handle(match config.sample_format() { cpal::SampleFormat::F32 => run::(&device, &config.into()), + cpal::SampleFormat::I32 => run::(&device, &config.into()), cpal::SampleFormat::I16 => run::(&device, &config.into()), cpal::SampleFormat::U16 => run::(&device, &config.into()), }) diff --git a/src/host/alsa/mod.rs b/src/host/alsa/mod.rs index d306519dd..9140a6a8e 100644 --- a/src/host/alsa/mod.rs +++ b/src/host/alsa/mod.rs @@ -321,18 +321,18 @@ impl Device { let hw_params = alsa::pcm::HwParams::any(&handle)?; // TODO: check endianess - const FORMATS: [(SampleFormat, alsa::pcm::Format); 3] = [ + const FORMATS: [(SampleFormat, alsa::pcm::Format); 4] = [ //SND_PCM_FORMAT_S8, //SND_PCM_FORMAT_U8, (SampleFormat::I16, alsa::pcm::Format::S16LE), //SND_PCM_FORMAT_S16_BE, (SampleFormat::U16, alsa::pcm::Format::U16LE), //SND_PCM_FORMAT_U16_BE, - //SND_PCM_FORMAT_S24_LE, + // (SampleFormat::I24, alsa::pcm::Format::S24LE), //SND_PCM_FORMAT_S24_BE, //SND_PCM_FORMAT_U24_LE, //SND_PCM_FORMAT_U24_BE, - //SND_PCM_FORMAT_S32_LE, + (SampleFormat::I32, alsa::pcm::Format::S32LE), //SND_PCM_FORMAT_S32_BE, //SND_PCM_FORMAT_U32_LE, //SND_PCM_FORMAT_U32_BE, @@ -348,7 +348,7 @@ impl Device { //SND_PCM_FORMAT_MPEG, //SND_PCM_FORMAT_GSM, //SND_PCM_FORMAT_SPECIAL, - //SND_PCM_FORMAT_S24_3LE, + //(SampleFormat::I24, alsa::pcm::Format::S243LE), //SND_PCM_FORMAT_S24_3BE, //SND_PCM_FORMAT_U24_3LE, //SND_PCM_FORMAT_U24_3BE, @@ -975,12 +975,14 @@ fn set_hw_params_from_format<'a>( match sample_format { SampleFormat::I16 => alsa::pcm::Format::S16BE, SampleFormat::U16 => alsa::pcm::Format::U16BE, + SampleFormat::I32 => alsa::pcm::Format::S32BE, SampleFormat::F32 => alsa::pcm::Format::FloatBE, } } else { match sample_format { SampleFormat::I16 => alsa::pcm::Format::S16LE, SampleFormat::U16 => alsa::pcm::Format::U16LE, + SampleFormat::I32 => alsa::pcm::Format::S32LE, SampleFormat::F32 => alsa::pcm::Format::FloatLE, } }; diff --git a/src/host/asio/device.rs b/src/host/asio/device.rs index 1a1a1aace..a11e03b70 100644 --- a/src/host/asio/device.rs +++ b/src/host/asio/device.rs @@ -213,13 +213,8 @@ pub(crate) fn convert_data_type(ty: &sys::AsioSampleType) -> Option SampleFormat::I16, sys::AsioSampleType::ASIOSTFloat32MSB => SampleFormat::F32, sys::AsioSampleType::ASIOSTFloat32LSB => SampleFormat::F32, - // NOTE: While ASIO does not support these formats directly, the stream callback created by - // CPAL supports converting back and forth between the following. This is because many ASIO - // drivers only support `Int32` formats, while CPAL does not support this format at all. We - // allow for this implicit conversion temporarily until CPAL gets support for an `I32` - // format. - sys::AsioSampleType::ASIOSTInt32MSB => SampleFormat::I16, - sys::AsioSampleType::ASIOSTInt32LSB => SampleFormat::I16, + sys::AsioSampleType::ASIOSTInt32MSB => SampleFormat::I32, + sys::AsioSampleType::ASIOSTInt32LSB => SampleFormat::I32, _ => return None, }; Some(fmt) diff --git a/src/host/asio/stream.rs b/src/host/asio/stream.rs index 9035045a5..c539c41fd 100644 --- a/src/host/asio/stream.rs +++ b/src/host/asio/stream.rs @@ -181,7 +181,7 @@ impl Device { // TODO: Add support for the following sample formats to CPAL and simplify the // `process_output_callback` function above by removing the unnecessary sample // conversion function. - (&sys::AsioSampleType::ASIOSTInt32LSB, SampleFormat::I16) => { + (&sys::AsioSampleType::ASIOSTInt32LSB, SampleFormat::I32) => { process_input_callback::( &mut data_callback, &mut interleaved, @@ -191,7 +191,7 @@ impl Device { from_le, ); } - (&sys::AsioSampleType::ASIOSTInt32MSB, SampleFormat::I16) => { + (&sys::AsioSampleType::ASIOSTInt32MSB, SampleFormat::I32) => { process_input_callback::( &mut data_callback, &mut interleaved, @@ -404,8 +404,8 @@ impl Device { // TODO: Add support for the following sample formats to CPAL and simplify the // `process_output_callback` function above by removing the unnecessary sample // conversion function. - (SampleFormat::I16, &sys::AsioSampleType::ASIOSTInt32LSB) => { - process_output_callback::( + (SampleFormat::I32, &sys::AsioSampleType::ASIOSTInt32LSB) => { + process_output_callback::( &mut data_callback, &mut interleaved, silence, @@ -415,8 +415,8 @@ impl Device { to_le, ); } - (SampleFormat::I16, &sys::AsioSampleType::ASIOSTInt32MSB) => { - process_output_callback::( + (SampleFormat::I32, &sys::AsioSampleType::ASIOSTInt32MSB) => { + process_output_callback::( &mut data_callback, &mut interleaved, silence, diff --git a/src/host/oboe/mod.rs b/src/host/oboe/mod.rs index 4e245cdb0..de0eb2e0d 100644 --- a/src/host/oboe/mod.rs +++ b/src/host/oboe/mod.rs @@ -397,6 +397,10 @@ impl DeviceTrait for Device { description: "U16 format is not supported on Android.".to_owned(), } .into()), + SampleFormat::I32 => Err(BackendSpecificError { + description: "I32 format is not supported on Android.".to_owned(), + } + .into()), } } diff --git a/src/host/wasapi/device.rs b/src/host/wasapi/device.rs index be9de5d9a..78154d8de 100644 --- a/src/host/wasapi/device.rs +++ b/src/host/wasapi/device.rs @@ -300,7 +300,7 @@ unsafe fn format_from_waveformatex_ptr( a.Data1 == b.Data1 && a.Data2 == b.Data2 && a.Data3 == b.Data3 && a.Data4 == b.Data4 } let sample_format = match ( - (*waveformatex_ptr).wBitsPerSample, + (*waveformatex_ptr).wBitsPerSample, // 8 or 16 for integers, 32 for floats (*waveformatex_ptr).wFormatTag, ) { (16, mmreg::WAVE_FORMAT_PCM) => SampleFormat::I16, diff --git a/src/lib.rs b/src/lib.rs index b82a7c95a..a88fd2689 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,6 +99,7 @@ //! let stream = match sample_format { //! SampleFormat::F32 => device.build_output_stream(&config, write_silence::, err_fn), //! 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), //! }.unwrap(); //! @@ -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, U16}; + use SampleFormat::{F32, I16, I32, U16}; let cmp_stereo = (self.channels == 2).cmp(&(other.channels == 2)); if cmp_stereo != Equal { @@ -642,6 +645,11 @@ impl SupportedStreamConfigRange { return cmp_u16; } + let cmp_i32 = (self.sample_format == I32).cmp(&(other.sample_format == I32)); + if cmp_i32 != Equal { + return cmp_i32; + } + 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 +701,13 @@ 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::I32, + }, ]; formats.sort_by(|a, b| a.cmp_default_heuristics(b)); @@ -703,25 +718,30 @@ 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::I32); 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::U16); 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::I16); 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].min_sample_rate(), SampleRate(1)); - assert_eq!(formats[4].max_sample_rate(), SampleRate(96000)); + assert_eq!(formats[4].max_sample_rate(), SampleRate(22050)); 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(96000)); + assert_eq!(formats[5].channels(), 2); } impl From for StreamConfig { diff --git a/src/samples_formats.rs b/src/samples_formats.rs index faa02319e..1f22097e5 100644 --- a/src/samples_formats.rs +++ b/src/samples_formats.rs @@ -5,6 +5,7 @@ use std::mem; pub enum SampleFormat { /// The value 0 corresponds to 0. I16, + I32, /// The value 0 corresponds to 32768. U16, /// The boundaries are (-1.0, 1.0). @@ -19,6 +20,7 @@ impl SampleFormat { SampleFormat::I16 => mem::size_of::(), SampleFormat::U16 => mem::size_of::(), SampleFormat::F32 => mem::size_of::(), + SampleFormat::I32 => mem::size_of::(), } } } @@ -30,13 +32,15 @@ pub unsafe trait Sample: Copy + Clone { /// Turns the sample into its equivalent as a floating-point. fn to_f32(&self) -> f32; - /// Converts this sample into a standard i16 sample. - fn to_i16(&self) -> i16; /// Converts this sample into a standard u16 sample. fn to_u16(&self) -> u16; + /// Converts this sample into a standard i16 sample. + fn to_i16(&self) -> i16; + /// Converts this sample into a standard i32 sample. + fn to_i32(&self) -> i32; - /// Converts any sample type to this one by calling `to_i16`, `to_u16` or `to_f32`. - fn from(&S) -> Self + /// Converts any sample type to this one by calling `to_i16`, `to_i32`, `to_u16`, or `to_f32`. + fn from(sample: &S) -> Self where S: Sample; } @@ -49,6 +53,11 @@ unsafe impl Sample for u16 { self.to_i16().to_f32() } + #[inline] + fn to_u16(&self) -> u16 { + *self + } + #[inline] fn to_i16(&self) -> i16 { if *self >= 32768 { @@ -59,8 +68,8 @@ unsafe impl Sample for u16 { } #[inline] - fn to_u16(&self) -> u16 { - *self + fn to_i32(&self) -> i32 { + self.to_f32().to_i32() } #[inline] @@ -84,11 +93,6 @@ unsafe impl Sample for i16 { } } - #[inline] - fn to_i16(&self) -> i16 { - *self - } - #[inline] fn to_u16(&self) -> u16 { if *self < 0 { @@ -98,6 +102,16 @@ unsafe impl Sample for i16 { } } + #[inline] + fn to_i16(&self) -> i16 { + *self + } + + #[inline] + fn to_i32(&self) -> i32 { + self.to_f32().to_i32() + } + #[inline] fn from(sample: &S) -> Self where @@ -115,6 +129,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 { @@ -125,8 +146,12 @@ unsafe impl Sample for f32 { } #[inline] - fn to_u16(&self) -> u16 { - (((*self + 1.0) * 0.5) * ::std::u16::MAX as f32).round() as u16 + fn to_i32(&self) -> 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] @@ -138,10 +163,82 @@ unsafe impl Sample for f32 { } } +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 { + (*self as f64 * (1.0 / -(::std::i32::MIN as f64))) as f32 + } else { + (*self as f64 * (1.0 / ::std::i32::MAX as f64)) as f32 + } + } + + /// 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() + } + + #[inline] + fn to_i32(&self) -> i32 { + *self + } + + #[inline] + fn from(sample: &S) -> Self + where + S: Sample, + { + sample.to_i32() + } +} + #[cfg(test)] mod test { use super::Sample; + #[test] + fn i32_to_i16() { + assert_eq!(std::i32::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 i32_to_i32() { + assert_eq!(std::i32::MAX.to_i32(), std::i32::MAX); + assert_eq!((std::i32::MIN / 2).to_i32(), std::i32::MIN / 2); + assert_eq!(std::i32::MIN.to_i32(), std::i32::MIN); + assert_eq!(0i32.to_i32(), 0); + } + + #[test] + fn i32_to_u16() { + assert_eq!(std::i32::MAX.to_u16(), std::u16::MAX); + assert_eq!(0i32.to_u16(), (std::u16::MAX as f32 / 2.0).round() as u16); + assert_eq!(std::i32::MIN.to_u16(), std::u16::MIN); + } + + #[test] + fn i32_to_f32() { + assert_eq!(std::i32::MAX.to_f32(), 1.0f32); + assert_eq!((std::i32::MAX / 8).to_f32(), 0.125f32); + assert_eq!((std::i32::MAX / -16).to_f32(), -0.0625f32); + assert_eq!((std::i32::MAX / -4).to_f32(), -0.25f32); + assert_eq!(std::i32::MIN.to_f32(), -1.0f32); + assert_eq!(0.to_f32(), 0f32); + } + #[test] fn i16_to_i16() { assert_eq!(0i16.to_i16(), 0); @@ -150,6 +247,13 @@ mod test { assert_eq!((-32768i16).to_i16(), -32768); } + #[test] + fn i16_to_i32() { + assert_eq!(0i16.to_i32(), 0); + assert_eq!(std::i16::MAX.to_i32(), std::i32::MAX); + assert_eq!(std::i16::MIN.to_i32(), std::i32::MIN); + } + #[test] fn i16_to_u16() { assert_eq!(0i16.to_u16(), 32768); @@ -162,6 +266,7 @@ mod test { fn i16_to_f32() { assert_eq!(0i16.to_f32(), 0.0); assert_eq!((-16384i16).to_f32(), -0.5); + assert_eq!((-16384i16 / 2).to_f32(), -0.25); assert_eq!(32767i16.to_f32(), 1.0); assert_eq!((-32768i16).to_f32(), -1.0); } @@ -174,6 +279,13 @@ mod test { assert_eq!(0u16.to_i16(), -32768); } + #[test] + fn u16_to_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] fn u16_to_u16() { assert_eq!(0u16.to_u16(), 0); @@ -197,6 +309,16 @@ mod test { assert_eq!((-1.0f32).to_i16(), ::std::i16::MIN); } + #[test] + fn f32_to_i32() { + assert_eq!(1.0f32.to_i32(), std::i32::MAX); + assert_eq!(0.5f32.to_i32(), 1073741824); + assert_eq!(0.25f32.to_i32(), 536870912); + assert_eq!(0.to_i32(), 0); + assert_eq!((-0.5f32).to_i32(), std::i32::MIN / 2); + assert_eq!((-1.0f32).to_i32(), std::i32::MIN); + } + #[test] fn f32_to_u16() { assert_eq!((-1.0f32).to_u16(), 0); From 20b0197f2da30ee5e9022990e2c283db28d3fcbc Mon Sep 17 00:00:00 2001 From: Julien Tregoat Date: Sun, 10 Jan 2021 19:58:38 -0500 Subject: [PATCH 2/6] fix missed rebase issues --- examples/android.rs | 1 + src/host/oboe/mod.rs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/examples/android.rs b/examples/android.rs index 7ca17da45..65619a8e3 100644 --- a/examples/android.rs +++ b/examples/android.rs @@ -18,6 +18,7 @@ fn main() { match config.sample_format() { cpal::SampleFormat::F32 => run::(&device, &config.into()).unwrap(), cpal::SampleFormat::I16 => run::(&device, &config.into()).unwrap(), + cpal::SampleFormat::I32 => run::(&device, &config.into()).unwrap(), cpal::SampleFormat::U16 => run::(&device, &config.into()).unwrap(), } } diff --git a/src/host/oboe/mod.rs b/src/host/oboe/mod.rs index de0eb2e0d..d81269eee 100644 --- a/src/host/oboe/mod.rs +++ b/src/host/oboe/mod.rs @@ -470,6 +470,10 @@ impl DeviceTrait for Device { .into()) } } + SampleFormat::I32 => Err(BackendSpecificError { + description: "I32 format is not supported on Android.".to_owned(), + } + .into()), SampleFormat::U16 => Err(BackendSpecificError { description: "U16 format is not supported on Android.".to_owned(), } From a245604ff87d520922a23e7848e2b63412d42e15 Mon Sep 17 00:00:00 2001 From: Julien Tregoat Date: Sun, 10 Jan 2021 20:05:02 -0500 Subject: [PATCH 3/6] missing wasapi format check --- src/host/wasapi/device.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/host/wasapi/device.rs b/src/host/wasapi/device.rs index 78154d8de..180808a70 100644 --- a/src/host/wasapi/device.rs +++ b/src/host/wasapi/device.rs @@ -1263,7 +1263,7 @@ fn config_to_waveformatextensible( let sub_format = match sample_format { SampleFormat::I16 => ksmedia::KSDATAFORMAT_SUBTYPE_PCM, SampleFormat::F32 => ksmedia::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, - SampleFormat::U16 => return None, + SampleFormat::U16 | SampleFormat::I32 => return None, }; let waveformatextensible = mmreg::WAVEFORMATEXTENSIBLE { Format: waveformatex, From cff24ffe8dc884e53647e59c275b47144b51f9e0 Mon Sep 17 00:00:00 2001 From: Julien Tregoat Date: Sun, 10 Jan 2021 20:22:20 -0500 Subject: [PATCH 4/6] missing wasapi format checks --- src/host/wasapi/device.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/host/wasapi/device.rs b/src/host/wasapi/device.rs index 180808a70..f6ea7e62c 100644 --- a/src/host/wasapi/device.rs +++ b/src/host/wasapi/device.rs @@ -1228,7 +1228,7 @@ fn config_to_waveformatextensible( let format_tag = match sample_format { SampleFormat::I16 => mmreg::WAVE_FORMAT_PCM, SampleFormat::F32 => mmreg::WAVE_FORMAT_EXTENSIBLE, - SampleFormat::U16 => return None, + SampleFormat::U16 | SampleFormat::I32 => return None, }; let channels = config.channels as WORD; let sample_rate = config.sample_rate.0 as DWORD; @@ -1243,7 +1243,7 @@ fn config_to_waveformatextensible( let ex_size = mem::size_of::(); (extensible_size - ex_size) as WORD } - SampleFormat::U16 => return None, + SampleFormat::U16 | SampleFormat::I32 => return None, }; let waveformatex = mmreg::WAVEFORMATEX { wFormatTag: format_tag, From cdaead43b64b9746a46d9ce7b39091d5e914b49b Mon Sep 17 00:00:00 2001 From: Julien Tregoat Date: Tue, 12 Jan 2021 22:42:34 -0500 Subject: [PATCH 5/6] fix missing match check for i32 asio --- src/host/asio/stream.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/host/asio/stream.rs b/src/host/asio/stream.rs index c539c41fd..439e06419 100644 --- a/src/host/asio/stream.rs +++ b/src/host/asio/stream.rs @@ -675,7 +675,7 @@ fn check_config( } // unsigned formats are not supported by asio match sample_format { - SampleFormat::I16 | SampleFormat::F32 => (), + SampleFormat::I16 | SampleFormat::I32 | SampleFormat::F32 => (), SampleFormat::U16 => return Err(BuildStreamError::StreamConfigNotSupported), } if *channels > num_asio_channels { From ae49d4918e4766898143e8341600822f581565df Mon Sep 17 00:00:00 2001 From: Julien Tregoat Date: Tue, 25 Jan 2022 16:15:22 -0500 Subject: [PATCH 6/6] fix i32 input conversion --- src/host/asio/stream.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/host/asio/stream.rs b/src/host/asio/stream.rs index 439e06419..ba021e88f 100644 --- a/src/host/asio/stream.rs +++ b/src/host/asio/stream.rs @@ -182,7 +182,7 @@ impl Device { // `process_output_callback` function above by removing the unnecessary sample // conversion function. (&sys::AsioSampleType::ASIOSTInt32LSB, SampleFormat::I32) => { - process_input_callback::( + process_input_callback::( &mut data_callback, &mut interleaved, asio_stream, @@ -192,7 +192,7 @@ impl Device { ); } (&sys::AsioSampleType::ASIOSTInt32MSB, SampleFormat::I32) => { - process_input_callback::( + process_input_callback::( &mut data_callback, &mut interleaved, asio_stream,