coreaudio/audio_unit/
sample_format.rs

1use super::audio_format::{self, LinearPcmFlags};
2
3/// Dynamic representation of audio data sample format.
4#[derive(Copy, Clone, Debug, PartialEq, Eq)]
5pub enum SampleFormat {
6    /// 32-bit float.
7    F32,
8    /// 32-bit signed integer.
9    I32,
10    /// 24-bit signed integer. Can be packed or not depending on the flags.
11    I24,
12    /// 16-bit signed integer.
13    I16,
14    /// 8-bit signed integer.
15    I8,
16}
17
18impl SampleFormat {
19    /// Check if the format flags are appropriate for the given format.
20    pub fn does_match_flags(&self, flags: audio_format::LinearPcmFlags) -> bool {
21        let is_float = flags.contains(LinearPcmFlags::IS_FLOAT);
22        let is_signed_integer = flags.contains(LinearPcmFlags::IS_SIGNED_INTEGER);
23        let is_packed = flags.contains(LinearPcmFlags::IS_PACKED);
24        match *self {
25            SampleFormat::F32 => is_float && !is_signed_integer && is_packed,
26            SampleFormat::I32 | SampleFormat::I16 | SampleFormat::I8 => {
27                is_signed_integer && !is_float && is_packed
28            }
29            SampleFormat::I24 => is_signed_integer && !is_float,
30        }
31    }
32
33    /// Convert format flags and bits_per_sample to a SampleFormat.
34    pub fn from_flags_and_bits_per_sample(
35        flags: audio_format::LinearPcmFlags,
36        bits_per_sample: u32,
37    ) -> Option<Self> {
38        let packed = flags.contains(LinearPcmFlags::IS_PACKED);
39        let sample_format = if flags.contains(LinearPcmFlags::IS_FLOAT) {
40            match (bits_per_sample, packed) {
41                (32, true) => SampleFormat::F32,
42                _ => return None,
43            }
44        } else if flags.contains(LinearPcmFlags::IS_SIGNED_INTEGER) {
45            match (bits_per_sample, packed) {
46                (8, true) => SampleFormat::I8,
47                (16, true) => SampleFormat::I16,
48                (24, _) => SampleFormat::I24,
49                (32, true) => SampleFormat::I32,
50                _ => return None,
51            }
52        } else {
53            // TODO: Check whether or not we need to consider other formats, like unsigned ints.
54            return None;
55        };
56        Some(sample_format)
57    }
58
59    /// Return the size of one sample in bytes, assuming that the format is packed.
60    pub fn size_in_bytes(&self) -> usize {
61        use std::mem::size_of;
62        match *self {
63            SampleFormat::F32 => size_of::<f32>(),
64            SampleFormat::I32 => size_of::<i32>(),
65            SampleFormat::I24 => 3 * size_of::<u8>(),
66            SampleFormat::I16 => size_of::<i16>(),
67            SampleFormat::I8 => size_of::<i8>(),
68        }
69    }
70
71    /// Return the number of valid bits for one sample.
72    pub fn size_in_bits(&self) -> u32 {
73        match *self {
74            SampleFormat::F32 => 32,
75            SampleFormat::I32 => 32,
76            SampleFormat::I24 => 24,
77            SampleFormat::I16 => 16,
78            SampleFormat::I8 => 8,
79        }
80    }
81}
82
83/// Audio data sample types.
84pub trait Sample {
85    /// Dynamic representation of audio data sample format.
86    fn sample_format() -> SampleFormat;
87}
88
89/// Simplified implementation of the `Sample` trait for sample types.
90/// This is only implemented for the sample types that map directly to a numeric type.
91macro_rules! impl_sample {
92    ($($T:ident $format:ident),* $(,)*) => {
93        $(
94            impl Sample for $T {
95                fn sample_format() -> SampleFormat {
96                    SampleFormat::$format
97                }
98            }
99        )*
100    }
101}
102
103impl_sample!(f32 F32, i32 I32, i16 I16, i8 I8);