| 1 | //! Use the [**Sample**](./trait.Sample.html) trait to remain generic over sample types, easily |
| 2 | //! access sample type conversions, apply basic audio operations and more. |
| 3 | //! |
| 4 | //! The **Sample** trait is the core abstraction throughout dasp on which most other abstractions |
| 5 | //! are based. |
| 6 | |
| 7 | #![cfg_attr (not(feature = "std" ), no_std)] |
| 8 | #![cfg_attr (not(feature = "std" ), feature(core_intrinsics))] |
| 9 | |
| 10 | #[cfg (not(feature = "std" ))] |
| 11 | extern crate alloc; |
| 12 | |
| 13 | pub use conv::{Duplex, FromSample, ToSample}; |
| 14 | pub use types::{I24, I48, U24, U48}; |
| 15 | |
| 16 | pub mod conv; |
| 17 | mod ops; |
| 18 | pub mod types; |
| 19 | |
| 20 | /// A trait for working generically across different **Sample** format types. |
| 21 | /// |
| 22 | /// Provides methods for converting to and from any type that implements the |
| 23 | /// [`FromSample`](./trait.FromSample.html) trait and provides methods for performing signal |
| 24 | /// amplitude addition and multiplication. |
| 25 | /// |
| 26 | /// # Example |
| 27 | /// |
| 28 | /// ```rust |
| 29 | /// use dasp_sample::{I24, Sample}; |
| 30 | /// |
| 31 | /// fn main() { |
| 32 | /// assert_eq!((-1.0).to_sample::<u8>(), 0); |
| 33 | /// assert_eq!(0.0.to_sample::<u8>(), 128); |
| 34 | /// assert_eq!(0i32.to_sample::<u32>(), 2_147_483_648); |
| 35 | /// assert_eq!(I24::new(0).unwrap(), Sample::from_sample(0.0)); |
| 36 | /// assert_eq!(0.0, Sample::EQUILIBRIUM); |
| 37 | /// } |
| 38 | /// ``` |
| 39 | pub trait Sample: Copy + Clone + PartialOrd + PartialEq { |
| 40 | /// When summing two samples of a signal together, it is necessary for both samples to be |
| 41 | /// represented in some signed format. This associated `Addition` type represents the format to |
| 42 | /// which `Self` should be converted for optimal `Addition` performance. |
| 43 | /// |
| 44 | /// For example, u32's optimal `Addition` type would be i32, u8's would be i8, f32's would be |
| 45 | /// f32, etc. |
| 46 | /// |
| 47 | /// Specifying this as an associated type allows us to automatically determine the optimal, |
| 48 | /// lossless Addition format type for summing any two unique `Sample` types together. |
| 49 | /// |
| 50 | /// As a user of the `sample` crate, you will never need to be concerned with this type unless |
| 51 | /// you are defining your own unique `Sample` type(s). |
| 52 | type Signed: SignedSample + Duplex<Self>; |
| 53 | |
| 54 | /// When multiplying two samples of a signal together, it is necessary for both samples to be |
| 55 | /// represented in some signed, floating-point format. This associated `Multiplication` type |
| 56 | /// represents the format to which `Self` should be converted for optimal `Multiplication` |
| 57 | /// performance. |
| 58 | /// |
| 59 | /// For example, u32's optimal `Multiplication` type would be f32, u64's would be f64, i8's |
| 60 | /// would be f32, etc. |
| 61 | /// |
| 62 | /// Specifying this as an associated type allows us to automatically determine the optimal, |
| 63 | /// lossless Multiplication format type for multiplying any two unique `Sample` types together. |
| 64 | /// |
| 65 | /// As a user of the `sample` crate, you will never need to be concerned with this type unless |
| 66 | /// you are defining your own unique `Sample` type(s). |
| 67 | type Float: FloatSample + Duplex<Self>; |
| 68 | |
| 69 | /// The equilibrium value for the wave that this `Sample` type represents. This is normally the |
| 70 | /// value that is equal distance from both the min and max ranges of the sample. |
| 71 | /// |
| 72 | /// # Example |
| 73 | /// |
| 74 | /// ```rust |
| 75 | /// use dasp_sample::Sample; |
| 76 | /// |
| 77 | /// fn main() { |
| 78 | /// assert_eq!(0.0, f32::EQUILIBRIUM); |
| 79 | /// assert_eq!(0, i32::EQUILIBRIUM); |
| 80 | /// assert_eq!(128, u8::EQUILIBRIUM); |
| 81 | /// assert_eq!(32_768_u16, Sample::EQUILIBRIUM); |
| 82 | /// } |
| 83 | /// ``` |
| 84 | /// |
| 85 | /// **Note:** This will likely be changed to an "associated const" if the feature lands. |
| 86 | const EQUILIBRIUM: Self; |
| 87 | |
| 88 | /// The multiplicative identity of the signal. |
| 89 | /// |
| 90 | /// In other words: A value which when used to scale/multiply the amplitude or frequency of a |
| 91 | /// signal, returns the same signal. |
| 92 | /// |
| 93 | /// This is useful as a default, non-affecting amplitude or frequency multiplier. |
| 94 | /// |
| 95 | /// # Example |
| 96 | /// |
| 97 | /// ```rust |
| 98 | /// use dasp_sample::{Sample, U48}; |
| 99 | /// |
| 100 | /// fn main() { |
| 101 | /// assert_eq!(1.0, f32::IDENTITY); |
| 102 | /// assert_eq!(1.0, i8::IDENTITY); |
| 103 | /// assert_eq!(1.0, u8::IDENTITY); |
| 104 | /// assert_eq!(1.0, U48::IDENTITY); |
| 105 | /// } |
| 106 | /// ``` |
| 107 | const IDENTITY: Self::Float = <Self::Float as FloatSample>::IDENTITY; |
| 108 | |
| 109 | /// Convert `self` to any type that implements `FromSample<Self>`. |
| 110 | /// |
| 111 | /// Find more details on type-specific conversion ranges and caveats in the `conv` module. |
| 112 | /// |
| 113 | /// # Example |
| 114 | /// |
| 115 | /// ```rust |
| 116 | /// use dasp_sample::Sample; |
| 117 | /// |
| 118 | /// fn main() { |
| 119 | /// assert_eq!(0.0.to_sample::<i32>(), 0); |
| 120 | /// assert_eq!(0.0.to_sample::<u8>(), 128); |
| 121 | /// assert_eq!((-1.0).to_sample::<u8>(), 0); |
| 122 | /// } |
| 123 | /// ``` |
| 124 | #[inline ] |
| 125 | fn to_sample<S>(self) -> S |
| 126 | where |
| 127 | Self: ToSample<S>, |
| 128 | { |
| 129 | self.to_sample_() |
| 130 | } |
| 131 | |
| 132 | /// Create a `Self` from any type that implements `ToSample<Self>`. |
| 133 | /// |
| 134 | /// Find more details on type-specific conversion ranges and caveats in the `conv` module. |
| 135 | /// |
| 136 | /// # Example |
| 137 | /// |
| 138 | /// ```rust |
| 139 | /// use dasp_sample::{Sample, I24}; |
| 140 | /// |
| 141 | /// fn main() { |
| 142 | /// assert_eq!(f32::from_sample(128_u8), 0.0); |
| 143 | /// assert_eq!(i8::from_sample(-1.0), -128); |
| 144 | /// assert_eq!(I24::from_sample(0.0), I24::new(0).unwrap()); |
| 145 | /// } |
| 146 | /// ``` |
| 147 | |
| 148 | #[inline ] |
| 149 | fn from_sample<S>(s: S) -> Self |
| 150 | where |
| 151 | Self: FromSample<S>, |
| 152 | { |
| 153 | FromSample::from_sample_(s) |
| 154 | } |
| 155 | |
| 156 | /// Converts `self` to the equivalent `Sample` in the associated `Signed` format. |
| 157 | /// |
| 158 | /// This is a simple wrapper around `Sample::to_sample` which may provide extra convenience in |
| 159 | /// some cases, particularly for assisting type inference. |
| 160 | /// |
| 161 | /// # Example |
| 162 | /// |
| 163 | /// ```rust |
| 164 | /// use dasp_sample::Sample; |
| 165 | /// |
| 166 | /// fn main() { |
| 167 | /// assert_eq!(128_u8.to_signed_sample(), 0i8); |
| 168 | /// } |
| 169 | /// ``` |
| 170 | fn to_signed_sample(self) -> Self::Signed { |
| 171 | self.to_sample() |
| 172 | } |
| 173 | |
| 174 | /// Converts `self` to the equivalent `Sample` in the associated `Float` format. |
| 175 | /// |
| 176 | /// This is a simple wrapper around `Sample::to_sample` which may provide extra convenience in |
| 177 | /// some cases, particularly for assisting type inference. |
| 178 | /// |
| 179 | /// # Example |
| 180 | /// |
| 181 | /// ```rust |
| 182 | /// use dasp_sample::Sample; |
| 183 | /// |
| 184 | /// fn main() { |
| 185 | /// assert_eq!(128_u8.to_float_sample(), 0.0); |
| 186 | /// } |
| 187 | /// ``` |
| 188 | fn to_float_sample(self) -> Self::Float { |
| 189 | self.to_sample() |
| 190 | } |
| 191 | |
| 192 | /// Adds (or "offsets") the amplitude of the `Sample` by the given signed amplitude. |
| 193 | /// |
| 194 | /// `Self` will be converted to `Self::Signed`, the addition will occur and then the result |
| 195 | /// will be converted back to `Self`. These conversions allow us to correctly handle the |
| 196 | /// addition of unsigned signal formats. |
| 197 | /// |
| 198 | /// # Example |
| 199 | /// |
| 200 | /// ```rust |
| 201 | /// use dasp_sample::Sample; |
| 202 | /// |
| 203 | /// fn main() { |
| 204 | /// assert_eq!(0.25.add_amp(0.5), 0.75); |
| 205 | /// assert_eq!(192u8.add_amp(-128), 64); |
| 206 | /// } |
| 207 | /// ``` |
| 208 | #[inline ] |
| 209 | fn add_amp(self, amp: Self::Signed) -> Self { |
| 210 | let self_s = self.to_signed_sample(); |
| 211 | (self_s + amp).to_sample() |
| 212 | } |
| 213 | |
| 214 | /// Multiplies (or "scales") the amplitude of the `Sample` by the given float amplitude. |
| 215 | /// |
| 216 | /// - `amp` > 1.0 amplifies the sample. |
| 217 | /// - `amp` < 1.0 attenuates the sample. |
| 218 | /// - `amp` == 1.0 yields the same sample. |
| 219 | /// - `amp` == 0.0 yields the `Sample::EQUILIBRIUM`. |
| 220 | /// |
| 221 | /// `Self` will be converted to `Self::Float`, the multiplication will occur and then the |
| 222 | /// result will be converted back to `Self`. These conversions allow us to correctly handle the |
| 223 | /// multiplication of integral signal formats. |
| 224 | /// |
| 225 | /// # Example |
| 226 | /// |
| 227 | /// ```rust |
| 228 | /// use dasp_sample::Sample; |
| 229 | /// |
| 230 | /// fn main() { |
| 231 | /// assert_eq!(64_i8.mul_amp(0.5), 32); |
| 232 | /// assert_eq!(0.5.mul_amp(-2.0), -1.0); |
| 233 | /// assert_eq!(64_u8.mul_amp(0.0), 128); |
| 234 | /// } |
| 235 | /// ``` |
| 236 | #[inline ] |
| 237 | fn mul_amp(self, amp: Self::Float) -> Self { |
| 238 | let self_f = self.to_float_sample(); |
| 239 | (self_f * amp).to_sample() |
| 240 | } |
| 241 | } |
| 242 | |
| 243 | /// A macro used to simplify the implementation of `Sample`. |
| 244 | macro_rules! impl_sample { |
| 245 | ($($T:ty: |
| 246 | Signed: $Addition:ty, |
| 247 | Float: $Modulation:ty, |
| 248 | EQUILIBRIUM: $EQUILIBRIUM:expr),*) => |
| 249 | { |
| 250 | $( |
| 251 | impl Sample for $T { |
| 252 | type Signed = $Addition; |
| 253 | type Float = $Modulation; |
| 254 | const EQUILIBRIUM: Self = $EQUILIBRIUM; |
| 255 | } |
| 256 | )* |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | // Expands to `Sample` implementations for all of the following types. |
| 261 | impl_sample! { |
| 262 | i8: Signed: i8, Float: f32, EQUILIBRIUM: 0, |
| 263 | i16: Signed: i16, Float: f32, EQUILIBRIUM: 0, |
| 264 | I24: Signed: I24, Float: f32, EQUILIBRIUM: types::i24::EQUILIBRIUM, |
| 265 | i32: Signed: i32, Float: f32, EQUILIBRIUM: 0, |
| 266 | I48: Signed: I48, Float: f64, EQUILIBRIUM: types::i48::EQUILIBRIUM, |
| 267 | i64: Signed: i64, Float: f64, EQUILIBRIUM: 0, |
| 268 | u8: Signed: i8, Float: f32, EQUILIBRIUM: 128, |
| 269 | u16: Signed: i16, Float: f32, EQUILIBRIUM: 32_768, |
| 270 | U24: Signed: i32, Float: f32, EQUILIBRIUM: types::u24::EQUILIBRIUM, |
| 271 | u32: Signed: i32, Float: f32, EQUILIBRIUM: 2_147_483_648, |
| 272 | U48: Signed: i64, Float: f64, EQUILIBRIUM: types::u48::EQUILIBRIUM, |
| 273 | u64: Signed: i64, Float: f64, EQUILIBRIUM: 9_223_372_036_854_775_808, |
| 274 | f32: Signed: f32, Float: f32, EQUILIBRIUM: 0.0, |
| 275 | f64: Signed: f64, Float: f64, EQUILIBRIUM: 0.0 |
| 276 | } |
| 277 | |
| 278 | /// Integral and floating-point **Sample** format types whose equilibrium is at 0. |
| 279 | /// |
| 280 | /// **Sample**s often need to be converted to some mutual **SignedSample** type for signal |
| 281 | /// addition. |
| 282 | pub trait SignedSample: |
| 283 | Sample<Signed = Self> |
| 284 | + core::ops::Add<Output = Self> |
| 285 | + core::ops::Sub<Output = Self> |
| 286 | + core::ops::Neg<Output = Self> |
| 287 | { |
| 288 | } |
| 289 | macro_rules! impl_signed_sample { ($($T:ty)*) => { $( impl SignedSample for $T {} )* } } |
| 290 | impl_signed_sample!(i8 i16 I24 i32 I48 i64 f32 f64); |
| 291 | |
| 292 | /// Sample format types represented as floating point numbers. |
| 293 | /// |
| 294 | /// **Sample**s often need to be converted to some mutual **FloatSample** type for signal scaling |
| 295 | /// and modulation. |
| 296 | pub trait FloatSample: |
| 297 | Sample<Signed = Self, Float = Self> |
| 298 | + SignedSample |
| 299 | + core::ops::Mul<Output = Self> |
| 300 | + core::ops::Div<Output = Self> |
| 301 | + Duplex<f32> |
| 302 | + Duplex<f64> |
| 303 | { |
| 304 | /// Represents the multiplicative identity of the floating point signal. |
| 305 | const IDENTITY: Self; |
| 306 | /// Calculate the square root of `Self`. |
| 307 | fn sample_sqrt(self) -> Self; |
| 308 | } |
| 309 | |
| 310 | impl FloatSample for f32 { |
| 311 | const IDENTITY: Self = 1.0; |
| 312 | #[inline ] |
| 313 | fn sample_sqrt(self) -> Self { |
| 314 | ops::f32::sqrt(self) |
| 315 | } |
| 316 | } |
| 317 | |
| 318 | impl FloatSample for f64 { |
| 319 | const IDENTITY: Self = 1.0; |
| 320 | #[inline ] |
| 321 | fn sample_sqrt(self) -> Self { |
| 322 | ops::f64::sqrt(self) |
| 323 | } |
| 324 | } |
| 325 | |