desc:LT_Expand
//An expander that works like ReaComp
//hacked together by ashcat_lt
//mostly from SaulT's code

slider1:0<-60,12,0.1>Threshold (dB)
slider2:0<0,250,1> Pre-comp (ms)
slider3:3<0,500,0.1>Attack (ms)
slider4:100<0,5000,1>Release (ms)
slider5:1<1,99,0.1>Ratio (X:1 99=infinity)
slider6:0<0,20,0.1>Knee size (dB)
slider7:0<0,1,1{main,aux}>Detector input(pair)
slider8:5<0,1000,1>RMS size (ms)
slider9:0<-121,12,0.1>Output Wet (dB -121=-inf)
slider10:-121<-121,12,0.1>Output Dry (dB -121=-inf)
slider13:0<0,1,1{off,on}>Delta (invert wet)
slider14:0<0,1,1{off,on}>Cv out

in_pin:main_L
in_pin:main_R
in_pin:aux_L
in_pin:aux_R
out_pin:main_L
out_pin:main_R
out_pin:aux_L
out_pin:aux_R
out_pin:CV
out_pin:CV


@init
bpos = 0;
bpint = 0;

function int(x) ( x|0 );
dbc = 20/log(10);
function db2ratio(d) ( exp(log(10)/20*d); ); //( 10^(d/20); );
function ratio2db(r) ( log(abs(r))*dbc; );

thresh = slider1;
thresh_r = db2ratio(thresh);
ratio = slider5;
ratio >= 99 ? ratio = 1000;
knee = slider6;
rms_ms = slider8;
att_ms = slider3;
rel_ms = slider4;

kneeL = thresh - knee/2;
kneeR = thresh + knee/2;


function attack_set(att_ms)
  instance(attack, iattack)
(
  attack = exp(-3/(att_ms / 1000 * srate));
  iattack = 1-attack;
);

function release_set(rel_ms)
  instance(release, irelease)
(
  release = exp(-3/(rel_ms / 1000 * srate));
  irelease = 1-release;
);

function RMS_set(rms_ms)
  instance(coeff, icoeff)
(
  coeff = exp(-1/(rms_ms / 1000 * srate));
  icoeff = 1-coeff;
);


function RMS(input)
  instance(rms_s, coeff, icoeff)
(
  rms_s = (rms_s * coeff) + (icoeff * input * input);
  sqrt(rms_s);
);

function att_rel(input)
  instance(output, attack, iattack, release, irelease, coeff, icoeff)
( attacking == 1 ?
  (coeff = attack;
   icoeff = iattack;):
  (coeff = release;
   icoeff = irelease;);
  output = (output * coeff) + (icoeff * input);
);


function spline2(mu,dv1,dv2) ( mu*dv1 + mu*mu*0.5*(check3=(dv2-dv1)); );

//intC = spline2(0.5,ratio,1);
//check4 = knee * intC;

function process(input) instance(in,out,mu,diff) (
  in = ratio2db(input);
  (in <= kneeL) ? out = intC + (in - kneeL) * ratio;
  (in >= kneeR) ? out = in; 
  (in > kneeL && in < kneeR) ? (
    mu = (in - kneeL)/knee; 
    mu = max(0, min(1, (in - kneeL)/knee));    
    out = intC   + check2=(spline2(mu,ratio,1) *knee);
    );
    check = out;
   diff = out - in;
   db2ratio(diff);
 );
 
pdc_bot_ch = 0; pdc_top_ch = 2;


@slider

thresh = slider1;
thresh_r = db2ratio(thresh);

delay_length = slider2 * srate/1000;
buffer_length = delay_length * 2;
pdc_delay = delay_length;

ratio = slider5;
ratio >= 99 ? ratio = 1000;
knee = slider6;
half_knee = knee/2;
kneeL = thresh - knee/2;
kneeR = thresh + knee/2;
intC = thresh - half_knee * ratio;

sidechain = slider7;

rms_ms = slider8;
rms0.RMS_set(rms_ms);

att_ms = slider3;
att_rel0.attack_set(att_ms);

rel_ms = slider4;
att_rel0.release_set(rel_ms);

slider9 <= -121 ?
  output_wet = 0 :
  output_wet = db2ratio(slider9);
slider10 <= -121 ?
  output_dry = 0 :
  output_dry = db2ratio(slider10);

auto_gain = 1;
limit = slider12;
slider13 == 1 ? 
  auto_gain = -1;
CV_out = slider14   


@sample

main_inputL = spl0;
main_inputR = spl1;


rms_in = ((1-sidechain)*(main_inputL+main_inputR)+sidechain*(aux_inputL+aux_inputR))/2;
rms_out = rms0.RMS(rms_in);

abs(rms_out) >= thresh_r ? 
  attacking = 1:
  attacking =0;
ar_out = att_rel0.att_rel (rms_out);

proc_gain = process(ar_out);

bpint[0] = main_inputL;
bpint[1] = main_inputR;
(bpint += 2) >=  buffer_length ? bpint = 0;

proc_inputL = bpint[0];
proc_inputR = bpint[1];

proc_outputL = proc_inputL*proc_gain*auto_gain;
proc_outputR = proc_inputR*proc_gain*auto_gain;

spl0 = proc_inputL * output_dry + proc_outputL * output_wet;
spl1 = proc_inputR * output_dry + proc_outputR * output_wet;

spl2 = spl2;
spl3 = spl3;
spl4 = proc_gain*CV_out;
spl5 = proc_gain*CV_out;
