desc:Simple mono/poly synth
// (c) Theo Niessink 2012-2015
// License: GPL - http://www.gnu.org/licenses/gpl.html

/*GUI mod by argee March 2015
  NOTE: @slider section code moved to @block section to preserve functionality
  Left MB sets control value, Right MB resets to default value
  Mouse wheel works on all controls except Mode selector - you must hold down Left MB to use wheel
  except on Waveform list
  CTRL (fine increment) and ALT (large increment) key modifiers work for click-drag and mouse wheel
*/

slider1:-6.0<-120.0,24.0,1.0>-Volume (dB)
slider2:0.0<-1200.0,1200.0,1.0>-Tuning (cent)
slider3:0<0,1>-Unused
slider4:3<0,5000,1>-Attack (ms)
slider5:1000<1,15000,1>-Decay (ms)
slider6:0.0<-120.0,24.0,1.0>-Sustain (dB)
slider7:8<0,5000,1>-Release (ms)
slider8:0<0,1>-Unused
slider9:7<0,14,1{Sine,Half-Wave Rectified Sine,Full-Wave Rectified Sine,Triangle,Trapezoid,Square,Pulse PW,Sawtooth,Modified Triangle PW,Triangular Pulse,Hammond,Staircase,Modified Square PW,Trapezoid PW,Triangular Pulse PW}>-Waveform
slider10:0.30<0.0,1.0,0.01>-Pulse Width
slider11:0<0,1>-Unused
slider12:200.0<0.0,1200.0,1.0>-Pitch Wheel Range (cent)
slider13:0<0,1>-Unused
slider14:-36.0<-36.0,0.0,1.0>-White Noise (dB)
slider15:0<0,1>-Unused
slider16:1.0<0.0,1.0,0.01>-Low-Pass Filter
slider17:0<0,15000,1>-Filter Decay (ms)
slider18:1.0<0.01,4.0,0.01>-Filter Q
slider19:0<0,1>-Unused
slider20:0<-100,100,1>-Pan (%)
slider21:0<0,1>-Unused
slider22:0<0,16,1{Any,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}>-MIDI Channel
slider23:0<0,1,1{Mono,Poly}>-Mode
slider24:100<0,100,1>-Velocity Control (%)
slider25:0<0,1>-Unused
slider26:6.0<0.01,12.0,0.001>-LFO Speed (Hz)
slider27:0<0,100,1>-LFO Strength (%)

out_pin:Synth output
out_pin:Synth output

import midi_queue.jsfx-inc
import adsr.jsfx-inc
import rc_filter.jsfx-inc
import zdf_filter.jsfx-inc
import sine_oscillator.jsfx-inc
import poly_blep.jsfx-inc
import noise_generator.jsfx-inc

@init

//load the waveform list starting at offset 100
strX=100;
strcpy(strX,"Sine"); strX+=1;
strcpy(strX,"Half-wave rectified sine"); strX+=1;
strcpy(strX,"Full-wave rectified sine"); strX+=1;
strcpy(strX,"Triangle"); strX+=1;
strcpy(strX,"Trapezoid"); strX+=1;
strcpy(strX,"Square"); strX+=1;
strcpy(strX,"Pulse PW"); strX+=1;
strcpy(strX,"Sawtooth"); strX+=1;
strcpy(strX,"Modified Triangle PW"); strX+=1;
strcpy(strX,"Triangular Pulse"); strX+=1;
strcpy(strX,"Hammond"); strX+=1;
strcpy(strX,"Staircase"); strX+=1;
strcpy(strX,"Modified Square PW"); strX+=1;
strcpy(strX,"Trapezoid PW"); strX+=1;
strcpy(strX,"Triangular Pulse PW");

function TestCtrl_at_Mouse(ctrlnum,minX, maxX, minY, maxY)
(
  mouse_x > minX && mouse_x < maxX && mouse_y > minY && mouse_y < maxY ?
  (ctrlnum):mouse_on;
);

function arc_knob(x,y,r,deg0,degf,rotation,arc_w,slideval,dec,ctrlnum,unit, hilite)
local(i,density,l,rad0,radf)
(   
    mouse_on == 0 ? mouse_on = TestCtrl_at_Mouse(ctrlnum,x-r,x+r,y-r,y+r);
    gfx_a=1;
    gfx_r=0.17;gfx_g=0.17;gfx_b=0.17;
    gfx_circle(x,y,r+2,1,0);

    gfx_x=x;gfx_y=y;
    hilite == 1? (gfx_r=0.6;gfx_g=1;gfx_b=0.6);
    hilite == 2? (gfx_r=0.6;gfx_g=0.7;gfx_b=1);
    hilite == 3? (gfx_r=1;gfx_g=0.6;gfx_b=1);
    hilite == 4? (gfx_r=1;gfx_g=1;gfx_b=0.5);
    hilite == 5? (gfx_r=gfx_g=gfx_b=0.5);

    gfx_circle(x,y,r-8,1,1);
    gfx_x=x-12;gfx_y=y-7;
    gfx_setfont(1,"Arial",14,0);
    gfx_r=gfx_g=gfx_b=0;
    gfx_drawnumber(slideval,dec);

    hilite == 1? (gfx_r=0.3;gfx_g=1;gfx_b=0.3);
    hilite == 2? (gfx_r=0.4;gfx_g=0.6;gfx_b=1);
    hilite == 3? (gfx_r=1;gfx_g=0;gfx_b=0.8);
    hilite == 4? (gfx_r=1;gfx_g=1;gfx_b=0.3);
    hilite == 5? (gfx_r=gfx_g=gfx_b=1);

    gfx_x=x+r+5;gfx_y=y-7;
    gfx_drawstr(unit);
    (deg0+rotation) ? rad0=(deg0+rotation)*(0.0174532925); 
    radf=((degf+rotation)*100)*(17.4532925)/100000;
    arc_w<=2?(density=1;l=1;); arc_w>2?(density=.5; l=2;);
    i=0;
      loop(arc_w*l,
        gfx_arc(x,y,(r)-i,rad0,radf,1);
        i+=density;
      );  
    i>arc_w*l?i=0;

    gfx_setfont(1,"Arial",14,0);
    gfx_x=x; gfx_y+=r+12;
);

function Handle_Mouse(inc, sliderval, minval, maxval, defval)
(
  mouse_cap == 5 ? (inc*=0.1);
  mouse_cap == 17? (inc*=3);
  mouse_cap != 2 ? (
    mouse_y > saveY+2 ? sliderval = Max(minval,sliderval-inc);
    mouse_y < saveY-2 ? sliderval = Min(maxval,sliderval+inc);
  ):(sliderval = defval;
  );

    mouse_wheel < 0? sliderval = Max(minval,sliderval-inc);
    mouse_wheel > 0? sliderval = Min(maxval,sliderval+inc);
    mouse_wheel = 0;

  sliderval;
);

note_buf = 0; max_poly = 16; note_size = 13;
hold_buf = note_buf + max_poly * note_size;
midiq.midiq_init(hold_buf + 128);

pitch = 1;

lpf.m = 50;
lpf.ln = log(lpf.m);

function int(x) ( x|0 );
function gain(db, inf) ( db <= inf ? 0 : 10^(db / 20) );
function mix(a, b, mix) ( (1.0 - mix) * a + mix * b );
function cache(x) ( x != this ? ( this = x; 1; ); );

smooth.rc_set(0.0033);
function smooth() ( smooth.lp = this.smooth; this.smooth = smooth.rc_lp(this); );

function set_tg(note)
  // global(tg*)
(
  tg.poly_setf(440 * 2^((note - 69) / 12));
);

function tg_wave(wave)
  // global(tg*)
(
  wave == 7  ? tg.poly_saw() :
  wave == 6  ? tg.poly_rect() :
  wave == 5  ? tg.poly_sqr() :
  wave == 4  ? tg.poly_trap() :
  wave == 3  ? tg.poly_tri() :
  wave == 2  ? tg.poly_full() :
  wave == 1  ? tg.poly_half() :
  wave == 0  ? tg.poly_sin() :
  wave == 8  ? tg.poly_tri2() :
  wave == 9  ? tg.poly_trip() :
  wave == 10 ? tg.poly_ham() :
  wave == 11 ? tg.poly_stairs() :
  wave == 12 ? tg.poly_sqr2() :
  wave == 13 ? tg.poly_trap2() :
/*wave == 14*/ tg.poly_trip();
);

function adsr_sets(g)
  instance(state)
(
  state == 4 ? state = 2;
  this.adsr_sets(g);
);

function load_adsr(p)
  // global(adsr*)
(
  adsr.state = p[3];
  adsr.env = p[4];
  adsr.scale = p[5];
  adsr.s = p[6];
);

function store_adsr(p)
  // global(adsr*)
(
  p[3] = adsr.state;
  p[4] = adsr.env;
  p[5] = adsr.scale;
  p[6] = adsr.s;
);

function load_lpf(p)
  // global(lpf*)
(
  lpf.env.lp = p[7];
  lpf.freq.smooth = p[8];
  lpf.zdf.g = p[9];
  lpf.zdf.h = p[10];
  lpf.zdf.s1 = p[11];
  lpf.zdf.s2 = p[12];
);

function store_lpf(p)
  // global(lpf*)
(
  p[7] = lpf.env.lp;
  p[8] = lpf.freq.smooth;
  p[9] = lpf.zdf.g;
  p[10] = lpf.zdf.h;
  p[11] = lpf.zdf.s1;
  p[12] = lpf.zdf.s2;
);

function lpf_freq(dt)
  // global(lpf*, srate)
(
  (lpf.env.a < 1 ? lpf.env.rc_lp(lpf.n) : lpf.n) * dt * srate;
);

function reset_lpf(dt)
  // global(lpf*)
(
  lpf.env.lp = 0;
  lpf.zdf.zdf_reset();
  lpf.freq.smooth = lpf_freq(dt);
  lpf.zdf.zdf_lp(lpf.freq.smooth, lpf.q);
);

function note_on(note, vel)
  // global(num_poly, mono_note, mono_dt, note_buf, num_notes, note_size, tg*, adsr*, lpf*, tuning)
  local(p, end)
(
  // Optimize for mono (poly code can also play mono, but is slower).
  num_poly == 1 ? (
    set_tg(note);

    !num_notes ? (
      adsr.adsr_reset();
      reset_lpf(tuning * tg.dt);
      num_notes = 1;
    );

    mono_note = note;
    mono_dt = tg.dt;
    
    adsr.adsr_a(vel);
    lpf.env.lp = lpf.m;
  ) :

  /* num_poly > 1 ? */ (
    p = note_buf;
    end = p + num_notes * note_size;
    while(p < end && p[] != note ? p += note_size);

    p >= end ? (
      set_tg(note);

      num_notes >= num_poly ? (
        // Set oscillator/ADSR state to first played note (to mimic old
        // mono_synth global state behaviour).
        tg.t = note_buf[1];
        load_adsr(note_buf);
        load_lpf(note_buf);

        p -= note_size;
        num_notes -= 1;
        num_notes > 0 ? memcpy(note_buf, note_buf + note_size, num_notes * note_size);
      ) : (
        // Don't reset oscillator on first note (old mono_synth behaviour).
        num_notes > 0 ? tg.t = 0;
        adsr.adsr_reset();
        reset_lpf(tuning * tg.dt);
      );

      num_notes += 1;
      p[0] = note;
      p[1] = tg.t;
      p[2] = tg.dt;
    ) : (
      load_adsr(p);
      load_lpf(p);
    );

    adsr.adsr_a(vel);
    lpf.env.lp = lpf.m;

    store_adsr(p);
    store_lpf(p);
  );
);

function note_off(note)
  // global(num_poly, mono_note, note_buf, note_size, num_notes, adsr*)
  local(p, end)
(
  num_poly == 1 ? (
    num_notes && note == mono_note ? adsr.adsr_r();
  ) :

  /* num_poly > 1 ? */ (
    p = note_buf;
    end = p + num_notes * note_size;
    while(p < end && p[] != note ? p += note_size);

    p < end ? (
      load_adsr(p);
      adsr.adsr_r();
      store_adsr(p);
    );
  );
);

function hold_note(note)
  // global(hold_buf, num_hold)
  local(p, end)
(
  // \todo Limit num_hold to num_poly.

  p = hold_buf;
  end = p + num_hold;
  while(p < end && p[] != note ? p += 1);

  p >= end ? (
    p[] = note;
    num_hold += 1;
  );
);

function release_notes()
  // global(hold_buf, num_hold)
  local(p)
(
  p = hold_buf;
  loop(num_hold,
    note_off(p[]);
    p += 1;
  );
  num_hold = 0;
);

function all_notes_off()
  // global(num_notes, num_hold)
(
  num_notes = num_hold = 0;
);

function pitch_bend(pitch_wheel)
  // global(pitch, pitch_range)
(
  pitch = pitch_range < 0.00001 ? 1 : 2^(pitch_wheel * pitch_range);
);

@slider

@block

midiq.midiq_collect(midi_ch, 3|8|64);

//@slider code moved here so it will respond to GUI changes
function adr(ms, lo, hi) ( max(lo, min(hi, ms)) * 0.001 );

function pan(gain, pos)
  // global(gain0, gain1)
(
  // REAPER default 0 dB pan law (thanks Justin!)
  // http://www.askjf.com/index.php?q=2342s

  pos *= 0.25*$pi;
  gain *= sqrt(2) * (1 - sqrt(0.5) * (1 / cos(pos) - 1));

  pos += 0.25*$pi;
  gain0 = cos(pos) * gain;
  gain1 = sin(pos) * gain;
);

pan(gain(slider1, -120.0), max(-100, min(100, slider20)) * 0.01);

adsr.adsr_seta(adr(slider4, 0, 5000));
adsr.adsr_setd(adr(slider5, 1, 15000));
adsr.adsr_sets(gain(slider6, -120.0));
adsr.adsr_setr(adr(slider7, 0, 5000));

tuning = 2^(slider2 / 1200);
wave = int(slider9);

// Limit pulse width for pulse, triangular pulse, modified square.
min_pw = wave == 6 || wave == 14 ? 0.10 : wave == 8 ? 0.01 : wave == 12 ? 0.20 : 0.0;
max_pw = wave == 6 ? 0.90 : wave == 8 ? 0.99 : 1.0;
pw = wave == 9 ? 0.5 : max(min_pw, min(max_pw, slider10));

noise_mix = gain(slider14, -36.0);

lpf.n = slider16 >= 1.0 ? lpf.m : exp(max(0.0, slider16) * lpf.ln);
slider17 < 1 ? lpf.env.a = 1 : lpf.env.rc_sets(0.001 * min(15000, slider17));
lpf.q = max(0.01, min(4.0, slider18));

pitch_range = max(0.0, slider12) / 1200;
midi_ch.cache(max(0, min(16, int(slider22))) - 1) ? all_notes_off();
num_poly.cache(slider23 < 0.5 ? 1 : max_poly) ? all_notes_off();
vel_range = max(0, min(100, slider24)) * 0.01;

lfo_range = max(0, min(100, slider27)) * 0.01;
lfo_range <= 0 ? (
  lfo_mod = 0;
) : wave == 6 || wave == 8 || wave >= 12 ? (
  lfo_mod = 1;
  lfo_range *= 0.5 * (max_pw - min_pw);
  pw = max(min_pw + lfo_range, min(max_pw - lfo_range, pw));
) : (
  lfo_mod = 2;
  lfo_range *= 0.5/12;
);
lfo_mod != 1 ? tg.poly_setpw(pw);
lfo_mod ? lfo.sin_setf(max(0.01, slider26))

@sample

while(midiq.midiq_remove() ? (
  midiq.msg1 &= 0xF0;

  // Note On
  midiq.msg1 == 0x90 && midiq.msg3 ? (
    note_on(midiq.msg2, (1.0 - vel_range) + vel_range * midiq.msg3 / 127);
  ) :

  // Note Off
  midiq.msg1 == 0x80 || midiq.msg1 == 0x90 ? (
    hold_pedal ? hold_note(midiq.msg2) : note_off(midiq.msg2);
  ) :

  // Pitch Wheel
  midiq.msg1 == 0xE0 ? (
    pitch_bend(((midiq.msg3 << 7 | midiq.msg2) - 8192) / (midiq.msg3 < 64 ? 8192 : 8191));
  ) :

  // Control Change
  midiq.msg1 == 0xB0 ? (

    // Damper Pedal (Sustain)
    midiq.msg2 == 64 ? (
      hold_pedal = midiq.msg3 >= 64;
      !hold_pedal ? release_notes();
    ) :

    // All Notes Off
    midiq.msg2 == 123 ? (
      all_notes_off();
    );
  );

  1; // while midiq.midiq_remove()
));

function sample_tg(t, dt)
  // global(adsr*, freq_mod, tg*, wave, white_noise, noise_mix)
(
  adsr.state ? (
    noise_mix < 1.0 ? (
      tg.t = t;
      tg.poly_setdt(freq_mod * dt);
      tg.poly_resetf();
      adsr.env * mix(tg_wave(wave), white_noise, noise_mix);
    ) : (
      adsr.env * white_noise;
    );    
  );
  // 0.0 otherwise
);

function apply_lpf(in, dt)
  // global(lpf*, tuning)
  local(out)
(
  lpf.freq = lpf_freq(tuning * dt);
  lpf.freq.smooth();

  // Recalculate LPF coefficients only every 16 samples.
  lpf.skip <= 0 && lpf.freq.smooth != lpf.zdf.freq ? (
    lpf.zdf.freq = lpf.freq.smooth;
    lpf.zdf.zdf_lp(lpf.zdf.freq, lpf.q);
  );

  out = lpf.zdf.zdf_svf_lp(in);
  lpf.n < lpf.m ? out : in;
);

function adsr_lpf_off()
  // global(adsr*, lpf.zdf*)
(
  !adsr.state && lpf.zdf.s1 == 0 && lpf.zdf.s2 == 0;
);

freq_mod = pitch * tuning;
lfo_mod ? lfo_mod == 1 ? tg.poly_setpw(pw + lfo_range * lfo.sin_sin()) : freq_mod *= 2^(lfo.sin_sin() * lfo_range);

white_noise = noise_mix > 0.0 ? noise.lcg_white();
out = 0.0;

num_poly == 1 ? (
  num_notes ? (
    adsr.adsr_process();
    out = apply_lpf(sample_tg(tg.t, mono_dt), mono_dt);
    adsr_lpf_off() ? num_notes = 0;
  );
) :

/* num_poly > 1 ? */ (
  sus = adsr.s;

  p = note_buf;
  end = p + num_notes * note_size;
  while(p < end ? (

    // Functions indexing memory seems to be slow, so manually inline them.
    /* load_adsr(p); */ adsr.state = p[3]; adsr.env = p[4]; adsr.scale = p[5]; adsr.s = p[6];
    adsr.s != sus ? adsr.adsr_sets(sus);
    adsr.adsr_process();
    /* store_adsr(p); */ p[3] = adsr.state; p[4] = adsr.env; p[5] = adsr.scale; p[6] = adsr.s;

    s = sample_tg(p[1], p[2]);
    p[1] = tg.t;

    /* load_lpf(p); */ lpf.env.lp = p[7]; lpf.freq.smooth = p[8]; lpf.zdf.g = p[9]; lpf.zdf.h = p[10]; lpf.zdf.s1 = p[11]; lpf.zdf.s2 = p[12];
    s = apply_lpf(s, p[2]);
    /* store_lpf(p); */ p[7] = lpf.env.lp; p[8] = lpf.freq.smooth; p[9] = lpf.zdf.g; p[10] = lpf.zdf.h; p[11] = lpf.zdf.s1; p[12] = lpf.zdf.s2;

    out += s;

    adsr_lpf_off() ? (
      num_notes -= 1;
      end -= note_size;
      p < end ? (
        memcpy(p, p + note_size, end - p);
        1; // while p < end
      );
    ) : (
      p += note_size;
    );
  ));
);

lpf.skip > 0 ? lpf.skip -= 1 : lpf.skip = 16 - 1;

spl0 += gain0.smooth() * out;
spl1 += gain1.smooth() * out;


@gfx 650 355
gfx_a=1;

//Graphics for the Main Background
gfx_r=0.05;gfx_g=0.05;gfx_b=0.1;gfx_rect(0,0,650,355);

//Graphics for the Header
gfx_x=0;gfx_y=0; gfx_gradrect(0,0,700,15,.55,.55,.6,1,0,0,0,0,-.03,-.03,-.03,0);
gfx_x=220;gfx_y=16; gfx_setfont(1,"Arial Bold",28,'b'); gfx_r=0.2;gfx_g=1;gfx_b=0;
gfx_drawstr("Tale's"); gfx_r=0.2;gfx_g=0.7;gfx_b=1.0; gfx_drawstr(" Mono/Poly Synth");

/*following commented lines used for design/debugging GUI
gfx_x=300;gfx_y=0;
gfx_r=gfx_g=gfx_b=1;
gfx_drawnumber(mouse_x,0);gfx_drawstr(", ");gfx_drawnumber(mouse_y,0);
*/

//mouse handling for controls (mouse_on assigned when controls were created)
//lmb sets control value, rmb resets to default value (except of ADSR control)
//mouse wheel works on all controls except Mode selector - you must hold down lmb to use wheel
//CTRL and ALT key modifiers work for click-drag and mouse wheel

mouse_cap > 0 ? (  //mouse button is down
  mouse_on == 1 ? slider1 = Handle_Mouse(3,slider1,-120,24, -6);  //Volume
  mouse_on == 2 ? slider20 = Handle_Mouse(5,slider20,-100,100,0);  //Pan
  mouse_on == 3 ? slider2 = Handle_Mouse(40,slider2,-1200,1200,0);  //Tuning
  mouse_on == 4 ? slider10 = Handle_Mouse(0.02,slider10,0,1,0.3);  //Pulse Width
  mouse_on == 5 ? slider12 = Handle_Mouse(20,slider12,0,1200,200);  //Pitch Wheel Range
  mouse_on == 6 ? slider16 = Handle_Mouse(0.02,slider16,0,1,1);  //Low Pass Filter
  mouse_on == 7 ? slider14 = Handle_Mouse(1,slider14,-36,0,-36);  //White Noise
  mouse_on == 8 ? slider24 = Handle_Mouse(3,slider24,0,100,100);  //Velocity Control
  mouse_on == 9 ? slider26 = Handle_Mouse(0.2,slider26,0.01,12,6);  //LFO Speed
  mouse_on == 10 ? slider27 = Handle_Mouse(2,slider27,0,100,0); //LFO Strength
  mouse_on == 11 ? slider22 = Handle_Mouse(1,slider22,0,16,0); //MIDI Channel
  mouse_on == 12 ? slider23 = 0;  //Mono mode
  mouse_on == 13 ? slider23 = 1;  //Poly mode

  mouse_on == 15 ? slider4 = Handle_Mouse(50,slider4,0,5000,200);  //Attack
  mouse_on == 16 ? slider5 = Handle_Mouse(200,slider5,0,15000,1000);  //Decay
  mouse_on == 17 ? slider6 = Handle_Mouse(3,slider6,-120,24,1);  //Decay
  mouse_on == 18 ? slider7 = Handle_Mouse(50,slider7,0,5000,0);  //Attack

  mouse_on == 19 ? slider17 = Handle_Mouse(200,slider17,0,15000,200); //MIDI Channel
  mouse_on == 20 ? slider18 = Handle_Mouse(0.1,slider18,0,4,1);  //Low Pass Filter

  saveX = mouse_x;
  saveY = mouse_y;
  
):(mouse_on = 0);
//end of section

//following section creates knob controls and also tests for mouse_on the control
//These are in no particular order as they have been moved around a lot

//Volume knob
new.arc_knob(220,90,30,-280,slider1*2.1,115,6,slider1,0,1,"dB",5); gfx_x-=18; gfx_drawstr("Volume");

//Pan knob
new.arc_knob(310,90,22,0,slider20*1.25,-360,6,slider20,0,2,"%",5); gfx_x-=9; gfx_drawstr("Pan");

//Tuning knob
new.arc_knob(410,120,22,0.5,slider2/9,0,6,slider2,0,3,"cnt",1); gfx_x-=16; gfx_drawstr("Tuning");

//Pulse Width knob
new.arc_knob(460,205,22,-15,slider10*300,-140,6,slider10,2,4,"",1); gfx_x-=27; gfx_drawstr("Pulse Width");

//Pitch Wheel Range knob
new.arc_knob(590,120,22,-15,slider12/4,-140,6,slider12,0,5,"cnt",1); gfx_x-=42; gfx_drawstr("Pitch Wheel Range");

//main label
gfx_x=250;gfx_y=155; gfx_r=1;gfx_g=1;gfx_b=0.3; gfx_drawstr("Low Pass Filter");
 
//Low Pass Filter knob
new.arc_knob(220,200,22,-15,slider16*300,-140,6,slider16,2,6,"",4); gfx_x-=19; gfx_drawstr("Amount");

//Low Pass Filter Decay knob
new.arc_knob(290,200,22,-20,slider17/50,-140,6,slider17,0,19,"ms",4); gfx_x-=14; gfx_drawstr("Decay");

//Low Pass Filter Q knob
new.arc_knob(360,200,22,-20,slider18*65,-120,6,slider18,2,20,"",4); gfx_x-=18; gfx_drawstr("Filter Q");

//White Noise knob
new.arc_knob(550,205,22,-300,slider14*8,150,6,slider14,0,7,"dB",1); gfx_x-=30; gfx_drawstr("White Noise");

//Velocity Control knob
new.arc_knob(500,120,22,-10,slider24*3,215,6,slider24,0,8,"%",1); gfx_x-=28; gfx_drawstr("Vel. Control");

//Label
gfx_r=1;gfx_g=0;gfx_b=0.8; gfx_x=545; gfx_y=255; gfx_drawstr("LFO");

//LFO Speed knob
new.arc_knob(520,300,22,-10,slider26*25,215,6,slider26,1,9,"Hz",3); gfx_x-=14; gfx_drawstr("Speed");

//LFO Strength knob
new.arc_knob(590,300,22,-10,slider27*3,215,6,slider27,0,10,"%",3); gfx_x-=20; gfx_drawstr("Strength");

//Label
gfx_r=0.4;gfx_g=0.6;gfx_b=1; gfx_x=285; gfx_y=255; gfx_drawstr("ADSR Envelope");

//Attack knob
new.arc_knob(220,300,22,-10,slider4/17,-140,6,slider4,0,15,"ms",2); gfx_x-=14; gfx_drawstr("Attack");

//Decay knob
new.arc_knob(290,300,22,-1,slider5/50,-150,6,slider5,0,16,"ms",2); gfx_x-=15; gfx_drawstr("Decay");

//Sustain knob
new.arc_knob(360,300,22,-250,slider6*2,-260,6,slider6,0,17,"dB",2); gfx_x-=18; gfx_drawstr("Sustain");

//Release knob
new.arc_knob(430,300,22,-10,slider7/17,-140,6,slider7,0,18,"ms",2); gfx_x-=18; gfx_drawstr("Release");

//end of section

//Graphics and mouse handling for the Waveform list
gfx_gradrect(10,37,160,26,0,0,1,1,0,0,0,0,0,0,-.025,0);
gfx_x=61;gfx_y=41;
gfx_setfont(1,"Arial",16,0);gfx_r=gfx_g=gfx_b=1; gfx_drawstr("Waveform");

gfx_x=20;gfx_y=70;gfx_setfont(1,"Arial",14,'b');linsp=gfx_texth+3;

gfx_r=0;gfx_g=0;gfx_b=0.3;
gfx_rect(10,65,160,270); gfx_gradrect(12,67,156,266,0,0,0.3,1,0,0,0,0,0,0,-.001,0);

mouse_x > 20 && mouse_x < 180 && mouse_y > 70 && mouse_y < 68+linsp*15 ? (
  Waveform = floor((mouse_y - 70)/linsp);
  gfx_r=0;gfx_g=0.2;gfx_b=0.4;
  gfx_rect(17,69+(Waveform)*linsp,145,linsp);
  mouse_cap == 1 ? (slider9=Waveform):(mouse_cap == 2 ? slider9=7);
  mouse_wheel > 0? slider9=max(0,slider9-1);
  mouse_wheel < 0? slider9=min(14,slider9+1);
  mouse_wheel=0;
);

gfx_x=20;gfx_y=70;
i = 100;
loop(15,
  slider9 == i-100? (gfx_r=gfx_g=gfx_b=0.2;gfx_rect(17,69+slider9*linsp,145,linsp);gfx_r=gfx_g=gfx_b=1;):(gfx_r=gfx_g=gfx_b=0.5);
  gfx_drawstr(i);
  gfx_x=20; gfx_y+=linsp;
  i+=1;
);
//end of section

//Graphics for Mode selector
mouse_on == 0 ? mouse_on = TestCtrl_at_Mouse(12,372,420,58,80);
mouse_on == 0 ? mouse_on = TestCtrl_at_Mouse(13,422,470,58,80);
gfx_r=0;gfx_g=0;gfx_b=0.7; gfx_rect(370,56,104,26);
gfx_r=0;gfx_g=0;gfx_b=0.5; gfx_rect(372,58,48,22);
gfx_r=0;gfx_g=0;gfx_b=0.3; gfx_rect(422,58,48,22);
gfx_r=1;gfx_g=1;gfx_b=0; gfx_setfont(1,"Arial",14,'b');
gfx_x=380;gfx_y=62;
slider23 > 0? (
  gfx_r=gfx_g=gfx_b=0.5; gfx_drawstr("Mono");
  gfx_r=1;gfx_g=1;gfx_b=1;
  gfx_x=435;gfx_y=62; gfx_drawstr("Poly");
):(
  gfx_r=1;gfx_g=1;gfx_b=1; gfx_drawstr("Mono");
  gfx_r=gfx_g=gfx_b=0.5;
  gfx_x=435;gfx_y=62; gfx_drawstr("Poly");
);

//Graphics for MIDI channel selector
mouse_on == 0 ? mouse_on = TestCtrl_at_Mouse(11,545,615,60,80);
gfx_r=0;gfx_g=0;gfx_b=0.7; gfx_rect(520,56,100,26);
gfx_r=0;gfx_g=0;gfx_b=0.5;
gfx_rect(522,58,56,22);
gfx_x=527;gfx_y=62; gfx_setfont(1,"Arial",14,'b');
gfx_r=gfx_g=gfx_b=0.6; gfx_drawstr("MIDI Ch.");
gfx_r=0;gfx_g=0;gfx_b=0.3; gfx_rect(575,58,42,22);
gfx_r=1;gfx_g=1;gfx_b=1; gfx_setfont(1,"Arial",14,'b');
slider22 > 0? (
  gfx_x=590;gfx_y=61; gfx_drawnumber(slider22,0);
):( slider22 == 0? gfx_x=583; gfx_y=61; gfx_drawstr("Any")
);

