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