use crate::{f, Flt};
use std::simd::f32x4;
#[inline]
pub fn process_1pole_lowpass(input: f32, freq: f32, israte: f32, z: &mut f32) -> f32 {
let b = (-std::f32::consts::TAU * freq * israte).exp();
let a = 1.0 - b;
*z = a * input + *z * b;
*z
}
#[derive(Debug, Clone, Copy, Default)]
pub struct OnePoleLPF<F: Flt> {
israte: F,
a: F,
b: F,
freq: F,
z: F,
}
impl<F: Flt> OnePoleLPF<F> {
pub fn new() -> Self {
Self {
israte: f::<F>(1.0) / f(44100.0),
a: f::<F>(0.0),
b: f::<F>(0.0),
freq: f::<F>(1000.0),
z: f::<F>(0.0),
}
}
pub fn reset(&mut self) {
self.z = f(0.0);
}
#[inline]
fn recalc(&mut self) {
self.b = (f::<F>(-1.0) * F::TAU() * self.freq * self.israte).exp();
self.a = f::<F>(1.0) - self.b;
}
#[inline]
pub fn set_sample_rate(&mut self, srate: F) {
self.israte = f::<F>(1.0) / srate;
self.recalc();
}
#[inline]
pub fn set_freq(&mut self, freq: F) {
if freq != self.freq {
self.freq = freq;
self.recalc();
}
}
#[inline]
pub fn process(&mut self, input: F) -> F {
self.z = self.a * input + self.z * self.b;
self.z
}
}
#[derive(Debug, Copy, Clone, Default)]
pub struct FixedOnePole {
b0: f32,
a1: f32,
y1: f32,
gain: f32,
}
impl FixedOnePole {
pub fn new(pole: f32, gain: f32) -> Self {
let b0 = if pole > 0.0 { 1.0 - pole } else { 1.0 + pole };
Self { b0, a1: -pole, y1: 0.0, gain }
}
pub fn reset(&mut self) {
self.y1 = 0.0;
}
pub fn set_gain(&mut self, gain: f32) {
self.gain = gain;
}
pub fn process(&mut self, input: f32) -> f32 {
let output = self.b0 * self.gain * input - self.a1 * self.y1;
self.y1 = output;
output
}
}
#[inline]
pub fn process_1pole_highpass(input: f32, freq: f32, israte: f32, z: &mut f32, y: &mut f32) -> f32 {
let b = (-std::f32::consts::TAU * freq * israte).exp();
let a = (1.0 + b) / 2.0;
let v = a * input - a * *z + b * *y;
*y = v;
*z = input;
v
}
#[derive(Debug, Clone, Copy, Default)]
pub struct OnePoleHPF<F: Flt> {
israte: F,
a: F,
b: F,
freq: F,
z: F,
y: F,
}
impl<F: Flt> OnePoleHPF<F> {
pub fn new() -> Self {
Self {
israte: f(1.0 / 44100.0),
a: f(0.0),
b: f(0.0),
freq: f(1000.0),
z: f(0.0),
y: f(0.0),
}
}
pub fn reset(&mut self) {
self.z = f(0.0);
self.y = f(0.0);
}
#[inline]
fn recalc(&mut self) {
self.b = (f::<F>(-1.0) * F::TAU() * self.freq * self.israte).exp();
self.a = (f::<F>(1.0) + self.b) / f(2.0);
}
pub fn set_sample_rate(&mut self, srate: F) {
self.israte = f::<F>(1.0) / srate;
self.recalc();
}
#[inline]
pub fn set_freq(&mut self, freq: F) {
if freq != self.freq {
self.freq = freq;
self.recalc();
}
}
#[inline]
pub fn process(&mut self, input: F) -> F {
let v = self.a * input - self.a * self.z + self.b * self.y;
self.y = v;
self.z = input;
v
}
}
#[inline]
pub fn process_1pole_tpt_lowpass(input: f32, freq: f32, israte: f32, z: &mut f32) -> f32 {
let g = (std::f32::consts::PI * freq * israte).tan();
let a = g / (1.0 + g);
let v1 = a * (input - *z);
let v2 = v1 + *z;
*z = v2 + v1;
v2
}
#[inline]
pub fn process_1pole_tpt_highpass(input: f32, freq: f32, israte: f32, z: &mut f32) -> f32 {
let g = (std::f32::consts::PI * freq * israte).tan();
let a1 = g / (1.0 + g);
let v1 = a1 * (input - *z);
let v2 = v1 + *z;
*z = v2 + v1;
input - v2
}
const FILTER_OVERSAMPLE_HAL_CHAMBERLIN: usize = 2;
#[inline]
pub fn process_hal_chamberlin_svf(
input: f32,
freq: f32,
res: f32,
israte: f32,
band: &mut f32,
low: &mut f32,
) -> (f32, f32) {
let q = 1.0 - res;
let cutoff = 2.0 * (std::f32::consts::PI * freq * 0.5 * israte).sin();
let mut high = 0.0;
let mut notch = 0.0;
for _ in 0..FILTER_OVERSAMPLE_HAL_CHAMBERLIN {
*low += cutoff * *band;
high = input - *low - q * *band;
*band += cutoff * high;
notch = high + *low;
}
(high, notch)
}
#[inline]
pub fn process_simper_svf(
input: f32,
freq: f32,
res: f32,
israte: f32,
ic1eq: &mut f32,
ic2eq: &mut f32,
) -> (f32, f32, f32) {
let k = 2f32 - (1.989f32 * res);
let w = std::f32::consts::PI * freq * israte;
let s1 = w.sin();
let s2 = (2.0 * w).sin();
let nrm = 1.0 / (2.0 + k * s2);
let g0 = s2 * nrm;
let g1 = (-2.0 * s1 * s1 - k * s2) * nrm;
let g2 = (2.0 * s1 * s1) * nrm;
let t0 = input - *ic2eq;
let t1 = g0 * t0 + g1 * *ic1eq;
let t2 = g2 * t0 + g0 * *ic1eq;
let v1 = t1 + *ic1eq;
let v2 = t2 + *ic2eq;
*ic1eq += 2.0 * t1;
*ic2eq += 2.0 * t2;
(v2, v1, input - k * v1 - v2)
}
#[inline]
pub fn process_stilson_moog(
input: f32,
freq: f32,
res: f32,
israte: f32,
b0: &mut f32,
b1: &mut f32,
b2: &mut f32,
b3: &mut f32,
delay: &mut [f32; 4],
) -> f32 {
let cutoff = 2.0 * freq * israte;
let p = cutoff * (1.8 - 0.8 * cutoff);
let k = 2.0 * (cutoff * std::f32::consts::PI * 0.5).sin() - 1.0;
let t1 = (1.0 - p) * 1.386249;
let t2 = 12.0 + t1 * t1;
let res = res * (t2 + 6.0 * t1) / (t2 - 6.0 * t1);
let x = input - res * *b3;
*b0 = x * p + delay[0] * p - k * *b0;
*b1 = *b0 * p + delay[1] * p - k * *b1;
*b2 = *b1 * p + delay[2] * p - k * *b2;
*b3 = *b2 * p + delay[3] * p - k * *b3;
*b3 -= (*b3 * *b3 * *b3) * 0.166667;
delay[0] = x;
delay[1] = *b0;
delay[2] = *b1;
delay[3] = *b2;
*b3
}
#[derive(Debug, Clone, Copy)]
pub struct DCBlockFilter<F: Flt> {
xm1: F,
ym1: F,
r: F,
}
impl<F: Flt> DCBlockFilter<F> {
pub fn new() -> Self {
Self { xm1: f(0.0), ym1: f(0.0), r: f(0.995) }
}
pub fn reset(&mut self) {
self.xm1 = f(0.0);
self.ym1 = f(0.0);
}
pub fn set_sample_rate(&mut self, srate: F) {
self.r = f(0.995);
if srate > f(90000.0) {
self.r = f(0.9965);
} else if srate > f(120000.0) {
self.r = f(0.997);
}
}
pub fn next(&mut self, input: F) -> F {
let y = input - self.xm1 + self.r * self.ym1;
self.xm1 = input;
self.ym1 = y;
y as F
}
}
#[derive(Debug, Clone)]
pub struct DCFilterX4 {
y0: f32x4,
x0: f32x4,
alpha: f32x4,
}
impl Default for DCFilterX4 {
fn default() -> Self {
Self {
y0: f32x4::splat(0.),
x0: f32x4::splat(0.),
alpha: f32x4::splat(0.9999),
}
}
}
impl DCFilterX4 {
pub fn process(&mut self, input: f32x4) -> f32x4 {
let y_new = input - self.x0 + self.alpha * self.y0;
self.x0 = input;
self.y0 = y_new;
y_new
}
pub fn reset(&mut self) {
self.y0 = f32x4::splat(0.);
self.x0 = f32x4::splat(0.);
self.alpha = f32x4::splat(0.9999);
}
}