// (C) 2008-2009, Lubomir I. Ivanov, 2006-2007, Michael Gruhn.
//
// 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/>.
//
//******************************************************************************
// butterworth filter implementation - 
// original port from apple.com au tutorial (c+)
// added HP version
// added 12 poles cascade
// * see note below about efficiency  
// added stereo distorted suturation
// version 21 feb 2018
//******************************************************************************

desc: Filtuar (Gazzuar)
//tags: filter, distirtion, saturator
//author: Gazzuar + Liteon + Looser

slider1:0<0,2,1{Full,Unfilterd,Filtered}>Monitoring
slider2:0<0,3,1{Off,12 dB/oct (2-pole),24 dB/oct (4-pole)}>HP Slope
slider3:0<0,100,0.01>HP Cutoff (Scale)
slider4:0<-16,16,0.01> HP Resonance (dB)
slider5:0<0,3,1{Off,12 dB/oct (2-pole),24 dB/oct (4-pole)}>LP Slope
slider6:100<0,100,0.01>LP Cutoff (Scale)
slider7:0<-16,16,0.01>LP Resonance (dB)

slider8:0 <-24,24,0.01>PreAmp Filt.(0dB = clear)
slider9:100 <1,500,0.1>Amount satur.(%, 100% = clear)
slider10:1 <0,2,0.01>Assymetry satur. (x1, 1 = clear)
slider11:0 <-1,1,0.01>PanPos satur.(0 = center)

slider15:0<-24,24,0.01>PostAmp Filt+Sat (dB)
slider16:0<-24,24,0.01>PostAmp UNFiltered (dB)

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


@init
gfx_clear = 0;


@slider
outgainF = 10^(slider15/20);
outgainU= 10^(slider16/20);
trsh = slider9/100;

//****************************
//hp

n_hp = slider2;
sx = 16+slider3*1.20103;
cx_hp = floor(exp(sx*log(1.059))*8.17742);
cutoff_hp = 2*cx_hp/srate;
res_hp = 10^(0.05*(-slider4/n_hp+1.5));

k = 0.5*res_hp*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;

//****************************
//lp

n_lp = slider5;
sx = 16+slider6*1.20103;
cx_lp = floor(exp(sx*log(1.059))*8.17742);
cutoff_lp = 2*cx_lp/srate;
res_lp = 10^(0.05*(-slider7/n_lp+1.5));

k = 0.5*res_lp*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;

@block
blah+=samplesblock;

@sample
inl = spl0;
inr = spl1;

n_hp > 0 ? (
out_hp_l_1 = a0_hp*inl+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 = inl;
mem_hp_l_14 = mem_hp_l_13;
mem_hp_l_13 = out_hp_l_1;
out_hp_l = out_hp_l_1;
out_hp_r_1 = a0_hp*inr+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 = inr;
mem_hp_r_14 = mem_hp_r_13;
mem_hp_r_13 = out_hp_r_1;
out_hp_r = out_hp_r_1;
n_hp > 1 ? (
out_hp_l_2 = a0_hp*out_hp_l_1+a1_hp*mem_hp_l_21+a2_hp*mem_hp_l_22-b1_hp*mem_hp_l_23-b2_hp*mem_hp_l_24;
mem_hp_l_22 = mem_hp_l_21;
mem_hp_l_21 = out_hp_l_1;
mem_hp_l_24 = mem_hp_l_23;
mem_hp_l_23 = out_hp_l_2;
out_hp_l = out_hp_l_2;
out_hp_r_2 = a0_hp*out_hp_r_1+a1_hp*mem_hp_r_21+a2_hp*mem_hp_r_22-b1_hp*mem_hp_r_23-b2_hp*mem_hp_r_24;
mem_hp_r_22 = mem_hp_r_21;
mem_hp_r_21 = out_hp_r_1;
mem_hp_r_24 = mem_hp_r_23;
mem_hp_r_23 = out_hp_r_2;
out_hp_r = out_hp_r_2;
);
n_hp > 2 ? (
out_hp_l_3 = a0_hp*out_hp_l_2+a1_hp*mem_hp_l_31+a2_hp*mem_hp_l_32-b1_hp*mem_hp_l_33-b2_hp*mem_hp_l_34;
mem_hp_l_32 = mem_hp_l_31;
mem_hp_l_31 = out_hp_l_2;
mem_hp_l_34 = mem_hp_l_33;
mem_hp_l_33 = out_hp_l_3;
out_hp_l = out_hp_l_3;
out_hp_r_3 = a0_hp*out_hp_r_2+a1_hp*mem_hp_r_31+a2_hp*mem_hp_r_32-b1_hp*mem_hp_r_33-b2_hp*mem_hp_r_34;
mem_hp_r_32 = mem_hp_r_31;
mem_hp_r_31 = out_hp_r_2;
mem_hp_r_34 = mem_hp_r_33;
mem_hp_r_33 = out_hp_r_3;
out_hp_r = out_hp_r_3;
);
) : (
out_hp_l = inl;
out_hp_r = inr;
);


n_lp > 0 ? (
out_lp_l_1 = a0_lp*out_hp_l+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 = out_hp_l;
mem_lp_l_14 = mem_lp_l_13;
mem_lp_l_13 = out_lp_l_1;
out_lp_l = out_lp_l_1;
out_lp_r_1 = a0_lp*out_hp_r+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 = out_hp_r;
mem_lp_r_14 = mem_lp_r_13;
mem_lp_r_13 = out_lp_r_1;
out_lp_r = out_lp_r_1;
n_lp > 1 ? (
out_lp_l_2 = a0_lp*out_lp_l_1+a1_lp*mem_lp_l_21+a2_lp*mem_lp_l_22-b1_lp*mem_lp_l_23-b2_lp*mem_lp_l_24;
mem_lp_l_22 = mem_lp_l_21;
mem_lp_l_21 = out_lp_l_1;
mem_lp_l_24 = mem_lp_l_23;
mem_lp_l_23 = out_lp_l_2;
out_lp_l = out_lp_l_2;
out_lp_r_2 = a0_lp*out_lp_r_1+a1_lp*mem_lp_r_21+a2_lp*mem_lp_r_22-b1_lp*mem_lp_r_23-b2_lp*mem_lp_r_24;
mem_lp_r_22 = mem_lp_r_21;
mem_lp_r_21 = out_lp_r_1;
mem_lp_r_24 = mem_lp_r_23;
mem_lp_r_23 = out_lp_r_2;
out_lp_r = out_lp_r_2;
);
n_lp > 2 ? (
out_lp_l_3 = a0_lp*out_lp_l_2+a1_lp*mem_lp_l_31+a2_lp*mem_lp_l_32-b1_lp*mem_lp_l_33-b2_lp*mem_lp_l_34;
mem_lp_l_32 = mem_lp_l_31;
mem_lp_l_31 = out_lp_l_2;
mem_lp_l_34 = mem_lp_l_33;
mem_lp_l_33 = out_lp_l_3;
out_lp_l = out_lp_l_3;
out_lp_r_3 = a0_lp*out_lp_r_2+a1_lp*mem_lp_r_31+a2_lp*mem_lp_r_32-b1_lp*mem_lp_r_33-b2_lp*mem_lp_r_34;
mem_lp_r_32 = mem_lp_r_31;
mem_lp_r_31 = out_lp_r_2;
mem_lp_r_34 = mem_lp_r_33; 
mem_lp_r_33 = out_lp_r_3;
out_lp_r = out_lp_r_3;
);
) : (
out_lp_l = out_hp_l;
out_lp_r = out_hp_r;
);

slider1 == 0 ? ( //FULL
spl0 = (spl0 - out_lp_l*outgainF*10^(slider8/20))*outgainU;
spl1 = (spl1 - out_lp_r*outgainF*10^(slider8/20))*outgainU;

L = out_lp_l*10^(slider8/20);
R = out_lp_r*10^(slider8/20);

spl0 += L > 0 
  ? min(outgainF,sign(L) * (1 - min(2,pow(abs(1-L*sign(L)),trsh*slider10*(1-slider11))) ) * outgainF)
  : max(-outgainF,sign(L) * (1 - min(2,pow(abs(1-L*sign(L)),trsh*(1-slider11))) )* outgainF);
spl1 += R > 0 
  ? min(outgainF,sign(R) * (1 - min(2,pow(abs(1-R*sign(R)),trsh*(1+slider11))) )* outgainF)
  : max(-outgainF,sign(R) * (1 - min(2,pow(abs(1-R*sign(R)),trsh*slider10*(1+slider11))) )* outgainF);
);


slider1 == 1 ? ( // UNFILTERED
spl0 = (spl0 - out_lp_l * outgainF * 10^(slider8/20) )*outgainU;
spl1 = (spl1 - out_lp_r * outgainF * 10^(slider8/20) )*outgainU; 
);
 
slider1 == 2 ? ( // FILTERED

L = out_lp_l*10^(slider8/20);
R = out_lp_r*10^(slider8/20);

spl0 = L > 0 
  ? min(outgainF,sign(L) * (1 - min(2,pow(abs(1-L*sign(L)),trsh*slider10*(1-slider11))) ) * outgainF)
  : max(-outgainF,sign(L) * (1 - min(2,pow(abs(1-L*sign(L)),trsh*(1-slider11))) )* outgainF);
spl1 = R > 0 
  ? min(outgainF,sign(R) * (1 - min(2,pow(abs(1-R*sign(R)),trsh*(1+slider11))) )* outgainF)
  : max(-outgainF,sign(R) * (1 - min(2,pow(abs(1-R*sign(R)),trsh*slider10*(1+slider11))) )* outgainF););

@gfx 256 192
gfx_x=gfx_y=5;
gfx_lineto(gfx_x, gfx_y,0);
gfx_r=0.7;
gfx_b=0.1;
gfx_g=1;
gfx_a=1;
gfx_drawchar($'H');
gfx_drawchar($'P');
gfx_drawchar($' ');
gfx_drawchar($'=');
gfx_drawchar($' ');
slider2 ? (gfx_drawnumber(cx_hp,0)) : (gfx_drawchar($' '));
gfx_drawchar($' ');
gfx_drawchar($'H');
gfx_drawchar($'z');
gfx_y += 15;
gfx_x = 5;
gfx_drawchar($'L');
gfx_drawchar($'P');
gfx_drawchar($' ');
gfx_drawchar($'=');
gfx_drawchar($' ');
slider5 ? (gfx_drawnumber(cx_lp,0)) : (gfx_drawchar($' '));
gfx_drawchar($' ');
gfx_drawchar($'H');
gfx_drawchar($'z');

gfxSize = min(gfx_w,gfx_h);


gfx_r=gfx_g=gfx_b=0.2; gfx_a=1;
gfx_x=0;
gfx_y=30;
gfx_rectto(gfx_w,gfx_h);

gfx_r=gfx_g=gfx_b=0.8; gfx_a=0.5;
gfx_x=gfxSize/2; gfx_y=30;
gfx_lineto(gfxSize/2,gfxSize,0);
gfx_x=0; gfx_y=gfxSize/2;
gfx_lineto(gfxSize*2,gfxSize/2,0);

gfx_x = gfxSize*1.2-20; gfx_y = gfxSize/2+5;
gfx_drawchar($'I');
gfx_drawchar($'N');

gfx_x = gfxSize/2+4; gfx_y = 35;
gfx_drawchar($'O');
gfx_drawchar($'U');
gfx_drawchar($'T');

slider9 ? (
  gfx_r=0.5; gfx_g=1; gfx_b=0; gfx_a=1;
  gfx_x=0; gfx_y=gfxSize;
  x = -2;
  while(
    //y = -sign(x)*pow(abs(x),2); // pow(abs(x-1),1.5)-1; //-sign(x)*pow(abs(x),trsh)*slider;
    y = y < 0 
      ? -sign(x) * (1 - pow(abs(1-x*sign(x)),trsh*slider10*(1-slider11))) 
      : -sign(x) * (1 - pow(abs(1-x*sign(x)),trsh*(1-slider11))) ;
//      : -sign(x) * pow(abs(x),trsh) ;
    gfx_lineto(x*gfxSize/2+gfxSize/2,y*gfxSize/2+gfxSize/2,1);
    (x+=0.01) <= 2;
  );
//  gfx_lineto(gfxSize,0,1);
):(
  gfx_r=0.5; gfx_g=1; gfx_b=0; gfx_a=1;
  gfx_x=0; gfx_y=gfxSize;
  gfx_lineto(gfxSize,0,1);
);

