From d353c97c30e6d3d1f40f2cda1780305a8ff7b2ab Mon Sep 17 00:00:00 2001 From: tomaka Date: Sat, 21 Oct 2017 09:45:02 +0200 Subject: [PATCH] Add samples conversion functions and publish 0.5.1 (#170) --- CHANGELOG.md | 4 ++ Cargo.toml | 2 +- src/samples_formats.rs | 147 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 151 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1db572e..186c401 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Unreleased +# Version 0.5.1 (2017-10-21) + +- Added `Sample::to_i16()`, `Sample::to_u16()` and `Sample::from`. + # Version 0.5.0 (2017-10-21) - Removed the dependency on the `futures` library. diff --git a/Cargo.toml b/Cargo.toml index a0451d8..4b2a097 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cpal" -version = "0.5.0" +version = "0.5.1" authors = ["The CPAL contributors", "Pierre Krieger "] description = "Low-level cross-platform audio playing library in pure Rust." repository = "https://github.com/tomaka/cpal" diff --git a/src/samples_formats.rs b/src/samples_formats.rs index 633ff38..4c40176 100644 --- a/src/samples_formats.rs +++ b/src/samples_formats.rs @@ -38,6 +38,14 @@ 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 any sample type to this one by calling `to_i16`, `to_u16` or `to_f32`. + fn from(&S) -> Self + where S: Sample; } unsafe impl Sample for u16 { @@ -48,7 +56,28 @@ unsafe impl Sample for u16 { #[inline] fn to_f32(&self) -> f32 { - ((*self as f32 / u16::max_value() as f32) - 0.5) * 2.0 // TODO: maybe wrong + self.to_i16().to_f32() + } + + #[inline] + fn to_i16(&self) -> i16 { + if *self >= 32768 { + (*self - 32768) as i16 + } else { + (*self as i16) - 32767 - 1 + } + } + + #[inline] + fn to_u16(&self) -> u16 { + *self + } + + #[inline] + fn from(sample: &S) -> Self + where S: Sample + { + sample.to_u16() } } @@ -66,6 +95,27 @@ unsafe impl Sample for i16 { *self as f32 / ::std::i16::MAX as f32 } } + + #[inline] + fn to_i16(&self) -> i16 { + *self + } + + #[inline] + fn to_u16(&self) -> u16 { + if *self < 0 { + (*self - ::std::i16::MIN) as u16 + } else { + (*self as u16) + 32768 + } + } + + #[inline] + fn from(sample: &S) -> Self + where S: Sample + { + sample.to_i16() + } } unsafe impl Sample for f32 { @@ -78,4 +128,99 @@ unsafe impl Sample for f32 { fn to_f32(&self) -> f32 { *self } + + #[inline] + fn to_i16(&self) -> i16 { + if *self >= 0.0 { + (*self * ::std::i16::MAX as f32) as i16 + } else { + (-*self * ::std::i16::MIN as f32) as i16 + } + } + + #[inline] + fn to_u16(&self) -> u16 { + (((*self + 1.0) * 0.5) * ::std::u16::MAX as f32).round() as u16 + } + + #[inline] + fn from(sample: &S) -> Self + where S: Sample + { + sample.to_f32() + } +} + +#[cfg(test)] +mod test { + use super::Sample; + + #[test] + fn i16_to_i16() { + assert_eq!(0i16.to_i16(), 0); + assert_eq!((-467i16).to_i16(), -467); + assert_eq!(32767i16.to_i16(), 32767); + assert_eq!((-32768i16).to_i16(), -32768); + } + + #[test] + fn i16_to_u16() { + assert_eq!(0i16.to_u16(), 32768); + assert_eq!((-16384i16).to_u16(), 16384); + assert_eq!(32767i16.to_u16(), 65535); + assert_eq!((-32768i16).to_u16(), 0); + } + + #[test] + fn i16_to_f32() { + assert_eq!(0i16.to_f32(), 0.0); + assert_eq!((-16384i16).to_f32(), -0.5); + assert_eq!(32767i16.to_f32(), 1.0); + assert_eq!((-32768i16).to_f32(), -1.0); + } + + #[test] + fn u16_to_i16() { + assert_eq!(32768u16.to_i16(), 0); + assert_eq!(16384u16.to_i16(), -16384); + assert_eq!(65535u16.to_i16(), 32767); + assert_eq!(0u16.to_i16(), -32768); + } + + #[test] + fn u16_to_u16() { + assert_eq!(0u16.to_u16(), 0); + assert_eq!(467u16.to_u16(), 467); + assert_eq!(32767u16.to_u16(), 32767); + assert_eq!(65535u16.to_u16(), 65535); + } + + #[test] + fn u16_to_f32() { + assert_eq!(0u16.to_f32(), -1.0); + assert_eq!(32768u16.to_f32(), 0.0); + assert_eq!(65535u16.to_f32(), 1.0); + } + + #[test] + fn f32_to_i16() { + assert_eq!(0.0f32.to_i16(), 0); + assert_eq!((-0.5f32).to_i16(), ::std::i16::MIN / 2); + assert_eq!(1.0f32.to_i16(), ::std::i16::MAX); + assert_eq!((-1.0f32).to_i16(), ::std::i16::MIN); + } + + #[test] + fn f32_to_u16() { + assert_eq!((-1.0f32).to_u16(), 0); + assert_eq!(0.0f32.to_u16(), 32768); + assert_eq!(1.0f32.to_u16(), 65535); + } + + #[test] + fn f32_to_f32() { + assert_eq!(0.1f32.to_f32(), 0.1); + assert_eq!((-0.7f32).to_f32(), -0.7); + assert_eq!(1.0f32.to_f32(), 1.0); + } }