sample/
lib.rs

1//! A crate of fundamentals for audio PCM DSP.
2//!
3//! - Use the [**Sample** trait](./trait.Sample.html) to remain generic across bit-depth.
4//! - Use the [**Frame** trait](./frame/trait.Frame.html) to remain generic over channel layout.
5//! - Use the [**Signal** trait](./signal/trait.Signal.html) for working with **Iterators** that yield **Frames**.
6//! - Use the [**slice** module](./slice/index.html) for working with slices of **Samples** and **Frames**.
7//! - See the [**conv** module](./conv/index.html) for fast conversions between slices, frames and samples.
8//! - See the [**types** module](./types/index.html) for provided custom sample types.
9//! - See the [**interpolate** module](./interpolate/index.html) for sample rate conversion and scaling.
10//! - See the [**ring_buffer** module](./ring_buffer/index.html) for fast FIFO queue options.
11
12#![recursion_limit="512"]
13#![cfg_attr(not(feature = "std"), no_std)]
14#![cfg_attr(not(feature = "std"), feature(alloc, core_intrinsics))]
15
16#[cfg(feature = "std")]
17extern crate core;
18
19#[cfg(not(feature = "std"))]
20extern crate alloc;
21
22#[cfg(not(feature = "std"))]
23type BTreeMap<K, V> = alloc::collections::btree_map::BTreeMap<K, V>;
24#[cfg(feature = "std")]
25type BTreeMap<K, V> = std::collections::BTreeMap<K, V>;
26
27#[cfg(not(feature = "std"))]
28type Vec<T> = alloc::vec::Vec<T>;
29#[cfg(feature = "std")]
30#[allow(dead_code)]
31type Vec<T> = std::vec::Vec<T>;
32
33#[cfg(not(feature = "std"))]
34type VecDeque<T> = alloc::collections::vec_deque::VecDeque<T>;
35#[cfg(feature = "std")]
36type VecDeque<T> = std::collections::vec_deque::VecDeque<T>;
37
38#[cfg(not(feature = "std"))]
39pub type Box<T> = alloc::boxed::Box<T>;
40#[cfg(feature = "std")]
41pub type Box<T> = std::boxed::Box<T>;
42
43#[cfg(not(feature = "std"))]
44type Rc<T> = alloc::rc::Rc<T>;
45#[cfg(feature = "std")]
46type Rc<T> = std::rc::Rc<T>;
47
48pub use conv::{FromSample, ToSample, Duplex, FromSampleSlice, ToSampleSlice, DuplexSampleSlice,
49               FromSampleSliceMut, ToSampleSliceMut, DuplexSampleSliceMut, FromBoxedSampleSlice,
50               ToBoxedSampleSlice, DuplexBoxedSampleSlice, FromFrameSlice, ToFrameSlice,
51               DuplexFrameSlice, FromFrameSliceMut, ToFrameSliceMut, DuplexFrameSliceMut,
52               FromBoxedFrameSlice, ToBoxedFrameSlice, DuplexBoxedFrameSlice, DuplexSlice,
53               DuplexSliceMut, DuplexBoxedSlice};
54pub use frame::Frame;
55pub use signal::Signal;
56pub use types::{I24, U24, I48, U48};
57
58pub mod slice;
59pub mod conv;
60pub mod envelope;
61pub mod frame;
62pub mod peak;
63pub mod ring_buffer;
64pub mod rms;
65pub mod signal;
66pub mod types;
67pub mod window;
68pub mod interpolate;
69
70mod ops {
71    pub mod f32 {
72        #[allow(unused_imports)]
73        use core;
74
75        #[cfg(not(feature = "std"))]
76        pub fn sqrt(x: f32) -> f32 {
77            unsafe { core::intrinsics::sqrtf32(x) }
78        }
79        #[cfg(feature = "std")]
80        pub fn sqrt(x: f32) -> f32 {
81            x.sqrt()
82        }
83
84        #[cfg(feature = "std")]
85        pub fn powf32(a: f32, b: f32) -> f32 {
86            a.powf(b)
87        }
88        #[cfg(not(feature = "std"))]
89        pub fn powf32(a: f32, b: f32) -> f32 {
90            unsafe { core::intrinsics::powf32(a, b) }
91        }
92    }
93
94    pub mod f64 {
95        #[allow(unused_imports)]
96        use core;
97
98        #[cfg(not(feature = "std"))]
99        pub fn floor(x: f64) -> f64 {
100            unsafe { core::intrinsics::floorf64(x) }
101        }
102        #[cfg(feature = "std")]
103        pub fn floor(x: f64) -> f64 {
104            x.floor()
105        }
106
107        #[cfg(not(feature = "std"))]
108        #[allow(dead_code)]
109        pub fn ceil(x: f64) -> f64 {
110            unsafe { core::intrinsics::ceilf64(x) }
111        }
112        #[cfg(feature = "std")]
113        #[allow(dead_code)]
114        pub fn ceil(x: f64) -> f64 {
115            x.ceil()
116        }
117
118        #[cfg(not(feature = "std"))]
119        pub fn sin(x: f64) -> f64 {
120            unsafe { core::intrinsics::sinf64(x) }
121        }
122        #[cfg(feature = "std")]
123        pub fn sin(x: f64) -> f64 {
124            x.sin()
125        }
126
127        #[cfg(not(feature = "std"))]
128        pub fn cos(x: f64) -> f64 {
129            unsafe { core::intrinsics::cosf64(x) }
130        }
131        #[cfg(feature = "std")]
132        pub fn cos(x: f64) -> f64 {
133            x.cos()
134        }
135
136        #[cfg(not(feature = "std"))]
137        pub fn sqrt(x: f64) -> f64 {
138            unsafe { core::intrinsics::sqrtf64(x) }
139        }
140        #[cfg(feature = "std")]
141        pub fn sqrt(x: f64) -> f64 {
142            x.sqrt()
143        }
144    }
145}
146
147
148/// A trait for working generically across different **Sample** format types.
149///
150/// Provides methods for converting to and from any type that implements the
151/// [`FromSample`](./trait.FromSample.html) trait and provides methods for performing signal
152/// amplitude addition and multiplication.
153///
154/// # Example
155///
156/// ```rust
157/// extern crate sample;
158///
159/// use sample::{I24, Sample};
160///
161/// fn main() {
162///     assert_eq!((-1.0).to_sample::<u8>(), 0);
163///     assert_eq!(0.0.to_sample::<u8>(), 128);
164///     assert_eq!(0i32.to_sample::<u32>(), 2_147_483_648);
165///     assert_eq!(I24::new(0).unwrap(), Sample::from_sample(0.0));
166///     assert_eq!(0.0, Sample::equilibrium());
167/// }
168/// ```
169pub trait Sample: Copy + Clone + PartialOrd + PartialEq {
170    /// When summing two samples of a signal together, it is necessary for both samples to be
171    /// represented in some signed format. This associated `Addition` type represents the format to
172    /// which `Self` should be converted for optimal `Addition` performance.
173    ///
174    /// For example, u32's optimal `Addition` type would be i32, u8's would be i8, f32's would be
175    /// f32, etc.
176    ///
177    /// Specifying this as an associated type allows us to automatically determine the optimal,
178    /// lossless Addition format type for summing any two unique `Sample` types together.
179    ///
180    /// As a user of the `sample` crate, you will never need to be concerned with this type unless
181    /// you are defining your own unique `Sample` type(s).
182    type Signed: SignedSample + Duplex<Self>;
183
184    /// When multiplying two samples of a signal together, it is necessary for both samples to be
185    /// represented in some signed, floating-point format. This associated `Multiplication` type
186    /// represents the format to which `Self` should be converted for optimal `Multiplication`
187    /// performance.
188    ///
189    /// For example, u32's optimal `Multiplication` type would be f32, u64's would be f64, i8's
190    /// would be f32, etc.
191    ///
192    /// Specifying this as an associated type allows us to automatically determine the optimal,
193    /// lossless Multiplication format type for multiplying any two unique `Sample` types together.
194    ///
195    /// As a user of the `sample` crate, you will never need to be concerned with this type unless
196    /// you are defining your own unique `Sample` type(s).
197    type Float: FloatSample + Duplex<Self>;
198
199    /// The equilibrium value for the wave that this `Sample` type represents. This is normally the
200    /// value that is equal distance from both the min and max ranges of the sample.
201    ///
202    /// # Example
203    ///
204    /// ```rust
205    /// extern crate sample;
206    ///
207    /// use sample::Sample;
208    ///
209    /// fn main() {
210    ///     assert_eq!(0.0, f32::equilibrium());
211    ///     assert_eq!(0, i32::equilibrium());
212    ///     assert_eq!(128, u8::equilibrium());
213    ///     assert_eq!(32_768_u16, Sample::equilibrium());
214    /// }
215    /// ```
216    ///
217    /// **Note:** This will likely be changed to an "associated const" if the feature lands.
218    fn equilibrium() -> Self;
219
220    /// The multiplicative identity of the signal.
221    ///
222    /// In other words: A value which when used to scale/multiply the amplitude or frequency of a
223    /// signal, returns the same signal.
224    ///
225    /// This is useful as a default, non-affecting amplitude or frequency multiplier.
226    ///
227    /// # Example
228    ///
229    /// ```rust
230    /// extern crate sample;
231    ///
232    /// use sample::{Sample, U48};
233    ///
234    /// fn main() {
235    ///     assert_eq!(1.0, f32::identity());
236    ///     assert_eq!(1.0, i8::identity());
237    ///     assert_eq!(1.0, u8::identity());
238    ///     assert_eq!(1.0, U48::identity());
239    /// }
240    /// ```
241    #[inline]
242    fn identity() -> Self::Float {
243        <Self::Float as FloatSample>::identity()
244    }
245
246    /// Convert `self` to any type that implements `FromSample<Self>`.
247    ///
248    /// Find more details on type-specific conversion ranges and caveats in the `conv` module.
249    ///
250    /// # Example
251    ///
252    /// ```rust
253    /// extern crate sample;
254    ///
255    /// use sample::Sample;
256    ///
257    /// fn main() {
258    ///     assert_eq!(0.0.to_sample::<i32>(), 0);
259    ///     assert_eq!(0.0.to_sample::<u8>(), 128);
260    ///     assert_eq!((-1.0).to_sample::<u8>(), 0);
261    /// }
262    /// ```
263    #[inline]
264    fn to_sample<S>(self) -> S
265    where
266        Self: ToSample<S>,
267    {
268        self.to_sample_()
269    }
270
271    /// Create a `Self` from any type that implements `ToSample<Self>`.
272    ///
273    /// Find more details on type-specific conversion ranges and caveats in the `conv` module.
274    ///
275    /// # Example
276    ///
277    /// ```rust
278    /// extern crate sample;
279    ///
280    /// use sample::{Sample, I24};
281    ///
282    /// fn main() {
283    ///     assert_eq!(f32::from_sample(128_u8), 0.0);
284    ///     assert_eq!(i8::from_sample(-1.0), -128);
285    ///     assert_eq!(I24::from_sample(0.0), I24::new(0).unwrap());
286    /// }
287    /// ```
288    #[inline]
289    fn from_sample<S>(s: S) -> Self
290    where
291        Self: FromSample<S>,
292    {
293        FromSample::from_sample_(s)
294    }
295
296    /// Converts `self` to the equivalent `Sample` in the associated `Signed` format.
297    ///
298    /// This is a simple wrapper around `Sample::to_sample` which may provide extra convenience in
299    /// some cases, particularly for assisting type inference.
300    ///
301    /// # Example
302    ///
303    /// ```rust
304    /// extern crate sample;
305    ///
306    /// use sample::Sample;
307    ///
308    /// fn main() {
309    ///     assert_eq!(128_u8.to_signed_sample(), 0i8);
310    /// }
311    /// ```
312    fn to_signed_sample(self) -> Self::Signed {
313        self.to_sample()
314    }
315
316    /// Converts `self` to the equivalent `Sample` in the associated `Float` format.
317    ///
318    /// This is a simple wrapper around `Sample::to_sample` which may provide extra convenience in
319    /// some cases, particularly for assisting type inference.
320    ///
321    /// # Example
322    ///
323    /// ```rust
324    /// extern crate sample;
325    ///
326    /// use sample::Sample;
327    ///
328    /// fn main() {
329    ///     assert_eq!(128_u8.to_float_sample(), 0.0);
330    /// }
331    /// ```
332    fn to_float_sample(self) -> Self::Float {
333        self.to_sample()
334    }
335
336    /// Adds (or "offsets") the amplitude of the `Sample` by the given signed amplitude.
337    ///
338    /// `Self` will be converted to `Self::Signed`, the addition will occur and then the result
339    /// will be converted back to `Self`. These conversions allow us to correctly handle the
340    /// addition of unsigned signal formats.
341    ///
342    /// # Example
343    ///
344    /// ```rust
345    /// extern crate sample;
346    ///
347    /// use sample::Sample;
348    ///
349    /// fn main() {
350    ///     assert_eq!(0.25.add_amp(0.5), 0.75);
351    ///     assert_eq!(192u8.add_amp(-128), 64);
352    /// }
353    /// ```
354    #[inline]
355    fn add_amp(self, amp: Self::Signed) -> Self {
356        let self_s = self.to_signed_sample();
357        (self_s + amp).to_sample()
358    }
359
360    /// Multiplies (or "scales") the amplitude of the `Sample` by the given float amplitude.
361    ///
362    /// - `amp` > 1.0 amplifies the sample.
363    /// - `amp` < 1.0 attenuates the sample.
364    /// - `amp` == 1.0 yields the same sample.
365    /// - `amp` == 0.0 yields the `Sample::equilibrium`.
366    ///
367    /// `Self` will be converted to `Self::Float`, the multiplication will occur and then the
368    /// result will be converted back to `Self`. These conversions allow us to correctly handle the
369    /// multiplication of integral signal formats.
370    ///
371    /// # Example
372    ///
373    /// ```rust
374    /// extern crate sample;
375    ///
376    /// use sample::Sample;
377    ///
378    /// fn main() {
379    ///     assert_eq!(64_i8.mul_amp(0.5), 32);
380    ///     assert_eq!(0.5.mul_amp(-2.0), -1.0);
381    ///     assert_eq!(64_u8.mul_amp(0.0), 128);
382    /// }
383    /// ```
384    #[inline]
385    fn mul_amp(self, amp: Self::Float) -> Self {
386        let self_f = self.to_float_sample();
387        (self_f * amp).to_sample()
388    }
389}
390
391/// A macro used to simplify the implementation of `Sample`.
392macro_rules! impl_sample {
393    ($($T:ty:
394       Signed: $Addition:ty,
395       Float: $Modulation:ty,
396       equilibrium: $equilibrium:expr),*) =>
397    {
398        $(
399            impl Sample for $T {
400                type Signed = $Addition;
401                type Float = $Modulation;
402                #[inline]
403                fn equilibrium() -> Self {
404                    $equilibrium
405                }
406            }
407        )*
408    }
409}
410
411// Expands to `Sample` implementations for all of the following types.
412impl_sample!{
413    i8:  Signed: i8,  Float: f32, equilibrium: 0,
414    i16: Signed: i16, Float: f32, equilibrium: 0,
415    I24: Signed: I24, Float: f32, equilibrium: types::i24::EQUILIBRIUM,
416    i32: Signed: i32, Float: f32, equilibrium: 0,
417    I48: Signed: I48, Float: f64, equilibrium: types::i48::EQUILIBRIUM,
418    i64: Signed: i64, Float: f64, equilibrium: 0,
419    u8:  Signed: i8,  Float: f32, equilibrium: 128,
420    u16: Signed: i16, Float: f32, equilibrium: 32_768,
421    U24: Signed: i32, Float: f32, equilibrium: types::u24::EQUILIBRIUM,
422    u32: Signed: i32, Float: f32, equilibrium: 2_147_483_648,
423    U48: Signed: i64, Float: f64, equilibrium: types::u48::EQUILIBRIUM,
424    u64: Signed: i64, Float: f64, equilibrium: 9_223_372_036_854_775_808,
425    f32: Signed: f32, Float: f32, equilibrium: 0.0,
426    f64: Signed: f64, Float: f64, equilibrium: 0.0
427}
428
429
430/// Integral and floating-point **Sample** format types whose equilibrium is at 0.
431///
432/// **Sample**s often need to be converted to some mutual **SignedSample** type for signal
433/// addition.
434pub trait SignedSample
435    : Sample<Signed = Self>
436    + core::ops::Add<Output = Self>
437    + core::ops::Sub<Output = Self>
438    + core::ops::Neg<Output = Self> {
439}
440macro_rules! impl_signed_sample { ($($T:ty)*) => { $( impl SignedSample for $T {} )* } }
441impl_signed_sample!(i8 i16 I24 i32 I48 i64 f32 f64);
442
443/// Sample format types represented as floating point numbers.
444///
445/// **Sample**s often need to be converted to some mutual **FloatSample** type for signal scaling
446/// and modulation.
447pub trait FloatSample
448    : Sample<Signed = Self, Float = Self>
449    + SignedSample
450    + core::ops::Mul<Output = Self>
451    + core::ops::Div<Output = Self>
452    + Duplex<f32>
453    + Duplex<f64> {
454    /// Represents the multiplicative identity of the floating point signal.
455    fn identity() -> Self;
456    /// Calculate the square root of `Self`.
457    fn sample_sqrt(self) -> Self;
458}
459
460impl FloatSample for f32 {
461    #[inline]
462    fn identity() -> Self {
463        1.0
464    }
465    #[inline]
466    fn sample_sqrt(self) -> Self {
467        ops::f32::sqrt(self)
468    }
469}
470
471impl FloatSample for f64 {
472    #[inline]
473    fn identity() -> Self {
474        1.0
475    }
476    #[inline]
477    fn sample_sqrt(self) -> Self {
478        ops::f64::sqrt(self)
479    }
480}