// (C) 2008-2009, Lubomir I. Ivanov

// NO WARRANTY IS GRANTED. THIS PLUG-IN IS PROVIDED ON AN "AS IS" BASIS, WITHOUT
// WARRANTY OF ANY KIND. NO LIABILITY IS GRANTED, INCLUDING, BUT NOT LIMITED TO,
// ANY DIRECT OR INDIRECT,  SPECIAL,  INCIDENTAL OR CONSEQUENTIAL DAMAGE ARISING
// OUT OF  THE  USE  OR INABILITY  TO  USE  THIS PLUG-IN,  COMPUTER FAILTURE  OF
// MALFUNCTION INCLUDED.  THE USE OF THE SOURCE CODE,  EITHER  PARTIALLY  OR  IN
// TOTAL, IS ONLY GRANTED,  IF USED IN THE SENSE OF THE AUTHOR'S INTENTION,  AND
// USED WITH ACKNOWLEDGEMENT OF THE AUTHOR. FURTHERMORE IS THIS PLUG-IN A  THIRD
// PARTY CONTRIBUTION,  EVEN IF INCLUDED IN REAPER(TM),  COCKOS INCORPORATED  OR
// ITS AFFILIATES HAVE NOTHING TO DO WITH IT.  LAST BUT NOT LEAST, BY USING THIS
// PLUG-IN YOU RELINQUISH YOUR CLAIM TO SUE IT'S AUTHOR, AS WELL AS THE CLAIM TO
// ENTRUST SOMEBODY ELSE WITH DOING SO.
// 
// Released under GPL:
// <http://www.gnu.org/licenses/>.

//******************************************************************************
// Stanley A. White
// Design of a digital biquadratic peaking or notch filters
// for digital audio equalization
// JAES, Vol. 34, No. 6, 1986 June
//
// HP, LP (AppleFilter) based on au unit tutorial (apple.com)
//******************************************************************************

desc: 3-Band Peak Filter
desc: 3-Band Peak Filter (PF-3A, PF-3B, Apple: HP, LP) [Liteon]
//tags: filter equalizer
//author: Liteon

slider1:0<0,1,1{Stereo,Mono}>Processing
slider2:0<0,100,0.01>HP Filter (2-Pole)
slider3:0<0,1,1{PF-3A,PF-3B}>Peak Filter Type
slider4:50<0,100,0.01>Frequency 1
slider5:0.3<0.005,1,0.00005>Bandwidth 1
slider6:0<-18,18,0.01>Gain 1
slider7:50<0,100,0.01>Frequency 2
slider8:0.3<0.005,1,0.00005>Bandwidth 2
slider9:0<-18,18,0.01>Gain 2
slider10:50<0,100,0.01>Frequency 3
slider11:0.3<0.005,1,0.00005>Bandwidth 3
slider12:0<-18,18,0.05>Gain 3
slider13:100<0,100,0.01>LP Filter (2-Pole)
slider14:0<0,100,0.05>Saturation (%)
slider15:0<-24,24,0.01>Output
slider16:0<0,1,1{Off,On}>Oversample (x2)

in_pin:left input
in_pin:right input
out_pin:left output
out_pin:right output

//=============================================================
@init
ext_tail_size = -1;
//fir restoration
fc1 = 1;
fc2 = -0.75;
fc3 = 0.17;
fgain = 4.5;

//fir bandlimit
bl_c1 = 0.52;
bl_c2 = 0.54;
bl_c3 = -0.02;

//denorm
denorm = 10^-30;

//=============================================================
@slider
os = slider16;
drive = slider14/350;
drv2_k = drive/(1-drive);
outv = 10^(slider15/20);
noisefloor = 10^(slider14/100)/10^6;

//hpf
//--------------------------------
sx = 16+slider2*1.20103;
cx_hp = floor(exp(sx*log(1.059))*8.17742);
cutoff_hp = 2*cx_hp/srate;

k = 0.5*sin($pi*cutoff_hp);
c1 = 0.5*(1-k)/(1+k);
c2 = (0.5+c1)*cos($pi*cutoff_hp);
c3 = (0.5+c1+c2)*0.25;

a0_hp = 2*c3;
a1_hp = -4*c3;
a2_hp = 2*c3;
b1_hp = -2*c2;
b2_hp = 2*c1;

//lpf
//--------------------------------
sx = 16+slider13*1.20103;
cx_lp = floor(exp(sx*log(1.059))*8.17742);
cutoff_lp = 2*cx_lp/srate;

k = 0.5*sin($pi*cutoff_lp);
c1 = 0.5*(1-k)/(1+k);
c2 = (0.5+c1)*cos($pi*cutoff_lp);
c3 = (0.5+c1-c2)*0.25;

a0_lp = 2*c3;
a1_lp = 4*c3;
a2_lp = 2*c3;
b1_lp = -2*c2;
b2_lp = 2*c1;


//pf1
//--------------------------------
sx = 16+slider4*1.20103;
freq1 = floor(exp(sx*log(1.059))*8.17742);
//if gain
slider5 != 0 ? (
//type a
//-------------
slider3 == 0 ? (
gdb = slider6;
bw = slider5;
k = 10^(gdb/20);
w = 2*$pi*freq1/srate;
bwr = bw*w;
gdb < 0 ? (
bw_inv = min(2*freq1+1500, 20000);
bwr = 2*$pi*(bw_inv)*(bw)/srate;
);
abw = (1-tan(bwr/2))/(1+tan(bwr/2));
gain = 0.5*(1+k+abw-k*abw);
cx1 = gain;
cx11 = gain*(-2*cos(w)*(1+abw))/(1+k+abw-k*abw);
cx12 = gain*(abw+k*abw+1-k)/(abw-k*abw+1+k);
cy11 = 2*cos(w)/(1+tan(bwr/2));
cy12 = -abw;
) : (
//type b
//-------------
m = 10^(slider6/20);
bw = slider5;
w0 = 2*$pi*freq1;
om = bw*w0;
ta = tan(om/srate/2);
p = 1.2;
slider6 < 0 ? p = 0.2;
d = ta+p;
cx1 = (p+m*ta)/d;
cx11 = -2*p*cos(w0/srate)/d;
cx12 = (p-m*ta)/d;
cy11 = 2*p*cos(w0/srate)/d;
cy12 = -(p-ta)/d;
);
);

//pf2
//--------------------------------
sx = 16+slider7*1.20103;
freq2 = floor(exp(sx*log(1.059))*8.17742);
//if gain
slider9 != 0 ? (
//type a
//-------------
slider3 == 0 ? (
gdb = slider9;
bw = slider8;
k = 10^(gdb/20);
w = 2*$pi*freq2/srate;
bwr = bw*w;
gdb < 0 ? (
bw_inv = min(2*freq2+1500, 20000);
bwr = 2*$pi*(bw_inv)*(bw)/srate;
);
abw = (1-tan(bwr/2))/(1+tan(bwr/2));
gain = 0.5*(1+k+abw-k*abw);
cx2 = gain;
cx21 = gain*(-2*cos(w)*(1+abw))/(1+k+abw-k*abw);
cx22 = gain*(abw+k*abw+1-k)/(abw-k*abw+1+k);
cy21 = 2*cos(w)/(1+tan(bwr/2));
cy22 = -abw;
) : (
//type b
//-------------
m = 10^(slider9/20);
bw = slider8;
w0 = 2*$pi*freq2;
om = bw*w0;
ta = tan(om/srate/2);
p = 1.2;
slider9 < 0 ? p = 0.2;
d = ta+p;
cx2 = (p+m*ta)/d;
cx21 = -2*p*cos(w0/srate)/d;
cx22 = (p-m*ta)/d;
cy21 = 2*p*cos(w0/srate)/d;
cy22 = -(p-ta)/d;
);
);

//pf3
//--------------------------------
sx = 16+slider10*1.20103;
freq3 = floor(exp(sx*log(1.059))*8.17742);
//if gain
slider12 != 0 ? (
//type a
//-------------
slider3 == 0 ? (
gdb = slider12;
bw = slider11;
k = 10^(gdb/20);
w = 2*$pi*freq3/srate;
bwr = bw*w;
gdb < 0 ? (
bw_inv = min(2*freq3+1500, 20000);
bwr = 2*$pi*(bw_inv)*(bw)/srate;
);
abw = (1-tan(bwr/2))/(1+tan(bwr/2));
gain = 0.5*(1+k+abw-k*abw);
cx3 = gain;
cx31 = gain*(-2*cos(w)*(1+abw))/(1+k+abw-k*abw);
cx32 = gain*(abw+k*abw+1-k)/(abw-k*abw+1+k);
cy31 = 2*cos(w)/(1+tan(bwr/2));
cy32 = -abw;
) : (
//type b
//-------------
m = 10^(slider12/20);
bw = slider11;
w0 = 2*$pi*freq3;
om = bw*w0;
ta = tan(om/srate/2);
p = 1.2;
slider12 < 0 ? p = 0.2;
d = ta+p;
cx3 = (p+m*ta)/d;
cx31 = -2*p*cos(w0/srate)/d;
cx32 = (p-m*ta)/d;
cy31 = 2*p*cos(w0/srate)/d;
cy32 = -(p-ta)/d;
);
);

//=============================================================
@sample

linl = spl0;
linr = spl1;

//mono
//-----------------------------------------------

slider1 == 1 ? (

//hp
//--------------------------------
slider2 > 0 ? (
out_hp_l_1 = a0_hp*linl+a1_hp*mem_hp_l_11+a2_hp*mem_hp_l_12-b1_hp*mem_hp_l_13-b2_hp*mem_hp_l_14;
mem_hp_l_12 = mem_hp_l_11;
mem_hp_l_11 = linl;
mem_hp_l_14 = mem_hp_l_13;
mem_hp_l_13 = out_hp_l_1;
linl = linr = out_hp_l_1;
);

//f1
//--------------------------------
slider6 != 0 ? (
x1l = (linl+linr)/2;
y1l = cx1*x1l+cx11*x11l+cx12*x12l+cy11*y11l+cy12*y12l;
x12l = x11l;
x11l = x1l;
y12l = y11l;
y11l = y1l;
f1outl = y1l;
) : (
f1outl = (linl+linr)/2;
);

//f2
//--------------------------------
slider9 != 0 ? (
x2l = f1outl;
y2l = cx2*x2l+cx21*x21l+cx22*x22l+cy21*y21l+cy22*y22l;
x22l = x21l;
x21l = x2l;
y22l = y21l;
y21l = y2l;
f2outl = y2l;
) : (
f2outl = f1outl;
);

//f3
//--------------------------------
slider12 != 0 ? (
x3l = f2outl;
y3l = cx3*x3l+cx31*x31l+cx32*x32l+cy31*y31l+cy32*y32l;
x32l = x31l;
x31l = x3l;
y32l = y31l;
y31l = y3l;
f3outl=y3l+denorm;
f3outr=y3l+denorm;
) : (
f3outl=f2outl+denorm;
f3outr=f2outl+denorm;
);

//lp
//-----------------------------------
slider13 < 100 ? (
out_lp_l_1 = a0_lp*f3outl+a1_lp*mem_lp_l_11+a2_lp*mem_lp_l_12-b1_lp*mem_lp_l_13-b2_lp*mem_lp_l_14;
mem_lp_l_12 = mem_lp_l_11;
mem_lp_l_11 = f3outl;
mem_lp_l_14 = mem_lp_l_13;
mem_lp_l_13 = out_lp_l_1;

f3outl = out_lp_l_1;
f3outr = out_lp_l_1;
);

//saturation
//-----------------------------------
linl = f3outl;
linr = f3outr;
slider14 > 0 ? (
(spl0 != 0 || spl1 != 0) ? (
whitel = (rand(2)-1)*noisefloor;
linl += whitel;
);

//oversampling?
os == 1 ? (
//---------------------------
//power series in
ps_out1l = 0.5*(linl+ps_out2l);
ps_out2l = 0.5*ps_out1l;

//---------------------------
//drive
o_in1l = (1+drv2_k)*ps_out1l/(1+drv2_k*abs(ps_out1l));
o_in2l = (1+drv2_k)*ps_out2l/(1+drv2_k*abs(ps_out2l));

//---------------------------
//bandlimit
bl3_1 = bl2_1;
bl3_2 = bl2_2;

bl2_1 = bl1_1;
bl2_2 = bl1_2;

bl1_1 = o_in1l;
bl1_2 = o_in2l;

bl_out1 = (bl1_1*bl_c1 + bl2_1*bl_c2 + bl3_1*bl_c3);
bl_out2 = (bl1_2*bl_c1 + bl2_2*bl_c2 + bl3_2*bl_c3);


//---------------------------
//power series out
o_out1l = 0.5*(bl_out1+o_out2l);
o_out2l = 0.5*(bl_out2+o_out1l);

//---------------------------
//fir restoration
s3l = s2l;
s2l = s1l;
s1l = o_out1l;

o_outl = (s1l*fc1+s2l*fc2+s3l*fc3)*fgain;

) : (

o_outl = (1+drv2_k)*linl/(1+drv2_k*abs(linl));
);

//out
spl0 = (o_outl)*outv+denorm;
spl1 = (o_outl)*outv+denorm;

) : (
spl0 = (linl)*outv+denorm;
spl1 = (linl)*outv+denorm;
);

) : (

//stereo
//-----------------------------------------------

//hp
//--------------------------------
slider2 > 0 ? (
out_hp_l_1 = a0_hp*linl+a1_hp*mem_hp_l_11+a2_hp*mem_hp_l_12-b1_hp*mem_hp_l_13-b2_hp*mem_hp_l_14;
mem_hp_l_12 = mem_hp_l_11;
mem_hp_l_11 = linl;
mem_hp_l_14 = mem_hp_l_13;
mem_hp_l_13 = out_hp_l_1;
out_hp_r_1 = a0_hp*linr+a1_hp*mem_hp_r_11+a2_hp*mem_hp_r_12-b1_hp*mem_hp_r_13-b2_hp*mem_hp_r_14;
mem_hp_r_12 = mem_hp_r_11;
mem_hp_r_11 = linr;
mem_hp_r_14 = mem_hp_r_13;
mem_hp_r_13 = out_hp_r_1;

linl = out_hp_l_1;
linr = out_hp_r_1;
);

//f1
//--------------------------------
slider6 != 0 ? (
x1l = linl;
x1r = linr;

y1l = cx1*x1l+cx11*x11l+cx12*x12l+cy11*y11l+cy12*y12l;
y1r = cx1*x1r+cx11*x11r+cx12*x12r+cy11*y11r+cy12*y12r;

x12l = x11l;
x12r = x11r;

x11l = x1l;
x11r = x1r;

y12l = y11l;
y12r = y11r;

y11l = y1l;
y11r = y1r;

f1outl = y1l;
f1outr = y1r;
) : (
f1outl = linl;
f1outr = linr;
);

//f2
//--------------------------------
slider9 != 0 ? (
x2l = f1outl;
x2r = f1outr;

y2l = cx2*x2l+cx21*x21l+cx22*x22l+cy21*y21l+cy22*y22l;
y2r = cx2*x2r+cx21*x21r+cx22*x22r+cy21*y21r+cy22*y22r;

x22l = x21l;
x22r = x21r;

x21l = x2l;
x21r = x2r;

y22l = y21l;
y22r = y21r;

y21l = y2l;
y21r = y2r;

f2outl = y2l;
f2outr = y2r;
) : (
f2outl = f1outl;
f2outr = f1outr;
);

//f3
//--------------------------------
slider12 != 0 ? (
x3l = f2outl;
x3r = f2outr;

y3l = cx3*x3l+cx31*x31l+cx32*x32l+cy31*y31l+cy32*y32l;
y3r = cx3*x3r+cx31*x31r+cx32*x32r+cy31*y31r+cy32*y32r;

x32l = x31l;
x32r = x31r;

x31l = x3l;
x31r = x3r;

y32l = y31l;
y32r = y31r;

y31l = y3l;
y31r = y3r;

f3outl=y3l+denorm;
f3outr=y3r+denorm;
) : (
f3outl=f2outl+denorm;
f3outr=f2outr+denorm;
);

//lp
//-----------------------------------
slider13 < 100 ? (
out_lp_l_1 = a0_lp*f3outl+a1_lp*mem_lp_l_11+a2_lp*mem_lp_l_12-b1_lp*mem_lp_l_13-b2_lp*mem_lp_l_14;
mem_lp_l_12 = mem_lp_l_11;
mem_lp_l_11 = f3outl;
mem_lp_l_14 = mem_lp_l_13;
mem_lp_l_13 = out_lp_l_1;
out_lp_r_1 = a0_lp*f3outr+a1_lp*mem_lp_r_11+a2_lp*mem_lp_r_12-b1_lp*mem_lp_r_13-b2_lp*mem_lp_r_14;
mem_lp_r_12 = mem_lp_r_11;
mem_lp_r_11 = f3outr;
mem_lp_r_14 = mem_lp_r_13;
mem_lp_r_13 = out_lp_r_1;

f3outl = out_lp_l_1;
f3outr = out_lp_r_1;
);

//saturation
//-----------------------------------
linl = f3outl;
linr = f3outr;
slider14 > 0 ? (
(spl0 != 0 || spl1 != 0) ? (
whitel = (rand(2)-1)*noisefloor;
whiter = (rand(2)-1)*noisefloor;
linl += whitel;
linr += whiter;
);

//oversample?
os == 1 ? (
//---------------------------
//power series in
ps_out1l = 0.5*(linl+ps_out2l);
ps_out2l = 0.5*ps_out1l;
ps_out1r = 0.5*(linr+ps_out2r);
ps_out2r = 0.5*ps_out1r;

//---------------------------
//drive
o_in1l = (1+drv2_k)*ps_out1l/(1+drv2_k*abs(ps_out1l));
o_in2l = (1+drv2_k)*ps_out2l/(1+drv2_k*abs(ps_out2l));
o_in1r = (1+drv2_k)*ps_out1r/(1+drv2_k*abs(ps_out1r));
o_in2r = (1+drv2_k)*ps_out2r/(1+drv2_k*abs(ps_out2r));

//---------------------------
//bandlimit
bl3_l1 = bl2_l1;
bl3_r1 = bl2_r1;
bl3_l2 = bl2_l2;
bl3_r2 = bl2_r2;

bl2_l1 = bl1_l1;
bl2_r1 = bl1_r1;
bl2_l2 = bl1_l2;
bl2_r2 = bl1_r2;

bl1_l1 = o_in1l;
bl1_r1 = o_in1r;
bl1_l2 = o_in2l;
bl1_r2 = o_in2r;

bl_out1l = (bl1_l1*bl_c1 + bl2_l1*bl_c2 + bl3_l1*bl_c3);
bl_out1r = (bl1_r1*bl_c1 + bl2_r1*bl_c2 + bl3_r1*bl_c3);
bl_out2l = (bl1_l2*bl_c1 + bl2_l2*bl_c2 + bl3_l2*bl_c3);
bl_out2r = (bl1_r2*bl_c1 + bl2_r2*bl_c2 + bl3_r2*bl_c3);

//---------------------------
//power series out
o_out1l = 0.5*(bl_out1l+o_out2l);
o_out2l = 0.5*(bl_out2l+o_out1l);

o_out1r = 0.5*(bl_out1r+o_out2r);
o_out2r = 0.5*(bl_out2r+o_out1r);

//---------------------------
//fir restoration
s3l = s2l;
s2l = s1l;
s1l = o_out1l;

s3r = s2r;
s2r = s1r;
s1r = o_out1r;

o_outl = (s1l*fc1+s2l*fc2+s3l*fc3)*fgain;
o_outr = (s1r*fc1+s2r*fc2+s3r*fc3)*fgain;

) : (
o_outl = (1+drv2_k)*linl/(1+drv2_k*abs(linl));
o_outr = (1+drv2_k)*linr/(1+drv2_k*abs(linr));
);

//out
spl0 = (o_outl)*outv+denorm;
spl1 = (o_outr)*outv+denorm;
) : (
spl0 = (linl)*outv+denorm;
spl1 = (linr)*outv+denorm;
);

);

//=============================================================
@gfx 100 78
gfx_x=gfx_y=5;
gfx_lineto(gfx_x, gfx_y,0);

//hp
//---------------------------------
slider2 > 0 ? (
gfx_r=0.7;
gfx_b=0.1;
gfx_g=1;
gfx_a=1;
) : (
gfx_r=0.3;
gfx_b=0.3;
gfx_g=0.3;
gfx_a=1;
);
gfx_drawchar($'H');
gfx_drawchar($'P');
gfx_drawchar($' ');
gfx_drawchar($'=');
gfx_drawchar($' ');
gfx_drawnumber(cx_hp,0);
gfx_drawchar($' ');
gfx_drawchar($'H');
gfx_drawchar($'z');
gfx_y += 15;
gfx_x = 5;
gfx_a=1;

//f1
//---------------------------------
slider6 != 0 ? (
slider3 == 0 ? (
gfx_r=1;
gfx_b=0;
gfx_g=0.8;
) : (
gfx_r=0;
gfx_b=1;
gfx_g=0.8;
);
) : (
gfx_r=0.6;
gfx_b=0.6;
gfx_g=0.6;
gfx_a=1;
);
gfx_drawchar($'F');
gfx_drawchar($'1');
gfx_drawchar($' ');
gfx_drawchar($'=');
gfx_drawchar($' ');
gfx_drawnumber(freq1,0);
gfx_drawchar($' ');
gfx_drawchar($'H');
gfx_drawchar($'z');
gfx_y += 15;
gfx_x = 5;

//f2
//---------------------------------
slider9 != 0 ? (
slider3 == 0 ? (
gfx_r=1;
gfx_b=0;
gfx_g=0.8;
) : (
gfx_r=0;
gfx_b=1;
gfx_g=0.8;
);
) : (
gfx_r=0.6;
gfx_b=0.6;
gfx_g=0.6;
gfx_a=1;
);
gfx_drawchar($'F');
gfx_drawchar($'2');
gfx_drawchar($' ');
gfx_drawchar($'=');
gfx_drawchar($' ');
gfx_drawnumber(freq2,0);
gfx_drawchar($' ');
gfx_drawchar($'H');
gfx_drawchar($'z');
gfx_y += 15;
gfx_x = 5;

//f3
//---------------------------------
slider12 != 0 ? (
slider3 == 0 ? (
gfx_r=1;
gfx_b=0;
gfx_g=0.8;
) : (
gfx_r=0;
gfx_b=1;
gfx_g=0.8;
);
) : (
gfx_r=0.6;
gfx_b=0.6;
gfx_g=0.6;
gfx_a=1;
);
gfx_drawchar($'F');
gfx_drawchar($'3');
gfx_drawchar($' ');
gfx_drawchar($'=');
gfx_drawchar($' ');
gfx_drawnumber(freq3,0);
gfx_drawchar($' ');
gfx_drawchar($'H');
gfx_drawchar($'z');
gfx_y += 15;
gfx_x = 5;

//lp
//---------------------------------
slider13 < 100 ? (
gfx_r=0.7;
gfx_b=0.1;
gfx_g=1;
gfx_a=1;
) : (
gfx_r=0.3;
gfx_b=0.3;
gfx_g=0.3;
gfx_a=1;
);
gfx_drawchar($'L');
gfx_drawchar($'P');
gfx_drawchar($' ');
gfx_drawchar($'=');
gfx_drawchar($' ');
gfx_drawnumber(cx_lp,0);
gfx_drawchar($' ');
gfx_drawchar($'H');
gfx_drawchar($'z');
