desc: Bass Professor

/*****************************************************
Copyright (C) 2015-2016 Stige T.
License: http://jsplugins.supermaailma.net/license.php
*****************************************************/

EffectName: Bass Professor I
VendorString: Stige T.
VendorVersion: 1000
UniqueId: 'BPR1'

slider1:0<0,40,1>-Profess
slider2:0<-20,20,0.5>-Output
slider3:0<0,10,0.1>-Presence
slider4:0<0,10,0.1>-Dirt
slider5:0<-6,6,0.1>-Bass
slider6:0<-6,6,0.1>-Middle
slider7:0<-6,6,0.1>-Treble
slider8:8<0.1,10,0.1>-Depth
slider9:0<0,10,0.1>-LFcut

filename:0,bassprofessor_gfx/knob.png
filename:1,bassprofessor_gfx/knob2.png
filename:2,bassprofessor_gfx/led.png
filename:3,bassprofessor_gfx/bg.png
filename:4,bassprofessor_gfx/knob3.png

resource:0,1,2,3,4

@init

!"#define VAL(A) (A)" "//";

buildStr = "build 161007";

t01 = exp(-1/(srate*0.001));
t20 = exp(-1/(srate*0.02));
t40 = exp(-1/(srate*0.04));
t60 = exp(-1/(srate*0.06));
t200 = exp(-1/(srate*0.2));
rmsw = 1-exp(-2*$pi*((1/1000)*1000)/srate);

m1 = m2 = m3 = m4 = 100;
    
//-------------------------------
function follower(input,att,rel)
instance (env,tmp) (
  tmp = input;
  (tmp > env) ? (
      env = att * (env - tmp) + tmp;
  ) : (
      env = rel * (env - tmp) + tmp;
  );
);
//-------------------------------
function megafilter(input)
instance(mX1,mX2,mY1,mY2,b0,b1,b2,a0,a1,a2,output)
(
  output = b0*input + b1*mX1 + b2*mX2 - a1*mY1 - a2*mY2;
  mX2 = mX1;
  mX1 = input;
  mY2 = mY1;
  mY1 = output;  
);

function megafilter_init(freq,Q,gain,type)
instance(omega,tsin,tcos,alpha,b0,b1,b2,a0,a1,a2,A,beta)
(
  type = max(type,1);
  type = min(type,8);
  Q = max(Q,0.01);
  Q = min(Q,10);
  freq = max(freq,0.1);
  freq = min(freq,srate/2);

  A = pow(10.0,(gain/40.0));
  omega = 2*$pi*freq/srate;
  tsin = sin(omega);
  tcos = cos(omega);
  alpha = tsin/(2.0*Q);
  beta =sqrt(A)/Q;
  temp = freq+Q+gain+type;
  
  type == 1 ? (
  //low-shelf
  b0 = (A*((A+1.0)-(A-1.0)*tcos+beta*tsin));
  b1 = (2.0*A*((A-1.0)-(A+1.0)*tcos));
  b2 = (A*((A+1.0)-(A-1.0)*tcos-beta*tsin));
  a0 = ((A+1.0)+(A-1.0)*tcos+beta*tsin);
  a1 = (-2.0*((A-1.0)+(A+1.0)*tcos));
  a2 = ((A+1.0)+(A-1.0)*tcos-beta*tsin);
  );
  type == 2 ? (
  //hi-shelf
  b0 = (A*((A+1.0)+(A-1.0)*tcos+beta*tsin));
  b1 = (-2.0*A*((A-1.0)+(A+1.0)*tcos));
  b2 = (A*((A+1.0)+(A-1.0)*tcos-beta*tsin));
  a0 = ((A+1.0)-(A-1.0)*tcos+beta*tsin);
  a1 = (2.0*((A-1.0)-(A+1.0)*tcos));
  a2 = ((A+1.0)-(A-1.0)*tcos-beta*tsin);
  );
  type == 3 ? (
  //peak
  b0 = 1.0+alpha*A;
  b1 = -2.0*tcos;
  b2 = 1.0-alpha*A;
  a0 = 1.0+alpha/A;
  a1 = -2.0*tcos;
  a2 = 1.0-alpha/A;
  );
  type == 4 ? (
  //low-pass
  b0 = (1-tcos)/2;
  b1 = 1-tcos;
  b2 = (1-tcos)/2;
  a0 = 1+alpha;
  a1 = -2*tcos;
  a2 = 1-alpha;
  );
  type == 5 ? (
  // hi-pass
  b0 = (1+tcos)/2;
  b1 = -(1+tcos);
  b2 = (1+tcos)/2;
  a0 = 1+alpha;
  a1 = -2*tcos;
  a2 = 1-alpha;
  );
  type == 6 ? (
  //band-pass
  b0 = alpha;
  b1 = 0.0;
  b2 = -alpha;
  a0 = 1.0+alpha;
  a1 = -2.0*tcos;
  a2 = 1.0-alpha;
  );
  type == 7 ? (
  //notch
  b0 = 1.0;
  b1 = -2.0*tcos;
  b2 = 1.0;
  a0 = 1.0+alpha;
  a1 = -2.0*tcos;
  a2 = 1.0-alpha;
  );
  type == 8 ? (
  //all-pass
  b0 = 1.0-alpha;
  b1 = -2.0*tcos;
  b2 = 1.0+alpha;
  a0 = 1.0+alpha;
  a1 = -2.0*tcos;
  a2 = 1.0-alpha;
  );

  b0 /= a0;
  b1 /= a0;
  b2 /= a0;
  a1 /= a0;
  a2 /= a0;
);
//-------------------------------
function limiter(input,threshold)
instance(env,e1,e2,e3,th)
(
  th = max(abs(input),threshold);
  th = th / threshold;
  th > 1 ? limit_active = 1;
  env = e1.follower(th,t01,t60);
  env = e2.follower(env,0,t20);
  env = e3.follower(env,0,t20);  
  env = max(env,1);
  input / env;
);
//-------------------------------
function compressor_init(att,rel,drive)
instance(attack,release,d)
(
  attack = exp(-1/(srate*att/1000));
  release = exp(-1/(srate*rel/1000));
  d = drive;
);

function compressor(input)
instance(env,e1,e2,e3,d,output,attack,release)
(
  env = e1.follower(abs(input)*d,attack,release);
  env = e2.follower(env,0,t20);
  env = e3.follower(env,0,t20);  
  env = 1/(env+boost);
  output = input * env;
);
//-------------------------------
function overdrive(input,gain)
instance(f1,f2,f3,f4,rms,s1)
(
  gain ? (
    input = f1.megafilter(input);
    rms = sqrt(s1 +=  rmsw * ( input^2 - s1 ));
    rms = 0.0001/(rms+0.0001) * 100;
    rms = min(rms,5.623);
    input = input * rms;
    input = atan(input*gain*800) * (0.03 + gain/100);
    input = f2.megafilter(input);
    input = f3.megafilter(input);
    input = f4.megafilter(input);
  );
);
//-------------------------------

od.f1.megafilter_init(2000,1,0,5);
od.f2.megafilter_init(1000,0.5,0,4);
od.f3.megafilter_init(1000,0.5,0,8);
od.f4.megafilter_init(300,0.9,0,5);
sf.megafilter_init(80,1,0,4);
lf1.megafilter_init(70,1,0,5);
lf2.megafilter_init(220,0.6,0,4);
mf1.megafilter_init(220,0.6,0,5);
mf2.megafilter_init(1600,0.7,0,4);

@slider

p1.val_pos = slider1;
p2.val_pos = slider2;
p3.val_pos = slider3;
p4.val_pos = slider4;
p5.val_pos = slider5;
p6.val_pos = slider6;
p7.val_pos = slider7;
p8.val_pos = slider8;
p9.val_pos = slider9;

  speed = (10-slider8) / 3 + 1;
  boost = 0.5 + (10-slider8)/20;
  locut = 1/(slider9+1.25)+0.20;
  profess = 10^(slider1/20);
  output = 10^(slider2/20);
  presence = (10-slider3) * 70 + 600;
  dirt = slider4/10;
  bass = slider5;
  middle = slider6;
  treble = slider7;

  sb1.megafilter_init(40,locut,0,5);
  hf1.megafilter_init(presence,0.7,0,5);
  eq1.megafilter_init(110,1.5,bass*3.3,3);
  eq2.megafilter_init(160,3,-bass*2.5,3);
  eq3.megafilter_init(60,0.5,bass,3);
  eq4.megafilter_init(1500,2,middle*0.75,3);
  eq5.megafilter_init(450,0.5,middle*1.5,3);
  eq6.megafilter_init(160,1,-middle/2,3);
  eq7.megafilter_init(350,2,middle*3,3);
  eq8.megafilter_init(6000,0.5,treble*3,3);
  eq12.megafilter_init(1600,2,treble,3);
  eq11.megafilter_init(2700,3,-treble,3);
  eq9.megafilter_init(1200,1.5,treble,2);
  eq10.megafilter_init(2700,2,treble*4,3);
  
  c1.compressor_init(30,60*speed,3);
  c2.compressor_init(10,60*speed,2);
  c3.compressor_init(5,40*speed,4);
  c4.compressor_init(0,60*speed,3);

@gfx 600 284

gfx_setfont(1,"Arial",14,'b');

function init_mouse() (
  !X ? (X = mouse_x;);
  !Y ? (Y = mouse_y;);
);
function uninit_mouse() (
  X = 0;
  Y = 0;
);
mouse_cap ? init_mouse() : uninit_mouse();

gfx_a = 1;
gfx_x = 0; gfx_y = 0;
gfx_blit(3,1,0);

function draw_led(input,pot_x,pot_y,frame_width,frame_height,frame_count,gfxindex)
instance(fpos,coordinatelist,i_temp)
(
  input = min(input,1);
  input < i_temp-0.05 ? input = i_temp-0.05;
  fpos = ceil(input * (frame_count-1)) * frame_height;
  coordinatelist[0] = 0;
  coordinatelist[1] = fpos;
  coordinatelist[2] = coordinatelist[6] = frame_width;
  coordinatelist[3] = coordinatelist[7] = frame_height;
  coordinatelist[4] = pot_x;
  coordinatelist[5] = pot_y;
  gfx_a=1;
  gfx_r=gfx_g=gfx_b=1;
  gfx_blitext(gfxindex, coordinatelist, 0);
  i_temp = input;
  limit_active = 0;
);

function draw_pot(pot_x,pot_y,min_val,max_val,step_size,
frame_width,frame_height,frame_count,showval,gfxindex)
instance(
  total_steps,rpos,pos_temp,val_pos,coordinatelist,
  val_temp,prec,val_str,unit,str_x,str_y,reset_val
)
(
  total_steps = (max_val - min_val) / step_size;
  val_temp != val_pos ? _Dirty = 1;
  !mouse_cap ? (pos_temp = mouse_y; val_temp = val_pos;);

  X > pot_x && X < pot_x+frame_width && Y > pot_y && Y < pot_y+frame_height ? (
    val_pos = -((mouse_y - pos_temp)/ (total_steps < 50 ? (1/total_steps*100) : 1) *step_size) + (val_temp / (total_steps / frame_height)) / (frame_height / total_steps);
    mouse_cap & 4 ? val_pos = reset_val;
  );

  val_pos = max(val_pos,min_val);
  val_pos = min(val_pos,max_val); 
  rpos = floor( (val_pos - min_val) * ((frame_count) / total_steps) / step_size) * frame_height;
  rpos = min(rpos,(frame_count * frame_height) - frame_height);
  coordinatelist[0] = 0;
  coordinatelist[1] = rpos;
  coordinatelist[2] = coordinatelist[6] = frame_width;
  coordinatelist[3] = coordinatelist[7] = frame_height;
  coordinatelist[4] = pot_x;
  coordinatelist[5] = pot_y;
  gfx_a=1;
  gfx_r=0.8;gfx_g=0.8;gfx_b=0.8;
  gfx_blitext(gfxindex, coordinatelist, 0);
  showval ? (    
    step_size >= 1 ? prec = "%.0f";
    step_size < 1 ? prec = "%.1f";
    step_size < 0.1 ? prec = "%.2f";
    val_str = sprintf (#,prec,val_pos);
    val_str = strcat(val_str, unit);
    gfx_measurestr(val_str,str_x,str_y);
    gfx_x = pot_x+(frame_width/2)-(str_x/2) ; gfx_y = 5+pot_y+frame_height-(str_y/8)-2;
    gfx_drawstr(val_str);
  );
  val_pos;
);

function dynmeter(in1,x_pos,y_pos,showval)
instance(redux,col1,col2,in1_gfx,in2_gfx,in3_gfx)
(
  gfx_r = 0.25; gfx_g = 0.25; gfx_b = 0.25; gfx_a = 0;
  gfx_x = x_pos; gfx_y = y_pos;
  gfx_rectto(200+x_pos,10+y_pos);
  gfx_r = 0; gfx_g = 0; gfx_b = 0; gfx_a = 0;
  gfx_x = x_pos+1; gfx_y = y_pos+1;
  gfx_rectto(199+x_pos,9+y_pos);
  gfx_r = 0.8; gfx_g = 0.8; gfx_b = 0.8; gfx_a = 0;
  showval ? (
    gfx_x = 199+x_pos; gfx_y = 10+y_pos;gfx_lineto(199+x_pos,20+y_pos,0);gfx_drawnumber(20,0);
    gfx_x = 161+x_pos; gfx_y = 10+y_pos;gfx_lineto(161+x_pos,20+y_pos,0);gfx_drawnumber(12,0);
    gfx_x = 130+x_pos; gfx_y = 10+y_pos;gfx_lineto(130+x_pos,20+y_pos,0);gfx_drawnumber(6,0);
    gfx_x = 100+x_pos; gfx_y = 10+y_pos;gfx_lineto(100+x_pos,20+y_pos,0);gfx_drawnumber(0,0);
    gfx_x = 69+x_pos; gfx_y = 10+y_pos;gfx_lineto(69+x_pos,20+y_pos,0);gfx_drawnumber(-6,0);
    gfx_x = 38+x_pos; gfx_y = 10+y_pos;gfx_lineto(38+x_pos,20+y_pos,0);gfx_drawnumber(-12,0);
    gfx_x = 0+x_pos; gfx_y = 10+y_pos;gfx_lineto(0+x_pos,20+y_pos,0);gfx_drawnumber(-20,0);
  );
  
  gfx_x = 101+x_pos; gfx_y = y_pos+2;
  in1 = max(in1,0.1);
  in1 = min(in1,10);
  gfx_a = 1;
  col1 = in1 >= 1 ? min(in1/4,1) : min((1/in1)/4,1);
  col2 = 1-col1;
  gfx_r = col1; gfx_g = col2; gfx_b = 0;  gfx_a = 0.7;
  in1_gfx = ceil(100 - log(1/in1)*43.3);
  gfx_rectto( in1_gfx + x_pos, 8 + y_pos);
    
  gfx_r = 0.5; gfx_g = 0.5; gfx_b = 0.5; gfx_a = 1;
  gfx_x = 100+x_pos; gfx_y = y_pos;
  gfx_rectto(101+x_pos,10+y_pos);
);

slider1 = p1.draw_pot(40,50,0,40,0.5,80,80,41,2,0);
slider2 = p2.draw_pot(480,50,-20,20,0.5,80,80,41,2,0);
slider3 = p3.draw_pot(50,180,0,10,0.2,60,60,31,2,1);
slider4 = p4.draw_pot(490,180,0,10,0.2,60,60,31,2,1);
slider5 = p5.draw_pot(200,180,-6,6,0.1,60,60,31,2,1);
slider6 = p6.draw_pot(270,180,-6,6,0.1,60,60,31,2,1);
slider7 = p7.draw_pot(340,180,-6,6,0.1,60,60,31,2,1);
slider8 = p8.draw_pot(435,120,0.1,10,0.1,40,40,31,2,4);
slider9 = p9.draw_pot(130,120,0,10,0.1,40,40,31,2,4);

m1.dynmeter(mtr1,200,70,0);
m2.dynmeter(mtr2,200,81,0);
m3.dynmeter(mtr3,200,92,0);
m4.dynmeter(mtr4,200,103,1);

led1.draw_led(limit_active,149,79,6,6,10,2);

_Dirty ? (

  speed = (10-slider8) / 3 + 1;
  boost = 0.5 + (10-slider8)/20;
  locut = 1/(slider9+1.25)+0.20;
  profess = 10^(slider1/20);
  output = 10^(slider2/20);
  presence = (10-slider3) * 70 + 600;
  dirt = slider4/10;
  bass = slider5;
  middle = slider6;
  treble = slider7;

  sb1.megafilter_init(40,locut,0,5);
  hf1.megafilter_init(presence,0.7,0,5);
  eq1.megafilter_init(110,1.5,bass*3.3,3);
  eq2.megafilter_init(160,3,-bass*2.5,3);
  eq3.megafilter_init(60,0.5,bass,3);
  eq4.megafilter_init(1500,2,middle*0.75,3);
  eq5.megafilter_init(450,0.5,middle*1.5,3);
  eq6.megafilter_init(160,1,-middle/2,3);
  eq7.megafilter_init(350,2,middle*3,3);
  eq8.megafilter_init(6000,0.5,treble*3,3);
  eq12.megafilter_init(1600,2,treble,3);
  eq11.megafilter_init(2700,3,-treble,3);
  eq9.megafilter_init(1200,1.5,treble,2);
  eq10.megafilter_init(2700,2,treble*4,3);
  
  c1.compressor_init(30,60*speed,3);
  c2.compressor_init(10,60*speed,2);
  c3.compressor_init(5,40*speed,4);
  c4.compressor_init(0,60*speed,3);
  
  _Dirty = 0;
  
);

gfx_x = 420; gfx_y = 255;
gfx_a = 0.5;
gfx_setfont(1,"Arial",11);
gfx_drawstr(buildStr);

@sample

sgn = spl0 + norm;
sgn = sb1.megafilter(sgn);
sgn = od.overdrive(sgn,dirt) + sgn;

sub = sf.megafilter(sgn);
low = lf1.megafilter(sgn);
low = lf2.megafilter(low);
mid = mf1.megafilter(sgn);
mid = mf2.megafilter(mid);
hi = hf1.megafilter(sgn);

process =
  c1.compressor(sub*profess) +
  c2.compressor(low*profess) +
  c3.compressor(mid*profess) +
  c4.compressor(hi*profess)
;

rms = sqrt(rmss +=  rmsw * ( process^2 - rmss ));
rms = max(rms,0.1);
threshold = rms * 5.01; //6.31

bass != 0 ? (
  bass > 0 ? (
    process = eq1.megafilter(process);
    process = eq2.megafilter(process);
  ) : (
    process = eq3.megafilter(process);
  );
);

middle != 0 ? (
  middle > 0 ? (
    process = eq4.megafilter(process);
    process = eq5.megafilter(process);
    process = eq6.megafilter(process);
  ) : (
    process = eq7.megafilter(process);
  );
);

treble != 0 ? (
treble > 0 ? (
  process = eq8.megafilter(process);
  process = eq12.megafilter(process);
  process = eq11.megafilter(process);
) : (
  process = eq9.megafilter(process);
  process = eq10.megafilter(process);
);
);

process = l1.limiter(process,threshold);

spl0 = process * output;
spl1 = process * output;

@block

abs(sgn) > 0.001 ? (
  mtr1 = c1.env;
  mtr2 = c2.env;
  mtr3 = c3.env;
  mtr4 = c4.env;
) : (
  mtr1 = ((mtr1 * 100) + 1) * 0.0099;
  mtr2 = ((mtr2 * 100) + 1) * 0.0099;
  mtr3 = ((mtr3 * 100) + 1) * 0.0099;
  mtr4 = ((mtr4 * 100) + 1) * 0.0099;
);

norm = (rand(1) * 0.0000000001);

