use std::ops::Add;
pub type Mono = f64;
pub type Stereo = [f64; 2];
pub fn mono(frame: impl AsRef<[f64]>) -> Mono {
frame.as_ref().iter().sum::<f64>() / frame.as_ref().len() as f64
}
pub fn stereo(frame: Mono) -> Stereo {
[frame; 2]
}
pub trait Frame: Clone {
const CHANNELS: usize;
fn uniform(amplitude: f64) -> Self;
fn get_channel(&self, index: usize) -> f64;
fn set_channel(&mut self, index: usize, amplitude: f64);
fn map(self, f: impl Fn(f64) -> f64) -> Self;
fn merge(&mut self, other: Self, f: impl Fn(f64, f64) -> f64);
fn avg(&self) -> f64 {
(0..Self::CHANNELS)
.map(|i| self.get_channel(i))
.sum::<f64>()
/ Self::CHANNELS as f64
}
fn add(mut self, other: Self) -> Self {
self.merge(other, Add::add);
self
}
fn write_slice(self, slice: &mut [f64]) {
match (Self::CHANNELS, slice.len()) {
(1, _) => slice.fill(self.get_channel(0)),
(_, 1) => slice[0] = self.avg(),
(a, b) => {
for i in 0..a.min(b) {
slice[i] = self.get_channel(i);
}
}
}
}
}
impl Frame for f64 {
const CHANNELS: usize = 1;
fn uniform(amplitude: f64) -> Self {
amplitude
}
fn get_channel(&self, _index: usize) -> f64 {
*self
}
fn set_channel(&mut self, _index: usize, amplitude: f64) {
*self = amplitude;
}
fn map(self, f: impl Fn(f64) -> f64) -> Self {
f(self)
}
fn merge(&mut self, other: Self, f: impl Fn(f64, f64) -> f64) {
*self = f(*self, other);
}
fn avg(&self) -> f64 {
*self
}
fn add(self, other: Self) -> Self {
self + other
}
}
impl<const N: usize> Frame for [f64; N]
where
Self: Default,
{
const CHANNELS: usize = N;
fn uniform(amplitude: f64) -> Self {
[amplitude; N]
}
fn get_channel(&self, index: usize) -> f64 {
self[index]
}
fn set_channel(&mut self, index: usize, amplitude: f64) {
self[index] = amplitude;
}
fn map(self, f: impl Fn(f64) -> f64) -> Self {
self.map(f)
}
fn merge(&mut self, other: Self, f: impl Fn(f64, f64) -> f64) {
for (a, b) in self.iter_mut().zip(other) {
*a = f(*a, b);
}
}
}