use std::fmt;
use super::*;
use crate::protocol::sample_spec::MAX_CHANNELS;
use crate::protocol::ProtocolError;
use enum_primitive_derive::Primitive;
#[allow(missing_docs)]
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Primitive)]
pub enum ChannelPosition {
#[default]
Mono = 0,
FrontLeft = 1,
FrontRight = 2,
FrontCenter = 3,
RearCenter = 4,
RearLeft = 5,
RearRight = 6,
Lfe = 7,
FrontLeftOfCenter = 8,
FrontRightOfCenter = 9,
SideLeft = 10,
SideRight = 11,
Aux0 = 12,
Aux1 = 13,
Aux2 = 14,
Aux3 = 15,
Aux4 = 16,
Aux5 = 17,
Aux6 = 18,
Aux7 = 19,
Aux8 = 20,
Aux9 = 21,
Aux10 = 22,
Aux11 = 23,
Aux12 = 24,
Aux13 = 25,
Aux14 = 26,
Aux15 = 27,
Aux16 = 28,
Aux17 = 29,
Aux18 = 30,
Aux19 = 31,
Aux20 = 32,
Aux21 = 33,
Aux22 = 34,
Aux23 = 35,
Aux24 = 36,
Aux25 = 37,
Aux26 = 38,
Aux27 = 39,
Aux28 = 40,
Aux29 = 41,
Aux30 = 42,
Aux31 = 43,
TopCenter = 44,
TopFrontLeft = 45,
TopFrontRight = 46,
TopFrontCenter = 47,
TopRearLeft = 48,
TopRearRight = 49,
TopRearCenter = 50,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct ChannelMap {
channels: u8,
map: [ChannelPosition; MAX_CHANNELS as usize],
}
impl Default for ChannelMap {
fn default() -> Self {
Self::mono()
}
}
impl ChannelMap {
pub fn new(channels: impl IntoIterator<Item = ChannelPosition>) -> Self {
let mut map = Self::empty();
for channel in channels {
map.push(channel);
}
map
}
pub fn empty() -> Self {
ChannelMap {
channels: 0,
map: [Default::default(); MAX_CHANNELS as usize],
}
}
pub fn mono() -> Self {
Self {
channels: 1,
map: [Default::default(); MAX_CHANNELS as usize],
}
}
pub fn stereo() -> Self {
let mut map = Self::empty();
map.push(ChannelPosition::FrontLeft);
map.push(ChannelPosition::FrontRight);
map
}
pub fn push(&mut self, position: ChannelPosition) {
if self.channels < MAX_CHANNELS {
self.map[self.channels as usize] = position;
self.channels += 1;
} else {
panic!("channel map full");
}
}
pub fn num_channels(&self) -> u8 {
self.channels
}
}
impl fmt::Debug for ChannelMap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.map[..self.channels.into()].fmt(f)
}
}
impl<'a> IntoIterator for &'a ChannelMap {
type Item = ChannelPosition;
type IntoIter = Iter<'a>;
fn into_iter(self) -> <Self as IntoIterator>::IntoIter {
Iter { map: self, next: 0 }
}
}
#[derive(Debug)]
pub struct Iter<'a> {
map: &'a ChannelMap,
next: u8,
}
impl Iterator for Iter<'_> {
type Item = ChannelPosition;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
if self.next < self.map.num_channels() {
self.next += 1;
Some(self.map.map[self.next as usize - 1])
} else {
None
}
}
}
impl TagStructRead for ChannelMap {
fn read(ts: &mut TagStructReader<'_>, _protocol_version: u16) -> Result<Self, ProtocolError> {
ts.expect_tag(Tag::ChannelMap)?;
let channels = ts.inner.read_u8()?;
if channels > MAX_CHANNELS {
return Err(ProtocolError::Invalid(format!(
"channel map too large (max is {MAX_CHANNELS} channels, got {channels})"
)));
}
let mut map = ChannelMap::empty();
for _ in 0..channels {
let raw = ts.inner.read_u8()?;
map.push(
ChannelPosition::from_u8(raw).ok_or_else(|| {
ProtocolError::Invalid(format!("invalid channel position {raw}"))
})?,
)
}
Ok(map)
}
}
impl TagStructWrite for ChannelMap {
fn write(
&self,
w: &mut TagStructWriter<'_>,
_protocol_version: u16,
) -> Result<(), ProtocolError> {
w.inner.write_u8(Tag::ChannelMap as u8)?;
w.inner.write_u8(self.num_channels())?;
for channel_pos in self {
w.inner.write_u8(channel_pos as u8)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::protocol::{test_util::test_serde_version, MAX_VERSION};
use super::*;
#[test]
fn roundtrip() -> anyhow::Result<()> {
let mut map = ChannelMap::empty();
map.push(ChannelPosition::FrontLeft);
map.push(ChannelPosition::FrontRight);
map.push(ChannelPosition::RearLeft);
map.push(ChannelPosition::RearRight);
test_serde_version(&map, MAX_VERSION)
}
}