/*
Sub Bass Synthesizer

More bass than you could ever need!

Type	Distort
	Takes the existing low frequencies, clips them to produce harmonics at a constant level,
	then filters out the higher harmonics. Has a similar effect to compressing the low frequencies.

	Divide
	As above, but works at an octave below the input frequency, like an octave divider guitar pedal.

	Invert
	Flips the phase of the low frequency signal once per cycle to add a smooth sub-octave.
	A simplified version of the classic Sub-Harmonic Synthesizer.

	Key Osc
	Adds a decaying "boom" - usually made with an oscillator before a noise gate keyed with the kick drum signal.

Level		Amount of synthesized low frequency signal to be added
Tune		Maximum frequency - keep as low as possible to reduce distortion
		In Key Osc mode sets the oscillator frequency
Dry Mix		Reduces the level of the original signal
Threshold		Increase to "gate" the low frequency effect and stop unwanted background rumbling
Release		Decay time in Key Osc mode

Be aware that you may be adding low frequency content outside the range of your monitor speakers.
To avoid clipping, follow with a limiter plug-in. 
*/

slider1:0<0,3,1{Distort,Divide,Invert,Key Osc}>type
slider2:0.3<0,1,0.01>level
slider3:0.6<0,1,0.01>tune
slider4:1<0,1,0.01>dry mix
slider5:0.6<0,1,0.01>threshold
slider6:0.65<0,1,0.01>release

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

@init
phi = env = filt1 = filt2 = filt3 = filt4 = filti = filto = 0;

dvd = 1;
phs = 1;
osc = 0; //oscillator phase

@slider
fParam1 = slider1; //type
fParam2 = slider2; //level
fParam3 = slider3; //tune
fParam4 = slider4; //dry mix
fParam5 = slider5; //thresh
fParam6 = slider6; //release

dvd = 1;
phs = 1;
osc = 0; //oscillator phase

typ = fParam1|0;
filti = (typ == 3) ? 0.018 : pow(10,-3 + (2 * fParam3));
filto = 1 - filti;

wet = fParam2;
dry = fParam4;

thr = pow(10,-3 + (3 * fParam5));
rls = (1 - pow(10,-2 - (3 * fParam6)));
dphi = (0.456159 * pow(10,-2.5 + (1.5 * fParam3)));

@sample
dph = dphi;
rl = rls;
phii = phi;
en = env;
os = osc;
th = thr;
dv = dvd;
ph = phs;
we = wet;
dr = dry;
f1 = filt1;
f2 = filt2;
f3 = filt3;
f4 = filt4;

fi = filti;
fo = filto;

a = spl0;
b = spl1;

f1 = (fo * f1) + (fi * (a + b));
f2 = (fo * f2) + (fi * f1);

sub = f2;
(sub > th) ? (
sub = 1;
):(
(sub < -th) ? (
sub = -1;
):(
sub = 0;
);
);

((sub * dv) < 0) ? //octave divider
(
dv = -dv; (dv < 0) ? ph = -ph;
);

(typ == 1) ? //divide
(
sub = ph * sub;
);
(typ == 2) ? //invert
(
sub = (ph * f2 * 2);
);
(typ == 3) ? //osc
(
(f2 > th) ? ( en = 1; ):( en = en * rl; );
sub = (en * sin(phii));
//phii = mod(phii + dph,6.283185);
test0 = phii + dph;
test1 = (test0 / 6.283185) |0;
test2 = test1 * 6.283185;
phii = test0 - test2;
);

f3 = (fo * f3) + (fi * sub);
f4 = (fo * f4) + (fi * f3);

c = (a * dr) + (f4 * we); // output
d = (b * dr) + (f4 * we);

spl0 = c;
spl1 = d;

(abs(f1)<0.0000000001) ? ( filt1=0; ):( filt1=f1; );
(abs(f2)<0.0000000001) ? ( filt2=0; ):( filt2=f2; );
(abs(f3)<0.0000000001) ? ( filt3=0; ):( filt3=f3; );
(abs(f4)<0.0000000001) ? ( filt4=0; ):( filt4=f4; );

dvd = dv;
phs = ph;
osc = os;
phi = phii;
env = en;

@gfx 0 120
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",(100 * wet) );
gfx_x =80; gfx_y =10;  gfx_drawchar($'%');
gfx_x =120; gfx_y =10;  gfx_printf("Level");

gfx_x =20; gfx_y =30;  gfx_printf("%.1f",(0.0726 * srate * pow(10,-2.5 + (1.5 * fParam3))) );
gfx_x =80; gfx_y =30;  gfx_printf("Hz");
gfx_x =120; gfx_y =30;  gfx_printf("Tune");

gfx_x =20; gfx_y =50;  gfx_printf("%.0f",(100 * dry) );
gfx_x =80; gfx_y =50;  gfx_drawchar($'%');
gfx_x =120; gfx_y =50;  gfx_printf("Dry Mix");

gfx_x =20; gfx_y =70;  gfx_printf("%.1f",(60 * fParam5 - 60) );
gfx_x =80; gfx_y =70;  gfx_printf("dB");
gfx_x =120; gfx_y =70;  gfx_printf("Threshold");

gfx_x =20; gfx_y =90;  gfx_printf("%.1f",(-301.03 / (srate * log10(rls))) );
gfx_x =80; gfx_y =90;  gfx_printf("ms");
gfx_x =120; gfx_y =90;  gfx_printf("Release");
