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}