ezk_audio/
sample_format.rs

1use crate::{Sample, I24, U24};
2use byte_slice_cast::AsByteSlice;
3use ezk::ValueRange;
4use std::alloc::Layout;
5use std::any::TypeId;
6use std::collections::VecDeque;
7use std::fmt;
8use std::mem::take;
9
10impl Format {
11    #[must_use]
12    pub fn is_float(self) -> bool {
13        matches!(self, Self::F32 | Self::F64)
14    }
15}
16
17macro_rules! sample_formats {
18    ($($variant:ident: $T:ident, $bits:expr;)+) => {
19        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
20        pub enum Format {
21            $($variant,)+
22        }
23
24        impl Format {
25            #[must_use]
26            pub fn all() -> ValueRange<Self> {
27                ValueRange::AnyOf(vec![
28                    $(ValueRange::Value(Self::$variant),)+
29                ])
30            }
31
32            #[must_use]
33            pub const fn bits_per_sample(&self) -> usize {
34                match self {
35                    $(Self::$variant => $bits,)+
36                }
37            }
38
39            #[must_use]
40            pub const fn bytes_per_sample(&self) -> usize {
41                self.bits_per_sample().div_ceil(8)
42            }
43        }
44
45        #[derive(Clone, PartialEq)]
46        pub enum Samples {
47            $($variant (Vec<$T>),)+
48        }
49
50        impl Samples {
51            #[must_use]
52            pub const fn empty(format: Format) -> Self {
53                match format {
54                    $(Format::$variant => Self::$variant(Vec::new()),)+
55                }
56            }
57
58            /// Create a new [`Samples`] filled with `len` amount of equilibrium samples (silence)
59            #[must_use]
60            pub fn equilibrium(format: Format, len: usize) -> Self {
61                match format {
62                    $(Format::$variant => Self::$variant(vec![<$T as Sample>::equilibrium(); len]),)+
63                }
64            }
65
66            #[must_use]
67            pub fn with_capacity(format: Format, capacity: usize) -> Self {
68                match format {
69                    $(Format::$variant => Self::$variant(Vec::with_capacity(capacity)),)+
70                }
71            }
72
73            /// Returns the amount of samples in the buffer
74            #[must_use]
75            pub fn len(&self) -> usize {
76                match self {
77                    $(Self::$variant(vec) => vec.len(),)+
78                }
79            }
80
81            #[must_use]
82            pub fn is_empty(&self) -> bool {
83                self.len() == 0
84            }
85
86            /// Returns the sample format of the buffer
87            #[must_use]
88            pub fn format(&self) -> Format {
89                match self {
90                    $(Self::$variant(..) => Format::$variant,)+
91                }
92            }
93
94            #[must_use]
95            pub fn as_bytes(&self) -> &[u8] {
96                match self {
97                    $(Self::$variant(v) => v.as_byte_slice(),)*
98                }
99            }
100
101            #[must_use]
102            pub fn from_ne_bytes(format: Format, bytes: &[u8]) -> Self {
103                if cfg!(target_endian = "big") {
104                    Self::from_be_bytes(format, bytes)
105                } else {
106                    Self::from_le_bytes(format, bytes)
107                }
108            }
109
110            #[must_use]
111            pub fn from_be_bytes(format: Format, bytes: &[u8]) -> Self {
112                let bytes_per_sample = format.bytes_per_sample();
113                assert_eq!(bytes.len() % bytes_per_sample, 0);
114
115                match format {
116                    $(Format::$variant => {
117                        Self::$variant(
118                            bytes
119                                .chunks_exact(bytes_per_sample)
120                                .map(|chunk| {
121                                    $T::from_be_bytes(chunk.try_into().expect("from_be_bytes must accept size_of::<Self> amount of bytes"))
122                                })
123                                .collect()
124                        )
125                    },)+
126                }
127            }
128
129            #[must_use]
130            pub fn from_le_bytes(format: Format, bytes: &[u8]) -> Self {
131                let bytes_per_sample = format.bytes_per_sample();
132                assert_eq!(bytes.len() % bytes_per_sample, 0);
133
134                match format {
135                    $(Format::$variant => {
136                        Self::$variant(
137                            bytes
138                                .chunks_exact(bytes_per_sample)
139                                .map(|chunk| {
140                                    $T::from_le_bytes(chunk.try_into().expect("from_le_bytes must accept size_of::<Self> amount of bytes"))
141                                })
142                                .collect()
143                        )
144                    },)+
145                }
146            }
147
148            /// Returns self in a vector of the provided sample type
149            #[must_use]
150            pub fn into_samples<S: Sample>(self) -> Vec<S> {
151                match self {
152                    $(
153                        Self::$variant(mut v) =>  {
154                            if TypeId::of::<$T>() == TypeId::of::<S>() {
155                                // Safety; Just checked that T and S are the same type
156                                unsafe { std::mem::transmute::<Vec<$T>, Vec<S>>(v) }
157                            } else if Layout::new::<$T>() == Layout::new::<S>() {
158                                // Safety: Just checked that the memory layout of $T and S are the same
159                                unsafe { convert_with_dst_and_src_type_inplace(&mut v) }
160                            } else {
161                                v.into_iter().map(|s| s.to_sample::<S>()).collect()
162                            }
163                        },
164                    )*
165                }
166            }
167
168            /// Creates a copy of the samples in the given format
169            #[must_use]
170            pub fn to_samples<S: Sample>(&self) -> Vec<S> {
171                match self {
172                    $(
173                        Self::$variant(v) => v.iter().map(|s| s.to_sample::<S>()).collect(),
174                    )*
175                }
176            }
177        }
178
179        impl fmt::Debug for Samples {
180            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181                match self {
182                    $(Self::$variant(v) => write!(f, "Samples(format = {}, len = {})", stringify!($variant), v.len()),)*
183                }
184            }
185        }
186
187        $(
188        impl From<Vec<$T>> for Samples {
189            fn from(vec: Vec<$T>) -> Self {
190                Self::$variant(vec.into())
191            }
192        }
193        )+
194
195        pub enum SamplesQueue {
196            $($variant (VecDeque<$T>),)+
197        }
198
199        impl SamplesQueue {
200            #[must_use]
201            pub fn empty(format: Format) -> Self {
202                match format {
203                    $(Format::$variant => Self::$variant(VecDeque::new()),)+
204                }
205            }
206
207            #[must_use]
208            pub fn len(&self) -> usize {
209                match self {
210                    $(Self::$variant(queue) => queue.len(),)+
211                }
212            }
213
214            #[must_use]
215            pub fn is_empty(&self) -> bool {
216                self.len() == 0
217            }
218
219            pub fn extend(&mut self, samples: &Samples) {
220                match (self, samples) {
221                    $(
222                        (Self::$variant(queue), Samples::$variant(vec)) => { queue.extend(vec.iter().copied()) },
223                    )+
224                    _ => panic!("Tried to extend SampleQueue with different sample format"),
225                }
226            }
227
228            pub fn pop_exact(&mut self, n: usize) -> Option<Samples> {
229                match self {
230                    $(Self::$variant(queue) => {
231                        if queue.len() < n {
232                            return None;
233                        }
234
235                        Some(Samples::$variant(queue.drain(..n).collect()))
236                    },)+
237                }
238            }
239        }
240
241        impl fmt::Debug for SamplesQueue {
242            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243                match self {
244                    $(Self::$variant(v) => write!(f, "SamplesQueue(format = {}, len = {})", stringify!($variant), v.len()),)*
245                }
246            }
247        }
248    }
249}
250
251sample_formats! {
252    F64: f64, 64;
253    F32: f32, 32;
254
255    I32: i32, 32;
256    U32: u32, 32;
257
258    I24: I24, 24;
259    U24: U24, 24;
260
261    I16: i16, 16;
262    U16: u16, 16;
263
264    I8:  i8,  8;
265    U8:  u8,  8;
266}
267
268// TODO: Wait for https://github.com/rust-lang/rust/issues/83527 and generate the macro
269/// For the given format call the given code and substitute any `#S` with the correct type related to the given `format`
270///
271/// # Example
272///
273/// ```
274/// # use ezk_audio::*;
275/// # use std::any::TypeId;
276/// fn assert_given_type_is_f32<S: 'static>() {
277///     assert_eq!(
278///         TypeId::of::<S>(),
279///         TypeId::of::<f32>()
280///     );
281/// }
282///
283/// let format = Format::F32;
284///
285/// match_format!(format, assert_given_type_is_f32::<#S>());
286/// ```
287#[macro_export]
288macro_rules! match_format {
289    ($format:expr, $($input:tt)*) => {
290        match $format {
291            $crate::Format::F64 => { $crate::substitute!($crate::__private_macro_exports::f64 => $($input)*) }
292            $crate::Format::F32 => { $crate::substitute!($crate::__private_macro_exports::f32 => $($input)*) }
293            $crate::Format::I32 => { $crate::substitute!($crate::__private_macro_exports::i32 => $($input)*) }
294            $crate::Format::U32 => { $crate::substitute!($crate::__private_macro_exports::u32 => $($input)*) }
295            $crate::Format::I24 => { $crate::substitute!($crate::__private_macro_exports::I24 => $($input)*) }
296            $crate::Format::U24 => { $crate::substitute!($crate::__private_macro_exports::U24 => $($input)*) }
297            $crate::Format::I16 => { $crate::substitute!($crate::__private_macro_exports::i16 => $($input)*) }
298            $crate::Format::U16 => { $crate::substitute!($crate::__private_macro_exports::u16 => $($input)*) }
299            $crate::Format::I8  => { $crate::substitute!($crate::__private_macro_exports::i8  => $($input)*) }
300            $crate::Format::U8  => { $crate::substitute!($crate::__private_macro_exports::u8  => $($input)*) }
301        }
302    };
303}
304
305/// Match one or more [`Samples`] and call a given function with the associated sample type
306///
307/// ```ignore
308/// let samples = Samples::empty(Format::F32);
309///
310/// match_samples!((&samples) => (s) => { println!("{}", s.len()) });
311///
312/// // This basically expands to the following
313/// match (&samples,) {
314///     (Samples::F64(s),) => { println!("{}", s.len()) }
315///     (Samples::F32(s),) => { println!("{}", s.len()) }
316///     ...
317/// }
318///
319/// // When matching multiple samples
320///  let samples1 = Samples::empty(Format::F32);
321///  let samples2 = Samples::empty(Format::F32);
322///
323/// match_samples!((&samples1, &samples2) => (s1, s2) => { println!("{} {}", s1.len(), s2.len()) });
324///
325/// // This expands to the following
326/// match (&samples1, &samples2,) {
327///     (Samples::F64(s1), Samples::F64(s2),) => { println!("{} {}", s1.len(), s2.len()) }
328///     (Samples::F32(s1), Samples::F64(s2),) => { println!("{} {}", s1.len(), s2.len()) }
329///     ...
330///     _ => panic!("Tried to match multiple samples with different sample types"),
331/// }
332/// ```
333///
334/// # Example
335///
336/// ```
337/// # use ezk_audio::*;
338/// # use std::any::TypeId;
339/// fn assert_given_type_is_f32<S: 'static>(samples: &[S]) {
340///     assert_eq!(samples.len(), 100);
341///     assert_eq!(
342///         TypeId::of::<S>(),
343///         TypeId::of::<f32>()
344///     );
345/// }
346///
347/// let samples = Samples::equilibrium(Format::F32, 100);
348///
349/// // matching a single samples
350/// match_samples!((&samples) => (s) => assert_given_type_is_f32::<#S>(s));
351///
352/// // matching a multiple samples
353/// match_samples!((&samples, &samples) => (s, _s) => assert_given_type_is_f32::<#S>(s));
354/// ```
355#[macro_export]
356macro_rules! match_samples {
357    (($($samples:expr),*) => ($($pat:pat),*) => $($input:tt)*) => {
358        match ($($samples,)*) {
359            ($($crate::Samples::F64($pat),)*) => { $crate::substitute!($crate::__private_macro_exports::f64 => $($input)*) }
360            ($($crate::Samples::F32($pat),)*) => { $crate::substitute!($crate::__private_macro_exports::f32 => $($input)*) }
361            ($($crate::Samples::I32($pat),)*) => { $crate::substitute!($crate::__private_macro_exports::i32 => $($input)*) }
362            ($($crate::Samples::U32($pat),)*) => { $crate::substitute!($crate::__private_macro_exports::u32 => $($input)*) }
363            ($($crate::Samples::I24($pat),)*) => { $crate::substitute!($crate::__private_macro_exports::I24 => $($input)*) }
364            ($($crate::Samples::U24($pat),)*) => { $crate::substitute!($crate::__private_macro_exports::U24 => $($input)*) }
365            ($($crate::Samples::I16($pat),)*) => { $crate::substitute!($crate::__private_macro_exports::i16 => $($input)*) }
366            ($($crate::Samples::U16($pat),)*) => { $crate::substitute!($crate::__private_macro_exports::u16 => $($input)*) }
367            ($($crate::Samples::I8($pat),)*)  => { $crate::substitute!($crate::__private_macro_exports::i8  => $($input)*) }
368            ($($crate::Samples::U8($pat),)*)  => { $crate::substitute!($crate::__private_macro_exports::u8  => $($input)*) }
369
370            #[allow(unreachable_patterns)] _ => panic!("Tried to match multiple samples with different sample types")
371        }
372    };
373}
374
375/// Substitute #S with the given $i1 in any type
376///
377/// # Example
378///
379/// ```
380/// # use ezk_audio::*;
381/// fn some_func<T>() {}
382/// substitute!(i64 => some_func::<#S>()); // expands to some_func::<i64>();
383/// ```
384#[macro_export]
385#[doc(hidden)]
386macro_rules! substitute {
387    ($i1:ty => $($input:tt)*) => {
388        $crate::substitute!(@inner $i1 => [] [$($input)*])
389    };
390    (@inner
391        $i1:ty =>
392        [$($processed:tt)*]
393        [#S $($input:tt)*]
394    ) => {
395        $crate::substitute!(@inner $i1 =>
396            [$($processed)* $i1]
397            [$($input)*]
398        )
399    };
400    (@inner
401        $i1:ty =>
402        [$($processed:tt)*]
403        [{ $($block_input:tt)* } $($input:tt)*]
404    ) => {
405        $crate::substitute!(@inner $i1 =>
406            [$($processed)* { $crate::substitute! { $i1 => $($block_input)* } }]
407            [$($input)*]
408        )
409    };
410    (@inner
411        $i1:ty =>
412        [$($processed:tt)*]
413        [$token:tt $($input:tt)*]
414    ) => {
415        $crate::substitute!(@inner $i1 =>
416            [$($processed)* $token]
417            [$($input)*]
418        )
419    };
420    (@inner
421        $i1:ty =>
422        [$($processed:tt)*]
423        []
424    ) => {
425        $($processed)*
426    };
427}
428
429/// Safety: Only valid if Src and Dst have the same Layout
430unsafe fn convert_with_dst_and_src_type_inplace<Src, Dst>(src: &mut Vec<Src>) -> Vec<Dst>
431where
432    Src: Sample,
433    Dst: Sample,
434{
435    let src = take(src);
436
437    let (ptr, len, cap) = vec_into_raw_parts(src);
438
439    for offset in 0..len {
440        let ptr = ptr.add(offset);
441        let src = ptr.read();
442        let ptr = ptr.cast::<Dst>();
443        ptr.write(src.to_sample());
444    }
445
446    Vec::from_raw_parts(ptr.cast::<Dst>(), len, cap)
447}
448
449fn vec_into_raw_parts<T>(vec: Vec<T>) -> (*mut T, usize, usize) {
450    let mut vec = std::mem::ManuallyDrop::new(vec);
451    (vec.as_mut_ptr(), vec.len(), vec.capacity())
452}