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"))]
11extern crate alloc;
12
13pub use conv::{Duplex, FromSample, ToSample};
14pub use types::{I24, I48, U24, U48};
15
16pub mod conv;
17mod ops;
18pub 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/// ```
39pub 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`.
244macro_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.
261impl_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.
282pub 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}
289macro_rules! impl_signed_sample { ($($T:ty)*) => { $( impl SignedSample for $T {} )* } }
290impl_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.
296pub 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
310impl 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
318impl 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