1use std::fmt;
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
34#[non_exhaustive]
35pub enum ChannelLayout {
36 Mono,
38 Stereo,
40 Stereo2_1,
42 Surround3_0,
44 Quad,
46 Surround5_0,
48 Surround5_1,
50 Surround6_1,
52 Surround7_1,
54 Other(u32),
56}
57
58impl ChannelLayout {
59 #[must_use]
73 pub const fn channels(&self) -> u32 {
74 match self {
75 Self::Mono => 1,
76 Self::Stereo => 2,
77 Self::Stereo2_1 | Self::Surround3_0 => 3,
78 Self::Quad => 4,
79 Self::Surround5_0 => 5,
80 Self::Surround5_1 => 6,
81 Self::Surround6_1 => 7,
82 Self::Surround7_1 => 8,
83 Self::Other(n) => *n,
84 }
85 }
86
87 #[must_use]
99 pub const fn name(&self) -> &'static str {
100 match self {
101 Self::Mono => "mono",
102 Self::Stereo => "stereo",
103 Self::Stereo2_1 => "2.1",
104 Self::Surround3_0 => "3.0",
105 Self::Quad => "quad",
106 Self::Surround5_0 => "5.0",
107 Self::Surround5_1 => "5.1",
108 Self::Surround6_1 => "6.1",
109 Self::Surround7_1 => "7.1",
110 Self::Other(_) => "custom",
111 }
112 }
113
114 #[must_use]
125 pub const fn is_mono(&self) -> bool {
126 matches!(self, Self::Mono)
127 }
128
129 #[must_use]
140 pub const fn is_stereo(&self) -> bool {
141 matches!(self, Self::Stereo)
142 }
143
144 #[must_use]
156 pub const fn is_surround(&self) -> bool {
157 matches!(
158 self,
159 Self::Stereo2_1
160 | Self::Surround3_0
161 | Self::Quad
162 | Self::Surround5_0
163 | Self::Surround5_1
164 | Self::Surround6_1
165 | Self::Surround7_1
166 ) || matches!(self, Self::Other(n) if *n > 2)
167 }
168
169 #[must_use]
181 pub const fn has_lfe(&self) -> bool {
182 matches!(
183 self,
184 Self::Stereo2_1 | Self::Surround5_1 | Self::Surround6_1 | Self::Surround7_1
185 )
186 }
187
188 #[must_use]
204 pub const fn from_channels(channels: u32) -> Self {
205 match channels {
206 1 => Self::Mono,
207 2 => Self::Stereo,
208 3 => Self::Stereo2_1,
210 4 => Self::Quad,
211 5 => Self::Surround5_0,
212 6 => Self::Surround5_1,
213 7 => Self::Surround6_1,
214 8 => Self::Surround7_1,
215 n => Self::Other(n),
216 }
217 }
218}
219
220impl Default for ChannelLayout {
221 fn default() -> Self {
223 Self::Stereo
224 }
225}
226
227impl fmt::Display for ChannelLayout {
228 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229 write!(f, "{}", self.name())
230 }
231}
232
233impl From<u32> for ChannelLayout {
234 fn from(channels: u32) -> Self {
235 Self::from_channels(channels)
236 }
237}
238
239#[cfg(test)]
240mod tests {
241 use super::*;
242
243 #[test]
244 fn test_channel_count() {
245 assert_eq!(ChannelLayout::Mono.channels(), 1);
246 assert_eq!(ChannelLayout::Stereo.channels(), 2);
247 assert_eq!(ChannelLayout::Stereo2_1.channels(), 3);
248 assert_eq!(ChannelLayout::Surround3_0.channels(), 3);
249 assert_eq!(ChannelLayout::Quad.channels(), 4);
250 assert_eq!(ChannelLayout::Surround5_0.channels(), 5);
251 assert_eq!(ChannelLayout::Surround5_1.channels(), 6);
252 assert_eq!(ChannelLayout::Surround6_1.channels(), 7);
253 assert_eq!(ChannelLayout::Surround7_1.channels(), 8);
254 assert_eq!(ChannelLayout::Other(16).channels(), 16);
255 }
256
257 #[test]
258 fn test_names() {
259 assert_eq!(ChannelLayout::Mono.name(), "mono");
260 assert_eq!(ChannelLayout::Stereo.name(), "stereo");
261 assert_eq!(ChannelLayout::Stereo2_1.name(), "2.1");
262 assert_eq!(ChannelLayout::Surround3_0.name(), "3.0");
263 assert_eq!(ChannelLayout::Quad.name(), "quad");
264 assert_eq!(ChannelLayout::Surround5_0.name(), "5.0");
265 assert_eq!(ChannelLayout::Surround5_1.name(), "5.1");
266 assert_eq!(ChannelLayout::Surround6_1.name(), "6.1");
267 assert_eq!(ChannelLayout::Surround7_1.name(), "7.1");
268 assert_eq!(ChannelLayout::Other(10).name(), "custom");
269 }
270
271 #[test]
272 fn test_display() {
273 assert_eq!(format!("{}", ChannelLayout::Mono), "mono");
274 assert_eq!(format!("{}", ChannelLayout::Surround5_1), "5.1");
275 assert_eq!(format!("{}", ChannelLayout::Other(10)), "custom");
276 }
277
278 #[test]
279 fn test_default() {
280 assert_eq!(ChannelLayout::default(), ChannelLayout::Stereo);
281 }
282
283 #[test]
284 fn test_is_mono_stereo() {
285 assert!(ChannelLayout::Mono.is_mono());
286 assert!(!ChannelLayout::Stereo.is_mono());
287 assert!(!ChannelLayout::Surround5_1.is_mono());
288
289 assert!(ChannelLayout::Stereo.is_stereo());
290 assert!(!ChannelLayout::Mono.is_stereo());
291 assert!(!ChannelLayout::Surround5_1.is_stereo());
292 }
293
294 #[test]
295 fn test_is_surround() {
296 assert!(!ChannelLayout::Mono.is_surround());
297 assert!(!ChannelLayout::Stereo.is_surround());
298 assert!(ChannelLayout::Stereo2_1.is_surround());
299 assert!(ChannelLayout::Surround3_0.is_surround());
300 assert!(ChannelLayout::Quad.is_surround());
301 assert!(ChannelLayout::Surround5_0.is_surround());
302 assert!(ChannelLayout::Surround5_1.is_surround());
303 assert!(ChannelLayout::Surround6_1.is_surround());
304 assert!(ChannelLayout::Surround7_1.is_surround());
305
306 assert!(ChannelLayout::Other(4).is_surround());
308 assert!(!ChannelLayout::Other(2).is_surround());
310 }
311
312 #[test]
313 fn test_has_lfe() {
314 assert!(!ChannelLayout::Mono.has_lfe());
315 assert!(!ChannelLayout::Stereo.has_lfe());
316 assert!(ChannelLayout::Stereo2_1.has_lfe());
317 assert!(!ChannelLayout::Surround3_0.has_lfe());
318 assert!(!ChannelLayout::Quad.has_lfe());
319 assert!(!ChannelLayout::Surround5_0.has_lfe());
320 assert!(ChannelLayout::Surround5_1.has_lfe());
321 assert!(ChannelLayout::Surround6_1.has_lfe());
322 assert!(ChannelLayout::Surround7_1.has_lfe());
323 }
324
325 #[test]
326 fn test_from_channels() {
327 assert_eq!(ChannelLayout::from_channels(1), ChannelLayout::Mono);
328 assert_eq!(ChannelLayout::from_channels(2), ChannelLayout::Stereo);
329 assert_eq!(ChannelLayout::from_channels(3), ChannelLayout::Stereo2_1);
330 assert_eq!(ChannelLayout::from_channels(4), ChannelLayout::Quad);
331 assert_eq!(ChannelLayout::from_channels(5), ChannelLayout::Surround5_0);
332 assert_eq!(ChannelLayout::from_channels(6), ChannelLayout::Surround5_1);
333 assert_eq!(ChannelLayout::from_channels(7), ChannelLayout::Surround6_1);
334 assert_eq!(ChannelLayout::from_channels(8), ChannelLayout::Surround7_1);
335 assert_eq!(ChannelLayout::from_channels(10), ChannelLayout::Other(10));
336 }
337
338 #[test]
339 fn test_from_u32() {
340 let layout: ChannelLayout = 2u32.into();
341 assert_eq!(layout, ChannelLayout::Stereo);
342
343 let layout: ChannelLayout = 6u32.into();
344 assert_eq!(layout, ChannelLayout::Surround5_1);
345 }
346
347 #[test]
348 fn test_debug() {
349 assert_eq!(format!("{:?}", ChannelLayout::Mono), "Mono");
350 assert_eq!(format!("{:?}", ChannelLayout::Surround5_1), "Surround5_1");
351 assert_eq!(format!("{:?}", ChannelLayout::Other(10)), "Other(10)");
352 }
353
354 #[test]
355 fn test_equality_and_hash() {
356 use std::collections::HashSet;
357
358 assert_eq!(ChannelLayout::Stereo, ChannelLayout::Stereo);
359 assert_ne!(ChannelLayout::Stereo, ChannelLayout::Mono);
360 assert_eq!(ChannelLayout::Other(4), ChannelLayout::Other(4));
361 assert_ne!(ChannelLayout::Other(4), ChannelLayout::Other(5));
362
363 let mut set = HashSet::new();
364 set.insert(ChannelLayout::Stereo);
365 set.insert(ChannelLayout::Surround5_1);
366 assert!(set.contains(&ChannelLayout::Stereo));
367 assert!(!set.contains(&ChannelLayout::Mono));
368 }
369
370 #[test]
371 fn test_copy() {
372 let layout = ChannelLayout::Surround5_1;
373 let copied = layout;
374 assert_eq!(layout, copied);
375 assert_eq!(layout.channels(), copied.channels());
376 }
377}