/*
Stereo Simulator

Add artificial width to a mono signal.

Width	Stereo width (turn to right for comb filter mode, left for Haas panning mode)
Delay	Delay time - use higher values for more filter "combs" across the frequency spectrum
Balance	Balance correction for Haas mode
Mod	Amount of delay modulation (defaults to OFF to reduce processor usage)
Rate	Modulation rate (note that modulation completely disappears in mono)

This plug converts a mono signal to a 'wide' signal using two techniques:
Comb filtering where the signal is panned left and right alternately with increasing frequency,
and Haas panning where a time delayed signal sounds appears to be
at the same level as a quieter non-delayed version.

Comb mode is mono compatible.
Haas mode is not, but sounds fine on some signals such as backing vocals.
This plug-in must be used in a stereo channel or bus!
*/

slider1:0.78<0,1,0.01>width
slider2:0.43<0,1,0.01>delay
slider3:0.5<0,1,0.01>balance
slider4:0<0,1,0.01>mod
slider5:0.5<0,1,0.01>rate
slider6:0.5<0,1,0.01>output

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

@init
ext_noinit = 1;

size = 4800;
bufpos = 0;
buffer = size;

memset(buffer, 0, size);

@slider
fParam1 = slider1; //Haas/Comb width
fParam2 = slider2; //delay
fParam3 = slider3; //balance
fParam4 = slider4; //mod
fParam5 = slider5; //rate
fParam6 = slider6; //output

phi = 0;
dphi = (3.141 * pow(10,-2 + 3 * fParam5) / srate);
mod = (2100 * pow(fParam4, 2));

(fParam1<0.5) ?
(
fli = (0.25 + (1.5 * fParam1));
fld = 0;
fri = (2 * fParam1);
frd = (1 - fri);
):(
fli = (1.5 - fParam1);
fld = (fParam1 - 0.5);
fri = fli;
frd = -fld;
);

fdel = (20 + 2080 * pow(fParam2, 2));

(fParam3>0.5) ?
(
fli *= ((1 - fParam3) * 2);
fld *= ((1 - fParam3) * 2);
):(
fri *= (2 * fParam3);
frd *= (2 * fParam3);
);

fri *= (0.5 + abs(fParam1 - 0.5));
frd *= (0.5 + abs(fParam1 - 0.5));
fli *= (0.5 + abs(fParam1 - 0.5));
fld *= (0.5 + abs(fParam1 - 0.5));

trim = pow(10, (2 * fParam6) - 1);

@sample
ph = phi;
bp = bufpos;

(mod>0) ? //modulated delay
(
a = spl0+spl1; //sum to mono

buf[buffer + bp] = a; //write
tmp = (bp + (fdel + abs(mod * sin(ph)))|0 ) % 4410;
b = buf[buffer + tmp];

c = (a * fli) - (b * fld); //output
d = (a * fri) - (b * frd);

bp = (bp - 1); (bp < 0) ? bp = 4410; //buffer position

ph = ph + dphi;

spl0 = c;
spl1 = d;

):(

a = spl0+spl1; //sum to mono

buf[buffer + bp] = a; //write
tmp = (bp + (fdel)|0 ) % 4410;
b = buf[buffer + tmp];

c = (a * fli) - (b * fld); //output
d = (a * fri) - (b * frd);

bp = (bp - 1); (bp < 0) ? bp = 4410; //buffer position

spl0 = c;
spl1 = d;

);

spl0*=trim;
spl1*=trim;

bufpos = bp;

//phi = mod(ph,6.2831853);
test1 = (ph / 6.2831853) |0;
test2 = test1 * 6.2831853;
phi = ph - test2;

@gfx 0 140
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("%.0f",(200 * abs(fParam1 - 0.5)) );
gfx_x =80; gfx_y =10;  gfx_drawchar($'%');
gfx_x =120; gfx_y =10;  gfx_printf("Width");
(fParam1<0.5) ? (
gfx_x =190; gfx_y =10;  gfx_printf("- Haas -");
):(
gfx_x =190; gfx_y =10;  gfx_printf("- Comb -");
);

gfx_x =20; gfx_y =30;  gfx_printf("%.3f",(1000 * fdel / srate) );
gfx_x =80; gfx_y =30;  gfx_printf("ms");
gfx_x =120; gfx_y =30;  gfx_printf("Delay");

gfx_x =20; gfx_y =50;  gfx_printf("%.0f",(200 * (fParam3 - 0.5)) );
gfx_x =80; gfx_y =50;  gfx_drawchar($'%');
gfx_x =120; gfx_y =50;  gfx_printf("Balance");

(mod>0) ? (
gfx_x =20; gfx_y =70;  gfx_printf("%.3f",(1000 * mod / srate) );
gfx_x =80; gfx_y =70;  gfx_printf("ms");
):(
gfx_x =20; gfx_y =70;  gfx_printf("OFF");
);
gfx_x =120; gfx_y =70;  gfx_printf("Mod");

gfx_x =20; gfx_y =90;  gfx_printf("%.3f",(pow(10,2 - 3 * fParam5)) );
gfx_x =80; gfx_y =90;  gfx_printf("sec");
gfx_x =120; gfx_y =90;  gfx_printf("Rate");

gfx_x =20; gfx_y =110;  gfx_printf("%.1f",(40*fParam6 - 20) );
gfx_x =80; gfx_y =110;  gfx_printf("dB");
gfx_x =120; gfx_y =110;  gfx_printf("Output");
