Skip to main content

firewheel_core/
channel_config.rs

1use core::{error::Error, fmt, num::NonZeroU32};
2
3pub const MAX_CHANNELS: usize = 64;
4
5/// A supported number of channels on an audio node.
6///
7/// This number cannot be greater than `64`.
8#[repr(transparent)]
9#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
10#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct ChannelCount(u32);
13
14impl ChannelCount {
15    pub const ZERO: Self = Self(0);
16    pub const MONO: Self = Self(1);
17    pub const STEREO: Self = Self(2);
18    pub const MAX: Self = Self(MAX_CHANNELS as u32);
19
20    /// Create a new [`ChannelCount`].
21    ///
22    /// Returns `None` if `count` is greater than `64`.
23    #[inline]
24    pub const fn new(count: u32) -> Option<Self> {
25        if count <= 64 { Some(Self(count)) } else { None }
26    }
27
28    #[inline]
29    pub const fn get(&self) -> u32 {
30        assert!(self.0 <= 64);
31
32        self.0
33    }
34}
35
36impl From<usize> for ChannelCount {
37    fn from(value: usize) -> Self {
38        Self::new(value as u32).unwrap()
39    }
40}
41
42impl From<ChannelCount> for u32 {
43    fn from(value: ChannelCount) -> Self {
44        value.get()
45    }
46}
47
48impl From<ChannelCount> for usize {
49    fn from(value: ChannelCount) -> Self {
50        value.get() as usize
51    }
52}
53
54/// A supported number of channels on an audio node.
55///
56/// This number cannot be `0` or greater than `64`.
57#[repr(transparent)]
58#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
59#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
60#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
61pub struct NonZeroChannelCount(NonZeroU32);
62
63impl NonZeroChannelCount {
64    pub const MONO: Self = Self(NonZeroU32::new(1).unwrap());
65    pub const STEREO: Self = Self(NonZeroU32::new(2).unwrap());
66    pub const MAX: Self = Self(NonZeroU32::new(64).unwrap());
67
68    /// Create a new [`NonZeroChannelCount`].
69    ///
70    /// Returns `None` if `count` is greater than `64`.
71    #[inline]
72    pub const fn new(count: u32) -> Option<Self> {
73        if count > 0 && count <= 64 {
74            Some(Self(NonZeroU32::new(count).unwrap()))
75        } else {
76            None
77        }
78    }
79
80    #[inline]
81    pub const fn get(&self) -> ChannelCount {
82        assert!(self.0.get() > 0 && self.0.get() <= 64);
83
84        ChannelCount(self.0.get())
85    }
86}
87
88impl Default for NonZeroChannelCount {
89    fn default() -> Self {
90        Self::STEREO
91    }
92}
93
94impl From<usize> for NonZeroChannelCount {
95    fn from(value: usize) -> Self {
96        Self::new(value as u32).unwrap()
97    }
98}
99
100impl From<NonZeroChannelCount> for NonZeroU32 {
101    fn from(value: NonZeroChannelCount) -> Self {
102        NonZeroU32::new(value.get().get()).unwrap()
103    }
104}
105
106impl From<NonZeroChannelCount> for usize {
107    fn from(value: NonZeroChannelCount) -> Self {
108        value.get().get() as usize
109    }
110}
111
112/// A supported number of channels on an audio node.
113#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
114#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
115#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
116pub struct ChannelConfig {
117    pub num_inputs: ChannelCount,
118    pub num_outputs: ChannelCount,
119}
120
121impl ChannelConfig {
122    pub fn new(num_inputs: impl Into<ChannelCount>, num_outputs: impl Into<ChannelCount>) -> Self {
123        Self {
124            num_inputs: num_inputs.into(),
125            num_outputs: num_outputs.into(),
126        }
127    }
128
129    pub fn verify(
130        &self,
131        min_num_inputs: ChannelCount,
132        max_num_inputs: ChannelCount,
133        min_num_outputs: ChannelCount,
134        max_num_outputs: ChannelCount,
135        equal_num_ins_outs: bool,
136    ) -> Result<(), ChannelConfigError> {
137        if self.num_inputs.get() < min_num_inputs.get()
138            || self.num_inputs.get() > max_num_inputs.get()
139        {
140            Err(ChannelConfigError::InvalidNumInputs {
141                min: min_num_inputs,
142                max: max_num_inputs,
143                got: self.num_inputs,
144            })
145        } else if self.num_outputs.get() < min_num_outputs.get()
146            || self.num_outputs.get() > max_num_outputs.get()
147        {
148            Err(ChannelConfigError::InvalidNumOutputs {
149                min: min_num_outputs,
150                max: max_num_outputs,
151                got: self.num_outputs,
152            })
153        } else if equal_num_ins_outs && self.num_inputs.get() != self.num_outputs.get() {
154            Err(ChannelConfigError::NumInOutNotEqual {
155                got_in: self.num_inputs,
156                got_out: self.num_outputs,
157            })
158        } else {
159            Ok(())
160        }
161    }
162
163    pub fn is_empty(&self) -> bool {
164        self.num_inputs == ChannelCount::ZERO && self.num_outputs == ChannelCount::ZERO
165    }
166}
167
168impl From<(usize, usize)> for ChannelConfig {
169    fn from(value: (usize, usize)) -> Self {
170        Self::new(value.0, value.1)
171    }
172}
173
174/// An invalid channel configuration
175#[derive(Debug, Clone, Copy, PartialEq, Eq)]
176pub enum ChannelConfigError {
177    InvalidNumInputs {
178        min: ChannelCount,
179        max: ChannelCount,
180        got: ChannelCount,
181    },
182    InvalidNumOutputs {
183        min: ChannelCount,
184        max: ChannelCount,
185        got: ChannelCount,
186    },
187    NumInOutNotEqual {
188        got_in: ChannelCount,
189        got_out: ChannelCount,
190    },
191}
192
193impl Error for ChannelConfigError {}
194
195impl fmt::Display for ChannelConfigError {
196    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197        match self {
198            Self::InvalidNumInputs { min, max, got } => {
199                write!(
200                    f,
201                    "Invalid number of input channels on audio node | got: {}, min: {}, max: {}",
202                    got.get(),
203                    min.get(),
204                    max.get()
205                )
206            }
207            Self::InvalidNumOutputs { min, max, got } => {
208                write!(
209                    f,
210                    "Invalid number of output channels on audio node | got: {}, min: {}, max: {}",
211                    got.get(),
212                    min.get(),
213                    max.get()
214                )
215            }
216            Self::NumInOutNotEqual { got_in, got_out } => {
217                write!(
218                    f,
219                    "Number of input channels does not equal number of output channels | in: {}, out: {}",
220                    got_in.get(),
221                    got_out.get()
222                )
223            }
224        }
225    }
226}