/*
Envelope follower and VCA.

L x |R|		- multiplies left channel signal by right channel level
IN/ENV		- left channel is not processed, right output is a DC signal derived from the input signal level
FLAT/ENV	- as IN/ENV but the left channel is processed to remove level variations

Normally two Envelope plug-ins will be used with the first set to 'FLAT/ENV' to separate
the signal waveform and envelope and the second set to 'L x |R|' to recombine them.
Effects applied to eith the left or right channel between these plug-ins can be used
to process the wavform and envelope separately,
for example delaying the envelope relative to the waveform,
or applying waveshaping with a constant "drive" level.

Note that in 'L x |R|' mode with a mono input the plug-in acts as a 2:1 expander.

This plug is intended for advanced users and is best suited to modular environments
such as AudioMulch. It can output high levels of DC which may damage speakers and other equipment.
*/

slider1:0<0,2,1{L x |R|,IN / ENV,FLAT / ENV}>mode
slider2:0.25<0,1,0.01>attack
slider3:0.4<0,1,0.01>release
slider4:0.5<0,1,0.01>output

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

@init
env = drel = 0;

@slider
fParam1=slider1;
fParam2=slider2;
fParam3=slider3;
fParam4=slider4;

mode = fParam1;
att = pow(10, -0.002-4 * fParam2);
rel = 1 - pow(10, -2-3 * fParam3);
out = pow(10,2*fParam4-1);
(mode==0) ? (out*=2;); (mode==1) ? (out*=0.5;); (mode==2) ? (out*=0.126;); //constant gain across modes

@sample
e=env;
dre=drel;

(dre>(1-rel)) ? dre = (1-rel); //can be unstable if re-edited
flat = (mode==2) ? 1 : 0; //flatten output audio?

(mode) ? ( //Envelope follower mode

b = spl0+spl1;

x = (b<0) ? -b : b; //rectify

(x>e) ? (
e += att * (x-e); //attack + reset rate
dre = 1-rel;
):(
e *= (rel+dre); //release
dre *= 0.9999; //increase release rate
);

x = out * b; //VCA

(flat) ? (
(e<0.01) ? (x*=100;) : (x/=e;); //flatten audio signal
);

spl1 = 0.5*e; //envelope out
spl0 = x; //audio out

):( //VCA mode

a = spl0;
b = spl1;

x = (b<0) ? -b : b; //rectify

(x>e) ? (
e += att * (x-e); //attack + reset rate
dre = 1-rel;
):(
e *= (rel+dre); //release
dre *= 0.9999; //increase release rate
);

x = out * a * e; //VCA

spl0 = x;
spl1 = x;

);

(abs(e)>0.0000000001) ? ( env=e; ):( env=0; );
(abs(dre)>0.0000000001) ? ( drel=dre; ):( drel=0; );

@gfx 0 80
gfx_r=0; gfx_g=0.9; gfx_b=0; gfx_a=1;
gfx_setfont(1,"Arial", 16);

gfx_x =20; gfx_y =10;  gfx_printf("%.1f",pow(10, 3*fParam2) );
gfx_x =70; gfx_y =10;  gfx_printf("ms");
gfx_x =110; gfx_y =10;  gfx_printf("Attack");

gfx_x =20; gfx_y =30;  gfx_printf("%.1f",pow(10, 4*fParam3) );
gfx_x =70; gfx_y =30;  gfx_printf("ms");
gfx_x =110; gfx_y =30;  gfx_printf("Release");

gfx_x =20; gfx_y =50;  gfx_printf("%.1f",(40 * fParam4 - 20) );
gfx_x =70; gfx_y =50;  gfx_printf("dB");
gfx_x =110; gfx_y =50;  gfx_printf("Output");
