use std::marker::PhantomData;
use crate::prelude::*;
pub trait Law: Copy + Default {
fn new(angle: f64) -> Self;
fn angle(&self) -> f64;
fn angle_mut(&mut self) -> &mut f64;
fn gain(&self) -> (f64, f64);
}
#[derive(Clone, Copy, Debug)]
pub struct Linear {
pub angle: f64,
}
impl Default for Linear {
fn default() -> Self {
Self { angle: 0.5 }
}
}
macro_rules! pan_boilerplate {
() => {
fn new(angle: f64) -> Self {
Self { angle }
}
fn angle(&self) -> f64 {
self.angle
}
fn angle_mut(&mut self) -> &mut f64 {
&mut self.angle
}
};
}
#[must_use]
pub fn linear_gain(angle: f64) -> (f64, f64) {
(1.0 - angle, angle)
}
impl Law for Linear {
pan_boilerplate!();
fn gain(&self) -> (f64, f64) {
linear_gain(self.angle)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Power {
pub angle: f64,
}
impl Default for Power {
fn default() -> Self {
Self { angle: 0.5 }
}
}
#[must_use]
pub fn power_gain(angle: f64) -> (f64, f64) {
let (r, l) = (std::f64::consts::FRAC_PI_2 * angle).sin_cos();
(l, r)
}
impl Law for Power {
pan_boilerplate!();
fn gain(&self) -> (f64, f64) {
power_gain(self.angle)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Mixed {
pub angle: f64,
}
impl Default for Mixed {
fn default() -> Self {
Self { angle: 0.5 }
}
}
#[must_use]
pub fn mixed_gain(angle: f64) -> (f64, f64) {
let linear = linear_gain(angle);
let power = power_gain(angle);
((linear.0 * power.0).sqrt(), (linear.1 * power.1).sqrt())
}
impl Law for Mixed {
pan_boilerplate!();
fn gain(&self) -> (f64, f64) {
mixed_gain(self.angle)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Wrapper<A: Audio, P: Law> {
pub pan_law: P,
phantom: PhantomData<A>,
}
impl<A: Audio, P: Law> Wrapper<A, P> {
pub const fn new(pan_law: P) -> Self {
Self {
phantom: PhantomData,
pan_law,
}
}
}
impl<A: Audio, P: Law> Map for Wrapper<A, P> {
type Input = A;
type Output = smp::Stereo;
fn eval(&self, sample: A) -> smp::Stereo {
let smp::Stereo(sl, sr) = sample.duplicate();
let (gl, gr) = self.pan_law.gain();
smp::Stereo(sl * gl, sr * gr)
}
}
pub type Panner<S, P> = eff::MapSgn<S, Wrapper<<S as Signal>::Sample, P>>;
impl<S: Signal, P: Law> Panner<S, P>
where
S::Sample: Audio,
{
pub const fn new_pan_law(sgn: S, pan_law: P) -> Self {
eff::MapSgn::new(sgn, Wrapper::new(pan_law))
}
pub fn new_pan(sgn: S, angle: f64) -> Self {
Self::new_pan_law(sgn, P::new(angle))
}
pub fn angle(&self) -> f64 {
self.map().pan_law.angle()
}
pub fn angle_mut(&mut self) -> &mut f64 {
self.map_mut().pan_law.angle_mut()
}
}
pub type LinearPanner<S> = Panner<S, Linear>;
impl<S: Signal> LinearPanner<S>
where
S::Sample: Audio,
{
pub const fn linear(sgn: S, angle: f64) -> Self {
Self::new_pan_law(sgn, Linear { angle })
}
}
pub type PowerPanner<S> = Panner<S, Power>;
impl<S: Signal> Panner<S, Power>
where
S::Sample: Audio,
{
pub const fn power(sgn: S, angle: f64) -> Self {
Self::new_pan_law(sgn, Power { angle })
}
}
pub type MixedPanner<S> = Panner<S, Mixed>;
impl<S: Signal> Panner<S, Mixed>
where
S::Sample: Audio,
{
pub const fn mixed(sgn: S, angle: f64) -> Self {
Self::new_pan_law(sgn, Mixed { angle })
}
}