// 2 compressors and a limiter in series
//
// set the desired compressor attack and release times in the code,
// but don't touch the limiter's attack time.
// individual envelope decay times can also be adjusted.

slider1:0<-30,0,0.1>Comp 1 Threshold (dB)
slider2:0<-30,0,0.1>Comp 2 Threshold (dB)
slider3:0<-30,0,0.1>Limiter Threshold (dB)
slider4:0<-18,0,0.1>Limiter Ceiling (dB)

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

@init
output = 1;
transfer_AA = 0;
transfer_BA = 1;
transfer_AB = 0;
transfer_BB = 1;
transfer_AC = 0;
transfer_BC = 1;
gainA = 1;
gainB = 1;
gainC = 1;
envA = 0;
envB = 0;
envC = 0;

// set your desired values here...
attackA = exp(-1/(25/1000*srate)); // e.g. 25 ms
attackB = exp(-1/(5/1000*srate)); // e.g. 5 ms
attackC = exp(-1/(0.005/1000*srate)); // don't touch it !!!

releaseA = exp(-1/(100/1000*srate));
releaseB = exp(-1/(250/1000*srate));
releaseC = exp(-1/(500/1000*srate));

envelope_decayA = exp(-1/(25/1000*srate));
envelope_decayB = exp(-1/(50/1000*srate));
envelope_decayC = exp(-1/(75/1000*srate));
// -------

log2dB = 8.6858896380650365530225783783321;
db2log = 0.11512925464970228420089957273422;
gr_meterA = 1;
gr_meterB = 1;
gr_meterC = 1;
gr_meter_decay = exp(1/(1*srate));

@slider
thresholdA = exp(slider1 * db2log);
transfer_AA = (1/8)-1;
transfer_BA = output * pow(thresholdA,-transfer_AA);

thresholdB = exp(slider2 * db2log);
transfer_AB = (1/2)-1;
transfer_BB = output * pow(thresholdB,-transfer_AB);

thresholdC = exp(slider3 * db2log);
transfer_AC = -1;
transfer_BC = output * pow(thresholdC,-transfer_AC);

ceilingC = 10^(slider4/20);
vol = ceilingC/thresholdC;

@sample
inL = spl0;
inR = spl1;

detA = max(abs(inL),abs(inR));
detA += 0.000000000001;
envA = detA >= envA ? detA : detA+envelope_decayA*(envA-detA);
transfer_gainA = envA > thresholdA ? pow(envA,transfer_AA)*transfer_BA:output;
gainA = transfer_gainA < gainA ? transfer_gainA+attackA*(gainA-transfer_gainA) : transfer_gainA+releaseA*(gainA-transfer_gainA);

out0 = inL * gainA;
out1 = inR * gainA;

detB = max(abs(out0),abs(out1));
envB = detB >= envB ? detB : detB+envelope_decayB*(envB-detB);
transfer_gainB = envB > thresholdB ? pow(envB,transfer_AB)*transfer_BB:output;
gainB = transfer_gainB < gainB ? transfer_gainB+attackB*(gainB-transfer_gainB) : transfer_gainB+releaseB*(gainB-transfer_gainB);

out2 = out0 * gainB;
out3 = out1 * gainB;

detC = max(abs(out2),abs(out3));
envC = detC >= envC ? detC : detC+envelope_decayC*(envC-detC);
transfer_gainC = envC > thresholdC ? pow(envC,transfer_AC)*transfer_BC:output;
gainC = transfer_gainC < gainC ? transfer_gainC+attackC*(gainC-transfer_gainC) : transfer_gainC+releaseC*(gainC-transfer_gainC);

spl0 = out2 * gainC * vol;
spl1 = out3 * gainC * vol;

grA = log(gainA)*log2dB;
grvA = exp(grA*db2log);
grvA < gr_meterA ? gr_meterA=grvA : ( gr_meterA*=gr_meter_decay; gr_meterA>1?gr_meterA=1; );
grminA = min( min(grA,grA) , grminA);

grB = log(gainB)*log2dB;
grvB = exp(grB*db2log);
grvB < gr_meterB ? gr_meterB=grvB : ( gr_meterB*=gr_meter_decay; gr_meterB>1?gr_meterB=1; );
grminB = min( min(grB,grB) , grminB);

grC = log(gainC)*log2dB;
grvC = exp(grC*db2log);
grvC < gr_meterC ? gr_meterC=grvC : ( gr_meterC*=gr_meter_decay; gr_meterC>1?gr_meterC=1; );
grminC = min( min(grC,grC) , grminC);

@gfx 0 52
gfx_a=0.8;

meter_bot=12;
meter_h=min(gfx_h,gfx_h-4);
xscale=gfx_w*20/meter_bot;

gfx_r=1; gfx_g=gfx_b=0; 
gfx_y=0;
gfx_x=gfx_w + log10(gr_meterA)*xscale;
gfx_rectto(gfx_w,meter_h/3);

gfx_r=1; gfx_g=0.5; gfx_b=0;
gfx_y=meter_h/3;
gfx_x=gfx_w + log10(gr_meterB)*xscale;
gfx_rectto(gfx_w,meter_h/1.5);

gfx_r=0; gfx_g=0.5; gfx_b=1;
gfx_y=meter_h/1.5;
gfx_x=gfx_w + log10(gr_meterC)*xscale;
gfx_rectto(gfx_w,meter_h);

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

s2=sqrt(2)/2;
g = s2;
while(
gfx_x=gfx_w + log10(g)*xscale;
gfx_x >= 0 ? (
gfx_y=0;
gfx_lineto(gfx_x,meter_h,0);
gfx_y=meter_h-gfx_texth;
gfx_x+=2;
gfx_drawnumber(log10(g)*20,0);
gfx_drawchar($'d');
gfx_drawchar($'B');
);
g*=s2;
gfx_x >=0;
);

(mouse_cap) ? (grminA=grminB=grminC=0;);

gfx_x=2; gfx_y=1/3*meter_h/2 - gfx_texth/2;
gfx_drawnumber(grminA,1);
gfx_x=2; gfx_y=1*meter_h/2 - gfx_texth/2;
gfx_drawnumber(grminB,1);
gfx_x=2; gfx_y=5/3*meter_h/2 - gfx_texth/2;
gfx_drawnumber(grminC,1);
