1use std::{mem, num::NonZeroU8, sync::LazyLock};
2
3use bitflags::bitflags;
4use smallvec::SmallVec;
5use strum::EnumCount;
6
7use crate::{error::Error, invalid_param_error, Result};
8
9#[derive(Clone, Copy, Debug, EnumCount, Eq, PartialEq)]
10#[repr(u8)]
11pub enum Channel {
12 FrontLeft,
13 FrontRight,
14 FrontCenter,
15 LowFrequency,
16 BackLeft,
17 BackRight,
18 FrontLeftOfCenter,
19 FrontRightOfCenter,
20 BackCenter,
21 SideLeft,
22 SideRight,
23 TopCenter,
24 TopFrontLeft,
25 TopFrontCenter,
26 TopFrontRight,
27 TopBackLeft,
28 TopBackCenter,
29 TopBackRight,
30}
31
32impl From<Channel> for u32 {
33 fn from(chn: Channel) -> Self {
34 chn as u32
35 }
36}
37
38impl From<Channel> for ChannelMasks {
39 fn from(chn: Channel) -> Self {
40 ChannelMasks::from_bits_truncate(1u32 << chn as u32)
41 }
42}
43
44impl TryFrom<u8> for Channel {
45 type Error = Error;
46
47 fn try_from(value: u8) -> Result<Self> {
48 if value < Channel::COUNT as u8 {
49 Ok(unsafe { mem::transmute::<u8, Channel>(value) })
50 } else {
51 Err(invalid_param_error!(value))
52 }
53 }
54}
55
56macro_rules! channel_masks {
57 ($($mask:ident)|+) => {
58 0 $(| ChannelMasks::$mask.bits())+
59 };
60 ($mask:ident) => {
61 ChannelMasks::$mask.bits()
62 };
63}
64
65bitflags! {
66 #[repr(transparent)]
67 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
68 pub struct ChannelMasks: u32 {
69 const FrontLeft = 1u32 << Channel::FrontLeft as u32;
70 const FrontRight = 1u32 << Channel::FrontRight as u32;
71 const FrontCenter = 1u32 << Channel::FrontCenter as u32;
72 const LowFrequency = 1u32 << Channel::LowFrequency as u32;
73 const BackLeft = 1u32 << Channel::BackLeft as u32;
74 const BackRight = 1u32 << Channel::BackRight as u32;
75 const FrontLeftOfCenter = 1u32 << Channel::FrontLeftOfCenter as u32;
76 const FrontRightOfCenter = 1u32 << Channel::FrontRightOfCenter as u32;
77 const BackCenter = 1u32 << Channel::BackCenter as u32;
78 const SideLeft = 1u32 << Channel::SideLeft as u32;
79 const SideRight = 1u32 << Channel::SideRight as u32;
80 const TopCenter = 1u32 << Channel::TopCenter as u32;
81 const TopFrontLeft = 1u32 << Channel::TopFrontLeft as u32;
82 const TopFrontCenter = 1u32 << Channel::TopFrontCenter as u32;
83 const TopFrontRight = 1u32 << Channel::TopFrontRight as u32;
84 const TopBackLeft = 1u32 << Channel::TopBackLeft as u32;
85 const TopBackCenter = 1u32 << Channel::TopBackCenter as u32;
86 const TopBackRight = 1u32 << Channel::TopBackRight as u32;
87
88 const Mono = channel_masks!(FrontCenter);
89 const Stereo = channel_masks!(FrontLeft | FrontRight);
90 const Surround_2_1 = channel_masks!(Stereo | LowFrequency);
91 const Surround = channel_masks!(Stereo | FrontCenter);
92 const Surround_3_0 = channel_masks!(Surround);
93 const Surround_3_0_FRONT = channel_masks!(Surround);
94 const Surround_3_0_BACK = channel_masks!(Stereo | BackCenter);
95 const Surround_3_1 = channel_masks!(Surround_3_0 | LowFrequency);
96 const Surround_3_1_2 = channel_masks!(Surround_3_1 | TopFrontLeft | TopFrontRight);
97 const Surround_4_0 = channel_masks!(Surround_3_0 | BackCenter);
98 const Surround_4_1 = channel_masks!(Surround_4_0 | LowFrequency);
99 const Surround_2_2 = channel_masks!(Stereo | SideLeft | SideRight);
100 const Quad = channel_masks!(Stereo | BackLeft | BackRight);
101 const Surround_5_0 = channel_masks!(Surround_3_0 | SideLeft | SideRight);
102 const Surround_5_1 = channel_masks!(Surround_5_0 | LowFrequency);
103 const Surround_5_0_BACK = channel_masks!(Surround_3_0 | BackLeft | BackRight);
104 const Surround_5_1_BACK = channel_masks!(Surround_5_0_BACK | LowFrequency);
105 const Surround_6_0 = channel_masks!(Surround_5_0 | BackCenter);
106 const Hexagonal = channel_masks!(Surround_5_0_BACK | BackCenter);
107 const Surround_6_1 = channel_masks!(Surround_6_0 | LowFrequency);
108 const Surround_6_0_FRONT = channel_masks!(Surround_2_2 | FrontLeftOfCenter | FrontRightOfCenter);
109 const Surround_6_1_FRONT = channel_masks!(Surround_6_0_FRONT | LowFrequency);
110 const Surround_6_1_BACK = channel_masks!(Surround_5_1_BACK | BackCenter);
111 const Surround_7_0 = channel_masks!(Surround_5_0 | BackLeft | BackRight);
112 const Surround_7_1 = channel_masks!(Surround_7_0 | LowFrequency);
113 const Surround_7_0_FRONT = channel_masks!(Surround_5_0 | FrontLeftOfCenter | FrontRightOfCenter);
114 const Surround_7_1_WIDE = channel_masks!(Surround_5_1 | FrontLeftOfCenter | FrontRightOfCenter);
115 const Surround_7_1_WIDE_BACK = channel_masks!(Surround_5_1_BACK | FrontLeftOfCenter | FrontRightOfCenter);
116 const Surround_5_1_2 = channel_masks!(Surround_5_1 | TopFrontLeft | TopFrontRight);
117 const Surround_5_1_2_BACK = channel_masks!(Surround_5_1_BACK | TopFrontLeft | TopFrontRight);
118 const Octagonal = channel_masks!(Surround_5_0 | BackLeft | BackCenter | BackRight);
119 const Cube = channel_masks!(Quad | TopFrontLeft | TopFrontRight | TopBackLeft | TopBackRight);
120 const Surround_5_1_4_BACK = channel_masks!(Surround_5_1_2 | TopBackLeft | TopBackRight);
121 const Surround_7_1_2 = channel_masks!(Surround_7_1 | TopFrontLeft | TopFrontRight);
122 const Surround_7_1_4_BACK = channel_masks!(Surround_7_1_2 | TopBackLeft | TopBackRight);
123 const Surround_9_1_4_BACK = channel_masks!(Surround_7_1_4_BACK | FrontLeftOfCenter | FrontRightOfCenter);
124 }
125}
126
127#[derive(Clone, Copy, Debug, Eq, PartialEq)]
128pub enum ChannelOrder {
129 Unspecified,
130 Native,
131 Custom,
132 MAX,
133}
134
135struct ChannelLayoutMap {
136 map: Vec<Option<Vec<(&'static str, ChannelLayout)>>>,
137}
138
139macro_rules! define_channel_layouts {
140 ( $(
141 $const_name:ident: [$name:literal, $mask:ident($channel_count:literal)]
142 ),* $(,)?
143 ) => {
144 impl ChannelLayout {
145 $(
146 pub const $const_name: Self = Self {
147 order: ChannelOrder::Native,
148 channels: NonZeroU8::new($channel_count).unwrap(),
149 spec: ChannelLayoutSpec::Mask(ChannelMasks::$mask),
150 };
151 )*
152 }
153
154 static CHANNEL_LAYOUT_MAP: LazyLock<ChannelLayoutMap> = LazyLock::new(|| {
155 let mut map = vec![None; DEFAULT_MAX_CHANNELS];
156 $(
157 let entry = map[($channel_count - 1) as usize].get_or_insert_with(Vec::new);
158 entry.push((
159 $name,
160 ChannelLayout::$const_name,
161 ));
162 )*
163 ChannelLayoutMap { map }
164 });
165 };
166}
167
168define_channel_layouts! {
169 MONO: ["mono", Mono(1)],
170 STEREO: ["stereo", Stereo(2)],
171 SURROUND_2_1: ["2.1", Surround_2_1(3)],
172 SURROUND_3_0: ["3.0", Surround_3_0(3)],
173 SURROUND_3_0_BACK: ["3.0(back)", Surround_3_0_BACK(3)],
174 SURROUND_4_0: ["4.0", Surround_4_0(4)],
175 QUAD: ["quad", Quad(4)],
176 SURROUND_2_2: ["quad(side)", Surround_2_2(4)],
177 SURROUND_3_1: ["3.1", Surround_3_1(4)],
178 SURROUND_5_0_BACK: ["5.0", Surround_5_0_BACK(5)],
179 SURROUND_5_0: ["5.0(side)", Surround_5_0(5)],
180 SURROUND_4_1: ["4.1", Surround_4_1(5)],
181 SURROUND_5_1_BACK: ["5.1", Surround_5_1_BACK(6)],
182 SURROUND_5_1: ["5.1(side)", Surround_5_1(6)],
183 SURROUND_6_0: ["6.0", Surround_6_0(6)],
184 SURROUND_6_0_FRONT: ["6.0(front)", Surround_6_0_FRONT(6)],
185 SURROUND_3_1_2: ["3.1.2", Surround_3_1_2(6)],
186 HEXAGONAL: ["hexagonal", Hexagonal(6)],
187 SURROUND_6_1: ["6.1", Surround_6_1(7)],
188 SURROUND_6_1_BACK: ["6.1(back)", Surround_6_1_BACK(7)],
189 SURROUND_6_1_FRONT: ["6.1(front)", Surround_6_1_FRONT(7)],
190 SURROUND_7_0: ["7.0", Surround_7_0(7)],
191 SURROUND_7_0_FRONT: ["7.0(front)", Surround_7_0_FRONT(7)],
192 SURROUND_7_1: ["7.1", Surround_7_1(8)],
193 SURROUND_7_1_WIDE_BACK: ["7.1(wide)", Surround_7_1_WIDE_BACK(8)],
194 SURROUND_7_1_WIDE: ["7.1(wide-side)", Surround_7_1_WIDE(8)],
195 SURROUND_5_1_2: ["5.1.2", Surround_5_1_2(8)],
196 SURROUND_5_1_2_BACK: ["5.1.2(back)", Surround_5_1_2_BACK(8)],
197 OCTAGONAL: ["octagonal", Octagonal(8)],
198 CUBE: ["cube", Cube(8)],
199 SURROUND_5_1_4_BACK: ["5.1.4", Surround_5_1_4_BACK(10)],
200 SURROUND_7_1_2: ["7.1.2", Surround_7_1_2(10)],
201 SURROUND_7_1_4_BACK: ["7.1.4", Surround_7_1_4_BACK(12)],
202 SURROUND_9_1_4_BACK: ["9.1.4", Surround_9_1_4_BACK(14)],
203}
204
205const DEFAULT_MAX_CHANNELS: usize = 16;
206
207#[derive(Clone, Debug, Eq, PartialEq)]
208pub enum ChannelLayoutSpec {
209 Mask(ChannelMasks),
210 Map(Option<SmallVec<[Channel; DEFAULT_MAX_CHANNELS]>>),
211}
212
213#[derive(Clone, Debug, Eq, PartialEq)]
214pub struct ChannelLayout {
215 pub order: ChannelOrder,
216 pub channels: NonZeroU8,
217 pub spec: ChannelLayoutSpec,
218}
219
220impl Default for ChannelLayout {
221 fn default() -> Self {
222 Self {
223 order: ChannelOrder::Unspecified,
224 channels: NonZeroU8::new(1).unwrap(),
225 spec: ChannelLayoutSpec::Mask(ChannelMasks::from_bits_truncate(0)),
226 }
227 }
228}
229
230impl TryFrom<ChannelMasks> for ChannelLayout {
231 type Error = Error;
232
233 fn try_from(mask: ChannelMasks) -> std::result::Result<Self, Self::Error> {
234 Self::from_mask(mask)
235 }
236}
237
238impl TryFrom<u8> for ChannelLayout {
239 type Error = Error;
240
241 fn try_from(channels: u8) -> std::result::Result<Self, Self::Error> {
242 Self::default_from_channels(channels)
243 }
244}
245
246impl ChannelLayout {
247 pub fn from_mask(mask: ChannelMasks) -> Result<Self> {
248 let channels = mask.bits().count_ones() as u8;
249 let spec = ChannelLayoutSpec::Mask(mask);
250
251 NonZeroU8::new(channels)
252 .map(|channels| Self {
253 order: ChannelOrder::Native,
254 channels,
255 spec,
256 })
257 .ok_or_else(|| invalid_param_error!("channel mask is empty"))
258 }
259
260 pub fn default_from_channels(channels: u8) -> Result<Self> {
261 let channels = NonZeroU8::new(channels).ok_or_else(|| invalid_param_error!(channels))?;
262
263 Ok(CHANNEL_LAYOUT_MAP
264 .map
265 .get((channels.get() - 1) as usize)
266 .and_then(|opt| opt.as_ref()?.first())
267 .map(|(_, layout)| layout.clone())
268 .unwrap_or_else(|| Self {
269 order: ChannelOrder::Unspecified,
270 channels,
271 spec: ChannelLayoutSpec::Mask(ChannelMasks::from_bits_truncate(0)),
272 }))
273 }
274
275 pub fn get_channel_from_index(&self, index: usize) -> Option<Channel> {
276 if index >= self.channels.get() as usize {
277 return None;
278 }
279
280 match (&self.order, &self.spec) {
281 (ChannelOrder::Native, ChannelLayoutSpec::Mask(mask)) => {
282 let mut remaining = index;
283 for chn in 0..Channel::COUNT {
284 let channel = Channel::try_from(chn as u8).ok()?;
285 if mask.contains(ChannelMasks::from(channel)) {
286 if remaining == 0 {
287 return Some(channel);
288 }
289 remaining -= 1;
290 }
291 }
292 None
293 }
294 (ChannelOrder::Custom, ChannelLayoutSpec::Map(Some(map))) => map.get(index).copied(),
295 _ => None,
296 }
297 }
298
299 pub fn get_index_from_channel(&self, channel: Channel) -> Option<usize> {
300 match (&self.order, &self.spec) {
301 (ChannelOrder::Native, ChannelLayoutSpec::Mask(mask)) => {
302 let channel_mask = ChannelMasks::from(channel);
303 mask.contains(channel_mask).then(|| {
304 let lower_bits = channel_mask.bits() - 1;
305 (mask.bits() & lower_bits).count_ones() as usize
306 })
307 }
308 (ChannelOrder::Custom, ChannelLayoutSpec::Map(Some(map))) => map.iter().position(|&c| c == channel),
309 _ => None,
310 }
311 }
312
313 pub fn is_valid(&self) -> bool {
314 if self.channels.get() == 0 {
315 return false;
316 }
317
318 match (&self.order, &self.spec) {
319 (ChannelOrder::Unspecified, _) => true,
320 (ChannelOrder::Native, ChannelLayoutSpec::Mask(mask)) => mask.bits().count_ones() as u8 == self.channels.get(),
321 (ChannelOrder::Custom, ChannelLayoutSpec::Map(Some(map))) => map.len() == self.channels.get() as usize,
322 _ => false,
323 }
324 }
325
326 pub fn subset(&self, mask: ChannelMasks) -> ChannelMasks {
327 match (&self.order, &self.spec) {
328 (ChannelOrder::Native, ChannelLayoutSpec::Mask(channel_mask)) => *channel_mask & mask,
329 (ChannelOrder::Custom, ChannelLayoutSpec::Map(Some(map))) => {
330 let mut subset_mask = ChannelMasks::empty();
331 for &channel in map.iter() {
332 let channel_mask = ChannelMasks::from(channel);
333 if mask.contains(channel_mask) {
334 subset_mask |= channel_mask;
335 }
336 }
337 subset_mask
338 }
339 _ => ChannelMasks::from_bits_truncate(0),
340 }
341 }
342}