use std::{
f32::consts::SQRT_2,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use crate::Panning;
#[derive(Debug, Copy, Clone, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Frame {
pub left: f32,
pub right: f32,
}
impl Frame {
pub const ZERO: Frame = Frame {
left: 0.0,
right: 0.0,
};
#[must_use]
pub fn new(left: f32, right: f32) -> Self {
Self { left, right }
}
#[must_use]
pub fn from_mono(value: f32) -> Self {
Self::new(value, value)
}
#[allow(clippy::float_cmp)]
#[must_use = "This method returns a new Frame and does not mutate the original value"]
pub fn panned(self, panning: Panning) -> Self {
if panning == Panning::CENTER {
return self;
}
let panning = panning.0.clamp(-1.0, 1.0);
let left_right_mix = (panning + 1.0) * 0.5;
Self::new(
self.left * (1.0 - left_right_mix).sqrt(),
self.right * left_right_mix.sqrt(),
) * SQRT_2
}
#[must_use = "This method returns a new Frame and does not mutate the original value"]
pub fn as_mono(self) -> Self {
Self::from_mono((self.left + self.right) / 2.0)
}
}
impl Add for Frame {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::new(self.left + rhs.left, self.right + rhs.right)
}
}
impl AddAssign for Frame {
fn add_assign(&mut self, rhs: Self) {
self.left += rhs.left;
self.right += rhs.right;
}
}
impl Sub for Frame {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self::new(self.left - rhs.left, self.right - rhs.right)
}
}
impl SubAssign for Frame {
fn sub_assign(&mut self, rhs: Self) {
self.left -= rhs.left;
self.right -= rhs.right;
}
}
impl Mul<f32> for Frame {
type Output = Self;
fn mul(self, rhs: f32) -> Self::Output {
Self::new(self.left * rhs, self.right * rhs)
}
}
impl MulAssign<f32> for Frame {
fn mul_assign(&mut self, rhs: f32) {
self.left *= rhs;
self.right *= rhs;
}
}
impl Div<f32> for Frame {
type Output = Self;
fn div(self, rhs: f32) -> Self::Output {
Self::new(self.left / rhs, self.right / rhs)
}
}
impl DivAssign<f32> for Frame {
fn div_assign(&mut self, rhs: f32) {
self.left /= rhs;
self.right /= rhs;
}
}
impl Neg for Frame {
type Output = Self;
fn neg(self) -> Self::Output {
Self::new(-self.left, -self.right)
}
}
#[must_use]
pub fn interpolate_frame(
previous: Frame,
current: Frame,
next_1: Frame,
next_2: Frame,
fraction: f32,
) -> Frame {
let c0 = current;
let c1 = (next_1 - previous) * 0.5;
let c2 = previous - current * 2.5 + next_1 * 2.0 - next_2 * 0.5;
let c3 = (next_2 - previous) * 0.5 + (current - next_1) * 1.5;
((c3 * fraction + c2) * fraction + c1) * fraction + c0
}