// Non linear digital implementation of the moog ladder filter ???

desc: Mono.

slider1:22000<20,22000,1>Frequency (Hz)
slider2:0<0,1,0.01>Resonance
slider3:0<-24,24,0.1>Output (dB)

in_pin:L in
in_pin:R in
out_pin:L out
out_pin:R out

@init
function tanh(x) 
( 
x = exp(2*x);
(x - 1) / (x + 1);
);

v2 = srate; //srate; //40000; // twice the 'thermal voltage of a transistor' ???
sr = srate; //srate/2; //22100; // sr is half the actual filter sampling rate ???

@slider
cutoff_hz = slider1;
resonance = min(slider2*0.9,0.9);
output = 10^(slider3/20);

kfc = cutoff_hz/sr;
kf = cutoff_hz/(sr*2);
// frequency & amplitude correction
kfcr = 1.8730*(kfc*kfc*kfc) + 0.4955*(kfc*kfc) - 0.6490*kfc + 0.9988;
kacr = -3.9364*(kfc*kfc) + 1.8409*kfc + 0.9968;
x = -2 * $pi * kfcr * kf; // temp var: input for taylor approximations
exp_out = exp(x);
k2vg = v2*(1-exp_out); // filter tuning

@sample
input = (spl0+spl1)*0.5;

x1 = (input - 4*resonance*amf*kacr) / v2;
tanh1 = tanh(x1);
x2 = az1/v2;
tanh2 = tanh(x2);
ay1 = az1 + k2vg * ( tanh1 - tanh2);
//ay1 = az1 + k2vg * ( tanh( (input - 4*resonance*amf*kacr) / v2) - tanh(az1/v2) );
az1 = ay1;
ay2 = az2 + k2vg * ( tanh(ay1/v2) - tanh(az2/v2) );
az2 = ay2;
ay3 = az3 + k2vg * ( tanh(ay2/v2) - tanh(az3/v2) );
az3 = ay3;
ay4 = az4 + k2vg * ( tanh(ay3/v2) - tanh(az4/v2) );
az4 = ay4;
// 1/2-sample delay for phase compensation
amf = (ay4+az5)*0.5;
az5 = ay4;
// oversampling (repeat same block)
ay1 = az1 + k2vg * ( tanh( (input - 4*resonance*amf*kacr) / v2) - tanh(az1/v2) );
az1 = ay1;
ay2 = az2 + k2vg * ( tanh(ay1/v2) - tanh(az2/v2) );
az2 = ay2;
ay3 = az3 + k2vg * ( tanh(ay2/v2) - tanh(az3/v2) );
az3 = ay3;
ay4 = az4 + k2vg * ( tanh(ay3/v2) - tanh(az4/v2) );
az4 = ay4;
// 1/2-sample delay for phase compensation
amf = (ay4+az5)*0.5;
az5 = ay4;
sigout = amf;

spl1=spl0=sigout * output;
