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