dasp_sample-0.11.0/.cargo_vcs_info.json0000644000000001121366425516300135060ustar00{ "git": { "sha1": "97c3bb9b2363c0b46ac1633858bf1054fd02a980" } } dasp_sample-0.11.0/Cargo.toml0000644000000020371366425516300115140ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "dasp_sample" version = "0.11.0" authors = ["mitchmindtree "] description = "An abstraction for audio PCM DSP samples, along with useful conversions and operations." homepage = "https://github.com/rustaudio/sample" readme = "../README.md" keywords = ["dsp", "bit-depth", "sample", "pcm", "audio"] license = "MIT OR Apache-2.0" repository = "https://github.com/rustaudio/sample.git" [package.metadata.docs.rs] all-features = true [features] default = ["std"] std = [] dasp_sample-0.11.0/Cargo.toml.orig010064400017510000164000000010231366425513200151730ustar0000000000000000[package] name = "dasp_sample" description = "An abstraction for audio PCM DSP samples, along with useful conversions and operations." version = "0.11.0" authors = ["mitchmindtree "] readme = "../README.md" keywords = ["dsp", "bit-depth", "sample", "pcm", "audio"] license = "MIT OR Apache-2.0" repository = "https://github.com/rustaudio/sample.git" homepage = "https://github.com/rustaudio/sample" edition = "2018" [features] default = ["std"] std = [] [package.metadata.docs.rs] all-features = true dasp_sample-0.11.0/src/conv.rs010064400017510000164000000444321366425513200144210ustar0000000000000000//! Pure functions and traits for converting between i8, i16, I24, i32, I48, i64, u8, u16, U24, //! u32, U48, u64, f32 and f64. //! //! Each conversion function is performance focused, memory-sensitive and expects that the user has //! validated their input prior to the function call. //! //! No conversion function will ever cast to a type with a size in bytes larger than the largest //! between the source and target sample types. //! //! The conversion functions do *not* check the range of incoming values for floating point values //! or any of the custom `I24`, `U24`, `I48` and `U48` types. //! //! Note that floating point conversions use the range -1.0 <= v < 1.0: //! `(1.0 as f64).to_sample::()` will overflow! use crate::types::{I24, I48, U24, U48}; macro_rules! conversion_fn { ($Rep:ty, $s:ident to_i8 { $body:expr }) => { #[inline] pub fn to_i8($s: $Rep) -> i8 { $body } }; ($Rep:ty, $s:ident to_i16 { $body:expr }) => { #[inline] pub fn to_i16($s: $Rep) -> i16 { $body } }; ($Rep:ty, $s:ident to_i24 { $body:expr }) => { #[inline] pub fn to_i24($s: $Rep) -> I24 { $body } }; ($Rep:ty, $s:ident to_i32 { $body:expr }) => { #[inline] pub fn to_i32($s: $Rep) -> i32 { $body } }; ($Rep:ty, $s:ident to_i48 { $body:expr }) => { #[inline] pub fn to_i48($s: $Rep) -> I48 { $body } }; ($Rep:ty, $s:ident to_i64 { $body:expr }) => { #[inline] pub fn to_i64($s: $Rep) -> i64 { $body } }; ($Rep:ty, $s:ident to_u8 { $body:expr }) => { #[inline] pub fn to_u8($s: $Rep) -> u8 { $body } }; ($Rep:ty, $s:ident to_u16 { $body:expr }) => { #[inline] pub fn to_u16($s: $Rep) -> u16 { $body } }; ($Rep:ty, $s:ident to_u24 { $body:expr }) => { #[inline] pub fn to_u24($s: $Rep) -> U24 { $body } }; ($Rep:ty, $s:ident to_u32 { $body:expr }) => { #[inline] pub fn to_u32($s: $Rep) -> u32 { $body } }; ($Rep:ty, $s:ident to_u48 { $body:expr }) => { #[inline] pub fn to_u48($s: $Rep) -> U48 { $body } }; ($Rep:ty, $s:ident to_u64 { $body:expr }) => { #[inline] pub fn to_u64($s: $Rep) -> u64 { $body } }; ($Rep:ty, $s:ident to_f32 { $body:expr }) => { #[inline] pub fn to_f32($s: $Rep) -> f32 { $body } }; ($Rep:ty, $s:ident to_f64 { $body:expr }) => { #[inline] pub fn to_f64($s: $Rep) -> f64 { $body } }; } macro_rules! conversion_fns { ($Rep:ty, $s:ident $fn_name:tt { $body:expr } $($rest:tt)*) => { conversion_fn!($Rep, $s $fn_name { $body }); conversion_fns!($Rep, $($rest)*); }; ($Rep:ty, ) => {}; } macro_rules! conversions { ($T:ident, $mod_name:ident { $($rest:tt)* }) => { pub mod $mod_name { use $crate::types::{I24, U24, I48, U48}; conversion_fns!($T, $($rest)*); } }; } conversions!(i8, i8 { s to_i16 { (s as i16) << 8 } s to_i24 { I24::new_unchecked((s as i32) << 16) } s to_i32 { (s as i32) << 24 } s to_i48 { I48::new_unchecked((s as i64) << 40) } s to_i64 { (s as i64) << 56 } s to_u8 { if s < 0 { // 128i8 overflows, so we must use 127 + 1 instead. (s + 127 + 1) as u8 } else { (s as u8) + 128 } } s to_u16 { if s < 0 { ((s + 127 + 1) as u16) << 8 } else { (s as u16 + 128) << 8 } } s to_u24 { U24::new_unchecked((s as i32 + 128) << 16) } s to_u32 { if s < 0 { ((s + 127 + 1) as u32) << 24 } else { (s as u32 + 128) << 24 } } s to_u48 { U48::new_unchecked((s as i64 + 128) << 40) } s to_u64 { if s < 0 { ((s + 127 + 1) as u64) << 56 } else { (s as u64 + 128) << 56 } } s to_f32 { s as f32 / 128.0 } s to_f64 { s as f64 / 128.0 } }); conversions!(i16, i16 { s to_i8 { (s >> 8) as i8 } s to_i24 { I24::new_unchecked((s as i32) << 8) } s to_i32 { (s as i32) << 16 } s to_i48 { I48::new_unchecked((s as i64) << 32) } s to_i64 { (s as i64) << 48 } s to_u8 { super::i8::to_u8(to_i8(s)) } s to_u16 { if s < 0 { // 32_768i16 overflows, so we must use + 1 instead. (s + 32_767 + 1) as u16 } else { s as u16 + 32_768 } } s to_u24 { if s < 0 { U24::new_unchecked(((s + 32_767 + 1) as i32) << 8) } else { U24::new_unchecked((s as i32 + 32_768) << 8) } } s to_u32 { if s < 0 { ((s + 32_767 + 1) as u32) << 16 } else { ((s as u32) + 32_768) << 16 } } s to_u48 { if s < 0 { U48::new_unchecked(((s + 32_767 + 1) as i64) << 32) } else { U48::new_unchecked((s as i64 + 32_768) << 32) } } s to_u64 { if s < 0 { ((s + 32_767 + 1) as u64) << 48 } else { ((s as u64) + 32_768) << 48 } } s to_f32 { s as f32 / 32_768.0 } s to_f64 { s as f64 / 32_768.0 } }); conversions!(I24, i24 { s to_i8 { (s.inner() >> 16) as i8 } s to_i16 { (s.inner() >> 8) as i16 } s to_i32 { s.inner() << 8 } s to_i48 { I48::new_unchecked((s.inner() as i64) << 24) } s to_i64 { (s.inner() as i64) << 40 } s to_u8 { super::i8::to_u8(to_i8(s)) } s to_u16 { super::i16::to_u16(to_i16(s)) } s to_u24 { U24::new_unchecked(s.inner() + 8_388_608) } s to_u32 { ((s.inner() + 8_388_608) as u32) << 8 } s to_u48 { U48::new_unchecked((s.inner() as i64 + 8_388_608) << 24) } s to_u64 { ((s.inner() + 8_388_608) as u64) << 40 } s to_f32 { s.inner() as f32 / 8_388_608.0 } s to_f64 { s.inner() as f64 / 8_388_608.0 } }); conversions!(i32, i32 { s to_i8 { (s >> 24) as i8 } s to_i16 { (s >> 16) as i16 } s to_i24 { I24::new_unchecked(s >> 8) } s to_i48 { I48::new_unchecked((s as i64) << 16) } s to_i64 { (s as i64) << 32 } s to_u8 { super::i8::to_u8(to_i8(s)) } s to_u16 { super::i16::to_u16(to_i16(s)) } s to_u24 { super::i24::to_u24(to_i24(s)) } s to_u32 { if s < 0 { (s + 2_147_483_647 + 1) as u32 } else { s as u32 + 2_147_483_648 } } s to_u48 { U48::new_unchecked((s as i64 + 2_147_483_648) << 16) } s to_u64 { if s < 0 { ((s + 2_147_483_647 + 1) as u64) << 32 } else { (s as u64) + 2_147_483_648 << 32 } } s to_f32 { s as f32 / 2_147_483_648.0 } s to_f64 { s as f64 / 2_147_483_648.0 } }); conversions!(I48, i48 { s to_i8 { (s.inner() >> 40) as i8 } s to_i16 { (s.inner() >> 32) as i16 } s to_i24 { I24::new_unchecked((s.inner() >> 24) as i32) } s to_i32 { (s.inner() >> 16) as i32 } s to_i64 { s.inner() << 16 } s to_u8 { super::i8::to_u8(to_i8(s)) } s to_u16 { super::i16::to_u16(to_i16(s)) } s to_u24 { super::i24::to_u24(to_i24(s)) } s to_u32 { super::i32::to_u32(to_i32(s)) } s to_u48 { U48::new_unchecked(s.inner() + 140_737_488_355_328) } s to_u64 { ((s.inner() + 140_737_488_355_328) as u64) << 16 } s to_f32 { s.inner() as f32 / 140_737_488_355_328.0 } s to_f64 { s.inner() as f64 / 140_737_488_355_328.0 } }); conversions!(i64, i64 { s to_i8 { (s >> 56) as i8 } s to_i16 { (s >> 48) as i16 } s to_i24 { I24::new_unchecked((s >> 40) as i32) } s to_i32 { (s >> 32) as i32 } s to_i48 { I48::new_unchecked(s >> 16) } s to_u8 { super::i8::to_u8(to_i8(s)) } s to_u16 { super::i16::to_u16(to_i16(s)) } s to_u24 { super::i24::to_u24(to_i24(s)) } s to_u32 { super::i32::to_u32(to_i32(s)) } s to_u48 { super::i48::to_u48(to_i48(s)) } s to_u64 { if s < 0 { (s + 9_223_372_036_854_775_807 + 1) as u64 } else { s as u64 + 9_223_372_036_854_775_808 } } s to_f32 { s as f32 / 9_223_372_036_854_775_808.0 } s to_f64 { s as f64 / 9_223_372_036_854_775_808.0 } }); conversions!(u8, u8 { s to_i8 { if s < 128 { s as i8 - 127 - 1 } else { (s - 128) as i8 } } s to_i16 { (s as i16 - 128) << 8 } s to_i24 { I24::new_unchecked((s as i32 - 128) << 16) } s to_i32 { (s as i32 - 128) << 24 } s to_i48 { I48::new_unchecked((s as i64 - 128) << 40) } s to_i64 { (s as i64 - 128) << 56 } s to_u16 { (s as u16) << 8 } s to_u24 { U24::new_unchecked((s as i32) << 16) } s to_u32 { (s as u32) << 24 } s to_u48 { U48::new_unchecked((s as i64) << 40) } s to_u64 { (s as u64) << 56 } s to_f32 { super::i8::to_f32(to_i8(s)) } s to_f64 { super::i8::to_f64(to_i8(s)) } }); conversions!(u16, u16 { s to_i8 { super::u8::to_i8(to_u8(s)) } s to_i16 { if s < 32_768 { s as i16 - 32_767 - 1 } else { (s - 32_768) as i16 } } s to_i24 { I24::new_unchecked((s as i32 - 32_768) << 8) } s to_i32 { (s as i32 - 32_768) << 16 } s to_i48 { I48::new_unchecked((s as i64 - 32_768) << 32) } s to_i64 { (s as i64 - 32_768) << 48 } s to_u8 { (s >> 8) as u8 } s to_u24 { U24::new_unchecked((s as i32) << 8) } s to_u32 { (s as u32) << 16 } s to_u48 { U48::new_unchecked((s as i64) << 32) } s to_u64 { (s as u64) << 48 } s to_f32 { super::i16::to_f32(to_i16(s)) } s to_f64 { super::i16::to_f64(to_i16(s)) } }); conversions!(U24, u24 { s to_i8 { super::u8::to_i8(to_u8(s)) } s to_i16 { super::u16::to_i16(to_u16(s)) } s to_i24 { I24::new_unchecked(s.inner() - 8_388_608) } s to_i32 { (s.inner() - 8_388_608) << 8 } s to_i48 { I48::new_unchecked(((s.inner() as i64) - 8_388_608) << 24) } s to_i64 { (s.inner() as i64 - 8_388_608) << 40 } s to_u8 { (s.inner() >> 16) as u8 } s to_u16 { (s.inner() >> 8) as u16 } s to_u32 { (s.inner() as u32) << 8 } s to_u48 { U48::new_unchecked((s.inner() as i64) << 24) } s to_u64 { (s.inner() as u64) << 40 } s to_f32 { super::i24::to_f32(to_i24(s)) } s to_f64 { super::i24::to_f64(to_i24(s)) } }); conversions!(u32, u32 { s to_i8 { super::u8::to_i8(to_u8(s)) } s to_i16 { super::u16::to_i16(to_u16(s)) } s to_i24 { super::u24::to_i24(to_u24(s)) } s to_i32 { if s < 2_147_483_648 { s as i32 - 2_147_483_647 - 1 } else { (s - 2_147_483_648) as i32 } } s to_i48 { I48::new_unchecked((s as i64 - 2_147_483_648) << 16) } s to_i64 { (s as i64 - 2_147_483_648) << 32 } s to_u8 { (s >> 24) as u8 } s to_u16 { (s >> 16) as u16 } s to_u24 { U24::new_unchecked((s >> 8) as i32) } s to_u48 { U48::new_unchecked((s as i64) << 16) } s to_u64 { (s as u64) << 32 } s to_f32 { super::i32::to_f32(to_i32(s)) } s to_f64 { super::i32::to_f64(to_i32(s)) } }); conversions!(U48, u48 { s to_i8 { super::u8::to_i8(to_u8(s)) } s to_i16 { super::u16::to_i16(to_u16(s)) } s to_i24 { super::u24::to_i24(to_u24(s)) } s to_i32 { super::u32::to_i32(to_u32(s)) } s to_i48 { I48::new_unchecked(s.inner() - 140_737_488_355_328) } s to_i64 { (s.inner() - 140_737_488_355_328) << 16 } s to_u8 { (s.inner() >> 40) as u8 } s to_u16 { (s.inner() >> 32) as u16 } s to_u24 { U24::new_unchecked((s.inner() >> 24) as i32) } s to_u32 { (s.inner() >> 16) as u32 } s to_u64 { (s.inner() as u64) << 16 } s to_f32 { super::i48::to_f32(to_i48(s)) } s to_f64 { super::i48::to_f64(to_i48(s)) } }); conversions!(u64, u64 { s to_i8 { super::u8::to_i8(to_u8(s)) } s to_i16 { super::u16::to_i16(to_u16(s)) } s to_i24 { super::u24::to_i24(to_u24(s)) } s to_i32 { super::u32::to_i32(to_u32(s)) } s to_i48 { super::u48::to_i48(to_u48(s)) } s to_i64 { if s < 9_223_372_036_854_775_808 { s as i64 - 9_223_372_036_854_775_807 - 1 } else { (s - 9_223_372_036_854_775_808) as i64 } } s to_u8 { (s >> 56) as u8 } s to_u16 { (s >> 48) as u16 } s to_u24 { U24::new_unchecked((s >> 40) as i32) } s to_u32 { (s >> 32) as u32 } s to_u48 { U48::new_unchecked((s >> 16) as i64) } s to_f32 { super::i64::to_f32(to_i64(s)) } s to_f64 { super::i64::to_f64(to_i64(s)) } }); // The following conversions assume `-1.0 <= s < 1.0` (note that +1.0 is excluded) and will // overflow otherwise. conversions!(f32, f32 { s to_i8 { (s * 128.0) as i8 } s to_i16 { (s * 32_768.0) as i16 } s to_i24 { I24::new_unchecked((s * 8_388_608.0) as i32) } s to_i32 { (s * 2_147_483_648.0) as i32 } s to_i48 { I48::new_unchecked((s * 140_737_488_355_328.0) as i64) } s to_i64 { (s * 9_223_372_036_854_775_808.0) as i64 } s to_u8 { super::i8::to_u8(to_i8(s)) } s to_u16 { super::i16::to_u16(to_i16(s)) } s to_u24 { super::i24::to_u24(to_i24(s)) } s to_u32 { super::i32::to_u32(to_i32(s)) } s to_u48 { super::i48::to_u48(to_i48(s)) } s to_u64 { super::i64::to_u64(to_i64(s)) } s to_f64 { s as f64 } }); // The following conversions assume `-1.0 <= s < 1.0` (note that +1.0 is excluded) and will // overflow otherwise. conversions!(f64, f64 { s to_i8 { (s * 128.0) as i8 } s to_i16 { (s * 32_768.0) as i16 } s to_i24 { I24::new_unchecked((s * 8_388_608.0) as i32) } s to_i32 { (s * 2_147_483_648.0) as i32 } s to_i48 { I48::new_unchecked((s * 140_737_488_355_328.0) as i64) } s to_i64 { (s * 9_223_372_036_854_775_808.0) as i64 } s to_u8 { super::i8::to_u8(to_i8(s)) } s to_u16 { super::i16::to_u16(to_i16(s)) } s to_u24 { super::i24::to_u24(to_i24(s)) } s to_u32 { super::i32::to_u32(to_i32(s)) } s to_u48 { super::i48::to_u48(to_i48(s)) } s to_u64 { super::i64::to_u64(to_i64(s)) } s to_f32 { s as f32 } }); /// Similar to the std `From` trait, but specifically for converting between sample types. /// /// We use this trait to be generic over the `Sample::to_sample` and `Sample::from_sample` methods. pub trait FromSample { fn from_sample_(s: S) -> Self; } impl FromSample for S { #[inline] fn from_sample_(s: S) -> Self { s } } /// Implement the `FromSample` trait for the given types. macro_rules! impl_from_sample { ($T:ty, $fn_name:ident from $({$U:ident: $Umod:ident})*) => { $( impl FromSample<$U> for $T { #[inline] fn from_sample_(s: $U) -> Self { self::$Umod::$fn_name(s) } } )* }; } impl_from_sample! {i8, to_i8 from {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64} {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64} {f32:f32} {f64:f64} } impl_from_sample! {i16, to_i16 from {i8:i8} {I24:i24} {i32:i32} {I48:i48} {i64:i64} {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64} {f32:f32} {f64:f64} } impl_from_sample! {I24, to_i24 from {i8:i8} {i16:i16} {i32:i32} {I48:i48} {i64:i64} {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64} {f32:f32} {f64:f64} } impl_from_sample! {i32, to_i32 from {i8:i8} {i16:i16} {I24:i24} {I48:i48} {i64:i64} {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64} {f32:f32} {f64:f64} } impl_from_sample! {I48, to_i48 from {i8:i8} {i16:i16} {I24:i24} {i32:i32} {i64:i64} {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64} {f32:f32} {f64:f64} } impl_from_sample! {i64, to_i64 from {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64} {f32:f32} {f64:f64} } impl_from_sample! {u8, to_u8 from {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64} {f32:f32} {f64:f64} } impl_from_sample! {u16, to_u16 from {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64} {u8:u8} {U24:u24} {u32:u32} {U48:u48} {u64:u64} {f32:f32} {f64:f64} } impl_from_sample! {U24, to_u24 from {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64} {u8:u8} {u16:u16} {u32:u32} {U48:u48} {u64:u64} {f32:f32} {f64:f64} } impl_from_sample! {u32, to_u32 from {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64} {u8:u8} {u16:u16} {U24:u24} {U48:u48} {u64:u64} {f32:f32} {f64:f64} } impl_from_sample! {U48, to_u48 from {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64} {u8:u8} {u16:u16} {U24:u24} {u32:u32} {u64:u64} {f32:f32} {f64:f64} } impl_from_sample! {u64, to_u64 from {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64} {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {f32:f32} {f64:f64} } impl_from_sample! {f32, to_f32 from {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64} {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64} {f64:f64} } impl_from_sample! {f64, to_f64 from {i8:i8} {i16:i16} {I24:i24} {i32:i32} {I48:i48} {i64:i64} {u8:u8} {u16:u16} {U24:u24} {u32:u32} {U48:u48} {u64:u64} {f32:f32} } /// Similar to the std `Into` trait, but specifically for converting between sample types. /// /// This trait has a blanket implementation for all types that implement /// [`FromSample`](./trait.FromSample.html). pub trait ToSample { fn to_sample_(self) -> S; } impl ToSample for T where U: FromSample, { #[inline] fn to_sample_(self) -> U { U::from_sample_(self) } } /// Sample types which may be converted to and from some type `S`. pub trait Duplex: FromSample + ToSample {} impl Duplex for T where T: FromSample + ToSample {} dasp_sample-0.11.0/src/lib.rs010064400017510000164000000252661366425513200142260ustar0000000000000000//! Use the [**Sample**](./trait.Sample.html) trait to remain generic over sample types, easily //! access sample type conversions, apply basic audio operations and more. //! //! The **Sample** trait is the core abstraction throughout dasp on which most other abstractions //! are based. #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(core_intrinsics))] #[cfg(not(feature = "std"))] extern crate alloc; pub use conv::{Duplex, FromSample, ToSample}; pub use types::{I24, I48, U24, U48}; pub mod conv; mod ops; pub mod types; /// A trait for working generically across different **Sample** format types. /// /// Provides methods for converting to and from any type that implements the /// [`FromSample`](./trait.FromSample.html) trait and provides methods for performing signal /// amplitude addition and multiplication. /// /// # Example /// /// ```rust /// use dasp_sample::{I24, Sample}; /// /// fn main() { /// assert_eq!((-1.0).to_sample::(), 0); /// assert_eq!(0.0.to_sample::(), 128); /// assert_eq!(0i32.to_sample::(), 2_147_483_648); /// assert_eq!(I24::new(0).unwrap(), Sample::from_sample(0.0)); /// assert_eq!(0.0, Sample::EQUILIBRIUM); /// } /// ``` pub trait Sample: Copy + Clone + PartialOrd + PartialEq { /// When summing two samples of a signal together, it is necessary for both samples to be /// represented in some signed format. This associated `Addition` type represents the format to /// which `Self` should be converted for optimal `Addition` performance. /// /// For example, u32's optimal `Addition` type would be i32, u8's would be i8, f32's would be /// f32, etc. /// /// Specifying this as an associated type allows us to automatically determine the optimal, /// lossless Addition format type for summing any two unique `Sample` types together. /// /// As a user of the `sample` crate, you will never need to be concerned with this type unless /// you are defining your own unique `Sample` type(s). type Signed: SignedSample + Duplex; /// When multiplying two samples of a signal together, it is necessary for both samples to be /// represented in some signed, floating-point format. This associated `Multiplication` type /// represents the format to which `Self` should be converted for optimal `Multiplication` /// performance. /// /// For example, u32's optimal `Multiplication` type would be f32, u64's would be f64, i8's /// would be f32, etc. /// /// Specifying this as an associated type allows us to automatically determine the optimal, /// lossless Multiplication format type for multiplying any two unique `Sample` types together. /// /// As a user of the `sample` crate, you will never need to be concerned with this type unless /// you are defining your own unique `Sample` type(s). type Float: FloatSample + Duplex; /// The equilibrium value for the wave that this `Sample` type represents. This is normally the /// value that is equal distance from both the min and max ranges of the sample. /// /// # Example /// /// ```rust /// use dasp_sample::Sample; /// /// fn main() { /// assert_eq!(0.0, f32::EQUILIBRIUM); /// assert_eq!(0, i32::EQUILIBRIUM); /// assert_eq!(128, u8::EQUILIBRIUM); /// assert_eq!(32_768_u16, Sample::EQUILIBRIUM); /// } /// ``` /// /// **Note:** This will likely be changed to an "associated const" if the feature lands. const EQUILIBRIUM: Self; /// The multiplicative identity of the signal. /// /// In other words: A value which when used to scale/multiply the amplitude or frequency of a /// signal, returns the same signal. /// /// This is useful as a default, non-affecting amplitude or frequency multiplier. /// /// # Example /// /// ```rust /// use dasp_sample::{Sample, U48}; /// /// fn main() { /// assert_eq!(1.0, f32::IDENTITY); /// assert_eq!(1.0, i8::IDENTITY); /// assert_eq!(1.0, u8::IDENTITY); /// assert_eq!(1.0, U48::IDENTITY); /// } /// ``` const IDENTITY: Self::Float = ::IDENTITY; /// Convert `self` to any type that implements `FromSample`. /// /// Find more details on type-specific conversion ranges and caveats in the `conv` module. /// /// # Example /// /// ```rust /// use dasp_sample::Sample; /// /// fn main() { /// assert_eq!(0.0.to_sample::(), 0); /// assert_eq!(0.0.to_sample::(), 128); /// assert_eq!((-1.0).to_sample::(), 0); /// } /// ``` #[inline] fn to_sample(self) -> S where Self: ToSample, { self.to_sample_() } /// Create a `Self` from any type that implements `ToSample`. /// /// Find more details on type-specific conversion ranges and caveats in the `conv` module. /// /// # Example /// /// ```rust /// use dasp_sample::{Sample, I24}; /// /// fn main() { /// assert_eq!(f32::from_sample(128_u8), 0.0); /// assert_eq!(i8::from_sample(-1.0), -128); /// assert_eq!(I24::from_sample(0.0), I24::new(0).unwrap()); /// } /// ``` #[inline] fn from_sample(s: S) -> Self where Self: FromSample, { FromSample::from_sample_(s) } /// Converts `self` to the equivalent `Sample` in the associated `Signed` format. /// /// This is a simple wrapper around `Sample::to_sample` which may provide extra convenience in /// some cases, particularly for assisting type inference. /// /// # Example /// /// ```rust /// use dasp_sample::Sample; /// /// fn main() { /// assert_eq!(128_u8.to_signed_sample(), 0i8); /// } /// ``` fn to_signed_sample(self) -> Self::Signed { self.to_sample() } /// Converts `self` to the equivalent `Sample` in the associated `Float` format. /// /// This is a simple wrapper around `Sample::to_sample` which may provide extra convenience in /// some cases, particularly for assisting type inference. /// /// # Example /// /// ```rust /// use dasp_sample::Sample; /// /// fn main() { /// assert_eq!(128_u8.to_float_sample(), 0.0); /// } /// ``` fn to_float_sample(self) -> Self::Float { self.to_sample() } /// Adds (or "offsets") the amplitude of the `Sample` by the given signed amplitude. /// /// `Self` will be converted to `Self::Signed`, the addition will occur and then the result /// will be converted back to `Self`. These conversions allow us to correctly handle the /// addition of unsigned signal formats. /// /// # Example /// /// ```rust /// use dasp_sample::Sample; /// /// fn main() { /// assert_eq!(0.25.add_amp(0.5), 0.75); /// assert_eq!(192u8.add_amp(-128), 64); /// } /// ``` #[inline] fn add_amp(self, amp: Self::Signed) -> Self { let self_s = self.to_signed_sample(); (self_s + amp).to_sample() } /// Multiplies (or "scales") the amplitude of the `Sample` by the given float amplitude. /// /// - `amp` > 1.0 amplifies the sample. /// - `amp` < 1.0 attenuates the sample. /// - `amp` == 1.0 yields the same sample. /// - `amp` == 0.0 yields the `Sample::EQUILIBRIUM`. /// /// `Self` will be converted to `Self::Float`, the multiplication will occur and then the /// result will be converted back to `Self`. These conversions allow us to correctly handle the /// multiplication of integral signal formats. /// /// # Example /// /// ```rust /// use dasp_sample::Sample; /// /// fn main() { /// assert_eq!(64_i8.mul_amp(0.5), 32); /// assert_eq!(0.5.mul_amp(-2.0), -1.0); /// assert_eq!(64_u8.mul_amp(0.0), 128); /// } /// ``` #[inline] fn mul_amp(self, amp: Self::Float) -> Self { let self_f = self.to_float_sample(); (self_f * amp).to_sample() } } /// A macro used to simplify the implementation of `Sample`. macro_rules! impl_sample { ($($T:ty: Signed: $Addition:ty, Float: $Modulation:ty, EQUILIBRIUM: $EQUILIBRIUM:expr),*) => { $( impl Sample for $T { type Signed = $Addition; type Float = $Modulation; const EQUILIBRIUM: Self = $EQUILIBRIUM; } )* } } // Expands to `Sample` implementations for all of the following types. impl_sample! { i8: Signed: i8, Float: f32, EQUILIBRIUM: 0, i16: Signed: i16, Float: f32, EQUILIBRIUM: 0, I24: Signed: I24, Float: f32, EQUILIBRIUM: types::i24::EQUILIBRIUM, i32: Signed: i32, Float: f32, EQUILIBRIUM: 0, I48: Signed: I48, Float: f64, EQUILIBRIUM: types::i48::EQUILIBRIUM, i64: Signed: i64, Float: f64, EQUILIBRIUM: 0, u8: Signed: i8, Float: f32, EQUILIBRIUM: 128, u16: Signed: i16, Float: f32, EQUILIBRIUM: 32_768, U24: Signed: i32, Float: f32, EQUILIBRIUM: types::u24::EQUILIBRIUM, u32: Signed: i32, Float: f32, EQUILIBRIUM: 2_147_483_648, U48: Signed: i64, Float: f64, EQUILIBRIUM: types::u48::EQUILIBRIUM, u64: Signed: i64, Float: f64, EQUILIBRIUM: 9_223_372_036_854_775_808, f32: Signed: f32, Float: f32, EQUILIBRIUM: 0.0, f64: Signed: f64, Float: f64, EQUILIBRIUM: 0.0 } /// Integral and floating-point **Sample** format types whose equilibrium is at 0. /// /// **Sample**s often need to be converted to some mutual **SignedSample** type for signal /// addition. pub trait SignedSample: Sample + core::ops::Add + core::ops::Sub + core::ops::Neg { } macro_rules! impl_signed_sample { ($($T:ty)*) => { $( impl SignedSample for $T {} )* } } impl_signed_sample!(i8 i16 I24 i32 I48 i64 f32 f64); /// Sample format types represented as floating point numbers. /// /// **Sample**s often need to be converted to some mutual **FloatSample** type for signal scaling /// and modulation. pub trait FloatSample: Sample + SignedSample + core::ops::Mul + core::ops::Div + Duplex + Duplex { /// Represents the multiplicative identity of the floating point signal. const IDENTITY: Self; /// Calculate the square root of `Self`. fn sample_sqrt(self) -> Self; } impl FloatSample for f32 { const IDENTITY: Self = 1.0; #[inline] fn sample_sqrt(self) -> Self { ops::f32::sqrt(self) } } impl FloatSample for f64 { const IDENTITY: Self = 1.0; #[inline] fn sample_sqrt(self) -> Self { ops::f64::sqrt(self) } } dasp_sample-0.11.0/src/ops.rs010064400017510000164000000010211366425513200142400ustar0000000000000000pub mod f32 { #[allow(unused_imports)] use core; #[cfg(not(feature = "std"))] pub fn sqrt(x: f32) -> f32 { unsafe { core::intrinsics::sqrtf32(x) } } #[cfg(feature = "std")] pub fn sqrt(x: f32) -> f32 { x.sqrt() } } pub mod f64 { #[allow(unused_imports)] use core; #[cfg(not(feature = "std"))] pub fn sqrt(x: f64) -> f64 { unsafe { core::intrinsics::sqrtf64(x) } } #[cfg(feature = "std")] pub fn sqrt(x: f64) -> f64 { x.sqrt() } } dasp_sample-0.11.0/src/types.rs010064400017510000164000000204511366425513200146130ustar0000000000000000//! A collection of custom, non-std **Sample** types. pub use self::i11::I11; pub use self::i20::I20; pub use self::i24::I24; pub use self::i48::I48; pub use self::u11::U11; pub use self::u20::U20; pub use self::u24::U24; pub use self::u48::U48; macro_rules! impl_from { ($T:ident: $Rep:ident from {$U:ident : $URep:ty}) => { impl From<$U> for $T { #[inline] fn from(other: $U) -> Self { $T(other.inner() as $Rep) } } }; ($T:ident: $Rep:ident from $U:ident) => { impl From<$U> for $T { #[inline] fn from(other: $U) -> Self { $T(other as $Rep) } } }; } macro_rules! impl_froms { ($T:ident: $Rep:ident, {$U:ident : $URep:ty}, $($rest:tt)*) => { impl_from!($T: $Rep from {$U: $URep}); impl_froms!($T: $Rep, $($rest)*); }; ($T:ident: $Rep:ident, {$U:ident : $URep:ty}) => { impl_from!($T: $Rep from {$U: $URep}); }; ($T:ident: $Rep:ident, $U:ident, $($rest:tt)*) => { impl_from!($T: $Rep from $U); impl_froms!($T: $Rep, $($rest)*); }; ($T:ident: $Rep:ident, $U:ident) => { impl_from!($T: $Rep from $U); }; ($T:ident: $Rep:ident,) => {}; } macro_rules! impl_neg { ($T:ident) => { impl ::core::ops::Neg for $T { type Output = $T; #[inline] fn neg(self) -> $T { $T(-self.0) } } }; } macro_rules! new_sample_type { ($T:ident: $Rep:ident, eq: $EQ:expr, min: $MIN:expr, max: $MAX:expr, total: $TOTAL:expr, from: $($rest:tt)*) => { pub const MIN: $T = $T($MIN); pub const MAX: $T = $T($MAX); pub const EQUILIBRIUM: $T = $T($EQ); const MIN_REP: $Rep = $MIN; const MAX_REP: $Rep = $MAX; const TOTAL: $Rep = $TOTAL; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)] pub struct $T($Rep); impl From<$Rep> for $T { #[inline] fn from(val: $Rep) -> Self { $T(val).wrap_overflow() } } impl $T { /// Construct a new sample if the given value is within range. /// /// Returns `None` if `val` is out of range. #[inline] pub fn new(val: $Rep) -> Option { if val > MAX_REP || val < MIN_REP { None } else { Some($T(val)) } } /// Constructs a new sample without checking for overflowing. /// /// This should *only* be used if the user can guarantee the sample will be within /// range and they require the extra performance. /// /// If this function is used, the sample crate can't guarantee that the returned sample /// or any interacting samples will remain within their MIN and MAX bounds. pub fn new_unchecked(s: $Rep) -> Self { $T(s) } /// Return the internal value used to represent the sample type. #[inline] pub fn inner(self) -> $Rep { self.0 } /// Wraps self once in the case that self has overflowed. #[inline] fn wrap_overflow_once(self) -> Self { if self.0 > MAX_REP { $T(self.0 - TOTAL) } else if self.0 < MIN_REP { $T(self.0 + TOTAL) } else { self } } /// Wraps self in the case that self has overflowed. #[inline] fn wrap_overflow(mut self) -> Self { while self.0 > MAX_REP { self.0 -= TOTAL; } while self.0 < MIN_REP { self.0 += TOTAL; } self } } impl ::core::ops::Add<$T> for $T { type Output = $T; #[inline] fn add(self, other: Self) -> Self { if cfg!(debug_assertions) { $T::new(self.0 + other.0).expect("arithmetic operation overflowed") } else { $T(self.0 + other.0).wrap_overflow_once() } } } impl ::core::ops::Sub<$T> for $T { type Output = $T; #[inline] fn sub(self, other: Self) -> Self { if cfg!(debug_assertions) { $T::new(self.0 - other.0).expect("arithmetic operation overflowed") } else { $T(self.0 - other.0).wrap_overflow_once() } } } impl ::core::ops::Mul<$T> for $T { type Output = $T; #[inline] fn mul(self, other: Self) -> Self { if cfg!(debug_assertions) { $T::new(self.0 * other.0).expect("arithmetic operation overflowed") } else { $T::from(self.0 * other.0) } } } impl ::core::ops::Div<$T> for $T { type Output = $T; #[inline] fn div(self, other: Self) -> Self { $T(self.0 / other.0) } } impl ::core::ops::Not for $T { type Output = $T; #[inline] fn not(self) -> $T { $T(!self.0) } } impl ::core::ops::Rem<$T> for $T { type Output = $T; #[inline] fn rem(self, other: Self) -> Self { $T(self.0 % other.0) } } impl ::core::ops::Shl<$T> for $T { type Output = $T; #[inline] fn shl(self, other: Self) -> Self { // TODO: Needs review $T(self.0 << other.0) } } impl ::core::ops::Shr<$T> for $T { type Output = $T; #[inline] fn shr(self, other: Self) -> Self { // TODO: Needs review $T(self.0 >> other.0) } } impl ::core::ops::BitAnd<$T> for $T { type Output = $T; #[inline] fn bitand(self, other: Self) -> Self { $T(self.0 & other.0) } } impl ::core::ops::BitOr<$T> for $T { type Output = $T; #[inline] fn bitor(self, other: Self) -> Self { $T(self.0 | other.0) } } impl ::core::ops::BitXor<$T> for $T { type Output = $T; #[inline] fn bitxor(self, other: Self) -> Self { $T(self.0 ^ other.0) } } impl_froms!($T: $Rep, $($rest)*); }; } pub mod i11 { new_sample_type!(I11: i16, eq: 0, min: -1024, max: 1023, total: 2048, from: i8, u8); impl_neg!(I11); } pub mod i20 { use super::{I11, U11}; new_sample_type!(I20: i32, eq: 0, min: -524_288, max: 524_287, total: 1_048_576, from: i8, {I11:i16}, i16, u8, {U11:i16}, u16); } pub mod i24 { use super::{I20, U20}; new_sample_type!(I24: i32, eq: 0, min: -8_388_608, max: 8_388_607, total: 16_777_216, from: i8, i16, {I20:i32}, u8, u16, {U20:i32}); impl_neg!(I24); } pub mod i48 { use super::{I20, I24, U20, U24}; new_sample_type!(I48: i64, eq: 0, min: -140_737_488_355_328, max: 140_737_488_355_327, total: 281_474_976_710_656, from: i8, i16, {I20:i32}, {I24:i32}, i32, u8, u16, {U20:i32}, {U24:i32}, u32); impl_neg!(I48); } pub mod u11 { new_sample_type!(U11: i16, eq: 1024, min: 0, max: 2047, total: 2048, from: u8); impl_neg!(U11); } pub mod u20 { new_sample_type!(U20: i32, eq: 524_288, min: 0, max: 1_048_575, total: 1_048_576, from: u8, u16); } pub mod u24 { use super::U20; new_sample_type!(U24: i32, eq: 8_388_608, min: 0, max: 16_777_215, total: 16_777_216, from: u8, u16, {U20:i32}); } pub mod u48 { use super::{U20, U24}; new_sample_type!(U48: i64, eq: 140_737_488_355_328, min: 0, max: 281_474_976_710_655, total: 281_474_976_710_656, from: u8, u16, {U20:i32}, {U24:i32}, u32); } dasp_sample-0.11.0/tests/conv.rs010064400017510000164000000505321366425513200147720ustar0000000000000000//! The following is a series of tests that check conversions between every combination of sample //! types available within this crate. //! //! We assert that each sample type's minimum, maximum and centre are correctly converted to the //! min, max and centre of every other available sample type. /// Expands to an `assert_eq` for each pre-conversion and post-conversion pair. /// /// Literals that must be wrapped by a custom sample type are wrapped using $T/$U::new_unchecked. macro_rules! conv_cmp { ($fn_name:ident, $pre_conv:expr, $post_conv:expr) => { assert_eq!($fn_name($pre_conv), $post_conv); }; ($fn_name:ident: $U:ident, $pre_conv:expr, $post_conv:expr) => { assert_eq!($fn_name($pre_conv), $U::new_unchecked($post_conv)); }; ($T:ident; $fn_name:ident, $pre_conv:expr, $post_conv:expr) => { assert_eq!($fn_name($T::new_unchecked($pre_conv)), $post_conv); }; ($T:ident; $fn_name:ident: $U:ident, $pre_conv:expr, $post_conv:expr) => { assert_eq!( $fn_name($T::new_unchecked($pre_conv)), $U::new_unchecked($post_conv) ); }; } /// Expands to a list of `assert_eq` statements. macro_rules! conv_cmps { ($fn_name:ident, $pre_conv:expr, $post_conv:expr; $($rest:tt)*) => { conv_cmp!($fn_name, $pre_conv, $post_conv); conv_cmps!($fn_name, $($rest)*); }; ($fn_name:ident: $U:ident, $pre_conv:expr, $post_conv:expr; $($rest:tt)*) => { conv_cmp!($fn_name:$U, $pre_conv, $post_conv); conv_cmps!($fn_name:$U, $($rest)*); }; ($T:ident; $fn_name:ident, $pre_conv:expr, $post_conv:expr; $($rest:tt)*) => { conv_cmp!($T; $fn_name, $pre_conv, $post_conv); conv_cmps!($T; $fn_name, $($rest)*); }; ($T:ident; $fn_name:ident: $U:ident, $pre_conv:expr, $post_conv:expr; $($rest:tt)*) => { conv_cmp!($T; $fn_name:$U, $pre_conv, $post_conv); conv_cmps!($T; $fn_name:$U, $($rest)*); }; ($fn_name:ident,) => {}; ($fn_name:ident: $U:ident,) => {}; ($T:ident; $fn_name:ident,) => {}; ($T:ident; $fn_name:ident: $U:ident,) => {}; } /// Expands to a test function for the given test function name. /// /// We must use one for each as: /// 1. There is no concat-idents macro for constructing unique names from other identifiers and /// 2. We need to check for functions that convert to custom sample types (i.e. to_i24 converts to /// `I24`). macro_rules! test_fn { (to_i8 { $($conv_cmps:tt)* }) => { #[test] fn test_to_i8() { conv_cmps!(to_i8, $($conv_cmps)*); } }; (to_i16 { $($conv_cmps:tt)* }) => { #[test] fn test_to_i16() { conv_cmps!(to_i16, $($conv_cmps)*); } }; (to_i24 { $($conv_cmps:tt)* }) => { #[test] fn test_to_i24() { conv_cmps!(to_i24: I24, $($conv_cmps)*); } }; (to_i32 { $($conv_cmps:tt)* }) => { #[test] fn test_to_i32() { conv_cmps!(to_i32, $($conv_cmps)*); } }; (to_i48 { $($conv_cmps:tt)* }) => { #[test] fn test_to_i48() { conv_cmps!(to_i48: I48, $($conv_cmps)*); } }; (to_i64 { $($conv_cmps:tt)* }) => { #[test] fn test_to_i64() { conv_cmps!(to_i64, $($conv_cmps)*); } }; (to_u8 { $($conv_cmps:tt)* }) => { #[test] fn test_to_u8() { conv_cmps!(to_u8, $($conv_cmps)*); } }; (to_u16 { $($conv_cmps:tt)* }) => { #[test] fn test_to_u16() { conv_cmps!(to_u16, $($conv_cmps)*); } }; (to_u24 { $($conv_cmps:tt)* }) => { #[test] fn test_to_u24() { conv_cmps!(to_u24: U24, $($conv_cmps)*); } }; (to_u32 { $($conv_cmps:tt)* }) => { #[test] fn test_to_u32() { conv_cmps!(to_u32, $($conv_cmps)*); } }; (to_u48 { $($conv_cmps:tt)* }) => { #[test] fn test_to_u48() { conv_cmps!(to_u48: U48, $($conv_cmps)*); } }; (to_u64 { $($conv_cmps:tt)* }) => { #[test] fn test_to_u64() { conv_cmps!(to_u64, $($conv_cmps)*); } }; (to_f32 { $($conv_cmps:tt)* }) => { #[test] fn test_to_f32() { conv_cmps!(to_f32, $($conv_cmps)*); } }; (to_f64 { $($conv_cmps:tt)* }) => { #[test] fn test_to_f64() { conv_cmps!(to_f64, $($conv_cmps)*); } }; // Test functions for wrapper sample types. ($T:ident: to_i8 { $($conv_cmps:tt)* }) => { #[test] fn test_to_i8() { conv_cmps!($T; to_i8, $($conv_cmps)*); } }; ($T:ident: to_i16 { $($conv_cmps:tt)* }) => { #[test] fn test_to_i16() { conv_cmps!($T; to_i16, $($conv_cmps)*); } }; ($T:ident: to_i24 { $($conv_cmps:tt)* }) => { #[test] fn test_to_i24() { conv_cmps!($T; to_i24: I24, $($conv_cmps)*); } }; ($T:ident: to_i32 { $($conv_cmps:tt)* }) => { #[test] fn test_to_i32() { conv_cmps!($T; to_i32, $($conv_cmps)*); } }; ($T:ident: to_i48 { $($conv_cmps:tt)* }) => { #[test] fn test_to_i48() { conv_cmps!($T; to_i48: I48, $($conv_cmps)*); } }; ($T:ident: to_i64 { $($conv_cmps:tt)* }) => { #[test] fn test_to_i64() { conv_cmps!($T; to_i64, $($conv_cmps)*); } }; ($T:ident: to_u8 { $($conv_cmps:tt)* }) => { #[test] fn test_to_u8() { conv_cmps!($T; to_u8, $($conv_cmps)*); } }; ($T:ident: to_u16 { $($conv_cmps:tt)* }) => { #[test] fn test_to_u16() { conv_cmps!($T; to_u16, $($conv_cmps)*); } }; ($T:ident: to_u24 { $($conv_cmps:tt)* }) => { #[test] fn test_to_u24() { conv_cmps!($T; to_u24: U24, $($conv_cmps)*); } }; ($T:ident: to_u32 { $($conv_cmps:tt)* }) => { #[test] fn test_to_u32() { conv_cmps!($T; to_u32, $($conv_cmps)*); } }; ($T:ident: to_u48 { $($conv_cmps:tt)* }) => { #[test] fn test_to_u48() { conv_cmps!($T; to_u48: U48, $($conv_cmps)*); } }; ($T:ident: to_u64 { $($conv_cmps:tt)* }) => { #[test] fn test_to_u64() { conv_cmps!($T; to_u64, $($conv_cmps)*); } }; ($T:ident: to_f32 { $($conv_cmps:tt)* }) => { #[test] fn test_to_f32() { conv_cmps!($T; to_f32, $($conv_cmps)*); } }; ($T:ident: to_f64 { $($conv_cmps:tt)* }) => { #[test] fn test_to_f64() { conv_cmps!($T; to_f64, $($conv_cmps)*); } }; } /// Expands to a list of test functions. macro_rules! test_fns { ($fn_name:tt { $($conv_cmps:tt)* } $($rest:tt)*) => { test_fn!($fn_name { $($conv_cmps)* }); test_fns!($($rest)*); }; ($T:ident: $fn_name:tt { $($conv_cmps:tt)* } $($rest:tt)*) => { test_fn!($T: $fn_name { $($conv_cmps)* }); test_fns!($T: $($rest)*); }; () => {}; ($T:ident:) => {}; } /// Expands to a unique test module containing a list of test functions. macro_rules! tests { ($T:ident { $($rest:tt)* }) => { pub mod $T { use dasp_sample::conv::$T::*; use dasp_sample::types::{I24, U24, I48, U48}; test_fns!($($rest)*); } }; ($T:ident: $mod_name:ident { $($rest:tt)* }) => { pub mod $mod_name { use dasp_sample::conv::$mod_name::*; use dasp_sample::types::{I24, U24, I48, U48}; test_fns!($T: $($rest)*); } }; } tests!(i8 { to_i16 { -128, -32_768; 0, 0; 127, 32_512; } to_i24 { -128, -8_388_608; 0, 0; 127, 8_323_072; } to_i32 { -128, -2_147_483_648; 0, 0; 127, 2_130_706_432; } to_i48 { -128, -140_737_488_355_328; 0, 0; 127, 139_637_976_727_552; } to_i64 { -128, -9_223_372_036_854_775_808; 0, 0; 127, 9_151_314_442_816_847_872; } to_u8 { -128, 0; 0, 128; 127, 255; } to_u16 { -128, 0; 0, 32_768; 127, 65_280; } to_u24 { -128, 0; 0, 8_388_608; 127, 16_711_680; } to_u32 { -128, 0; 0, 2_147_483_648; 127, 4_278_190_080; } to_u48 { -128, 0; 0, 140_737_488_355_328; 127, 280_375_465_082_880; } to_u64 { -128, 0; 0, 9_223_372_036_854_775_808; 127, 18_374_686_479_671_623_680; } to_f32 { -128, -1.0; 0, 0.0; } to_f64 { -128, -1.0; 0, 0.0; } }); tests!(i16 { to_i8 { -32_768, -128; 0, 0; 32_767, 127; } to_i24 { -32_768, -8_388_608; 0, 0; 32_767, 8_388_352; } to_i32 { -32_768, -2_147_483_648; 0, 0; 32_767, 2_147_418_112; } to_i48 { -32_768, -140_737_488_355_328; 0, 0; 32_767, 140_733_193_388_032; } to_i64 { -32_768, -9_223_372_036_854_775_808; 0, 0; 32_767, 9_223_090_561_878_065_152; } to_u8 { -32_768, 0; 0, 128; 32_767, 255; } to_u16 { -32_768, 0; 0, 32_768; 32_767, 65_535; } to_u24 { -32_768, 0; 0, 8_388_608; 32_767, 16_776_960; } to_u32 { -32_768, 0; 0, 2_147_483_648; 32_767, 4_294_901_760; } to_u48 { -32_768, 0; 0, 140_737_488_355_328; 32_767, 281_470_681_743_360; } to_u64 { -32_768, 0; 0, 9_223_372_036_854_775_808; 32_767, 18_446_462_598_732_840_960; } to_f32 { -32_768, -1.0; 0, 0.0; } to_f64 { -32_768, -1.0; 0, 0.0; } }); tests!(I24: i24 { to_i8 { -8_388_608, -128; 0, 0; 8_388_607, 127; } to_i16 { -8_388_608, -32_768; 0, 0; 8_388_607, 32_767; } to_i32 { -8_388_608, -2_147_483_648; 0, 0; 8_388_607, 2_147_483_392; } to_i48 { -8_388_608, -140_737_488_355_328; 0, 0; 8_388_607, 140_737_471_578_112; } to_i64 { -8_388_608, -9_223_372_036_854_775_808; 0, 0; 8_388_607, 9_223_370_937_343_148_032; } to_u8 { -8_388_608, 0; 0, 128; 8_388_607, 255; } to_u16 { -8_388_608, 0; 0, 32_768; 8_388_607, 65_535; } to_u24 { -8_388_608, 0; 0, 8_388_608; 8_388_607, 16_777_215; } to_u32 { -8_388_608, 0; 0, 2_147_483_648; 8_388_607, 4_294_967_040; } to_u48 { -8_388_608, 0; 0, 140_737_488_355_328; 8_388_607, 281_474_959_933_440; } to_u64 { -8_388_608, 0; 0, 9_223_372_036_854_775_808; 8_388_607, 18_446_742_974_197_923_840; } to_f32 { -8_388_608, -1.0; 0, 0.0; } to_f64 { -8_388_608, -1.0; 0, 0.0; } }); tests!(i32 { to_i8 { -2_147_483_648, -128; 0, 0; 2_147_483_647, 127; } to_i16 { -2_147_483_648, -32_768; 0, 0; 2_147_483_647, 32_767; } to_i24 { -2_147_483_648, -8_388_608; 0, 0; 2_147_483_647, 8_388_607; } to_i48 { -2_147_483_648, -140_737_488_355_328; 0, 0; 2_147_483_647, 140_737_488_289_792; } to_i64 { -2_147_483_648, -9_223_372_036_854_775_808; 0, 0; 2_147_483_647, 9_223_372_032_559_808_512; } to_u8 { -2_147_483_648, 0; 0, 128; 2_147_483_647, 255; } to_u16 { -2_147_483_648, 0; 0, 32_768; 2_147_483_647, 65_535; } to_u24 { -2_147_483_648, 0; 0, 8_388_608; 2_147_483_647, 16_777_215; } to_u32 { -2_147_483_648, 0; 0, 2_147_483_648; 2_147_483_647, 4_294_967_295; } to_u48 { -2_147_483_648, 0; 0, 140_737_488_355_328; 2_147_483_647, 281_474_976_645_120; } to_u64 { -2_147_483_648, 0; 0, 9_223_372_036_854_775_808; 2_147_483_647, 18_446_744_069_414_584_320; } to_f32 { -2_147_483_648, -1.0; 0, 0.0; } to_f64 { -2_147_483_648, -1.0; 0, 0.0; } }); tests!(I48: i48 { to_i8 { -140_737_488_355_328, -128; 0, 0; 140_737_488_355_327, 127; } to_i16 { -140_737_488_355_328, -32_768; 0, 0; 140_737_488_355_327, 32_767; } to_i24 { -140_737_488_355_328, -8_388_608; 0, 0; 140_737_488_355_327, 8_388_607; } to_i32 { -140_737_488_355_328, -2_147_483_648; 0, 0; 140_737_488_355_327, 2_147_483_647; } to_i64 { -140_737_488_355_328, -9_223_372_036_854_775_808; 0, 0; 140_737_488_355_327, 9_223_372_036_854_710_272; } to_u8 { -140_737_488_355_328, 0; 0, 128; 140_737_488_355_327, 255; } to_u16 { -140_737_488_355_328, 0; 0, 32_768; 140_737_488_355_327, 65_535; } to_u24 { -140_737_488_355_328, 0; 0, 8_388_608; 140_737_488_355_327, 16_777_215; } to_u32 { -140_737_488_355_328, 0; 0, 2_147_483_648; 140_737_488_355_327, 4_294_967_295; } to_u48 { -140_737_488_355_328, 0; 0, 140_737_488_355_328; 140_737_488_355_327, 281_474_976_710_655; } to_u64 { -140_737_488_355_328, 0; 0, 9_223_372_036_854_775_808; 140_737_488_355_327, 18_446_744_073_709_486_080; } }); tests!(i64 { to_i8 { -9_223_372_036_854_775_808, -128; 0, 0; 9_223_372_036_854_775_807, 127; } to_i16 { -9_223_372_036_854_775_808, -32_768; 0, 0; 9_223_372_036_854_775_807, 32_767; } to_i24 { -9_223_372_036_854_775_808, -8_388_608; 0, 0; 9_223_372_036_854_775_807, 8_388_607; } to_i32 { -9_223_372_036_854_775_808, -2_147_483_648; 0, 0; 9_223_372_036_854_775_807, 2_147_483_647; } to_i48 { -9_223_372_036_854_775_808, -140_737_488_355_328; 0, 0; 9_223_372_036_854_775_807, 140_737_488_355_327; } to_u8 { -9_223_372_036_854_775_808, 0; 0, 128; 9_223_372_036_854_775_807, 255; } to_u16 { -9_223_372_036_854_775_808, 0; 0, 32_768; 9_223_372_036_854_775_807, 65_535; } to_u24 { -9_223_372_036_854_775_808, 0; 0, 8_388_608; 9_223_372_036_854_775_807, 16_777_215; } to_u32 { -9_223_372_036_854_775_808, 0; 0, 2_147_483_648; 9_223_372_036_854_775_807, 4_294_967_295; } to_u48 { -9_223_372_036_854_775_808, 0; 0, 140_737_488_355_328; 9_223_372_036_854_775_807, 281_474_976_710_655; } to_u64 { -9_223_372_036_854_775_808, 0; 0, 9_223_372_036_854_775_808; 9_223_372_036_854_775_807, 18_446_744_073_709_551_615; } to_f32 { -9_223_372_036_854_775_808, -1.0; 0, 0.0; } to_f64 { -9_223_372_036_854_775_808, -1.0; 0, 0.0; } }); tests!(u8 { to_i8 { 0, -128; 128, 0; 255, 127; } to_i16 { 0, -32_768; 128, 0; 255, 32_512; } to_i24 { 0, -8_388_608; 128, 0; 255, 8_323_072; } to_i32 { 0, -2_147_483_648; 128, 0; 255, 2_130_706_432; } to_i48 { 0, -140_737_488_355_328; 128, 0; 255, 139_637_976_727_552; } to_i64 { 0, -9_223_372_036_854_775_808; 128, 0; 255, 9_151_314_442_816_847_872; } to_u16 { 0, 0; 128, 32_768; 255, 65_280; } to_u24 { 0, 0; 128, 8_388_608; 255, 16_711_680; } to_u32 { 0, 0; 128, 2_147_483_648; 255, 4_278_190_080; } to_u48 { 0, 0; 128, 140_737_488_355_328; 255, 280_375_465_082_880; } to_u64 { 0, 0; 128, 9_223_372_036_854_775_808; 255, 18_374_686_479_671_623_680; } to_f32 { 0, -1.0; 128, 0.0; } to_f64 { 0, -1.0; 128, 0.0; } }); tests!(u16 { to_i8 { 0, -128; 32_768, 0; 65_535, 127; } to_i16 { 0, -32_768; 32_768, 0; 65_535, 32_767; } to_i24 { 0, -8_388_608; 32_768, 0; 65_535, 8_388_352; } to_i32 { 0, -2_147_483_648; 32_768, 0; 65_535, 2_147_418_112; } to_i48 { 0, -140_737_488_355_328; 32_768, 0; 65_535, 140_733_193_388_032; } to_i64 { 0, -9_223_372_036_854_775_808; 32_768, 0; 65_535, 9_223_090_561_878_065_152; } to_u8 { 0, 0; 32_768, 128; 65_535, 255; } to_u24 { 0, 0; 32_768, 8_388_608; 65_535, 16_776_960; } to_u32 { 0, 0; 32_768, 2_147_483_648; 65_535, 4_294_901_760; } to_u48 { 0, 0; 32_768, 140_737_488_355_328; 65_535, 281_470_681_743_360; } to_u64 { 0, 0; 32_768, 9_223_372_036_854_775_808; 65_535, 18_446_462_598_732_840_960; } to_f32 { 0, -1.0; 32_768, 0.0; } to_f64 { 0, -1.0; 32_768, 0.0; } }); tests!(U24: u24 { to_i8 { 0, -128; 8_388_608, 0; 16_777_215, 127; } to_i16 { 0, -32_768; 8_388_608, 0; 16_777_215, 32_767; } to_i24 { 0, -8_388_608; 8_388_608, 0; 16_777_215, 8_388_607; } to_i32 { 0, -2_147_483_648; 8_388_608, 0; 16_777_215, 2_147_483_392; } to_i48 { 0, -140_737_488_355_328; 8_388_608, 0; 16_777_215, 140_737_471_578_112; } to_i64 { 0, -9_223_372_036_854_775_808; 8_388_608, 0; 16_777_215, 9_223_370_937_343_148_032; } to_u8 { 0, 0; 8_388_608, 128; 16_777_215, 255; } to_u16 { 0, 0; 8_388_608, 32_768; 16_777_215, 65_535; } to_u32 { 0, 0; 8_388_608, 2_147_483_648; 16_777_215, 4_294_967_040; } to_u48 { 0, 0; 8_388_608, 140_737_488_355_328; 16_777_215, 281_474_959_933_440; } to_u64 { 0, 0; 8_388_608, 9_223_372_036_854_775_808; 16_777_215, 18_446_742_974_197_923_840; } to_f32 { 0, -1.0; 8_388_608, 0.0; } to_f64 { 0, -1.0; 8_388_608, 0.0; } }); tests!(u32 { to_i8 { 0, -128; 2_147_483_648, 0; 4_294_967_295, 127; } to_i16 { 0, -32_768; 2_147_483_648, 0; 4_294_967_295, 32_767; } to_i24 { 0, -8_388_608; 2_147_483_648, 0; 4_294_967_295, 8_388_607; } to_i32 { 0, -2_147_483_648; 2_147_483_648, 0; 4_294_967_295, 2_147_483_647; } to_i48 { 0, -140_737_488_355_328; 2_147_483_648, 0; 4_294_967_295, 140_737_488_289_792; } to_i64 { 0, -9_223_372_036_854_775_808; 2_147_483_648, 0; 4_294_967_295, 9_223_372_032_559_808_512; } to_u8 { 0, 0; 2_147_483_648, 128; 4_294_967_295, 255; } to_u16 { 0, 0; 2_147_483_648, 32_768; 4_294_967_295, 65_535; } to_u24 { 0, 0; 2_147_483_648, 8_388_608; 4_294_967_295, 16_777_215; } to_u48 { 0, 0; 2_147_483_648, 140_737_488_355_328; 4_294_967_295, 281_474_976_645_120; } to_u64 { 0, 0; 2_147_483_648, 9_223_372_036_854_775_808; 4_294_967_295, 18_446_744_069_414_584_320; } to_f32 { 0, -1.0; 2_147_483_648, 0.0; } to_f64 { 0, -1.0; 2_147_483_648, 0.0; } }); tests!(U48: u48 { to_i8 { 0, -128; 140_737_488_355_328, 0; 281_474_976_710_655, 127; } to_i16 { 0, -32_768; 140_737_488_355_328, 0; 281_474_976_710_655, 32_767; } to_i24 { 0, -8_388_608; 140_737_488_355_328, 0; 281_474_976_710_655, 8_388_607; } to_i32 { 0, -2_147_483_648; 140_737_488_355_328, 0; 281_474_976_710_655, 2_147_483_647; } to_i48 { 0, -140_737_488_355_328; 140_737_488_355_328, 0; 281_474_976_710_655, 140_737_488_355_327; } to_i64 { 0, -9_223_372_036_854_775_808; 140_737_488_355_328, 0; 281_474_976_710_655, 9_223_372_036_854_710_272; } to_u8 { 0, 0; 140_737_488_355_328, 128; 281_474_976_710_655, 255; } to_u16 { 0, 0; 140_737_488_355_328, 32_768; 281_474_976_710_655, 65_535; } to_u24 { 0, 0; 140_737_488_355_328, 8_388_608; 281_474_976_710_655, 16_777_215; } to_u32 { 0, 0; 140_737_488_355_328, 2_147_483_648; 281_474_976_710_655, 4_294_967_295; } to_u64 { 0, 0; 140_737_488_355_328, 9_223_372_036_854_775_808; 281_474_976_710_655, 18_446_744_073_709_486_080; } to_f32 { 0, -1.0; 140_737_488_355_328, 0.0; } to_f64 { 0, -1.0; 140_737_488_355_328, 0.0; } }); tests!(u64 { to_i8 { 0, -128; 9_223_372_036_854_775_808, 0; 18_446_744_073_709_551_615, 127; } to_i16 { 0, -32_768; 9_223_372_036_854_775_808, 0; 18_446_744_073_709_551_615, 32_767; } to_i24 { 0, -8_388_608; 9_223_372_036_854_775_808, 0; 18_446_744_073_709_551_615, 8_388_607; } to_i32 { 0, -2_147_483_648; 9_223_372_036_854_775_808, 0; 18_446_744_073_709_551_615, 2_147_483_647; } to_i48 { 0, -140_737_488_355_328; 9_223_372_036_854_775_808, 0; 18_446_744_073_709_551_615, 140_737_488_355_327; } to_i64 { 0, -9_223_372_036_854_775_808; 9_223_372_036_854_775_808, 0; 18_446_744_073_709_551_615, 9_223_372_036_854_775_807; } to_u8 { 0, 0; 9_223_372_036_854_775_808, 128; 18_446_744_073_709_551_615, 255; } to_u16 { 0, 0; 9_223_372_036_854_775_808, 32_768; 18_446_744_073_709_551_615, 65_535; } to_u24 { 0, 0; 9_223_372_036_854_775_808, 8_388_608; 18_446_744_073_709_551_615, 16_777_215; } to_u32 { 0, 0; 9_223_372_036_854_775_808, 2_147_483_648; 18_446_744_073_709_551_615, 4_294_967_295; } to_u48 { 0, 0; 9_223_372_036_854_775_808, 140_737_488_355_328; 18_446_744_073_709_551_615, 281_474_976_710_655; } to_f32 { 0, -1.0; 9_223_372_036_854_775_808, 0.0; } to_f64 { 0, -1.0; 9_223_372_036_854_775_808, 0.0; } }); tests!(f32 { to_i8 { -1.0, -128; 0.0, 0; } to_i16 { -1.0, -32_768; 0.0, 0; } to_i24 { -1.0, -8_388_608; 0.0, 0; } to_i32 { -1.0, -2_147_483_648; 0.0, 0; } to_i48 { -1.0, -140_737_488_355_328; 0.0, 0; } to_i64 { -1.0, -9_223_372_036_854_775_808; 0.0, 0; } to_u8 { -1.0, 0; 0.0, 128; } to_u16 { -1.0, 0; 0.0, 32_768; } to_u24 { -1.0, 0; 0.0, 8_388_608; } to_u32 { -1.0, 0; 0.0, 2_147_483_648; } to_u48 { -1.0, 0; 0.0, 140_737_488_355_328; } to_u64 { -1.0, 0; 0.0, 9_223_372_036_854_775_808; } to_f64 { -1.0, -1.0; 0.0, 0.0; } }); tests!(f64 { to_i8 { -1.0, -128; 0.0, 0; } to_i16 { -1.0, -32_768; 0.0, 0; } to_i24 { -1.0, -8_388_608; 0.0, 0; } to_i32 { -1.0, -2_147_483_648; 0.0, 0; } to_i48 { -1.0, -140_737_488_355_328; 0.0, 0; } to_i64 { -1.0, -9_223_372_036_854_775_808; 0.0, 0; } to_u8 { -1.0, 0; 0.0, 128; } to_u16 { -1.0, 0; 0.0, 32_768; } to_u24 { -1.0, 0; 0.0, 8_388_608; } to_u32 { -1.0, 0; 0.0, 2_147_483_648; } to_u48 { -1.0, 0; 0.0, 140_737_488_355_328; } to_u64 { -1.0, 0; 0.0, 9_223_372_036_854_775_808; } to_f32 { -1.0, -1.0; 0.0, 0.0; } }); dasp_sample-0.11.0/tests/types.rs010064400017510000164000000052411366425513200151660ustar0000000000000000/// Expands to a unique module with a variety of tests for the given sample newtype. /// /// Tests include basic operations and over/underflow checks. macro_rules! test_type { ($T:ident, $mod_name:ident) => { mod $mod_name { #[test] fn ops() { use dasp_sample::types::$mod_name::$T; assert_eq!( $T::new(8).unwrap() + $T::new(12).unwrap(), $T::new(20).unwrap() ); assert_eq!( $T::new(12).unwrap() - $T::new(4).unwrap(), $T::new(8).unwrap() ); assert_eq!( $T::new(2).unwrap() * $T::new(2).unwrap(), $T::new(4).unwrap() ); assert_eq!( $T::new(3).unwrap() * $T::new(3).unwrap(), $T::new(9).unwrap() ); assert_eq!( $T::new(5).unwrap() * $T::new(10).unwrap(), $T::new(50).unwrap() ); assert_eq!( $T::new(16).unwrap() / $T::new(8).unwrap(), $T::new(2).unwrap() ); assert_eq!( $T::new(8).unwrap() % $T::new(3).unwrap(), $T::new(2).unwrap() ); } #[cfg(debug_assertions)] #[test] #[should_panic] fn add_panic_debug() { use dasp_sample::types::$mod_name::{self, $T}; let _ = $mod_name::MAX + $T::new(1).unwrap(); } #[cfg(debug_assertions)] #[test] #[should_panic] fn sub_panic_debug() { use dasp_sample::types::$mod_name::{self, $T}; let _ = $mod_name::MIN - $T::new(1).unwrap(); } #[cfg(debug_assertions)] #[test] #[should_panic] fn mul_panic_debug() { use dasp_sample::types::$mod_name::{self, $T}; let _ = $mod_name::MAX * $T::new(2).unwrap(); } #[cfg(not(debug_assertions))] #[test] fn release_wrapping() { use dasp_sample::types::$mod_name::{self, $T}; assert_eq!($mod_name::MIN - $T::new(1).unwrap(), $mod_name::MAX); assert_eq!($mod_name::MAX + $T::new(1).unwrap(), $mod_name::MIN); } } }; } test_type!(I11, i11); test_type!(U11, u11); test_type!(I20, i20); test_type!(U20, u20); test_type!(I24, i24); test_type!(U24, u24); test_type!(I48, i48); test_type!(U48, u48);