/**********************************
BusComp [Build 140325] by Stige T.
**********************************/

Compressor with peak+rms detectors
Reaper 4.59+ Required

filename:0,surrcomp_gfx/liuku.png
filename:1,surrcomp_gfx/liuku2.png
filename:2,surrcomp_gfx/switch.png
filename:3,surrcomp_gfx/sm_liuku.png

@serialize

file_var(0,p1.val_pos);
file_var(0,p2.val_pos);
file_var(0,p3.val_pos);
file_var(0,p4.val_pos);
file_var(0,p5.val_pos);
file_var(0,p12.val_pos);
file_var(0,p19.val_pos);
file_var(0,p20.val_pos);
file_var(0,bt1.val_pos);
file_var(0,bt2.val_pos);

file_var(0,attack);
file_var(0,release);
file_var(0,attack2);
file_var(0,release2);
file_var(0,ratio);
file_var(0,knee);
file_var(0,weight);
file_var(0,weight2);
file_var(0,bcomp);
file_var(0,rmix);
file_var(0,pmix);
file_var(0,tre1);
file_var(0,mkup1);
file_var(0,mt_range);
file_var(0,slink);
file_var(0,HC);
file_var(0,LC);

!p2.val_pos ? p2.val_pos = 200;
!p3.val_pos ? p3.val_pos = 4;

@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));
t200 = exp(-1/(srate*0.2));
tn = exp(-1/(srate*0.3));

bcomp = 0.0078125;
tb50 = exp(-1/(srate*0.05*bcomp));
tb200 = exp(-1/(srate*0.2*bcomp));

/*
dB = 20 * log10( 0.95 );
lin = 10 ^ (dB / 20);
weight = 1-exp(-1/(300 / 1000 * srate));
*/

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

function filterLP(input,freq)
instance(temp,freq,out,n0,weight)
(
  temp != freq ? (
    n0 = 0;
    weight = 1-exp(-2*$pi*freq/srate);
    temp = freq;
  );
  
  out = (n0+=((input-n0)*weight));
);

function filterHP(input,freq)
instance(temp,freq,out,n0,weight)
(
  temp != freq ? (
    n0 = 0;
    weight = 1-exp(-2*$pi*freq/srate);
    temp = freq;
  );
  
  out = input - (n0+=((input-n0)*weight));
);

function samplesniffer(input)
instance(x0,x1,x2,x3,x4,flag) (
  x0 = input;
  x4 = x3;
  x3 = x2;
  x2 = x1;
  x1 = x0;
  (!x1 && !x2 && !x3 && !x4) ? flag = 0 : flag = 1;
);

function peak_block(input,threshold,attack,release,ratio,knee)
instance(e0,e1,envp,dBp,sn,rmod)
(
  threshold < 0 && sn.samplesniffer(input) ? (
    threshold -= knee;
    
    dBp = 20 * log10( input );
    envp = dBp - min(dBp,threshold);
    envp = envp^2 / (envp+knee);
    envp = envp * (1-(1/ratio));
    
    rmod = release;
    release > t20 ? (
      rmod = e0.follower(envp,0,t200,t50);
      rmod = sqrt(release / (0.00001 * rmod+1));
    );
  
    envp = e1.follower(envp,attack,rmod,t10);
    envp = exp((envp * 0.05) * log(10));
  ) : (1);
);

function rms_block(input,threshold,attack,release,ratio,knee)
instance(e0,e1,s,envr,dBr,sn,rmod)
(
  threshold < 0 && sn.samplesniffer(input) ? (
    threshold -= knee;
      
    dBr = 20 * log10( sqrt(s+=weight2*((input*2)^2 - s)) );
    envr = dBr - min(dBr,threshold);
    envr = envr^2 / (envr+knee);
    envr = envr * (1-(1/ratio));
    
    rmod = e0.follower(envr,0,tb200,tb50);
    rmod = sqrt(release / (0.00001 * rmod+1));
    
    envr = dBr - min(dBr,threshold);
    envr = envr^2 / (envr+knee);
    envr = envr * (1-(1/ratio));  
  
    envr = e1.follower(envr,attack,rmod,0);
    envr = exp((envr * 0.05) * log(10));
  ) : (1);
);

@block

@sample

left = abs((spl0*HC)+(spl1*LC));
right = abs((spl0*LC)+(spl1*HC));
rms_input1 = left > rms_input1 ? left : rms_input1;
rms_input2 = right > rms_input2 ? right : rms_input2;

sleep += 1;
sleep >= 128 ? (
  sleep = 0;

  rms_env1 = c1r.rms_block(rms_input1*0.708 * rmix,tre1,attack2,release2,ratio,knee);
  rms_env2 = c2r.rms_block(rms_input2*0.708 * rmix,tre1,attack2,release2,ratio,knee);
  rms_input1 = rms_input2 = 0;
);

peak_env1 = c1p.peak_block( left * pmix,tre1,attack,release,ratio,knee);
peak_env2 = c2p.peak_block( right * pmix,tre1,attack,release,ratio,knee);

spl0 = (spl0/((rms_env1+peak_env1)*0.5)) * mkup1;
spl1 = (spl1/((rms_env2+peak_env2)*0.5)) * mkup1;

@gfx 405 300

// Calculate meters

db_rms1 = 20 * log10(rms_env1)/2;
db_peak1 = 20 * log10(peak_env1)/2;
db_sum1 = db_peak1+db_rms1;
rms1 = 1/exp(( (db_rms1) / 20) * log(10));
peak1 = 1/exp(( (db_peak1+db_rms1) / 20) * log(10));

db_rms2 = 20 * log10(rms_env2)/2;
db_peak2 = 20 * log10(peak_env2)/2;
db_sum2 = db_peak2+db_rms2;
rms2 = 1/exp(( (db_rms2) / 20) * log(10));
peak2 = 1/exp(( (db_peak2+db_rms2) / 20) * log(10));

// ------------------

function init_mouse() (
  !X ? (X = mouse_x;);
  !Y ? (Y = mouse_y;);
); 
function uninit_mouse() (
  X = 0;
  Y = 0;
);
mouse_cap ? init_mouse() : uninit_mouse();

function vert_rmeter(input,input2,range_db,psize_db,width,height,x_pos,y_pos)
instance(range,pheight_px,redux,i,pos,peakhold,redux2,ptmp,pw,nolabels,peak)
(

  range = range_db/psize_db;
  pheight_px = psize_db/range_db*height;
  
  gfx_r = 1; gfx_g = 1; gfx_b = 1; gfx_a = 1;
  gfx_x = x_pos; gfx_y = y_pos;
  gfx_rectto(width+x_pos,height+y_pos);
  
  !nolabels ? (
  
    gfx_setfont(1,Arial,12);
    gfx_x = x_pos+width; gfx_y = y_pos;
    gfx_lineto(x_pos+width+5,y_pos,0);
    gfx_drawnumber(0,0);
    
      i = 1;
      loop(range-1,
        pos = (pheight_px*i)+y_pos;
        
        gfx_x = x_pos+width; gfx_y = pos;
        gfx_lineto(x_pos+width+5,pos,0);
        gfx_y -= 10;
        gfx_drawnumber(i*psize_db,0);
      
        i += 1;  
      );
      
    gfx_x = x_pos+width; gfx_y = y_pos+height-1;
    gfx_lineto(x_pos+width+5,y_pos+height-1,0);
    gfx_y -= 10;
    gfx_drawnumber(range_db,0);
  
  );
  
  input ? (
    gfx_r = 0; gfx_g = 0.8; gfx_b = 0;
    gfx_x = x_pos+1; gfx_y = y_pos+1;
    input <= ptmp ? ptmp = input : (ptmp < 1 ? ptmp += 0.003 : 1;); 
    peak = 20 * log10(ptmp);
    redux = height - ceil( height + ( log( input ) * (43.4 * (10/psize_db) / (50/pheight_px) ) ) )+1;
    redux = max(min(redux,height-1),1);
    gfx_rectto(x_pos+width-1,redux+y_pos);
    
    gfx_r = 0.3; gfx_g = 0.5; gfx_b = 0.3; gfx_a = 1;
    peakhold <= redux ? peakhold = redux : peakhold > 1 ? peakhold -= 1 : 1;  
    gfx_rect(x_pos+1,peakhold+y_pos,width-2,1);   
  );
  
  input2 ? (
    gfx_r = 0.3; gfx_g = 0.5; gfx_b = 0.3; gfx_a = 1;
    gfx_x = x_pos+1;
    redux2 = height - ceil( height + ( log( input2 ) * (43.4 * (10/psize_db) / (50/pheight_px) ) ) )+1;
    redux2 = max(min(redux2,height-1),1);
    gfx_rectto(x_pos+width-1,redux2+y_pos);
  );
  
    gfx_setfont(1,Arial,10);
    gfx_r = 0; gfx_g = 0; gfx_b = 0; gfx_a = 1;
    peak = sprintf(#,"%.1f",abs(peak));
    gfx_measurestr(peak,pw,0);
    gfx_x = x_pos+(width/2)-(pw/2); gfx_y = min(peakhold+y_pos+5,height+60);
    gfx_drawstr(peak);   
      
);

function draw_slider(pot_x,pot_y,min_val,max_val,step_size,frame_width,frame_height,frame_count,showval,gfxindex)
instance(
  total_steps,fpos,pos_temp,
  val_pos,pot_x,pot_y,min_val,
  max_val,step_size,frame_width,
  frame_height,frame_count,showval,
  gfxindex,coordinatelist,prec,
  val_str,str_x,str_y,unit
)
(
  !mouse_cap ? (pos_temp = mouse_y;);

  X > pot_x && X < pot_x+frame_width && Y > pot_y && Y < pot_y+frame_height ? (
    mouse_cap & 4 ? val_pos = 0;
    pos_temp != mouse_y ? (
      mouse_cap & 16 ? (
        mouse_y > pos_temp ? val_pos -= step_size;
        mouse_y < pos_temp ? val_pos += step_size;
      ) : (
        val_pos = floor(  (max_val - (((max_val - min_val)/(frame_height-(frame_height/7.5))) * (mouse_y-pot_y-(frame_height/15)))) * (1/step_size)  ) / (1/step_size);
      );
    );
    pos_temp = mouse_y;
  );
  
  val_pos = max(val_pos,min_val);
  val_pos = min(val_pos,max_val);
  fpos = floor(((val_pos - min_val) * (frame_count-1))/(max_val - min_val)) * frame_height;
  coordinatelist[0] = 0;
  coordinatelist[1] = fpos;
  coordinatelist[2] = coordinatelist[6] = frame_width;
  coordinatelist[3] = coordinatelist[7] = frame_height;
  coordinatelist[4] = pot_x;
  coordinatelist[5] = pot_y;
  gfx_blitext(gfxindex, coordinatelist, 0);
  showval ? (
    step_size >= 1 ? prec = "%.0f";
    step_size < 1 ? prec = "%.1f";
    step_size < 0.1 ? prec = "%.2f";
    val_str = sprintf (#,prec,val_pos);
    val_str = strcat(val_str, unit);
    gfx_measurestr(val_str,str_x,str_y);
    gfx_x = pot_x+(frame_width/2)-(str_x/2) ; gfx_y = pot_y+frame_height+5-(str_y/8);
    gfx_drawstr(val_str);  
  );
  val_pos;
);

function draw_button(pos_x,pos_y,frame_width,frame_height,gfxindex)
instance(val_pos,fpos,coordinatelist,adj)
(
  X > pos_x && X < pos_x+frame_width && Y > pos_y && Y < pos_y+frame_height ? (
    
    !val_pos && !adj ? (
      val_pos = 1;
      adj = 1;
    );
    
    val_pos && !adj ? (
      val_pos = 0;
      adj = 1;
    );
    
  ) : (adj = 0;);
  
  fpos = val_pos * frame_height;

  coordinatelist[0] = 0;
  coordinatelist[1] = fpos;
  coordinatelist[2] = coordinatelist[6] = frame_width;
  coordinatelist[3] = coordinatelist[7] = frame_height;
  coordinatelist[4] = pos_x;
  coordinatelist[5] = pos_y;
  gfx_a=1;
  gfx_blitext(gfxindex, coordinatelist, 0);
  val_pos;
);

pt_x = 20;
pt_y = 60;

// Background
gfx_r = 0.2; gfx_g = 0.3; gfx_b = 0.3; gfx_a = 0.75;
gfx_rect(0,0,405,300);

// Boxes
gfx_r = 0.2; gfx_g = 0.3; gfx_b = 0.3; gfx_a = 0.5;
gfx_rect(pt_x-10,pt_y-25,160,255);
gfx_rect(mt_x-10,mt_y-35,65,255);
gfx_rect(pt_x+235,pt_y-25,65,255);
gfx_rect(pt_x+310,pt_y-25,65,255);

gfx_r = 1; gfx_g = 1; gfx_b = 1; gfx_a = 1;

att = p1.draw_slider(0+pt_x,10+pt_y,0,100,1,20,200,41,1,0); // attack
rel = p2.draw_slider(30+pt_x,10+pt_y,20,1000,10,20,200,41,1,0); // release
rat = p3.draw_slider(60+pt_x,10+pt_y,1,20,0.1,20,200,41,1,0); // ratio
kne = p4.draw_slider(90+pt_x,10+pt_y,0,20,1,20,200,41,1,0); // knee
rmss = p19.draw_slider(125+pt_x,35+pt_y,-1,1,0.1,10,60,41,1,3); // rms speed
rpmix = p20.draw_slider(125+pt_x,125+pt_y,-1,1,0.1,10,60,41,1,3); // rms peak mix
bcomp = 0.0078125 * (rmss >= 0 ? (rmss+1)^3 : rmss/1.5+1);

attack = exp(-1/(srate*att/1000));
release = exp(-1/(srate*rel/1000));
attack2 = exp(-1/(srate*att*bcomp/1000));
release2 = exp(-1/(srate*rel*bcomp/1000));
ratio = rat;
knee = kne;
makeup = 10 ^ (slider6 / 20);
weight = 1-exp(-1/( (max(rel*3,200)) / 1000 * srate));
weight2 = 1-exp(-1/( (max(rel*3,200)) * bcomp / 1000 * srate));
rmix = (rpmix+1);
pmix = abs(rpmix-1);

tre1 = p5.draw_slider(258+pt_x,10+pt_y,-50,0,1,20,200,41,1,0); // threshold 1
out1 = p12.draw_slider(333+pt_x,10+pt_y,-20,20,0.5,20,200,41,1,0); // out 1
mkup1 = 10 ^ (out1 / 20);

mt_range = bt1.draw_button(-1+mt_x,205+mt_y,20,10,2);
mt_range = (mt_range*10) + 10;

slink = bt2.draw_button(330,5,20,10,2);
slink ? (
  LC = 0.3;
  HC = 0.7;
) : (
  LC = 0;
  HC = 1;
);

mt_x = 190;
mt_y = 70;

mt1.nolabels = 1;
mt1.vert_rmeter(peak1,rms1,mt_range,3,15,200,0+mt_x,0+mt_y);
mt2.vert_rmeter(peak2,rms2,mt_range,3,15,200,22+mt_x,0+mt_y);


gfx_r = 1; gfx_g = 1; gfx_b = 1; gfx_a = 1;

gfx_setfont(1,Arial,18);
gfx_x = 10; gfx_y = 10;
gfx_drawstr("Stereo Hybrid Bus Compressor");

gfx_setfont(1,Arial,12);
gfx_x = 355; gfx_y = 4;
gfx_drawstr("Stereo link");

gfx_x = pt_x+37; gfx_y = pt_y-20;
gfx_drawstr("COMPRESSOR");

gfx_x = pt_x+4; gfx_y = pt_y-2;
gfx_drawstr("Att");
gfx_x = pt_x+33; gfx_y = pt_y-2;
gfx_drawstr("Rel");
gfx_x = pt_x+60; gfx_y = pt_y-2;
gfx_drawstr("Ratio");
gfx_x = pt_x+90; gfx_y = pt_y-2;
gfx_drawstr("Knee");
gfx_x = pt_x+118; gfx_y = pt_y+23;
gfx_drawstr("RMST");
gfx_x = pt_x+118; gfx_y = pt_y+113;
gfx_drawstr("RMSM");

gfx_x = mt_x+1; gfx_y = mt_y-30;
gfx_drawstr("METERS");

gfx_x = mt_x+25; gfx_y = pt_y+214;
gfx_drawstr("Range");

gfx_x = mt_x+6; gfx_y = mt_y-12;
gfx_drawstr("L");
gfx_x = mt_x+27; gfx_y = mt_y-12;;
gfx_drawstr("R");

gfx_x = pt_x+239; gfx_y = pt_y-20;
gfx_drawstr("THRESHOLD");

gfx_x = pt_x+325; gfx_y = pt_y-20;
gfx_drawstr("OUTPUT");

p1.unit =
p2.unit =
"ms";

p3.unit = ":1";

p4.unit =
p5.unit =
p6.unit =
p7.unit =
p8.unit =
p9.unit =
p10.unit =
p11.unit =
p12.unit =
p13.unit =
p14.unit =
p15.unit =
p16.unit =
p17.unit =
p18.unit =
"dB";
