desc:FXRack 1.01
/*
Short Description:
CP is channel pair, aka chain(1/2,3/4 etc)
Gain    = -60 - 30 (dB)
// In functions names - CP = chan pair, 1 = 1/2; 2 = 3/4 etc
*/

//==============================================================================
//-- CP 1 - 4 ----------------
slider1:Out1.Gain=0<-60,30,0.1>-Gain 1
slider2:Out2.Gain=0<-60,30,0.1>-Gain 2
slider3:Out3.Gain=0<-60,30,0.1>-Gain 3
slider4:Out4.Gain=0<-60,30,0.1>-Gain 4

//-- CP 5 - 8 ----------------
slider5:Out5.Gain=0<-60,30,0.1>-Gain 5
slider6:Out6.Gain=0<-60,30,0.1>-Gain 6
slider7:Out7.Gain=0<-60,30,0.1>-Gain 7
slider8:Out8.Gain=0<-60,30,0.1>-Gain 8

//-- Inputs --------
in_pin:input L
in_pin:input R

//-- Outputs -------
out_pin:out 1 L
out_pin:out 1 R
out_pin:out 2 L
out_pin:out 2 R
out_pin:out 3 L
out_pin:out 3 R
out_pin:out 4 L
out_pin:out 4 R

out_pin:out 5 L
out_pin:out 5 R
out_pin:out 6 L
out_pin:out 6 R
out_pin:out 7 L
out_pin:out 7 R
out_pin:out 8 L
out_pin:out 8 R



@init
gfx_clear = 0x180E01; //  bg color
col1 = 0xB9C1D4; // controls color

//-- Mouse -----------------------------
//-- if point(p_x, p_y) in rect(x,y,w,h) area ----
function pointINrect(p_x,p_y, x,y,w,h) ( p_x>=x && p_x<=x+w && p_y>=y && p_y<=y+h; );
//-- if mouse cursor in rect(x,y,w,h) area -------
function mouseINrect(x,y,w,h) ( pointINrect(mouse_x, mouse_y, x,y,w,h); );
//-- Left Mouse Button ---------------------------
function mouseDown(x,y,w,h) ( mouse_down && mouseINrect(x,y,w,h); );

//-- Set RRGGBB color ------------------
function SetRGB(RGB)
(
  gfx_r = (RGB & 0xFF0000) / 16711680; // 256*256*255
  gfx_g = (RGB & 0x00FF00) / 65280; // 256*255
  gfx_b = (RGB & 0x0000FF) / 255; // 255
  gfx_a = 1
);

//--------------------------------------
function minmax(x, minv, maxv)
(
  min(max(x, minv), maxv); 
);

//--------------------------------------
function DB2VAL(x)
(
  exp((x)*0.11512925464970228420089957273422);
);

//--------------------------------------
//-- Splitter functions ----------------
//--------------------------------------
function CPOut_Init()
  instance(Gain, src_vol, tgt_vol)
(
  src_vol = tgt_vol = DB2VAL(Gain);
);
//--------
function CPOut_Slider()
  instance(Gain, tgt_vol)
(  
  tgt_vol = DB2VAL(Gain);
);
//--------
function CPOut_Block()
  instance(d_vol, tvol, src_vol, tgt_vol)
(  
  d_vol = (tgt_vol-src_vol)/samplesblock;
  tvol = src_vol;
  src_vol = tgt_vol;
);
//--------
function CPOut_Sample()
  instance(d_vol, tvol, LR)
(  
  tvol += d_vol;
  LR = tvol;
);


//--------------------------------------
function Splitter_Init()
(
  Out1.CPOut_Init();
  Out2.CPOut_Init();
  Out3.CPOut_Init();
  Out4.CPOut_Init();
  Out5.CPOut_Init();
  Out6.CPOut_Init();
  Out7.CPOut_Init();
  Out8.CPOut_Init();
);
//--------------------------------------
function Splitter_Slider()
(
  Out1.CPOut_Slider();
  Out2.CPOut_Slider();
  Out3.CPOut_Slider();
  Out4.CPOut_Slider();
  Out5.CPOut_Slider();
  Out6.CPOut_Slider();
  Out7.CPOut_Slider();
  Out8.CPOut_Slider();
);
//--------------------------------------
function Splitter_Block()
(
  Out1.CPOut_Block();
  Out2.CPOut_Block();
  Out3.CPOut_Block();
  Out4.CPOut_Block();
  Out5.CPOut_Block();
  Out6.CPOut_Block();
  Out7.CPOut_Block();
  Out8.CPOut_Block();
);
//--------------------------------------
function Splitter_Sample()
(
  Out1.CPOut_Sample();
  Out2.CPOut_Sample();
  Out3.CPOut_Sample();
  Out4.CPOut_Sample();
  Out5.CPOut_Sample();
  Out6.CPOut_Sample();
  Out7.CPOut_Sample();
  Out8.CPOut_Sample();
);


//--------------------------------------
//--------------------------------------
Splitter_Init();


@slider
Splitter_Slider(); // Update if sliders changed

@block
Splitter_Block();

@sample
Splitter_Sample();

in1 = spl0;
in2 = spl1;

spl0 = in1 * Out1.LR; 
spl1 = in2 * Out1.LR;

spl2 = in1 * Out2.LR;
spl3 = in2 * Out2.LR;

spl4 = in1 * Out3.LR;
spl5 = in2 * Out3.LR;

spl6 = in1 * Out4.LR;
spl7 = in2 * Out4.LR;

spl8 = in1 * Out5.LR; 
spl9 = in2 * Out5.LR;

spl10 = in1 * Out6.LR;
spl11 = in2 * Out6.LR;

spl12 = in1 * Out7.LR;
spl13 = in2 * Out7.LR;

spl14 = in1 * Out8.LR;
spl15 = in2 * Out8.LR;


//==================================================================================================

@gfx 480 320
//==========================================================
//** Simple label ******************************************
//==========================================================
function SL_Label(x,y,w,h, flag, RGB, lbl)
(
  SetRGB(RGB);
  gfx_x = x + 4; gfx_y = y;
  gfx_drawstr(lbl, flag, x+w-4, y+h);
  //----------------
  gfx_r *= 0.3; gfx_g *= 0.3; gfx_b *= 0.3;// bg col
  gfx_roundrect(x-1,y-1,w,h,2,0);  // frame
);

//==========================================================
//** Simple slider-linked button ***************************
//==========================================================
function SL_BtnDraw(x,y,w,h, RGB, lbl)
(
  this.isChanged = 0;
  mouseDown(x,y,w,h) ? (
    this = !this; 
    slider_automate(this);
    this.isChanged = 1;
  );
  
  this ? (
    SetRGB(RGB); gfx_a = 0.2;
    gfx_rect(x,y,w,h, 1);
  );
  
  SL_Label(x,y,w,h, 5, RGB, lbl);
);

//==========================================================
//** Simple slider-linked knob *****************************
//==========================================================
function SL_KnobImage(x,y,w,h, RGB, normval)
  local(cx, cy, rds, offs, angmax, ang1, ang2, i) 
( 
   cx = x + w/2; cy = y + h/2; rds = w/2;
   angmax = 2.75*$pi;  // max val ang
   offs = 1.25 * $pi;  //$pi + $pi*0.25;
   ang1 = offs - 0.01; // 0.01 mini offset 
   ang2 = offs + (1.5 * $pi) * normval; // cur val ang
   //-------------------------
   SetRGB(RGB); 
   gfx_r *= 0.3; gfx_g *= 0.3; gfx_b *= 0.3;// bg col
   gfx_circle(cx, cy, rds-7, 1);
   //gfx_rect(x,y,w,h,0); // test rect    
   //-------------------------
   i=0;
   loop(5, 
     gfx_arc(cx, cy, rds-i,  ang1, angmax, 1); 
     i+=0.5; 
   );
   //-------------------------
   SetRGB(RGB); // val arc col
   i=0;
   loop(5, 
     gfx_arc(cx, cy, rds-i,  ang1, ang2, 1);
     i+=0.5;
   );
);

//--------------------------------------
function SL_KnobDraw(x,y,w,h, RGB, lbl, minval, maxval, valstep)
  local(normval, K)
(
  this.isChanged = 0;
  mouse_cap&1 && pointINrect(mouse_down_x, mouse_down_y, x,y,w,h) ? (
    mouse_last_y - mouse_y ? (
      mouse_cap&4 ? K = valstep : K = valstep*4; // drag coeff
      this = minmax(this + (mouse_last_y - mouse_y)*K, minval, maxval);
      slider_automate(this);
      this.isChanged = 1;
    ); 
  );
  
  //-- knob image ------------
  normval = (this - minval) / (maxval - minval);
  SL_KnobImage(x,y,w,h, RGB, normval);
  
  //-- knob label ------------
  lbl = sprintf(#, "%s: %.1f", lbl, this);
  SL_Label(x+w+5, y, 85, h, 4, RGB, lbl);

);

//**********************************************************
function CPOut_Draw(x, y, h, lbl)
  instance(Gain, Power )
  local(xx, yy, w, RGB)
(  
  RGB = col1;
  //-- CP knobs --------------
  w = 22;
  xx = x;
  Gain.SL_KnobDraw(xx, y, w, h, RGB, "Gain", -60, 30, 0.1);
  
  //-- CP wire ---------------
  SetRGB(RGB);
  xx = x + 130; yy = y + h/2;
  gfx_line(xx, yy, xx + 90, yy, 0);
  gfx_circle(xx, yy, 2, 1);
  gfx_circle(xx + 90, yy, 2, 1);
  
  //-- CP label --------------
  w = 45;
  xx = x + 240;
  SL_Label(xx,y,w,h, 5, RGB, lbl);
  
  
  //-- Update Splitter if changed ------
  Gain.isChanged ? Splitter_Slider(); 
);


//**********************************************************
function Draw()
  local(x, y, h, offs, xx, yy, mx, my, lbl, RGB)
(
  x = 20; y = 20; // Start drawing position
  h = 22;         // CP heigth
  offs = h + 8;   // CP vertical offset
  gfx_setfont(1, "Tahoma", 14); // main font
  RGB = col1;
  
  //-- Label ---------------------------
  xx = x + 140; yy = y;
  SL_Label(xx, yy, 285, h, 5, RGB, "FXRack Splitter");
  
  //-- CP Outs -------------------------
  xx = x + 140; yy = y;
  //-- 1 - 4 -------
  Out1.CPOut_Draw(xx, yy+=offs, h, "1/2");
  Out2.CPOut_Draw(xx, yy+=offs, h, "3/4");
  Out3.CPOut_Draw(xx, yy+=offs, h, "5/6");
  Out4.CPOut_Draw(xx, yy+=offs, h, "7/8");
  //-- 5 - 8 -------
  Out5.CPOut_Draw(xx, yy+=offs, h, "9/10");
  Out6.CPOut_Draw(xx, yy+=offs, h, "11/12");
  Out7.CPOut_Draw(xx, yy+=offs, h, "13/14");
  Out8.CPOut_Draw(xx, yy+=offs, h, "15/16");

  //-- Wires ---------------------------
  SetRGB(RGB);
  my = y + offs * 4.5 - 4;
  mx = x + 60;
  xx = x + 120 ; yy = y + offs + h/2;
  loop(8,
    gfx_x = mx; gfx_y = my;
    gfx_lineto(xx - 10, yy, 1);
    gfx_lineto(xx, yy, 1);
    gfx_circle(xx, yy, 2, 1);
    yy+=offs; 
  );
  //-- In label --------------
  gfx_circle(mx, my, 2, 1);
  xx = x; yy = y + offs * 4;
  SL_Label(xx, yy, 45, h, 5, RGB, "1/2");
  

);


//**********************************************************
mouse_down = mouse_cap&1 && !mouse_last_cap&1;
mouse_down ? (mouse_down_x = mouse_x; mouse_down_y = mouse_y);

Draw(); // Main Draw function

mouse_last_cap = mouse_cap;
mouse_last_x = mouse_x;
mouse_last_y = mouse_y;
