/****************
Growl by Stige T.
****************/

desc:Growl [Build 151009]

slider1:-80<-80,0,1>Threshold
slider2:2800<20,20000,10>Low Pass
slider3:0.5<0,1,0.01>Resonance
slider4:0<0,1,0.01>Filter Mod
slider5:-20<-50,0,5>Compander

slider9:0.5<0,1,0.01>Mix
slider10:0<-20,20,1>Output

@init

t01 = exp(-1/(srate*0.001));
t05 = exp(-1/(srate*0.005));
t10 = exp(-1/(srate*0.01));
t20 = exp(-1/(srate*0.02));
t30 = exp(-1/(srate*0.03));
t50 = exp(-1/(srate*0.05));
t100 = exp(-1/(srate*0.1));
t200 = exp(-1/(srate*0.2));

function follower(input,att,rel,t)
instance (env,tmp) (
  tmp = input >= tmp ? input : input + t * (tmp-input);
  (tmp > env) ? (
      env = att * (env - tmp) + tmp;
  ) : (
      env = rel * (env - tmp) + tmp;
  );
);

function HFLF_init(freq)
instance(n0,weight)
(
  n0 = 0;
  weight = 1-exp(-2*$pi*freq/srate);
);

function LFcut(input)
instance(out,n0,weight)
(
  out = input - (n0+=((input-n0)*weight));
);

function limiter(input,threshold)
instance(env,hpf) (
  env = hpf.LFcut( max(abs(input),threshold)-threshold);
);

function SPLP_init(freq,res)
instance(f,p,k,t,t2,r) (
  f = (freq+freq) / srate;
  p = f * (1.8-0.8*f);
  k = p + p -1.0;
  t = (1.0-p) * 1.386249;
  t2 = 12.0 + t * t;
  r = res * (t2+6.0*t) / (t2-6.0*t);
);

function SPLP(input)
instance(x,y1,y2,y3,y4,oldx,oldy,oldy1,oldy2,oldy3)
(
  x = input - SPLPCOEFF.r * y4;
  y1 = x * SPLPCOEFF.p + oldx * SPLPCOEFF.p - SPLPCOEFF.k * y1;
  y2 = y1 * SPLPCOEFF.p + oldy1 * SPLPCOEFF.p - SPLPCOEFF.k * y2;
  y3 = y2 * SPLPCOEFF.p + oldy2 * SPLPCOEFF.p - SPLPCOEFF.k * y3;
  y4 = y3 * SPLPCOEFF.p + oldy3 * SPLPCOEFF.p - SPLPCOEFF.k * y4;
  y4 = y4 - ((y4*y4*y4)/6.0);
  oldx = x;
  oldy1 = y1;
  oldy2 = y2;
  oldy3 = y3;
  y4;
);

function swing(input)
instance(env,e0) (
  env = e0.follower(abs(input),t01,t10,t10);
  env = lim / (env + comp);
  input * env;
);

maxbcount = 32;
function blocksniffer(inL,inR) (
  (this.bcount <= maxbcount) ? (
    inL <= 0.0000001 ? this.zspl += 1;
    inL == inR ? this.mspl += 1;
    this.bcount += 1;
  ) : (
    (this.zspl == maxbcount) ? sniffer.hasInput = 0 : sniffer.hasInput = 1;
    (sniffer.hasInput && this.mspl == maxbcount) ? sniffer.isMono = 1 : sniffer.isMono = 0;
    this.mspl = 0;
    this.zspl = 0;
    this.bcount = 1;
  );
);

l0.hpf.HFLF_init(20);
l1.hpf.HFLF_init(20);

@slider

threshold = 10 ^ (slider1 / 20);
freq = slider2;
res = slider3;
out = 10 ^ (slider10 / 20);
mix = slider9;
comp = 10 ^ (slider5 / 20);
lim = comp^0.3;
fmod = slider4;

SPLPCOEFF.SPLP_init(freq,res);

@block

blocksniffer(In.L,In.R);

@sample

In.L = spl0;
In.R = spl1;

aenv = (e0.follower( (max(abs(In.L),threshold)-threshold) * 4,t01,t200,t10) * fmod) + (1-fmod);
aenv != lastaenv ? (
  SPLPCOEFF.SPLP_init(min(max(aenv*freq,20),20000),res);
);
lastaenv = aenv;

wetL = f0.SPLP( l0.limiter(In.L,threshold));
wetL = sw0.swing(wetL);

!sniffer.isMono ? (
  wetR = f1.SPLP( l1.limiter(In.R,threshold));
  wetR = sw1.swing(wetR);
) : (
  wetR = wetL;
);

spl0 = ( (wetL * mix) + (spl0 * (1-mix)) ) * out;
spl1 = ( (wetR * mix) + (spl1 * (1-mix)) ) * out;
