56 lines
1.3 KiB
Rust
56 lines
1.3 KiB
Rust
// implemented from https://cytomic.com/files/dsp/SvfLinearTrapOptimised2.pdf
|
|
// thanks, andy!
|
|
|
|
use std::f32::consts;
|
|
|
|
use packed_simd::f32x4;
|
|
|
|
|
|
pub struct SVFSimper {
|
|
pub a1: f32x4,
|
|
pub a2: f32x4,
|
|
pub a3: f32x4,
|
|
|
|
pub ic1eq: f32x4,
|
|
pub ic2eq: f32x4
|
|
}
|
|
|
|
impl SVFSimper {
|
|
pub fn new(cutoff: f32, resonance: f32, sample_rate: f32) -> Self {
|
|
let g = (consts::PI * (cutoff / sample_rate)).tan();
|
|
let k = 2f32 - (1.9f32 * resonance.min(1f32).max(0f32));
|
|
|
|
let a1 = 1.0 / (1.0 + (g * (g + k)));
|
|
let a2 = g * a1;
|
|
let a3 = g * a2;
|
|
|
|
SVFSimper {
|
|
a1: f32x4::splat(a1),
|
|
a2: f32x4::splat(a2),
|
|
a3: f32x4::splat(a3),
|
|
|
|
ic1eq: f32x4::splat(0.0),
|
|
ic2eq: f32x4::splat(0.0)
|
|
}
|
|
}
|
|
|
|
pub fn set(&mut self, cutoff: f32, resonance: f32, sample_rate: f32) {
|
|
let new = Self::new(cutoff, resonance, sample_rate);
|
|
|
|
self.a1 = new.a1;
|
|
self.a2 = new.a2;
|
|
self.a3 = new.a3;
|
|
}
|
|
|
|
#[inline]
|
|
pub fn process(&mut self, v0: f32x4) -> f32x4 {
|
|
let v3 = v0 - self.ic2eq;
|
|
let v1 = (self.a1 * self.ic1eq) + (self.a2 * v3);
|
|
let v2 = self.ic2eq + (self.a2 * self.ic1eq) + (self.a3 * v3);
|
|
|
|
self.ic1eq = (2.0 * v1) - self.ic1eq;
|
|
self.ic2eq = (2.0 * v2) - self.ic2eq;
|
|
|
|
v2
|
|
}
|
|
}
|