// Copyright 2006, Thomas Scott Stillwell
// All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are permitted 
//provided that the following conditions are met:
//
//Redistributions of source code must retain the above copyright notice, this list of conditions 
//and the following disclaimer. 
//
//Redistributions in binary form must reproduce the above copyright notice, this list of conditions 
//and the following disclaimer in the documentation and/or other materials provided with the distribution. 
//
//The name of Thomas Scott Stillwell may not be used to endorse or 
//promote products derived from this software without specific prior written permission. 
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
//IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
//FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 
//BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
//STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
//THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
desc:compressor/limiter, similar to F670

slider1:0<-60,0,0.1>L/Lat Threshold (dB)
slider2:0<-60,0,0.1>R/Vert Threshold (dB)
slider3:70<0,100,0.1>L/Lat Bias
slider4:70<0,100,0.1>R/Vert Bias
slider5:0<-30,30,0.1>L/Lat Makeup gain
slider6:0<-30,30,0.1>R/Vert Makeup gain
slider7:0<0,1,1{Left/Right,Lat/Vert}>AGC
slider8:1<1,6,1>L/Lat Time Constant
slider9:1<1,6,1>R/Vert Time Constant
slider10:100<1,10000,1>L/Lat RMS window
slider11:100<1,10000,1>R/Vert RMS window
//slider13:1<1,50,0.1>L/Lat Current comp. ratio
//slider14:1<1,50,0.1>R/Vert Current comp. ratio
//slider15:0<-90,0,0.1>L/Lat Gain reduction
//slider16:0<-90,0,0.1>R/Vert Gain reduction

@init
  log2db = 8.6858896380650365530225783783321; // 20 / ln(10)
  db2log = 0.11512925464970228420089957273422; // ln(10) / 20 
  i=0;
  lattime=0.0002; //200us
  lreltime=0.300; //300ms
  lrmstime=0.000050; //50us
  lmaxover=0;
  lratio=0;
  lcratio=0;
  lrundb=0;
  loverdb=0;
  lmaxover=0;
  latcoef=exp(-1/(attime * srate));
  lrelcoef=exp(-1/(reltime * srate));
  lrmscoef=exp(-1/(rmstime * srate));
  rattime=0.0002; //200us
  rreltime=0.300; //300ms
  rrmstime=0.000050; //50us
  rmaxover=0;
  rratio=0;
  rcratio=0;
  rrundb=0;
  roverdb=0;
  rmaxover=0;
  ratcoef=exp(-1/(attime * srate));
  rrelcoef=exp(-1/(reltime * srate));
  rrmscoef=exp(-1/(rmstime * srate));
  leftright = 0;
  latvert = 1;
  lgr_meter=1;
  lgr_meter_decay = exp(1/(1*srate));
  rgr_meter=1;
  rgr_meter_decay = exp(1/(1*srate));

@slider
  agc = slider7;

  agc == leftright ? (
    lthresh = slider1;
    lthreshv = exp(lthresh * db2log);
    lratio = 20;
    lbias = 80 * slider3 / 100;
    lcthresh = lthresh - lbias;
    lcthreshv = exp(lcthresh * db2log);
    lmakeup = slider5;
    lmakeupv = exp(lmakeup * db2log);
    ltimeconstant = slider8;
    ltimeconstant == 1 ? (
      lattime = 0.0002;
      lreltime = 0.300;
    );
    ltimeconstant == 2 ? (
      lattime = 0.0002;
      lreltime = 0.800;
    );
    ltimeconstant == 3 ? (
      lattime = 0.0004;
      lreltime = 2.000;
    );
    ltimeconstant == 4 ? (
      lattime = 0.0008;
      lreltime = 5.000;
    );
    ltimeconstant == 5 ? (
      lattime = 0.0002;
      lreltime = 10.000;
    );
    ltimeconstant == 6 ? (
      lattime = 0.0004;
      lreltime = 25.000;
    );
    latcoef = exp(-1 / (lattime * srate));
    lrelcoef = exp(-1 / (lreltime * srate));
    
    lrmstime = slider10 / 1000000; 
    lrmscoef=exp(-1/(lrmstime * srate));

    slider2 = slider1;
    slider4 = slider3;
    slider6 = slider5;
    slider9 = slider8;
    slider11 = slider10;
  ) : (
    lthresh = slider1;
    lthreshv = exp(lthresh * db2log);
    lratio = 20;
    lbias = 80 * slider3 / 100;
    lcthresh = lthresh - lbias;
    lcthreshv = exp(lcthresh * db2log);
    lmakeup = slider5;
    lmakeupv = exp(lmakeup * db2log);
    ltimeconstant = slider8;
    ltimeconstant == 1 ? (
      lattime = 0.0002;
      lreltime = 0.300;
    );
    ltimeconstant == 2 ? (
      lattime = 0.0002;
      lreltime = 0.800;
    );
    ltimeconstant == 3 ? (
      lattime = 0.0004;
      lreltime = 2.000;
    );
    ltimeconstant == 4 ? (
      lattime = 0.0008;
      lreltime = 5.000;
    );
    ltimeconstant == 5 ? (
      lattime = 0.0002;
      lreltime = 10.000;
    );
    ltimeconstant == 6 ? (
      lattime = 0.0004;
      lreltime = 25.000;
    );
    latcoef = exp(-1 / (lattime * srate));
    lrelcoef = exp(-1 / (lreltime * srate));
    
    lrmstime = slider10 / 1000000; 
    lrmscoef=exp(-1/(lrmstime * srate));
    rthresh = slider2;
    rthreshv = exp(rthresh * db2log);
    rratio = 20;
    rbias = 80 * slider4 / 100;
    rcthresh = rthresh - rbias;
    rcthreshv = exp(rcthresh * db2log);
    rmakeup = slider6;
    rmakeupv = exp(rmakeup * db2log);
    rtimeconstant = slider9;
    rtimeconstant == 1 ? (
      rattime = 0.0002;
      rreltime = 0.300;
    );
    rtimeconstant == 2 ? (
      rattime = 0.0002;
      rreltime = 0.800;
    );
    rtimeconstant == 3 ? (
      rattime = 0.0004;
      rreltime = 2.000;
    );
    rtimeconstant == 4 ? (
      rattime = 0.0008;
      rreltime = 5.000;
    );
    rtimeconstant == 5 ? (
      rattime = 0.0002;
      rreltime = 10.000;
    );
    rtimeconstant == 6 ? (
      rattime = 0.0004;
      rreltime = 25.000;
    );
    ratcoef = exp(-1 / (rattime * srate));
    rrelcoef = exp(-1 / (rreltime * srate));
    
    rrmstime = slider11 / 1000000; 
    rrmscoef=exp(-1/(rrmstime * srate));
  );

@sample
  agc == leftright ? (
    aspl0 = abs(spl0);
    aspl1 = abs(spl1);
    lmaxspl = max(aspl0, aspl1);
    lmaxspl = lmaxspl * lmaxspl;

    lrunave = lmaxspl + lrmscoef * (lrunave - lmaxspl);
    ldet = sqrt(max(0,lrunave));

    loverdb = 2.08136898 * log(ldet/lthreshv) * log2db;
    loverdb = max(0,loverdb);

    loverdb > lrundb ? (
      lrundb = loverdb + latcoef * (lrundb - loverdb);
    ) : (
      lrundb = loverdb + lrelcoef * (lrundb - loverdb);
    );
    loverdb = max(lrundb,0);

    lbias == 0 ? (
      lcratio = lratio;
    ) : (
      lcratio = 1 + (lratio-1) * sqrt((loverdb + dcoffset) / (lbias + dcoffset));
    );
    //slider13 = lcratio;
    //slider14 = lcratio;
  
    lgr = -loverdb * (lcratio-1)/lcratio;
    //slider15 = -lgr;
    //slider16 = -lgr;
    lgrv = exp(lgr * db2log);


    lgrv < lgr_meter ? lgr_meter=lgrv : ( lgr_meter*=lgr_meter_decay; lgr_meter>1?lgr_meter=1; );
  
  ) : (  
    aspl0 = abs(spl0+spl1)/2;
    aspl1 = abs(spl0-spl1)/2;
    lmaxspl = aspl0;
    lmaxspl = lmaxspl * lmaxspl;

    lrunave = lmaxspl + lrmscoef * (lrunave - lmaxspl);
    ldet = sqrt(max(0,lrunave));

    loverdb = 2.08136898 * log(ldet/lthreshv) * log2db;
    loverdb = max(0,loverdb);

    loverdb > lrundb ? (
      lrundb = loverdb + latcoef * (lrundb - loverdb);
    ) : (
      lrundb = loverdb + lrelcoef * (lrundb - loverdb);
    );
    loverdb = max(lrundb,0);

    lbias == 0 ? (
      lcratio = lratio;
    ) : (
      lcratio = 1 + (lratio-1) * sqrt((loverdb + dcoffset) / (lbias + dcoffset));
    );

    rmaxspl = aspl1;
    rmaxspl = rmaxspl * rmaxspl;

    rrunave = rmaxspl + rrmscoef * (rrunave - rmaxspl);
    rdet = sqrt(max(0,rrunave));

    roverdb = 2.08136898 * log(rdet/rthreshv) * log2db;
    roverdb = max(0,roverdb);

    roverdb > rrundb ? (
      rrundb = roverdb + ratcoef * (rrundb - roverdb);
    ) : (
      rrundb = roverdb + rrelcoef * (rrundb - roverdb);
    );
    roverdb = max(rrundb,0);

    rbias == 0 ? (
      rcratio = rratio;
    ) : (
      rcratio = 1 + (rratio-1) * sqrt((roverdb + dcoffset) / (rbias + dcoffset));
    );

    //slider13 = lcratio;
    //slider14 = rcratio;
  
    lgr = -loverdb * (lcratio-1)/lcratio;
    rgr = -roverdb * (rcratio-1)/rcratio;
    //slider15 = -lgr;
    //slider16 = -rgr;
    lgrv = exp(lgr * db2log);
    rgrv = exp(rgr * db2log);

    lgrv < lgr_meter ? lgr_meter=lgrv : ( lgr_meter*=lgr_meter_decay; lgr_meter>1?lgr_meter=1; );
    rgrv < rgr_meter ? rgr_meter=rgrv : ( rgr_meter*=rgr_meter_decay; rgr_meter>1?rgr_meter=1; );
  
  );

  agc == leftright ? (
    spl0 *= lgrv * lmakeupv;
    spl1 *= lgrv * lmakeupv;
  ) : (
    sav0 = (spl0 + spl1) * lgrv;
    sav1 = (spl0 - spl1) * rgrv;
    sav0 *= lmakeupv;
    sav1 *= rmakeupv;
    spl0 = (sav0 + sav1) * 0.5;
    spl1 = (sav0 - sav1) * 0.5;
  );

@gfx 0 64 // request horizontal/vertical heights (0 means dont care)
  
  //L/Lat Meter
  lgr_meter *= exp(1/30); lgr_meter>1?lgr_meter=1; // decay meter here so if the audio processing stops it doesnt "stick"
   
  //R/Vert Meter
  rgr_meter *= exp(1/30); rgr_meter>1?rgr_meter=1; // decay meter here so if the audio processing stops it doesnt "stick"
  
  //Draw Gain Reduction Bar L/Lat Meter
  gfx_r=1;gfx_g=gfx_b=0; gfx_a=0.8;//Gain Reducition Colour
  meter_bot=20;
  lmeter_h=min(gfx_h,(gfx_h-(gfx_h*0.15))/2);
  lxscale=gfx_w*20/meter_bot;
  gfx_y=0;
  gfx_x=gfx_w + log10(lgr_meter)*lxscale;
  gfx_rectto(gfx_w,lmeter_h);
   
  //Draw Gain Reduction Bar R/Vert Meter
  gfx_r=1;gfx_g=0.6;gfx_b=0.5; gfx_a=0.8;  
  rmeter_h=min(gfx_h-lmeter_h,(gfx_h-(gfx_h*0.15))/2);
  rxscale=gfx_w*20/meter_bot;
  gfx_y=lmeter_h;//Starts where the other meter ends
  gfx_x=gfx_w + log10(rgr_meter)*rxscale;
  gfx_rectto(gfx_w,rmeter_h+lmeter_h);
  
  gfx_r=gfx_g=gfx_b=1.0; gfx_a=1;//White
  
  //Draw Gain Reduction Number L/Lat Meter
  gfx_x=10; gfx_y=lmeter_h/2 - gfx_texth/2;
  gfx_drawnumber(log10(lgr_meter)*20,1);
  gfx_drawchar($'d');
  gfx_drawchar($'B');
  //Draw Gain Reduction Number R/Vert Meter
  gfx_x=10; gfx_y=(rmeter_h/2) + lmeter_h - gfx_texth/2;
  gfx_drawnumber(log10(rgr_meter)*20,1);
  gfx_drawchar($'d');
  gfx_drawchar($'B');
 
  //Draw Ratio Number and Text L/Lat Meter
  gfx_x=10; gfx_y=gfx_h - gfx_h*0.15/2 - gfx_texth/2;
  gfx_drawchar($'L');
  gfx_drawchar($'/');
  gfx_drawchar($'L');
  gfx_drawchar($'a');
  gfx_drawchar($'t');
  gfx_drawchar($' ');
  gfx_drawchar($'R');
  gfx_drawchar($'a');
  gfx_drawchar($'t');
  gfx_drawchar($'i');
  gfx_drawchar($'o');
  gfx_drawchar($':');
  gfx_drawchar($' ');
  gfx_drawnumber(lcratio,0);  
  
  //Draw Ratio Number and Text R/Vert Meter
  gfx_x=(gfx_w/2) ; gfx_y=gfx_h - gfx_h*0.15/2 - gfx_texth/2;
  gfx_drawchar($' ');
  gfx_drawchar($'R');
  gfx_drawchar($'/');
  gfx_drawchar($'V');
  gfx_drawchar($'e');
  gfx_drawchar($'r');
  gfx_drawchar($'t');
  gfx_drawchar($' ');
  gfx_drawchar($'R');
  gfx_drawchar($'a');
  gfx_drawchar($'t');
  gfx_drawchar($'i');
  gfx_drawchar($'o');
  gfx_drawchar($':');
  gfx_drawchar($' ');
  gfx_drawnumber(rcratio,0);
  
  //Draw Gain Reduction Scale Grid
  gfx_r=gfx_g=gfx_b=1.0; gfx_a=0.6;
  s2=sqrt(2)/2;
  lg = s2;
  
  while(
    gfx_x=gfx_w + log10(lg)*lxscale;
    gfx_x >= 0 ? 
    (
      gfx_y=0;
      gfx_lineto(gfx_x,rmeter_h+lmeter_h,0);
      gfx_y=lmeter_h-gfx_texth/2;
      gfx_x+=2;
      gfx_drawnumber(log10(lg)*20,0);
      gfx_drawchar($'d');
      gfx_drawchar($'B');
    );
    lg*=s2;
    gfx_x >=0;
  );
  //Separation Line 
  gfx_x=0; gfx_y=rmeter_h + lmeter_h;
  gfx_lineto(gfx_w,rmeter_h + lmeter_h,0);
  
