/*
Multi-Band Compressor

Three-band soft-knee compressor with switchable M or S component processing.

As well as just "squashing everything" this plug-in can be used to "overcook" the mid-frequencies
while leaving the low end unprocessed, enhancing playback over small speakers
without affecting the overall sound too much.

Listen		Audition the low, mid and high bands individually
X-Over 1		Low / mid crossover frequency
X-Over 2		Mid / high crossover frequency
L/M/H Comp	Compression amount for each of the 3 bands
L/M/H Trim	Output level trims (for spectrum shaping - make-up gain is applied automatically)
Attack		Attack time
Release		Release time
Stereo Width	Used to restore stereo width when heavy processing is applied to Mono component
Process		Select Mono (mid) or Stereo (side) component

To give more control when mastering (and to offer something different from other dynamics processors)
in 'Mid' mode this plug does not compress any stereo information,
but in 'Side' mode only the stereo component is processed
giving control over ambience and space with a similar sound to strereo "shufflers"
- but be careful with the levels!
The stereo width control works as a "mono depth" control in 'Side' mode.
*/

slider1:0<0,3,1{Output,Lo,Mid,Hi}>|------------------- listen
slider2:0.25<0,1,0.001>x-over 1
slider3:0.75<0,1,0.001>x-over 2
slider4:0<0,1,0.01>|-------------- lo comp
slider5:0<0,1,0.01>mid comp
slider6:0<0,1,0.01>hi comp
slider7:0.5<0,1,0.01>|------------------ lo trim
slider8:0.5<0,1,0.01>mid trim
slider9:0.5<0,1,0.01>hi trim
slider10:0.5<0,1,0.001>|---------------- attack
slider11:0.5<0,1,0.001>release
slider12:0.5<0,1,0.01>width
slider13:0<0,1,1{Mid,Side}>process
slider14:0.5<0,1,0.01>main out

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

@init
gain1 = 0; // ???
gain2 = 0;
gain3 = 0;

fb1 = fb2 = fb3 = 0;

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

@slider
fParam1=slider1; // listen
fParam2=slider2; // lo<>mid
fParam3=slider3; // mid<>hi
fParam4=slider4; // lo comp
fParam5=slider5; // mid comp
fParam6=slider6; // hi comp
fParam7=slider7; // lo out
fParam8=slider8; // mid out
fParam9=slider9; // hi out
fParam10=slider10; // attack
fParam11=slider11; // release
fParam12=slider12; // width
fParam13=slider13; // ms swap
fParam14=slider14; // main out

driv1 = pow(10,(2.5 * fParam4) - 1);
trim1 = (0.5 + (4 - 2 * fParam10) * (fParam4 * fParam4 * fParam4));
trim1 = (trim1 * pow(10, 2 * fParam7 - 1));
att1 = pow(10, -0.05 - (2.5 * fParam10));
rel1 = pow(10, -2 - (3.5 * fParam11));

driv2 = pow(10,(2.5 * fParam5) - 1);
trim2 = (0.5 + (4 - 2 * fParam10) * (fParam5 * fParam5 * fParam5));
trim2 = (trim2 * pow(10, 2 * fParam8 - 1));
att2 = pow(10, -0.05 - (2 * fParam10));
rel2 = pow(10, -2 - (3 * fParam11));

driv3 = pow(10,(2.5 * fParam6) - 1);
trim3 = (0.5 + (4 - 2 * fParam10) * (fParam6 * fParam6 * fParam6));
trim3 = (trim3 * pow(10, 2 * fParam9 - 1));
att3 = pow(10, -0.05 - (1.5 * fParam10));
rel3 = pow(10, -2 - (2.5 * fParam11));

switch = fParam1|0;

(switch==0) ? (
slev=fParam12; // width (side-level)
);
(switch==1) ? (
trim2=0; trim3=0; slev=0;
);
(switch==2) ? (
trim1=0; trim3=0; slev=0;
);
(switch==3) ? (
trim1=0; trim2=0; slev=0;
);

fi1 = pow(10,fParam2 - 1.70); fo1=(1 - fi1);
fi2 = pow(10,fParam3 - 1.05); fo2=(1 - fi2);

(fParam13>0.5) ? mswap=1 : mswap=0;

main = pow(10, 2 * fParam14 - 1);

@sample
b1=fb1;
b2=fb2;
l=fb3;

g1=gain1;
g2=gain2;
g3=gain3;

r1=1-rel1;
r2=1-rel2;
r3=1-rel3;

a = spl0;
b = spl1;

b = (mswap) ? -b : b;
s = (a - b) * slev; // keep stereo component for later
a += b;

b2 = (fi2 * a) + (fo2 * b2); // crossovers
b1 = (fi1 * b2) + (fo1 * b1);
l = (fi1 * b1) + (fo1 * l);
m = b2 - l;
h = a - b2;

tmp1 = (l>0) ? l : -l; // lo
g1 = (tmp1>g1) ? g1+att1*(tmp1-g1) : g1*r1;
tmp1 = 1 / (1 + driv1 * g1);

tmp2 = (m>0) ? m : -m; // mid
g2 = (tmp2>g2) ? g2+att2*(tmp2-g2) : g2*r2;
tmp2 = 1 / (1 + driv2 * g2);

tmp3 = (h>0) ? h : -h; // hi
g3 = (tmp3>g3) ? g3+att3*(tmp3-g3) : g3*r3;
tmp3 = 1 / (1 + driv3 * g3);

a = (l*tmp1*trim1) + (m*tmp2*trim2) + (h*tmp3*trim3);

c = a + s; // output
d = (mswap) ? s - a : a - s;

spl0 = c * main;
spl1 = d * main;

gain1=(g1<0.0000000001) ? 0 : g1;
gain2=(g2<0.0000000001) ? 0 : g2;
gain3=(g3<0.0000000001) ? 0 : g3;

(abs(b1)<0.0000000001) ? ( fb1=0; fb2=0; fb3=0; ):( fb1=b1; fb2=b2; fb3=l; );

// meter
grA = log(tmp1)*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(tmp2)*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(tmp3)*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 300
gfx_r=0; gfx_g=0.9; gfx_b=0; gfx_a=1;
gfx_setfont(1,"Arial", 16);

gfx_x =20; gfx_y =50;  gfx_printf("%.0f",srate * fi1 * (0.098 + 0.09*fi1 + 0.5*pow(fi1,8.2)));
gfx_x =70; gfx_y =50;  gfx_printf("Hz");
gfx_x =110; gfx_y =50;  gfx_printf("X-Over 1");

gfx_x =20; gfx_y =70;  gfx_printf("%.0f",srate * fi2 * (0.015 + 0.15*fi2 + 0.9*pow(fi2,8.2)));
gfx_x =70; gfx_y =70;  gfx_printf("Hz");
gfx_x =110; gfx_y =70;  gfx_printf("X-Over 2");

gfx_r=0.8; gfx_g=0.8; gfx_b=0.2;

gfx_x =20; gfx_y =90;  gfx_printf("%.1f",30 * fParam4);
gfx_x =70; gfx_y =90;  gfx_printf("dB");
gfx_x =110; gfx_y =90;  gfx_printf("Lo Comp");

gfx_x =20; gfx_y =110;  gfx_printf("%.1f",30 * fParam5);
gfx_x =70; gfx_y =110;  gfx_printf("dB");
gfx_x =110; gfx_y =110;  gfx_printf("Mid Comp");

gfx_x =20; gfx_y =130;  gfx_printf("%.1f",30 * fParam6);
gfx_x =70; gfx_y =130;  gfx_printf("dB");
gfx_x =110; gfx_y =130;  gfx_printf("Hi Comp");

gfx_r=0.8; gfx_g=0.5; gfx_b=0.2;

gfx_x =20; gfx_y =150;  gfx_printf("%.1f",(40 * fparam7 - 20));
gfx_x =70; gfx_y =150;  gfx_printf("dB");
gfx_x =110; gfx_y =150;  gfx_printf("Lo Trim");

gfx_x =20; gfx_y =170;  gfx_printf("%.1f",(40 * fparam8 - 20));
gfx_x =70; gfx_y =170;  gfx_printf("dB");
gfx_x =110; gfx_y =170;  gfx_printf("Mid Trim");

gfx_x =20; gfx_y =190;  gfx_printf("%.1f",(40 * fparam9 - 20));
gfx_x =70; gfx_y =190;  gfx_printf("dB");
gfx_x =110; gfx_y =190;  gfx_printf("Hi Trim");

gfx_r=0.2; gfx_g=0.8; gfx_b=0.8;

gfx_x =20; gfx_y =210;  gfx_printf("%.1f",(-301030.1 / (srate * log10(1 - att2))));
gfx_x =70; gfx_y =210;  gfx_printf("s");
gfx_x =110; gfx_y =210;  gfx_printf("Attack");

gfx_x =20; gfx_y =230;  gfx_printf("%.1f",(-301.0301 / (srate * log10(1 - rel2))));
gfx_x =70; gfx_y =230;  gfx_printf("ms");
gfx_x =110; gfx_y =230;  gfx_printf("Release");

gfx_x =20; gfx_y =250;  gfx_printf("%.0f",(200 * fParam12));
gfx_x =70; gfx_y =250;  gfx_drawchar($'%');
gfx_x =110; gfx_y =250;  gfx_printf("Width");

gfx_x =20; gfx_y =270;  gfx_printf("%.1f",(40 * fparam14 - 20));
gfx_x =70; gfx_y =270;  gfx_printf("dB");
gfx_x =110; gfx_y =270;  gfx_printf("Main Out");

// meter
gfx_a=0.8;

meter_bot= fParam13 ? 15 : 30;
meter_h=39;
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;
gm = s2;
while(
gfx_x=gfx_w + log10(gm)*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(gm)*20,0);
gfx_drawchar($'d');
gfx_drawchar($'B');
);
gm*=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);
