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