// place Reaverb after this effect and load a cab IR.
// you can find some in the Reaper/Data/Cabs folder.

slider1:100<-100,100,1>bias (%)
slider2:24<0,48,0.1>drive (dB)
slider3:0<-36,12,0.1>output (dB)
slider10:2<1,8,1>--oversampling
slider12:7<0,10,0.1>color
slider13:8<0,10,0.1>depth
slider14:5<0.5,10,0.1>width
slider16:0<0,1,1{mono,stereo}>mode

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

@init
ext_nodenorm=1;

last_aa=0;

function singlepole_set(ms)
instance(coeff)
(
coeff = exp(-1/(ms/1000*srate));
);

function singlepole(in,target)
instance(coeff)
(
in*coeff + target*(1-coeff);
);

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

@slider
bias = -slider1*0.5;

input = 10^(slider2/20);
output = 10^((slider3-9.6)/20);

aasize=(slider10+0.5)|0;
aasize<1?aasize=1:aasize>256?aasize=256;

aasize != last_aa ? (

aasize>1 ? (
Q=0.707;
pos=0.9/aasize * $pi;

cpos=cos(pos);
spos=sin(pos);

alpha=spos/(2*Q);

sc = 1/( 1 + alpha);
b1 = (1-cpos) * sc;
b2 = b0 = b1*0.5;
a1 = -2 * cpos * sc;
a2 = (1-alpha)*sc;
);
last_aa=aasize;

hist4=hist5=hist6=hist7=0;
hist8=hist9=hist10=hist11=0;
hist12=hist13=hist14=hist15=0;
hist16=hist17=hist18=hist19=0;
);

AP1Freq = 5 * (2 ^(slider12)) + 50;
depth = slider13/20;
idepth = 1 - abs(depth);
width = slider14;

LP1period = 300/(5248*width);
HP1freq = 800 / width;
HP1period = 1000/HP1freq;

AP1_dsc = AP1Freq*2/srate;
AP1_coef = (1-AP1_dsc)/(1+AP1_dsc);

LP1.singlepole_set(LP1period);
HP1.singlepole_set(HP1period);

stereo_mode = slider16;

@sample
stereo_mode==0 ? (
sspos=0;
src0=(spl0+spl1)*0.5;

loop(aasize,
// run input filter
aasize > 1 ? (
sspl0 = src0*b0 + hist4*b1 + hist5*b2 - hist6*a1 - hist7*a2;
hist5=hist4; hist4=src0; hist7=hist6; hist6=sspl0;
) : (
sspl0=src0;
);


in=(sspl0)*input;
mu = atan(1/(0.001+sign(in)));
E = (75/$pi)*log(1+abs(in)*exp(100*(1+mu+(100-bias)/sqrt(75^2))));
P = (E/1000)*(1+sign(E));
out = tanh(in*P);
sspl0=out*output;

// run output filters
aasize > 1 ? (

(sspos+=1)==1 ? (
spl0 = sspl0*b0 + hist12*b1 + hist13*b2 - hist14*a1 - hist15*a2;
spl1 = spl0;
hist13=hist12; hist12=sspl0; hist15=hist14; hist14=(spl0+spl1)*0.5;
) : (
tmp0 = sspl0*b0 + hist12*b1 + hist13*b2 - hist14*a1 - hist15*a2;
hist13=hist12; hist12=sspl0; hist15=hist14; hist14=tmp0;
);
) : (
spl0=sspl0;
spl1=spl0;
);
);
);

stereo_mode==1 ? (
sspos=0;
src0=spl0;
src1=spl1;

loop(aasize,

// run input filter
aasize > 1 ? (
sspl0 = src0*b0 + hist4*b1 + hist5*b2 - hist6*a1 - hist7*a2;
hist5=hist4; hist4=src0; hist7=hist6; hist6=sspl0;

sspl1 = src1*b0 + hist8*b1 + hist9*b2 - hist10*a1 - hist11*a2;
hist9=hist8; hist8=src1; hist11=hist10; hist10=sspl1;
) : (
sspl0=src0; 
sspl1=src1;
);

in0=(sspl0)*input;
mu0 = atan(1/(0.001+sign(in0)));
E0 = (75/$pi)*log(1+abs(in0)*exp(100*(1+mu0+(100-bias)/sqrt(75^2))));
P0 = (E0/1000)*(1+sign(E0));
out0 = tanh(in0*P0);
sspl0=out0*output;

in1=(sspl1)*input;
mu1 = atan(1/(0.001+sign(in1)));
E1 = (75/$pi)*log(1+abs(in1)*exp(100*(1+mu1+(100-bias)/sqrt(75^2))));
P1 = (E1/1000)*(1+sign(E1));
out1 = tanh(in1*P1);
sspl1=out1*output;

// run output filters
aasize > 1 ? (

(sspos+=1)==1 ? (
spl0 = sspl0*b0 + hist12*b1 + hist13*b2 - hist14*a1 - hist15*a2;
spl1 = sspl1*b0 + hist16*b1 + hist17*b2 - hist18*a1 - hist19*a2;

hist13=hist12; hist12=sspl0; hist15=hist14; hist14=spl0;
hist17=hist16; hist16=sspl1; hist19=hist18; hist18=spl1;
) : (
tmp0 = sspl0*b0 + hist12*b1 + hist13*b2 - hist14*a1 - hist15*a2;
tmp1 = sspl1*b0 + hist16*b1 + hist17*b2 - hist18*a1 - hist19*a2;

hist13=hist12; hist12=sspl0; hist15=hist14; hist14=tmp0;
hist17=hist16; hist16=sspl1; hist19=hist18; hist18=tmp1;
);
) : (
spl0=sspl0;
spl1=sspl1;
);
);
);

x1 = spl0;
ly1 = AP1_coef * (ly1 + x1) - lx1; lx1 = x1;
ly2 = AP1_coef * (ly2 + ly1) - lx2; lx2 = ly1;

rx = spl1;
ry1 = AP1_coef * (ry1 + rx) - rx1; rx1 = rx;
ry2 = AP1_coef * (ry2 + ry1) - rx2; rx2 = ry1;

colored_l = idepth*spl0 + depth*ly2;
colored_r = idepth*spl1 + depth*ry2;

LP1_l = LP1.singlepole(LP1_l,colored_l);
LP1_r = LP1.singlepole(LP1_r,colored_r);

HP1_l = LP1_l - HP1_l_L = HP1.singlepole(HP1_l_L,LP1_l);
HP1_r = LP1_r - HP1_r_L = HP1.singlepole(HP1_r_L,LP1_r);

spl0 = HP1_l;
spl1 = HP1_r;
