diff --git a/CHANGELOG.md b/CHANGELOG.md index 50af51e7..ddadcf52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added -- `WriteOptions` ([issue](https://github.com/Serial-ATA/lofty-rs/issues/228)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/361)): +- **WriteOptions** ([issue](https://github.com/Serial-ATA/lofty-rs/issues/228)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/361)): - ⚠️ Important ⚠️: This update introduces `WriteOptions` to allow for finer grained control over how Lofty writes tags. These are best used as global user-configurable options, as most options will not apply to all files. The defaults are set to be as safe as possible, see [here](https://docs.rs/lofty/latest/lofty/struct.WriteOptions.html#impl-Default-for-WriteOptions). +- **ChannelMask** ([PR](https://github.com/Serial-ATA/lofty-rs/pull/370)) + - `BitAnd` and `BitOr` implementations + - Associated constants for common channels, ex. `ChannelMask::FRONT_LEFT` ### Fixed - **Vorbis**: Fix panic when reading properties of zero-length files ([issue](https://github.com/Serial-ATA/lofty-rs/issues/342)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/365)) diff --git a/src/properties.rs b/src/properties.rs index 9fa9ef0a..72d96d5e 100644 --- a/src/properties.rs +++ b/src/properties.rs @@ -86,29 +86,72 @@ impl FileProperties { } } +use std::ops::{Add, BitAnd, BitOr}; + +macro_rules! define_channels { + ([ + $( + $(#[$meta:meta])? + $name:ident => $shift:literal + ),+ + ]) => { + impl ChannelMask { + $( + $(#[$meta])? + #[allow(missing_docs)] + pub const $name: Self = Self(1 << $shift); + )+ + } + }; +} + /// Channel mask /// /// A mask of (at least) 18 bits, one for each channel. /// -/// * Standard speaker channels: +/// * Standard speaker channels: /// * CAF channel bitmap: -/// * WAV default channel ordering: +/// * WAV default channel ordering: /// * FFmpeg: #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] #[repr(transparent)] pub struct ChannelMask(pub(crate) u32); +define_channels! { + [ + FRONT_LEFT => 0, + FRONT_RIGHT => 1, + FRONT_CENTER => 2, + LOW_FREQUENCY => 3, + BACK_LEFT => 4, + BACK_RIGHT => 5, + FRONT_LEFT_OF_CENTER => 6, + FRONT_RIGHT_OF_CENTER => 7, + BACK_CENTER => 8, + SIDE_LEFT => 9, + SIDE_RIGHT => 10, + TOP_CENTER => 11, + TOP_FRONT_LEFT => 12, + TOP_FRONT_CENTER => 13, + TOP_FRONT_RIGHT => 14, + TOP_BACK_LEFT => 15, + TOP_BACK_CENTER => 16, + TOP_BACK_RIGHT => 17 + ] +} + impl ChannelMask { /// A single front center channel #[must_use] pub const fn mono() -> Self { - Self(0x4) // front center + Self::FRONT_CENTER } /// Front left+right channels #[must_use] pub const fn stereo() -> Self { - Self(0x3) // front left (0x1) + front right (0x2) + // TODO: #![feature(const_trait_impl)] + Self(Self::FRONT_LEFT.0 | Self::FRONT_RIGHT.0) } /// The bit mask @@ -118,6 +161,22 @@ impl ChannelMask { } } +impl BitOr for ChannelMask { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self { + Self(self.0 | rhs.0) + } +} + +impl BitAnd for ChannelMask { + type Output = Self; + + fn bitand(self, rhs: Self) -> Self { + Self(self.0 & rhs.0) + } +} + #[cfg(test)] mod tests { use crate::aac::{AACProperties, AacFile};