desc:wild wave fu - extreme dynamic nonlinear waveshaper - v0.28beta

/*** quick reference ***

edit a/b: selects which shaper the controls edit.  also has several utility
functions, and toggles for the limiter and inverter options.

input gain: boost/cut input to the fx.  this control does not affect the
shaper graph.  it operates and crossfades in decibels.

output gain: boost/cut output from the rx.  it operates and crossfades in
decibels.

mod X - drive: controls "linear" input gain, shown in the shaper graph.

drive range: set range of mod X control, from 2x to 40x.

drive bias: biases drive for the negative half of the range.

mod Y - saturation: controls nonlinear boost using sine function.  at
higher mod X settings more of the sine is effective, which generates
"oscillations" in the shaper.

mod Z - lag: controls nonlinear cut using a reordered sine function.  this
generates a concave shaper at low mod X values, which can be useful for
counteracting the tendancy for mod X & Y to produce high gain.  at higher
mod X values this generates "pointy oscillations".

+/- nonlinearity: generates a bend in shaper.  +/- affect the upper and
lower parts of the shaper respectively.  when + & - nonlinearities are not
symetric this produces even harmonics.

+/- knee: generates a soft, rounded corner for the nonlinearity bend

+/- thresh: sets the level at which the nonlinearity bend occurs.  when +/-
thresh is set to its minimum or maximum values,

+/- gain: independent output gain controls for positive/negative inputs to
the shaper. so unlike the nonlinearity controls, +/- gain affect the
right/left halves of the shaper.  +/- gain fades in a bit near the origin to
reduce nonlinearities there when +/- gains are different.

mod Z before Y: controls the order of processing for mod Y & Z.

undriven mod Z: applies the mod Z nonlinear cut to the pre mod X inputs,
and uses those values to scale the post mod X/Y values.  this eliminates
mod Z "oscillations" for high mod X values and strengthens the mod Z effect
of reducing shaper gain.

oversampling: controls variable oversampling.  values above 2 seem to have
minimal benefit.  oversampling is off when this control is 1.

os: aa filter cascades: oversampling uses cascaded Butterworth filters to
reduce aliasing.  this control sets the number of cascades.  each cascade
adds 12 dB/oct. note that there is some high frequency rolloff with more
cascades that can affect tone and confuse the apparent antialiasing.

os: aa filter bandwidth: controls the cutoff of the aa filter from half to
full bandwidth.

A/B threshold: sets the levels at which the A/B shapers are fully in
effect.  between these levels A/B shapers are blended by interpolating all
their control settings based on input volume envelope and transience
detectors.  if A & B thresholds are equal, no blending occurs and only the
A shaper is effective, which saves quite a bit of processing.

A/B curve: controls the shape if the A/B blend, from concave, which favors
A, to convex, which favors B.  at the left/right extremes, this control
forces the input to be controlled entirely by the A/B shapers respectively.

A/B morph: if not -1, controls the A/B mix.  automatable.

A/B transience: biases the A/B blend based on the difference between 
the main and transient envelope detectors.  when this transient difference is
detected, the envelop detector output is biased toward the A/B shapers when
this control is negative/positive.

response time: controls the main envelope detector.  sets an approximate
time over which the input level is averaged.

transience time: controls the transience envelope detector.  set the time
over which the transience input level is averaged as a ratio of the
response time.

shaper graph: shows the overall mapping curves from input to output as set
by the shaper controls.  if A/B thresholds are different, shows the A curve
in green, the B curve in red, and the dynamic morphed curve in yellow.  A/B
input and output gains are shown as green/red lines next to the in and out
axes.  the A/B response curve is shown as a grey curve from bottom-left to
top-right.  small grey diamonds show realtime input and output
envelope/transience values on the bottom and right of the graph. 
transience is indicated by a horizontal line from the main input envelope
value to the diamond which shows the net value including transience. a
history of the average input envelope and min/max transience levels is
shown as a vertically scrolling graph.  peak input levels after input gain
are shown as a pair of blue * symbols connected by a faint blue line.  this
extent is projected onto the active, morphed shape as two vertical blue
tick marks that give an idea of how much of the current shape is affecting
the input.

shortcuts: leftclick and drag in the graph to change in/outgain for both A
and B shapes together.  drag left-right to change ingain or up-down for
outgain. rightclick in the graph to swap A/B.  shift-rightclick to copy the
shape A parameters, or the current mix in A/B morph mode.
shift-alt/option-right click to paste the copied params into shape A.
shift-click in A/B sliders to change both together. control/command-click
in +/- sliders to change both together.  option-click in sliders to set
extreme values when sensible.

***/

/***//@ release notes

v0.28beta
- move slmunge logic to @sample via syncd, double buffered sliders

v0.26beta
- color aa text!  :^)

v0.25beta 
- remove crufty commented out code
- fix sliderchange/_automate logic
- move memvars/sliders to internal sli.slz
- rename include files w/ bangzero_ prefix
- tweaks to avoid some more glitches on preset loads
- move blitargs= mem() to gfx_ini() to ensure alloc
- replace ...btn3() w/ ...varbtn w/ variable # of texts

v0.24beta - mea culpa release
- shuffle tweak sliders around a bit
- move squish logic after whack ingain for graph accuracy & intuitive results
- change drive range morph logic to fix abmorph copy & for consistency
- fix glitches due to abrupt curve changes on preset change
- fix abmorph copy to reflect ab curve
- fix curve updating to work when @sample inactive
- made zero crossing curve not ^2

v0.23beta
- add extra slop when slider active
- fix snap back logic for mem sliders
- fix std font fallback logic
- add main/transient env envelopes to snaps
- refine snaps trigger logic near end of circ buf
- refactor put number fn to make num len accessible for right justification
- add transient env soft limiting
- add squish and crunch, pre/post whack soft limit/saturation
- optimize a/b curve logic to use non-squared inverse curve
- replaced most ^2 invcurves w/ similar ^1 curves; optimized inline expansions

v0.20beta
- make curve slew limiting variable
- add variable transience decay/order/offset
- add option for sidechain inputs 3/4 to env/trans logic
- add transience only mod if A&B thresh equal and trans not zero
- compact, custom gui w/ aa font
- add freeze frame to trans wave display that superimposes input wave 
- make env/wave display scale (spl/pix) variable
- add true +/- transience option to -=+ and +only
- dedicated A/B morph slider

v0.14beta
- add peak transience to env/trans graph
- minor gui tweeks/fix
- dark envelope option w/ peak transience waveform display

v0.13beta
- general code cleanup & small optimizations
- click & drag in graph to change A & B in/outgain together
- rename wwhack.jsfx-inc to whack.jsfx-inc: w(ave)hack
- refactor graphing code; add bangzero_gfx.jsfx-inc w/ pane/hue classes
- improve a/b morph slew limit logic
- tweek a/b curve slider response
- realtime response/transience graph
- more transient transience: new transient detection logic
- bipolar/positive transience parameter

v0.12alpha
- kinder, gentler mod Z/lag: previously added gritty distortion even at very
  minimal mod amounts
- optimize env logic when a/b morph mode active
- optimize slider logic to avoid some calcs when using param modulation
- change default for limit output to enabled
- add mix option inside oversample logic for per patch saves and to avoid aa 
  filter phase wierdness

v0.11alpha
- slew limit env2 deltas to avoid morph noise
- fix morph curve graph to work when fx disable/no @sample
- add peak meter w/ projection onto rt shape morph
- avoid bogus morphs if a/b thresholds not both ==/!= -60
- optimize env logic

***/

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

import bangzero/bangzero_core.jsfx-inc
import bangzero/bangzero_gfx.jsfx-inc
import bangzero/butterworthFilter.jsfx-inc
import bangzero/bangzero_invcurve.jsfx-inc
import bangzero/bangzero_sl.jsfx-inc
import bangzero/bangzero_whack.jsfx-inc

slider1:0<0,1,1{–}>-et cetera
slider2:0<-30,30,0.1>-input gain (dB)
slider3:0<-30,30,0.1>-output gain (dB)
slider4:0<0,100,0.1>- mod X - drive
slider5:0<0,95,0.1>-drive range
slider6:0<-1,1,.01>-drive bias
slider7:0<0,200,0.1>-mod Y - saturation
slider8:0<0,200,0.1>-mod Z - lag
slider9:1<1,10,0.01>-+ nonlinearity
slider10:0<0,10,0.01>-+nl: knee
slider11:-12<-60,0,0.01>-+nl: thresh (dB)
slider12:1<1,10,0.01>-– nonlinearity
slider13:0<0,10,0.01>-–nl: knee
slider14:-12<-60,0,0.01>-–nl: thresh (dB)
slider15:0<-24,24,0.01>-+ gain (dB)
slider16:0<-24,24,0.01>-– gain (dB)
slider17:0<0,1,1{no,YES}>-mod Z before Y
slider18:0<0,1,1{no,YES}>-undriven mod Z
slider19:1<1,16,1>-oversampling
slider20:4<1,12,1>-os: aa filter cascades
slider21:1<.5,1,.01>-os: aa filter bandwidth
slider22:-48<-100,6,1>-A threshold (dB)
slider23:-48<-100,6,1>-B threshold (dB)
slider24:0<-100,100,1>-A/B curve
slider25:0<-100,100,1>-A/B transience/morph
slider26:23<1,100,1>-response time (ms)
slider27:8<.1,32,.1>-transience time (ratio)
slider28:100<0,100,.1>-wet mix (%)
slider29:-1<-1,100,.1>-A/B morph
slider30:0<-30,30,0.1>-B input gain (dB)
slider31:0<-30,30,0.1>-B output gain (dB)
slider32:0<0,100,0.1>-B  mod X - drive
slider33:0<0,95,0.1>-B drive range
slider34:0<-1,1,.01>-B drive bias
slider35:0<0,200,0.1>-B mod Y - saturation
slider36:0<0,200,0.1>-B mod Z - lag
slider37:1<1,10,0.01>-B + nonlinearity
slider38:0<0,10,0.01>-B +nl: knee
slider39:-12<-60,0,0.01>-B +nl: thresh (dB)
slider40:1<1,10,0.01>-B – nonlinearity
slider41:0<0,10,0.01>-B –nl: knee
slider42:-12<-60,0,0.01>-B –nl: thresh (dB)
slider43:0<-24,24,0.01>-B + gain (dB)
slider44:0<-24,24,0.01>-B – gain (dB)
slider45:0<0,101,1>-squish
slider46:0<0,100,1>-crunch
slider47:0<-36,36,1>-master gain
slider48:0<0,2,1>-transience polarity
slider49:2<1,5,.1>-transience power
slider50:1<1,.1,.0001>-curve s-limit
slider51:0<0,10,.01>-transience decay
slider52:0<-24,24,.1>-transience offset
slider53:0<0,100,1>-freeze thresh

filename:0,bangzero_files/monofur.png

@init

// ii= 0; while( while ( eq= (ii+= 1) != ii+1; eq; ); eq; );
// a..ii= ii;
// a..jj= ii+1;
// a..eq= eq;
// a..eq1= a..ii != a..jj;
// a..eq2= ii != ii+1;

fontfile= 0; //used in gfxini();
fontyoff= -3; //make baseline match default font; specific to font
txth= 9; //actual 14, but squish lines

// automatable sliders
ii= 0;

sleditab= ii+= 1;
sligain= ii+= 1;
slogain= ii+= 1;
slmodx= ii+= 1;
slmodxrng= ii+= 1;

slmodxbias= ii+= 1;
slmody= ii+= 1;
slmodz= ii+= 1;
slpnl= ii+= 1;
slpnlk= ii+= 1;

slpnlt= ii+= 1;
slnnl= ii+= 1;
slnnlk= ii+= 1;
slnnlt= ii+= 1;
slpgain= ii+= 1;

slngain= ii+= 1;
slzb4y= ii+= 1;
slnodrivez= ii+= 1;
slostimes= ii+= 1;
sloscascades= ii+= 1;

slosbw= ii+= 1;
slathresh= ii+= 1;
slbthresh= ii+= 1;
slabcurve=ii+= 1;
sltrans= ii+= 1;

slresptm= ii+= 1;
sltranstm= ii+= 1;
slwetmix= ii+= 1;

//newish
slabmorphval= ii+= 1;

ii0= ii;
sligainb= ii+= 1;
slogainb= ii+= 1;
slmodxb= ii+= 1;
slmodxrngb= ii+= 1;
slmodxbiasb= ii+= 1;
slmodyb= ii+= 1;
slmodzb= ii+= 1;
slpnlb= ii+= 1;
slpnlkb= ii+= 1;
slpnltb= ii+= 1;
slnnlb= ii+= 1;
slnnlkb= ii+= 1;
slnnltb= ii+= 1;
slpgainb= ii+= 1;
slngainb= ii+= 1;
abslcnt= ii-ii0; //abslcnt= 16-abslbase+1; // was 12==17-abslbase+1;

slsquishcrv= ii+= 1;
slcrunchcrv= ii+= 1;
slmgain= ii+= 1;

slbptrans= ii+= 1;
slenvtpow= ii+= 1;
slenv2slim= ii+= 1;
slenvtenv= ii+= 1;
slenvtoff= ii+= 1;
slesnapthx= ii+= 1;

slused= ii;
slmax= 64;
abslbase= sligain; //was 6;
abslbaseb= sligainb; //was 6;
abslaboff= abslbaseb-abslbase;
abslmax= 32;

//internal preset sliders
slibase= 128;
slimax= 256;
ii0= ii= slibase - 1;
slenvtlimit= ii+= 1;
slenvtlimcrv= ii+= 1;

slinvert= ii+= 1;
slunlimit= ii+= 1;
slsidechain= ii+= 1;

sliused= ii-ii0;

//transient sliders
sltbase= 512;
ii0= ii= sltbase - 1;

sldbgraph= ii+= 1;
slenvgax= ii+= 1;
slesnapavc= ii+= 1;
sltweaks= ii+= 1;

sltused= ii-ii0;

// mem allocating class fns
function gshapeinit( sz_, dbmin_ )
  instance( inc, sz, memsz, xmem, ymem, xycnt, dbmin, dbinc )
(
  ! memsz || sz != sz_ ?(
    sz= sz_;
    inc= 2/sz;
    dbmin= dbmin_;
    dbinc= (-dbmin*2)/sz;
    memsz < sz ?(
      xmem= mem(sz+1); //+1 for db graph crossover
      ymem= mem(sz+1);
      memsz= sz;
    );
  );
);
  
function gcurveinit( sz_ )
  instance( inc, sz, memsz, xmem, ymem, xycnt )
(
  ! memsz || sz != sz_ ?(
    sz= sz_;
    inc= 1/sz;
    memsz < sz ?(
      xmem= mem(sz);
      ymem= mem(sz);
      memsz= sz;
    );
  );
);
  
//@ init mem/vars --------------------------------

gfx_clear= -1;

log2db = 8.6858896380650365530225783783321; // 20 / ln(10)
db2log = 0.11512925464970228420089957273422; // ln(10) / 20
halfpi = $pi / 2;
twopi= $pi * 2;
last_aa= 0;
maxigain= 36;
maxogain= 36;
gdbmin= -60;
esnapavgcnt= 0; //4;
esnaptm= 3; //secs
esnapmax0= esnaptm * 96000; // * esnapavgcnt; //(1/30) * 96000 * esnapavgcnt;
esnapmax= esnaptm * srate > esnapmax0 ? esnapmax0 : esnaptm * srate;
// abcurveexp= 0;
//ensure initialupdates of these in @sample:
curve1= crunchcrv1= envtlimcrv1= -99999; 

gdirty= 1;

// once only/mem alloc inits
! init1 ?(

  // all automated sliders backbuffer
  sl.slnew( 1, slmax, slused, 1 ); 
  slfile.slnew( 1, slmax, slused, 0 ); // tmp all sliders for @serialize
  slold.slnew( 1, slused, slused, 0 );
  slxl.slnew( 1, slmax, slused, 0 ); // translation all sliders
  sl1.slnew( 1, slmax, slused, 0 ); // for slmunge1()
  
  // a/b slider mirrors
  sl.slpush(); sla.slmirror( abslbase, abslcnt, 0 );
  sl.slpush(); slb.slmirror( abslbase, abslcnt, sligainb-sligain );
  slclip.slnew( abslbase, abslcnt, abslcnt, 0 ); //note max==abslcnt for a/b mirrored subsections
  slabxl.slnew( abslbase, abslcnt, abslcnt, 0 );
  slaold.slnew( abslbase, abslmax, abslcnt, 0 ); // for old presets
  slbold.slnew( abslbase, abslmax, abslcnt, 0 ); // for old presets
  sl1.slpush(); sla1.slmirror( abslbase, abslcnt, 0 ); // for slmunge1()
  sl1.slpush(); slb1.slmirror( abslbase, abslcnt, sligainb-sligain ); // for slmunge1()
  
  // internal preset sliders backbuffer
  sli.slnew( slibase, slimax, sliused, 0 );  
  slifile.slnew( slibase, slimax, sliused, 0 );
  sliold.slnew( slibase, sliused, sliused, 0 );
  sli1.slnew( slibase, slimax, sliused, 0 ); // for slmunge1() 
  
  // transient sliders backbuffer
  slt.slnew( sltbase, sltused, sltused, 0 );  
  sltold.slnew( sltbase, sltused, sltused, 0 );
  slt1.slnew( sltbase, sltused, sltused, 0 ); // for slmunge1() 
  
  // a/b sliders non-zero defaults
  sla.slx(slpnl, 1); sla.slx(slnnl, 1); 
  sla.slx(slpnlt, -12); sla.slx(slnnlt, -12);
  slb.slx(slpnl, 1); slb.slx(slnnl, 1);
  slb.slx(slpnlt, -12); slb.slx(slnnlt, -12);
  sl.slx(slathresh, -48); sl.slx(slbthresh, -48);
  sl.slx(slabmorphval, -1);
  sl.slx(slwetmix, 100);
  sli.slx(slenvtlimcrv, 25);
  sl.slx(slostimes, 1);
  sl.slx(sloscascades, 4);
  sl.slx(slosbw, 1);
  sl.slx(slenvtpow, 2);

  // initialize env graph & freeze buffers to max size
  ehistmax= gszmax= 800;
  abc.gcurveinit(gszmax);
  gwhacka.ga.gshapeinit(gszmax, gdbmin);
  gwhackb.gb.gshapeinit(gszmax, gdbmin);
  gwhackab.gab.gshapeinit(gszmax, gdbmin);
  ehistenv= mem(ehistmax); ii= -1; loop(ehistmax, ehistenv[ii+= 1]= -240; );
  ehistenvtmax= mem(ehistmax);
  ehistenvtmin= mem(ehistmax);
  esnapenvt= mem(esnapmax0);
  esnapenv1= mem(esnapmax0);
  esnapenvt0= mem(esnapmax0);
  esnapspl= mem(esnapmax0);
  
  //old: mem sliders - only needed for preset <= v13 support
  //esnapavcmem= mem(memslsz); esnapavcmem[]= esnapavcmem[memslxval]= esnapavgcnt;
  esnapthxmem= mem(memslsz); //esnapthxmem[]= esnapthxmem[memslxval]= 0;
  env2slimmem= mem(memslsz);
  envtenvmem= mem(memslsz);
  envtoffmem= mem(memslsz); //envtoffmem[]= envtoffmem[memslxval]= 0;
  envtpowmem= mem(memslsz); //envtpowmem[]= envtpowmem[memslxval]= 2;
  
  init1= 1;
);
  
function setwhacka()
  local( ii )
(
  whacka0.whackinit(
    sla1.sl(sligain), sla1.sl(slogain), //igain, ogain
    sla1.sl(slmodx), sla1.sl(slmodxrng), sla1.sl(slmodxbias), sla1.sl(slmody), sla1.sl(slmodz),  //modx, modxrng, mody, modz
    sla1.sl(slpnl), sla1.sl(slpnlk), 
    sla1.sl(slpnlt) != -60 || ! doabtr || slb1.sl(slpnlt) == -60 ? sla1.sl(slpnlt) : -59.99, 
        // avoid bogus morphs if a/b thresholds not both ==/!= -60
    sla1.sl(slnnl), sla1.sl(slnnlk),
    sla1.sl(slnnlt) != -60 || ! doabtr || slb1.sl(slnnlt) == -60 ? sla1.sl(slnnlt) : -59.99, 
        //pnonlin, pthresh, pknee, nthresh, nnonlin, nknee
    sla1.sl(slpgain), sla1.sl(slngain), sl1.sl(slzb4y), sl1.sl(slnodrivez)  //pgain0, ngain0, swapyz0, undrivenz0
  );
  sl1.sl(slsquishcrv) ?(
    whacka0.squishon= 1;
    ii= (sl1.sl(slsquishcrv)-1)/99*7.5-2.5;
    whacka0.squishcrv.invcurveinit((ii<0?-1:1) * abs(ii)^2 * 3, 1);
  ):(
    whacka0.squishon= 0;
  );
  whacka0.whackpush();
  gwhacka.whackpop();
  gwhacka.ingain= gwhacka.outgain= 1;
);

function setwhackb()
  local( ii )
(
  whackb0.whackinit(
    slb1.sl(sligain), slb1.sl(slogain), //igain, ogain
    slb1.sl(slmodx), slb1.sl(slmodxrng), slb1.sl(slmodxbias), slb1.sl(slmody), slb1.sl(slmodz),  //modx, modxrng, mody, modz
    slb1.sl(slpnl), slb1.sl(slpnlk), 
    slb1.sl(slpnlt) != -60 || sla1.sl(slpnlt) == -60 ? slb1.sl(slpnlt) : -59.99, 
    slb1.sl(slnnl), slb1.sl(slnnlk), 
    slb1.sl(slnnlt) != -60 || sla1.sl(slnnlt) == -60 ? slb1.sl(slnnlt) : -59.99, 
        //pnonlin, pthresh, pknee, nthresh, nnonlin, nknee
    slb1.sl(slpgain), slb1.sl(slngain), sl1.sl(slzb4y), sl1.sl(slnodrivez)  //pgain0, ngain0, swapyz0, undrivenz0
  );
  sl1.sl(slsquishcrv) ?(
    whackb0.squishon= 1;
    ii= (sl1.sl(slsquishcrv)-1)/99*7.5-2.5;
    whackb0.squishcrv.invcurveinit((ii<0?-1:1) * abs(ii)^2 * 3, 1);
  ):(
    whackb0.squishon= 0;
  );
  whackb0.whackpush();
  gwhackb.whackpop();
  gwhackb.ingain= gwhackb.outgain= 1;
);

function setwhackab()
(
  setwhacka();
  setwhackb();
  newwhack= 1;
);

function curvelimit( s0 )
  local( xx )
(
    s0 > 1 ? s0= 1 //or: s0 > thresh
    : s0 < -1 ? s0= -1
    :(
      xx= abs(s0); //or: ...* 1/thresh
      s0= (s0<0?-1:1) * (xx + (1-xx) * this.invcurve(xx) ); //or: (xx * thresh +
    );
    s0; //or: s0 * thresh
);

function slmunge1()
  local( ii, jj, kk )
(
  abenv = exp((-1/(sl1.sl(slresptm) * 0.001)) * twopi / srate);
  abenv1= 1-abenv;
  env2slim= 
      sl1.sl(slenv2slim) < 1 ? .1 * sl1.sl(slenv2slim)*sl1.sl(slenv2slim)*sl1.sl(slenv2slim) : 0;
      //  env2slim= max(.001, .001 * 1/( sl1.sl(slresptm)*sl1.sl(slresptm)*sl1.sl(slresptm)*.1*.1*.1 ));
  absusenv = exp(( -1/(sl1.sl(slresptm) * 0.001 * sl1.sl(sltranstm)))*twopi/srate);
  absusenv1 = 1-absusenv;
  ehistspls= .023 * srate | 0; //23ms
  ehistspls2= (sl1.sl(slresptm) * 0.001 * srate) | 0;
  ehistspls2 > ehistspls ? ehistspls2= ehistspls;
  ehistspls2i= 1/ehistspls2;
  envtenv= exp((-1/(sl1.sl(slenvtenv) * 0.001))*twopi/srate);
      //envtenv= exp((-1/(envtenvmem[] * 0.001))*twopi/srate);
  envtenv1= 1-envtenv;
  
  trans= sl1.sl(sltrans)/20;
  ! bptrans ? trans*= 1.5;
  
  envtoff= sl1.sl(slenvtoff); //envtoffmem[];
  envtpow= sl1.sl(slenvtpow); //envtpowmem[];
  // threshold for trans^2 logic: db's < thresh reduced by squaring
  //   based on trans tm ratio: >ratio == >trans db diffs, so higher thres
  envtthxn= sl1.sl(sltranstm);
  envtthxn= envtthxn >= 1 ? envtthxn/3 : (1/envtthxn)/3;
  envtthxn*= envtpow*.5;
  envtthxdi= 1/(envtthxn^envtpow);
  envtthx= envtthxn * envtthxdi; 

  curve= sl1.sl(slabcurve);
  curve == 100 ? curve= 10000
  : curve == -100 ? curve= -10000;
      //   abcurveexp ? curve= 10^(-curve/100) :
  curve0= (abs(curve)*.04)^2*4 * (curve<0 ? -1 : 1); //was ^2.5
  abcurve.invcurveinit(curve0, 1);
  adb=sl1.sl(slathresh);
  bdb=sl1.sl(slbthresh);
  doab= adb != bdb;
  doabtr= doab || trans;
  abrng= envtrng= abs(bdb-adb);
  abrngi= envtrngi= 1/abrng;
  abmin= adb < bdb ? adb : bdb;
  ! doab ?(
    envtrng= 24;
    envtrngi= 1/envtrng;
  );
  envtbdb= 0; //fixed upper bound on env graph in trans mode
  envtlimit= sli1.sl(slenvtlimit)/100 * envtrng;
  envtlimiti= 1/envtlimit;
  envtlimcrv0= (sli1.sl(slenvtlimcrv)*.04)^2*4+4;
  envtlimcrv.invcurveinit(envtlimcrv0, 1);
  esnapthx= sl1.sl(slesnapthx)/100; //esnapthxmem[]/100;
  esnapth= doab ? abmin+abrng*esnapthx : envtrng*esnapthx;
  esnapavgcnt= slt1.sl(slesnapavc); //esnapavcmem[]; //4;
  esnapavgcnt ? esnapavgcnti= 1/esnapavgcnt;
  sl1.sl(slcrunchcrv) ?(
    crunchcrvon= 1;
    ii= (sl1.sl(slcrunchcrv)-1)/99*7.5-2.5;
    crunchcrv0= (ii<0?-1:1) * abs(ii)^2 * 3;
    crunchcrv.invcurveinit(crunchcrv0, 1);
    crunchcomp= .0625/crunchcrv.curvelimit(.0625);
  ): crunchcrvon= 0;
  
  aasize=(sl1.sl(slostimes)+0.5)|0;
  aasize < 1 ? aasize= 1 : aasize > 256 ? aasize= 256;
  n12= sl1.sl(sloscascades);
  cut= srate*sl1.sl(slosbw)/2;

  aasize != last_aa || n12 != lastn12 || cut != lastcut ?(
    aasize > 1 ?(
      aadiv= 1/aasize;
      zaalp_i0.butterworthFilterInit( 1, n12, cut, 0, srate * aasize );
      zaalp_o0.butterworthFilterInit( 1, n12, cut, 0, srate * aasize );
    );
    last_aa= aasize;
    lastn12= n12;
    lastcut= cut;
  );
  
  mgain0= exp(sl1.sl(slmgain) * db2log);
  wetmix0= sl1.sl(slwetmix)/100;
  mgain= mgain0;
  wetmix1= 1-(wetmix= wetmix0);
  
  abmorph= sl1.sl(slabmorphval) >= 0;
  abmorphval= sl1.sl(slabmorphval) / 100;
  
  invert= sli1.sl(slinvert);
  unlimit= sli1.sl(slunlimit);
  sidechain= sli1.sl(slsidechain);
  bptrans= sl1.sl(slbptrans);
  
  //update whacks only if sliders have change: better for automation
  sl1.sl(slzb4y) != slold.sl(slzb4y) 
      || sl1.sl(slnodrivez) != slold.sl(slnodrivez) 
      || sl1.sl(slsquishcrv) != slold.sl(slsquishcrv)
      || newwhackpre
  ?(
    setwhackab();
  ):(
    ii= abslbase-1; jj= abslbaseb-1; kk= 0; while ( 
      ii+= 1; jj+= 1;
      sl1.sl(ii) == slold.sl(ii)
          && sl1.sl(jj) == slold.sl(jj)
          && (kk+= 1) < abslcnt;
    );
    kk < abslcnt ?(
      setwhackab();
    );
  );

  slold.slcopy(sl1.self);
  //sliold.slcopy(sli1.self);
  //sltold.slcopy(slt1.self);
  
  gdirty= 1;
);

function slmunge()
(
  ! doslmunge1 ?(
    redoslmunge= 0;
    sl1.slcopy(sl.self);
    sli1.slcopy(sli.self);
    slt1.slcopy(slt.self);
    doslmunge1= 1;
  ):(
    redoslmunge= 1;
  );
  
  dbgraph= slt.sl(sldbgraph);
  envgax= slt.sl(slenvgax) ? .7 : 0;
);

@slider

sl.slgetsliders(); // set backbuffer from new slider values
slmunge(); // process changes in backbuffer

@serialize

serialversion= 14;
serialread= (file_avail(0) >= 0);

fileserial= serialversion;
file_var( 0, fileserial );

// actual read/write
! serialread ?(
  slfile.slcopy(sl.self);
  slifile.slcopy(sli.self);
);
slfile.slfile(0);
fileserial <= 13 ?(
  file_var(0, invertold);         //membtn2sl
  file_var(0, unlimitold);        //membtn2sl
  fileserial <= 11 ?(
    slaold.slfile( 0 );
    slbold.slfile( 0 );
    file_var(0, zold.abmorph); //abmorph n/a - now calc'd from abmorphval in slmunge()
    file_var(0, zold.abmorphval);
  );
  file_var(0, bptransold);        //membtn2sl
  file_mem(0, envtpowmem, 1);  //memsl2sl //was trans2
  file_mem(0, env2slimmem, 1); //memsl2sl
  file_var(0, sidechainold);      //membtn2sl
  file_mem(0, envtenvmem, 1); //memsl2sl
  file_mem(0, envtoffmem, 1);  //memsl2sl
);
slifile.slfile(0);

// postprocess
serialread ?(
  readserial= fileserial;
  
  fileserial <= 5 ?(
    slfile.slx( 27, 0 );
  );
  fileserial <= 6 ?(
    //from: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27
    //to:   1,2,3,4,5, 27,6,7,8,10, 9,11,13,12,14, 15,16,17,18,19, 20,21,22,23,24, 25,26
    slxl.slxlini(slfile.self, slfile.base);
    slxl(1,2,3,4,5); slxl(27,6,7,8,10); slxl(9,11,13,12,14); slxl(15,16,17,18,19);
    slxl(20,21,22,23,24); slxl(25,26,0,0,0);
    slfile.slcopy(slxl.self);
    //from: 2,3,4,5,6, 7,8,9,10,11, 12,13,14,15
    //to:   2,3,4,5,0, 6,7,8,10,9,  11,13,12,14,15
    slabxl.slxlini(slaold.self, slaold.base);
    slabxl.slxl(2,3,4,5,0); slabxl.slxl(6,7,8,10,9); slabxl.slxl(11,13,12,14,15);
    slaold.slcopy(slabxl.self);
    slaold.slx(6, slfile.sl(6));
    slabxl.slxlini(slbold.self, slbold.base);
    slabxl.slxl(2,3,4,5,0); slabxl.slxl(6,7,8,10,9); slabxl.slxl(11,13,12,14,15);
    slbold.slcopy(slabxl.self);
    slbold.slx(6, slfile.sl(6));
  );
  fileserial <= 7 ?(
    zold.abmorph= 0; //n/a: abmorphval= 0;
  );
  fileserial <= 8 ?(
    slfile.slx(slwetmix,100);
  );
  fileserial <= 9 ?(
    bptrans= 1;
  );
  fileserial <= 10 ?(
    env2slimmem[]= 1;
    sidechain= 0;
    envtpowmem[]= 0;
    envtenvmem[]= 0;
    slfile.slx(sltrans, slfile.sl(sltrans)*.2);
    slaold.slx(sltrans, slaold.sl(sltrans)*.2);
    slbold.slx(sltrans, slbold.sl(sltrans)*.2);
  );
  fileserial <= 11 ?(
    zold.abmorph ? slfile.slx(slabmorphval, zold.abmorphval) : slfile.slx(slabmorphval, -1);
    fii= sligain; loop ( abslcnt, slfile.slx(fii, slaold.sl(fii)); fii+= 1; );
    fii= sligain; fjj= sligainb; loop ( abslcnt, slfile.slx(fjj, slbold.sl(fii)); fii+= 1; fjj+= 1; );
    envtoffmem[]= 0;
    envtpowmem[] ? envtpowmem[]= 1 : envtpowmem[]= 2;
  );
  fileserial <= 12 ?(
    slfile.slx(slsquishcrv, 0);
    slfile.slx(slcrunchcrv, 0);
    slfile.slx(slmgain, 0);
    slifile.slx(slenvtlimit, 0);
    slifile.slx(slenvtlimcrv, 25);
  );
  fileserial <= 13 ?(
    slifile.slx(slinvert, invertold);
    slifile.slx(slunlimit, unlimitold);
    slifile.slx(slsidechain, sidechainold);
    slfile.slx(slbptrans, bptransold);
    slfile.slx(slenvtpow, envtpowmem[]);
    slfile.slx(slenv2slim, env2slimmem[]);
    slfile.slx(slenvtenv, envtenvmem[]);
    slfile.slx(slenvtoff, envtoffmem[]);
    slfile.slx(slesnapthx, 0);
//   env2slimmem[memslxval]= env2slimmem[];
//   envtenvmem[memslxval]= envtenvmem[]; 
//   envtoffmem[memslxval]= envtoffmem[]; 
//   envtpowmem[memslxval]= envtpowmem[]; 
  );
 
  sli.slcopy(slifile.self);
  sl.slcopy(slfile.self);
  newwhackpre= 1;
  slmunge();
);

@sample

osampts= sampts; sampts+= 1; sampts == osampts ? sampts= 0; //debug sample timestamp

//avoid odd intermediate whack states during preset loads !?
redoslmunge ? slmunge();
doslmunge1 ?( 
  newwhackpre ?( 
    ! sfadeout ? sfadeout= sfademax= (srate * .1) | 0;
  ):(
    slmunge1();
    newwhack ?(
      whacka0.whackpush(); whacka.whackpop();
      whackb0.whackpush(); whackb.whackpop(); 
      newwhack= 0;
    );
    doslmunge1= 0;
  );
);

sfadein ?( 
  spl0*= 1 - (sfadein-= 1)/sfademax; spl1*= 1 - sfadein/sfademax; 
);
sfadeout ?( 
  spl0*= (sfadeout-= 1)/sfademax; spl1*= sfadeout/sfademax; 
  sfadeout <= 0 ?( 
    sfadein= sfademax; 
    envavg= envtavg= 0; 
    newwhackpre= 0; 
  );
);

sspos=0;
src0=spl0;
src1=spl1;
aasize > 1 ?(
  src0inc= (src0 - lastsrc0) * aadiv;
  src1inc= (src1 - lastsrc1) * aadiv;
  outsum0= outsum1= 0;
);

splmax= sidechain ? max(abs(spl2),abs(spl3)) : max(abs(spl0),abs(spl1));
doabtr ?(
  abmorph ?(
    env0= env1= abmorphval;
  ):(
    envavg= envavg*abenv + splmax*abenv1;
    envavg > 1 ? envavg= 1 : envavg < 0 ? envavg= 0;
    envdb= env1= log(abs(envavg)) * log2db;
    trans ?(
      envtavg= envtavg*absusenv + splmax*absusenv1;
      envtavg > 1 ? envtavg= 1 : envtavg < 0 ? envtavg= 0;
      //old, both up & down transience:
      envtdb0= log(abs(envtavg)) * log2db;
      bptrans == 2 ? envtdb= envdb - envtdb0 
      : bptrans ? envtdb= abs(envdb - envtdb0)
      :( envtdb= envdb - envtdb0; envtdb < 0 ? envtdb= 0; );
      envtpow == 1 ? envt= envtdb*envtthx // * 2 //old
      : envtpow == 2 ? envt= (envtdb<0?-1:1)*envtdb*envtdb*envtthx
      : envt= (envtdb<0?-1:1)*abs(envtdb)^envtpow*envtthx;
      envtenv ?(
        envt > envtavg2 ? envtavg2= envt
          : envtavg2= envtavg2*envtenv + envt*envtenv1;
        envt= envtavg2 * trans;
      ): envt*= trans;
      envtlimit ?(
        sxx= abs(envt)*envtlimiti*.1;
        sxx > 1 ?( envt= (envt<0?-1:1) * envtlimit; )
                :( envt*= .1 * (envtlimcrv.invcurve(sxx)/sxx); );
      );
      envt+= envtoff; //trans < 0 ? - envtoff : envtoff; //bptrans == 2 && 
    ): envt= 0;
    doab ?(
      env0= envdb - (adb < bdb ? adb : bdb);
      env1= (env0 + envt) * abrngi;
    ):(
      env0= env1= envt * envtrngi;
    );
    env1 < 0 ? env1= 0 : env1 > 1 ? env1= 1;
  );
//   abcurveexp ?  env2x= curve != 1 ? env1^curve : env1 :(
  sxx= env1;
  env2x= 
    abcurve.curve > 9999 ?( abcurve.pcurve ? 1 : 0; ):
    //abcurve.invcurve(env1); /* expanded:
    abcurve.pcurve ?( 
      //syy= sxx= abcurve.curve * sxx + 1;
      //loop( abcurve.power, syy*= sxx; );
      (1 - 1/(abcurve.curve * sxx + 1)) * abcurve.posk1i;
    ): abcurve.ncurve ?(
      //syy= sxx= abcurve.curve * sxx - abcurve.curve - 1;
      //loop ( abcurve.power, syy*= sxx; );
      ((abcurve.oddncurve?-1:1)/(abcurve.curve * sxx - abcurve.curve - 1) - abcurve.negk0) * abcurve.negk01i;
    ): sxx;
    //*/

// debug: sample max env2 delta
// zze2diff= abs(env2x - zzlaste2);
// zzlaste2= env2x;
// a0e2diffavg= a0e2diffavg*.999 + zze2diff*.001;
// zze2maxcnt ?( zze2diff2 < zze2diff ? zze2diff2= zze2diff; zze2maxcnt-= 1; )
//            :( a0e2diffmax= zze2diff2; zze2diff2= zze2diff; zze2maxcnt= srate*1; );
// a0env2slim= env2slim;

  // slew limit env2 deltas to avoid morph noise
  env2slim ?(
    env2-env2x > env2slim ? env2-= env2slim
    : env2x-env2 > env2slim ? env2+= env2slim
    : env2= env2x;
      //old way:
      //   senv2avg= senv2avg*e2env + e2env1*env2x;
      //   env2= senv2avg;
  ): env2= env2x;
  
  env3= adb > bdb ? 1 - env2 : env2;
  
  genvdone ?(
    doab && ! abmorph ? env0*= abrngi;
    env0 < 0 ? env0= 0 : env0 > 1 ? env0= 1;
    genv0= env0;
    genv1= env1;
    genv2x= env2x;
    genv2= env2;
    genv3= env3;
  );

  //@sample envdb/envtdb max over env avg period
  (ehistcnt-= 1) <= 0 ?(
    ehistenv[ehistndx]= envdbsum * ehistspls2i;
    ehistenvtmin[ehistndx]= envtmin;
    ehistenvtmax[ehistndx]= envtmax;
    ehistndx+= 1; ehistndx >= ehistmax ? ehistndx= 0;
    envdbsum= envdb;
    envtmax= envtmin= envt;
    ehistcnt= ehistspls;
    ehistcnt2= ehistspls2;
  ): (ehistcnt2-= 1) >= 0 ?(
    envdbsum+= envdb;
    envt > envtmax ? envtmax= envt;
    envt < envtmin ? envtmin= envt;
  );
  esnapavgcnt && trans ?(
    //get snapshot data
    esnapenvt[esnapndx]= envt;
    esnapenv1[esnapndx]= envdb;
    esnapenvt0[esnapndx]= envtdb0;
    esnapspl[esnapndx]= sidechain ? max(abs(spl0),abs(spl1)) : splmax;
    (esnapndx+= 1) > esnapmax ? esnapndx= 0;
  );
);

doabtr && env3 ?(
  env3 != 1 ?(
    whackab.whackmixab( env3 );
    singain= whackab.ingain;
  ):(
    singain= whackb.ingain;
  );
):(
  singain= whacka.ingain;
);

genvdone ?( 
  envmax= envmax0;
  envmax0 = splmax * singain;
  genvdone= 0; 
):(
  splmax*= singain;
  envmax0 < splmax ? envmax0= splmax;
);

//@oversample loop
loop ( aasize,

  // run input filters
  aasize > 1 ?(
    sspl0 = zaalp_i0.butterworthFilter2( lastsrc0+= src0inc, lastsrc1+= src1inc );
    sspl1 = stack_pop();
  ):(
    sspl0=src0;
    sspl1=src1;
  );

  sspl0dry= sspl0;
  sspl1dry= sspl1;
  
  doabtr && env3 ?(
    env3 != 1 ?(
      sspl0= whackab.whack( sspl0, sspl1 );
    ):(
      sspl0= whackb.whack( sspl0, sspl1 );
    );
  ):(
    sspl0= whacka.whack( sspl0, sspl1 );
  );
  sspl1= stack_pop();

  crunchcrvon ?(
    //sspl0= crunchcrv.curvelimit(sspl0) * crunchcomp; /* expanded:
    sspl0>1 ? sspl0= 1 * crunchcomp 
    : sspl0<-1 ? sspl0= -1 * crunchcomp
    :(
      szz= abs(sspl0);
      syy= 
          crunchcrv.pcurve ?  (1 - 1/(crunchcrv.curve * szz + 1)) * crunchcrv.posk1i
          : crunchcrv.ncurve ? ((crunchcrv.oddncurve?-1:1)/(crunchcrv.curve * szz - crunchcrv.curve - 1) - crunchcrv.negk0) * crunchcrv.negk01i
          : szz;
      sspl0= (sspl0<0?-1:1) * (szz + (1-szz) * syy) * crunchcomp;
    ); 
    //*/
    //sspl1= crunchcrv.curvelimit(sspl1) * crunchcomp; /* expanded:
    sspl1>1 ? sspl1= 1 * crunchcomp 
    : sspl1<-1 ? sspl1= -1 * crunchcomp
    :(
      szz= abs(sspl1);
      syy= 
          crunchcrv.pcurve ?  (1 - 1/(crunchcrv.curve * szz + 1)) * crunchcrv.posk1i
          : crunchcrv.ncurve ? ((crunchcrv.oddncurve?-1:1)/(crunchcrv.curve * szz - crunchcrv.curve - 1) - crunchcrv.negk0) * crunchcrv.negk01i
          : szz;
      sspl1= (sspl1<0?-1:1) * (szz + (1-szz) * syy) * crunchcomp;
    ); 
    //*/
  ):(
    ! unlimit ?(
      sspl0>1 ? sspl0= 1 : sspl0<-1 ? sspl0= -1;
      sspl1>1 ? sspl1= 1 : sspl1<-1 ? sspl1= -1;
    );
  );

  invert ?(
    sspl0= -sspl0;
    sspl1= -sspl1;
  );

  sspl0= sspl0 * mgain * wetmix + sspl0dry * wetmix1;
  sspl1= sspl1 * mgain * wetmix + sspl1dry * wetmix1;
  
  // run output filters
  aasize > 1 ?(
    outsum0+= zaalp_o0.butterworthFilter2( sspl0, sspl1 );
    outsum1+= stack_pop();
    (sspos+= 1) == aasize ?(
      spl0= outsum0 * aadiv;
      spl1= outsum1 * aadiv;
    );
   ):(
    spl0=sspl0;
    spl1=sspl1;
  );
);

lastsrc0= src0;
lastsrc1= src1;

@gfx 768 590

function gshapemake()
  instance( inc, sz, xmem, ymem, xycnt, dbmin, dbinc )
  local( ii, x, y, xdb, ydb, nx )
(
  dbgraph ?(
      xdb = 0;
      nx = 1;
  ): x = -1;
  ii= 0;
  while(
      dbgraph ? x= (nx?-1:1) * exp(xdb * db2log);
      y= this..whack( x, 0 );
      stack_pop();
      crunchcrvon ? y= crunchcrv.curvelimit(y); // * crunchcomp; 
      //y > 1 ? y= 1 : y < -1 ? y= -1;
      dbgraph ?(
          ydb = max( log(abs(y)) * log2db, dbmin );
          x = (nx ? -xdb+dbmin : xdb-dbmin)/-dbmin;
          y = (y < 0 ? -ydb+dbmin : ydb-dbmin)/-dbmin;
      );
      xmem[ii]= x;
      ymem[ii]= y;
      ii+= 1;
      dbgraph ?(
          nx ?( 
            xdb == dbmin ?(
              nx= 0; 
            ):(
              xdb-= dbinc; 
              xdb < dbmin ? xdb= dbmin;
            ); 
          ): xdb+= dbinc; 
          nx || xdb < 0;
      ): (x += inc) < 1;
  );
  xycnt= ii;
);

function gshapedraw()
  instance( inc, sz, xmem, ymem, xycnt, dbmin, dbinc )
  local( ii )
(
  ii= 1;
  while(
    pp.plineaa(xmem[ii-1],ymem[ii-1],xmem[ii],ymem[ii]);
    (ii+= 1) < xycnt;
  );
);

function gcurvemake()
  instance( inc, sz, xmem, ymem, xycnt )
  local( ii, x, y )
(
  x= 0;
  ii= 0;
  while (
//     y= abcurveexp ? (x^curve) : abcurve.invcurve(x);
    y= abcurve.invcurve(x);
    xmem[ii]= x;
    ymem[ii]= y;
    ii+= 1;
    (x += inc) < 1;
  );
  xycnt= ii;
);

function gcurvedraw()
  instance( inc, sz, xmem, ymem, xycnt )
  local(ii)
(
  ii= 1;
  while (
    ppc.plineaa(xmem[ii-1],ymem[ii-1],xmem[ii],ymem[ii]);
    (ii+= 1) < xycnt;
  );
);

function abslalt(slnum)
(
    slnum >= abslbase && slnum < abslbase+abslcnt ?( slnum+abslaboff; )
    : slnum >= abslbaseb && slnum < abslbaseb+abslcnt ?( slnum-abslaboff; )
    : slnum == slathresh ? slbthresh
    : slnum == slbthresh ? slathresh
    : 0;
);
function pnslalt(slnum)
(
  slnum == slpnl ? slnnl : slnum == slnnl ? slpnl
  : slnum == slpnlk ? slnnlk : slnum == slnnlk ? slpnlk
  : slnum == slpnlt ? slnnlt : slnum == slnnlt ? slpnlt
  : slnum == slpgain ? slngain : slnum == slngain ? slpgain
  : slnum == slpnlb ? slnnlb : slnum == slnnlb ? slpnlb
  : slnum == slpnlkb ? slnnlkb : slnum == slnnlkb ? slpnlkb
  : slnum == slpnltb ? slnnltb : slnum == slnnltb ? slpnltb
  : slnum == slpgainb ? slngainb : slnum == slngainb ? slpgainb
  : 0;
);
function abpnslalt(slnum, abalt, pnalt)
(
  slnum == abslalt(abalt) ? pnslalt(abalt) : abslalt(pnalt);
);
  
function dosl0( slnum, min, max, def, rnd, prec, bp, inv, xtr, txt )
  local( vv, v2 )
(
  xtr && this.slactive(slnum) && (optdown&&cmddown&&!shiftdown) ?( min*= 8; max*= 8; );
  this.psl.pslop(slysz*.5+.5|0, slysz*.5+.5|0, 0, 0, 23, 1);
  this.psl.paneini(gxo, gyo, slxsz, slysz, min, 0, max, 1);
  this.psl.pslhit(slnum) ?( 
    this.slx(slnum, 
      dblclick ? def 
      : rightdown && this.slactive(slnum) ?( 
          vv= clickval + ((mouse_x-clickx)*.25*(.005*abs(max-min)/rnd)^.5|0) * rnd; xtr ? vv : limit(vv,min,max); )
      : this.psl.pmxrnd(rnd)
    ); 
    (vv= abslalt(slnum)) ?(
      leftclick || rightclick ? abclickval= this.sl(vv);
      shiftdown && ! optdown ? this.slx(vv, this.sl(slnum)) : this.slx(vv, abclickval);
    );
    (v2= pnslalt(slnum)) ?(
      leftclick || rightclick ? pnclickval= this.sl(v2);
      cmddown && ! optdown ? this.slx(v2, this.sl(slnum)) : this.slx(v2, pnclickval);
    );
    vv && v2 ?(
      vv= abpnslalt(slnum, vv, v2);
      leftclick || rightclick ? abpnclickval= this.sl(vv);
      shiftdown && cmddown && ! optdown ? this.slx(vv, this.sl(slnum)) : this.slx(vv, abpnclickval);
    );
    this.slx(slnum, this.sl(slnum)); //re-set this so it is last one automated
    slmunge();
  ): this.slactive(slnum) ?( 
    (vv= abslalt(slnum)) ?( this.slx(vv, abclickval); );
    (v2= pnslalt(slnum)) ?( this.slx(v2, pnclickval); );
    vv && v2 ?( this.slx(abpnslalt(slnum, vv, v2), abpnclickval); );
    this.slx(slnum, clickval); 
    slmunge(); 
  );
  gyo+= slyspc;
);
function dosl( slnum, min, max, def, rnd, prec, bp, inv, xtr, txt )
(
  this.dosl0( slnum, min, max, def, rnd, prec, bp, inv, xtr, txt );
  this.psl.pslider( this.sl(slnum), this.sltxtval(slnum), prec, bp, inv, def, txt);
);
function doslz( slnum, min, max, def, rnd, prec, bp, inv, xtr, zval, ztxt, txt )
(
  this.dosl0( slnum, min, max, def, rnd, prec, bp, inv, xtr, txt );
  this.psl.psliderz( this.sl(slnum), this.sltxtval(slnum), prec, bp, inv, def, zval, ztxt, txt);
);

function doslbtn( slnum, txt0, txt1, txt )
(
  this.psl.pslop(slysz*.5+.5|0, slysz*.5+.5|0, 0, 0, 23, 1);
  this.psl.paneini(gxo, gyo, slxsz, slysz, 0, 0, 1, 1);
  this.psl.pchit() ?( 
    this.slx(slnum, ! this.sl(slnum)); 
    slmunge(); 
  );
  this.psl.pbutton( this.sl(slnum), txt0, txt1, txt );
  gyo+= slyspc;
);
function doslbtnval( slnum, valz, txt0, txt )
(
  this.psl.pslop(slysz*.5+.5|0, slysz*.5+.5|0, 0, 0, 23, 1);
  this.psl.paneini(gxo, gyo, slxsz, slysz, 0, 0, 1, 1);
  this.psl.pchit() ?( 
    this.slx(slnum, this.sl(slnum)==valz-1 ? 0 : this.sl(slnum) + 1 );
    slmunge();
  );
  this.psl.pbuttonval( this.sl(slnum), txt0, txt );
  gyo+= slyspc;
);

mouseini();
    // sets leftclick, rightclick, clickx, clicky, leftup, rightup,
    //    plainclick, shiftclick, optclick, cmdclick,
    //    leftdown, rightdown, shiftdown, optdown, cmddown
    // used by pane mouse logic

//@ brave new sliders
zhfxbg.hueset(.93, .93, .93, 1);
gfx_x= 0; gfx_y= 0; 
gfx_rectto(gfx_w+1, graphyx);

slxsz= (gfx_w-20)*.5*.9; slysz= 13; slyspc1= 8; slyspc2= 5;

graphyr= gfx_w-5-slxsz;
gyo= 5; gxo= graphyr;

zha.hueset(0, .5, 0, .6); //a shape - green
zhb.hueset(.7, .4, .4, .6); //b shape - red
zhab.hueset(.9, .7, .4, 1); //ab shape - yellow
zhtxta.hueset(.3, .6, .3, 1); //a text - green
zhtxtb.hueset(.7, .5, .5, 1); //b text - red
zhtxt.hueset(.5, .5, .5, 1); //text - grey
zhcrv.hueset(.6, .6, .6, 1); //ab curve - grey
zhpeak.hueset(.4, .5, .8, 1); //peak crosses - blue
zhpeak2.hueset(.5, .6, 1, 1); //peak shape ticks
zhpeakbar.hueset(.75, .85, .95, 1); //peak bar - lt blue
zhetick.hueset(.4, .4, .4, 1); //env ticks - grey
zhebar.hueset(.6, .6, .6, 1); //env bar - lt grey
zhebar2.hueset(.8, .8, .8, 1); //env bar - lter grey
zhax.hueset(.7, .7, .7, 1); //graph axes

zhtxta.huepush(); zhsla.huepop(); //zhsla.hueset(.25,.85,.25,1);
zhtxtb.huepush(); zhslb.huepop(); //zhslb.hueset(.85,.28,.28,1);
zhslbtn.hueset(.78,.78,.78,1);
zhsl.hueset(.5,.5,.5,1);
/*!ztxt.no='no';*/                                (!ztxt.no ?(ztxt.no=mem(3); ztxt.no[0]=2; ztxt.no[1]=($'n');ztxt.no[2]=($'o'););ztxt.no;);
/*!ztxt.yes='YES';*/                              (!ztxt.yes ?(ztxt.yes=mem(4); ztxt.yes[0]=3; ztxt.yes[1]=($'Y');ztxt.yes[2]=($'E');ztxt.yes[3]=($'S'););ztxt.yes;);
/*!ztxt.off='off';*/                              (!ztxt.off ?(ztxt.off=mem(4); ztxt.off[0]=3; ztxt.off[1]=($'o');ztxt.off[2]=($'f');ztxt.off[3]=($'f'););ztxt.off;);
/*!ztxt.nil='';*/                                 (!ztxt.nil ?(ztxt.nil=mem(1); ztxt.nil[0]=0; );ztxt.nil;);

! tweaks ?(

// A controls
  abgyo= gyo;
  zhsla.hue();
  slyspc= slysz+slysz+slyspc2+1;
  //dosl( slnum, min, max, def, rnd, prec, bp, inv, xtr, txt )
  sl.dosl( sligain,   -36, 36, 0, .1, 1, 1, 0, 0, /*!ztxt.sligain='in gain (dB)');*/ (!ztxt.sligain ?(ztxt.sligain=mem(13); ztxt.sligain[0]=12; ztxt.sligain[1]=($'i');ztxt.sligain[2]=($'n');ztxt.sligain[3]=($' ');ztxt.sligain[4]=($'g');ztxt.sligain[5]=($'a');ztxt.sligain[6]=($'i');ztxt.sligain[7]=($'n');ztxt.sligain[8]=($' ');ztxt.sligain[9]=($'(');ztxt.sligain[10]=($'d');ztxt.sligain[11]=($'B');ztxt.sligain[12]=($')'););ztxt.sligain;));

  zhsl.hue();
  slyspc= slysz+slyspc1+2;
  sl.doslz( slsquishcrv, 0, 100, 0, 1, 0, 0, 0, 0, 0, ztxt.off, /*!ztxt.slsquishcrv='squish');*/ (!ztxt.slsquishcrv ?(ztxt.slsquishcrv=mem(7); ztxt.slsquishcrv[0]=6; ztxt.slsquishcrv[1]=($'s');ztxt.slsquishcrv[2]=($'q');ztxt.slsquishcrv[3]=($'u');ztxt.slsquishcrv[4]=($'i');ztxt.slsquishcrv[5]=($'s');ztxt.slsquishcrv[6]=($'h'););ztxt.slsquishcrv;));

  zhsla.hue();
  slyspc= slysz+slysz+slyspc2+1;
  slyspc-= 5;
  sl.dosl( slmodx,     0, 100, 0, .1, 1, 0, 0, 0, /*!ztxt.slmodx='mod X - drive');*/ (!ztxt.slmodx ?(ztxt.slmodx=mem(14); ztxt.slmodx[0]=13; ztxt.slmodx[1]=($'m');ztxt.slmodx[2]=($'o');ztxt.slmodx[3]=($'d');ztxt.slmodx[4]=($' ');ztxt.slmodx[5]=($'X');ztxt.slmodx[6]=($' ');ztxt.slmodx[7]=($'-');ztxt.slmodx[8]=($' ');ztxt.slmodx[9]=($'d');ztxt.slmodx[10]=($'r');ztxt.slmodx[11]=($'i');ztxt.slmodx[12]=($'v');ztxt.slmodx[13]=($'e'););ztxt.slmodx;));
  sl.dosl( slmodxrng,   0, 95, 0, .1, 1, 0, 0, 0, /*!ztxt.slmodxrng=' \1 drive range');*/ (!ztxt.slmodxrng ?(ztxt.slmodxrng=mem(16); ztxt.slmodxrng[0]=14; ztxt.slmodxrng[1]=($' ');ztxt.slmodxrng[2]=(1);ztxt.slmodxrng[3]=($' ');ztxt.slmodxrng[4]=($'d');ztxt.slmodxrng[5]=($'r');ztxt.slmodxrng[6]=($'i');ztxt.slmodxrng[7]=($'v');ztxt.slmodxrng[8]=($'e');ztxt.slmodxrng[9]=($' ');ztxt.slmodxrng[10]=($'r');ztxt.slmodxrng[11]=($'a');ztxt.slmodxrng[12]=($'n');ztxt.slmodxrng[13]=($'g');ztxt.slmodxrng[14]=($'e'););ztxt.slmodxrng;));
  slyspc+= 5;
  sl.dosl( slmodxbias, -1, 1, 0, .01, 2, 1, 0, 0, /*!ztxt.slmodxbias=' \1 drive bias');*/ (!ztxt.slmodxbias ?(ztxt.slmodxbias=mem(15); ztxt.slmodxbias[0]=13; ztxt.slmodxbias[1]=($' ');ztxt.slmodxbias[2]=(1);ztxt.slmodxbias[3]=($' ');ztxt.slmodxbias[4]=($'d');ztxt.slmodxbias[5]=($'r');ztxt.slmodxbias[6]=($'i');ztxt.slmodxbias[7]=($'v');ztxt.slmodxbias[8]=($'e');ztxt.slmodxbias[9]=($' ');ztxt.slmodxbias[10]=($'b');ztxt.slmodxbias[11]=($'i');ztxt.slmodxbias[12]=($'a');ztxt.slmodxbias[13]=($'s'););ztxt.slmodxbias;));
  sl.dosl( slmody,     0, 200, 0, .1, 1, 0, 0, 1, /*!ztxt.slmody='mod Y - saturation');*/ (!ztxt.slmody ?(ztxt.slmody=mem(19); ztxt.slmody[0]=18; ztxt.slmody[1]=($'m');ztxt.slmody[2]=($'o');ztxt.slmody[3]=($'d');ztxt.slmody[4]=($' ');ztxt.slmody[5]=($'Y');ztxt.slmody[6]=($' ');ztxt.slmody[7]=($'-');ztxt.slmody[8]=($' ');ztxt.slmody[9]=($'s');ztxt.slmody[10]=($'a');ztxt.slmody[11]=($'t');ztxt.slmody[12]=($'u');ztxt.slmody[13]=($'r');ztxt.slmody[14]=($'a');ztxt.slmody[15]=($'t');ztxt.slmody[16]=($'i');ztxt.slmody[17]=($'o');ztxt.slmody[18]=($'n'););ztxt.slmody;));
  sl.dosl( slmodz,     0, 200, 0, .1, 1, 0, 0, 1, /*!ztxt.slmodz='mod Z - lag');*/ (!ztxt.slmodz ?(ztxt.slmodz=mem(12); ztxt.slmodz[0]=11; ztxt.slmodz[1]=($'m');ztxt.slmodz[2]=($'o');ztxt.slmodz[3]=($'d');ztxt.slmodz[4]=($' ');ztxt.slmodz[5]=($'Z');ztxt.slmodz[6]=($' ');ztxt.slmodz[7]=($'-');ztxt.slmodz[8]=($' ');ztxt.slmodz[9]=($'l');ztxt.slmodz[10]=($'a');ztxt.slmodz[11]=($'g'););ztxt.slmodz;));
  slyspc-= 5;
  sl.dosl( slpnl,      1, 10, 1, .01, 2, 0, 0, 1, /*!ztxt.slpnl='+ nonlinearity');*/ (!ztxt.slpnl ?(ztxt.slpnl=mem(15); ztxt.slpnl[0]=14; ztxt.slpnl[1]=($'+');ztxt.slpnl[2]=($' ');ztxt.slpnl[3]=($'n');ztxt.slpnl[4]=($'o');ztxt.slpnl[5]=($'n');ztxt.slpnl[6]=($'l');ztxt.slpnl[7]=($'i');ztxt.slpnl[8]=($'n');ztxt.slpnl[9]=($'e');ztxt.slpnl[10]=($'a');ztxt.slpnl[11]=($'r');ztxt.slpnl[12]=($'i');ztxt.slpnl[13]=($'t');ztxt.slpnl[14]=($'y'););ztxt.slpnl;));
  sl.dosl( slpnlk,     0, 10, 1, .01, 2, 0, 0, 1, /*!ztxt.slpnlk=' \1 +nl knee');*/ (!ztxt.slpnlk ?(ztxt.slpnlk=mem(13); ztxt.slpnlk[0]=11; ztxt.slpnlk[1]=($' ');ztxt.slpnlk[2]=(1);ztxt.slpnlk[3]=($' ');ztxt.slpnlk[4]=($'+');ztxt.slpnlk[5]=($'n');ztxt.slpnlk[6]=($'l');ztxt.slpnlk[7]=($' ');ztxt.slpnlk[8]=($'k');ztxt.slpnlk[9]=($'n');ztxt.slpnlk[10]=($'e');ztxt.slpnlk[11]=($'e'););ztxt.slpnlk;));
  slyspc+= 5;
  sl.dosl( slpnlt,   -60, 0, -12, .1, 1, 0, 0, 1, /*!ztxt.slpnlt=' \1 +nl thresh (dB)');*/ (!ztxt.slpnlt ?(ztxt.slpnlt=mem(20); ztxt.slpnlt[0]=18; ztxt.slpnlt[1]=($' ');ztxt.slpnlt[2]=(1);ztxt.slpnlt[3]=($' ');ztxt.slpnlt[4]=($'+');ztxt.slpnlt[5]=($'n');ztxt.slpnlt[6]=($'l');ztxt.slpnlt[7]=($' ');ztxt.slpnlt[8]=($'t');ztxt.slpnlt[9]=($'h');ztxt.slpnlt[10]=($'r');ztxt.slpnlt[11]=($'e');ztxt.slpnlt[12]=($'s');ztxt.slpnlt[13]=($'h');ztxt.slpnlt[14]=($' ');ztxt.slpnlt[15]=($'(');ztxt.slpnlt[16]=($'d');ztxt.slpnlt[17]=($'B');ztxt.slpnlt[18]=($')'););ztxt.slpnlt;));
  slyspc-= 5;
  sl.dosl( slnnl,      1, 10, 1, .01, 2, 0, 0, 1, /*!ztxt.slnnl='- nonlinearity');*/ (!ztxt.slnnl ?(ztxt.slnnl=mem(15); ztxt.slnnl[0]=14; ztxt.slnnl[1]=($'-');ztxt.slnnl[2]=($' ');ztxt.slnnl[3]=($'n');ztxt.slnnl[4]=($'o');ztxt.slnnl[5]=($'n');ztxt.slnnl[6]=($'l');ztxt.slnnl[7]=($'i');ztxt.slnnl[8]=($'n');ztxt.slnnl[9]=($'e');ztxt.slnnl[10]=($'a');ztxt.slnnl[11]=($'r');ztxt.slnnl[12]=($'i');ztxt.slnnl[13]=($'t');ztxt.slnnl[14]=($'y'););ztxt.slnnl;));
  sl.dosl( slnnlk,     0, 10, 1, .01, 2, 0, 0, 1, /*!ztxt.slnnlk=' \1 -nl knee');*/ (!ztxt.slnnlk ?(ztxt.slnnlk=mem(13); ztxt.slnnlk[0]=11; ztxt.slnnlk[1]=($' ');ztxt.slnnlk[2]=(1);ztxt.slnnlk[3]=($' ');ztxt.slnnlk[4]=($'-');ztxt.slnnlk[5]=($'n');ztxt.slnnlk[6]=($'l');ztxt.slnnlk[7]=($' ');ztxt.slnnlk[8]=($'k');ztxt.slnnlk[9]=($'n');ztxt.slnnlk[10]=($'e');ztxt.slnnlk[11]=($'e'););ztxt.slnnlk;));
  slyspc+= 5;
  sl.dosl( slnnlt,   -60, 0, -12, .1, 1, 0, 0, 1, /*!ztxt.slnnlt=' \1 -nl thresh (dB)');*/ (!ztxt.slnnlt ?(ztxt.slnnlt=mem(20); ztxt.slnnlt[0]=18; ztxt.slnnlt[1]=($' ');ztxt.slnnlt[2]=(1);ztxt.slnnlt[3]=($' ');ztxt.slnnlt[4]=($'-');ztxt.slnnlt[5]=($'n');ztxt.slnnlt[6]=($'l');ztxt.slnnlt[7]=($' ');ztxt.slnnlt[8]=($'t');ztxt.slnnlt[9]=($'h');ztxt.slnnlt[10]=($'r');ztxt.slnnlt[11]=($'e');ztxt.slnnlt[12]=($'s');ztxt.slnnlt[13]=($'h');ztxt.slnnlt[14]=($' ');ztxt.slnnlt[15]=($'(');ztxt.slnnlt[16]=($'d');ztxt.slnnlt[17]=($'B');ztxt.slnnlt[18]=($')'););ztxt.slnnlt;));
  slyspc-= 5;
  sl.dosl( slpgain,   -24, 24, 0, .1, 1, 1, 0, 0, /*!ztxt.slpgain='+ gain (dB)');*/ (!ztxt.slpgain ?(ztxt.slpgain=mem(12); ztxt.slpgain[0]=11; ztxt.slpgain[1]=($'+');ztxt.slpgain[2]=($' ');ztxt.slpgain[3]=($'g');ztxt.slpgain[4]=($'a');ztxt.slpgain[5]=($'i');ztxt.slpgain[6]=($'n');ztxt.slpgain[7]=($' ');ztxt.slpgain[8]=($'(');ztxt.slpgain[9]=($'d');ztxt.slpgain[10]=($'B');ztxt.slpgain[11]=($')'););ztxt.slpgain;));
  slyspc+= 5;
  sl.dosl( slngain,   -24, 24, 0, .1, 1, 1, 0, 0, /*!ztxt.slngain='- gain (dB)');*/ (!ztxt.slngain ?(ztxt.slngain=mem(12); ztxt.slngain[0]=11; ztxt.slngain[1]=($'-');ztxt.slngain[2]=($' ');ztxt.slngain[3]=($'g');ztxt.slngain[4]=($'a');ztxt.slngain[5]=($'i');ztxt.slngain[6]=($'n');ztxt.slngain[7]=($' ');ztxt.slngain[8]=($'(');ztxt.slngain[9]=($'d');ztxt.slngain[10]=($'B');ztxt.slngain[11]=($')'););ztxt.slngain;));
  sl.dosl( slogain,   -36, 36, 0, .1, 1, 1, 0, 0, /*!ztxt.slogain='out gain (dB)');*/ (!ztxt.slogain ?(ztxt.slogain=mem(14); ztxt.slogain[0]=13; ztxt.slogain[1]=($'o');ztxt.slogain[2]=($'u');ztxt.slogain[3]=($'t');ztxt.slogain[4]=($' ');ztxt.slogain[5]=($'g');ztxt.slogain[6]=($'a');ztxt.slogain[7]=($'i');ztxt.slogain[8]=($'n');ztxt.slogain[9]=($' ');ztxt.slogain[10]=($'(');ztxt.slogain[11]=($'d');ztxt.slogain[12]=($'B');ztxt.slogain[13]=($')'););ztxt.slogain;));

  // B controls
  gyo= abgyo+slysz+2; gxo= graphyr;
  zhslb.hue();
  slyspc= slysz+slysz+slyspc2+1;
  //dosl( slnum, min, max, def, rnd, prec, bp, inv, xtr, txt )
  sl.dosl( sligainb, -36, 36, 0, .1, 1, 1, 1, 0, ztxt.nil ); ///*!ztxt.sligain='in gain (dB)');*/ (!ztxt.sligain ?(ztxt.sligain=mem(13); ztxt.sligain[0]=12; ztxt.sligain[1]=($'i');ztxt.sligain[2]=($'n');ztxt.sligain[3]=($' ');ztxt.sligain[4]=($'g');ztxt.sligain[5]=($'a');ztxt.sligain[6]=($'i');ztxt.sligain[7]=($'n');ztxt.sligain[8]=($' ');ztxt.sligain[9]=($'(');ztxt.sligain[10]=($'d');ztxt.sligain[11]=($'B');ztxt.sligain[12]=($')'););ztxt.sligain;));

  gyo+= slysz+slyspc1+2;
  slyspc-= 5;
  sl.dosl( slmodxb,   0, 100, 0, .1, 1, 0, 1, 0, ztxt.nil ); ///*!ztxt.slmodx='mod X - drive');*/ (!ztxt.slmodx ?(ztxt.slmodx=mem(14); ztxt.slmodx[0]=13; ztxt.slmodx[1]=($'m');ztxt.slmodx[2]=($'o');ztxt.slmodx[3]=($'d');ztxt.slmodx[4]=($' ');ztxt.slmodx[5]=($'X');ztxt.slmodx[6]=($' ');ztxt.slmodx[7]=($'-');ztxt.slmodx[8]=($' ');ztxt.slmodx[9]=($'d');ztxt.slmodx[10]=($'r');ztxt.slmodx[11]=($'i');ztxt.slmodx[12]=($'v');ztxt.slmodx[13]=($'e'););ztxt.slmodx;));
  sl.dosl( slmodxrngb, 0, 95, 0, .1, 1, 0, 1, 0, ztxt.nil ); ///*!ztxt.slmodxrng='   drive range');*/ (!ztxt.slmodxrng ?(ztxt.slmodxrng=mem(15); ztxt.slmodxrng[0]=14; ztxt.slmodxrng[1]=($' ');ztxt.slmodxrng[2]=($' ');ztxt.slmodxrng[3]=($' ');ztxt.slmodxrng[4]=($'d');ztxt.slmodxrng[5]=($'r');ztxt.slmodxrng[6]=($'i');ztxt.slmodxrng[7]=($'v');ztxt.slmodxrng[8]=($'e');ztxt.slmodxrng[9]=($' ');ztxt.slmodxrng[10]=($'r');ztxt.slmodxrng[11]=($'a');ztxt.slmodxrng[12]=($'n');ztxt.slmodxrng[13]=($'g');ztxt.slmodxrng[14]=($'e'););ztxt.slmodxrng;));
  slyspc+= 5;
  sl.dosl( slmodxbiasb,-1, 1, 0,.01, 2, 1, 1, 0, ztxt.nil ); ///*!ztxt.slmodxbias='   drive bias');*/ (!ztxt.slmodxbias ?(ztxt.slmodxbias=mem(14); ztxt.slmodxbias[0]=13; ztxt.slmodxbias[1]=($' ');ztxt.slmodxbias[2]=($' ');ztxt.slmodxbias[3]=($' ');ztxt.slmodxbias[4]=($'d');ztxt.slmodxbias[5]=($'r');ztxt.slmodxbias[6]=($'i');ztxt.slmodxbias[7]=($'v');ztxt.slmodxbias[8]=($'e');ztxt.slmodxbias[9]=($' ');ztxt.slmodxbias[10]=($'b');ztxt.slmodxbias[11]=($'i');ztxt.slmodxbias[12]=($'a');ztxt.slmodxbias[13]=($'s'););ztxt.slmodxbias;));
  sl.dosl( slmodyb,   0, 200, 0, .1, 1, 0, 1, 1, ztxt.nil ); ///*!ztxt.slmody='mod Y - saturation');*/ (!ztxt.slmody ?(ztxt.slmody=mem(19); ztxt.slmody[0]=18; ztxt.slmody[1]=($'m');ztxt.slmody[2]=($'o');ztxt.slmody[3]=($'d');ztxt.slmody[4]=($' ');ztxt.slmody[5]=($'Y');ztxt.slmody[6]=($' ');ztxt.slmody[7]=($'-');ztxt.slmody[8]=($' ');ztxt.slmody[9]=($'s');ztxt.slmody[10]=($'a');ztxt.slmody[11]=($'t');ztxt.slmody[12]=($'u');ztxt.slmody[13]=($'r');ztxt.slmody[14]=($'a');ztxt.slmody[15]=($'t');ztxt.slmody[16]=($'i');ztxt.slmody[17]=($'o');ztxt.slmody[18]=($'n'););ztxt.slmody;));
  sl.dosl( slmodzb,   0, 200, 0, .1, 1, 0, 1, 1, ztxt.nil ); ///*!ztxt.slmodz='mod Z - lag');*/ (!ztxt.slmodz ?(ztxt.slmodz=mem(12); ztxt.slmodz[0]=11; ztxt.slmodz[1]=($'m');ztxt.slmodz[2]=($'o');ztxt.slmodz[3]=($'d');ztxt.slmodz[4]=($' ');ztxt.slmodz[5]=($'Z');ztxt.slmodz[6]=($' ');ztxt.slmodz[7]=($'-');ztxt.slmodz[8]=($' ');ztxt.slmodz[9]=($'l');ztxt.slmodz[10]=($'a');ztxt.slmodz[11]=($'g'););ztxt.slmodz;));
  slyspc-= 5;
  sl.dosl( slpnlb,    1, 10, 1, .01, 2, 0, 1, 1, ztxt.nil ); ///*!ztxt.slpnl='+ nonlinearity');*/ (!ztxt.slpnl ?(ztxt.slpnl=mem(15); ztxt.slpnl[0]=14; ztxt.slpnl[1]=($'+');ztxt.slpnl[2]=($' ');ztxt.slpnl[3]=($'n');ztxt.slpnl[4]=($'o');ztxt.slpnl[5]=($'n');ztxt.slpnl[6]=($'l');ztxt.slpnl[7]=($'i');ztxt.slpnl[8]=($'n');ztxt.slpnl[9]=($'e');ztxt.slpnl[10]=($'a');ztxt.slpnl[11]=($'r');ztxt.slpnl[12]=($'i');ztxt.slpnl[13]=($'t');ztxt.slpnl[14]=($'y'););ztxt.slpnl;));
  sl.dosl( slpnlkb,   0, 10, 1, .01, 2, 0, 1, 1, ztxt.nil ); ///*!ztxt.slpnlk='   +nl knee');*/ (!ztxt.slpnlk ?(ztxt.slpnlk=mem(12); ztxt.slpnlk[0]=11; ztxt.slpnlk[1]=($' ');ztxt.slpnlk[2]=($' ');ztxt.slpnlk[3]=($' ');ztxt.slpnlk[4]=($'+');ztxt.slpnlk[5]=($'n');ztxt.slpnlk[6]=($'l');ztxt.slpnlk[7]=($' ');ztxt.slpnlk[8]=($'k');ztxt.slpnlk[9]=($'n');ztxt.slpnlk[10]=($'e');ztxt.slpnlk[11]=($'e'););ztxt.slpnlk;));
  slyspc+= 5;
  sl.dosl( slpnltb, -60, 0, -12, .1, 1, 0, 1, 1, ztxt.nil ); ///*!ztxt.slpnlt='   +nl thresh (dB)');*/ (!ztxt.slpnlt ?(ztxt.slpnlt=mem(19); ztxt.slpnlt[0]=18; ztxt.slpnlt[1]=($' ');ztxt.slpnlt[2]=($' ');ztxt.slpnlt[3]=($' ');ztxt.slpnlt[4]=($'+');ztxt.slpnlt[5]=($'n');ztxt.slpnlt[6]=($'l');ztxt.slpnlt[7]=($' ');ztxt.slpnlt[8]=($'t');ztxt.slpnlt[9]=($'h');ztxt.slpnlt[10]=($'r');ztxt.slpnlt[11]=($'e');ztxt.slpnlt[12]=($'s');ztxt.slpnlt[13]=($'h');ztxt.slpnlt[14]=($' ');ztxt.slpnlt[15]=($'(');ztxt.slpnlt[16]=($'d');ztxt.slpnlt[17]=($'B');ztxt.slpnlt[18]=($')'););ztxt.slpnlt;));
  slyspc-= 5;
  sl.dosl( slnnlb,    1, 10, 1, .01, 2, 0, 1, 1, ztxt.nil ); ///*!ztxt.slnnl='- nonlinearity');*/ (!ztxt.slnnl ?(ztxt.slnnl=mem(15); ztxt.slnnl[0]=14; ztxt.slnnl[1]=($'-');ztxt.slnnl[2]=($' ');ztxt.slnnl[3]=($'n');ztxt.slnnl[4]=($'o');ztxt.slnnl[5]=($'n');ztxt.slnnl[6]=($'l');ztxt.slnnl[7]=($'i');ztxt.slnnl[8]=($'n');ztxt.slnnl[9]=($'e');ztxt.slnnl[10]=($'a');ztxt.slnnl[11]=($'r');ztxt.slnnl[12]=($'i');ztxt.slnnl[13]=($'t');ztxt.slnnl[14]=($'y'););ztxt.slnnl;));
  sl.dosl( slnnlkb,   0, 10, 1, .01, 2, 0, 1, 1, ztxt.nil ); ///*!ztxt.slnnlk='   -nl knee');*/ (!ztxt.slnnlk ?(ztxt.slnnlk=mem(12); ztxt.slnnlk[0]=11; ztxt.slnnlk[1]=($' ');ztxt.slnnlk[2]=($' ');ztxt.slnnlk[3]=($' ');ztxt.slnnlk[4]=($'-');ztxt.slnnlk[5]=($'n');ztxt.slnnlk[6]=($'l');ztxt.slnnlk[7]=($' ');ztxt.slnnlk[8]=($'k');ztxt.slnnlk[9]=($'n');ztxt.slnnlk[10]=($'e');ztxt.slnnlk[11]=($'e'););ztxt.slnnlk;));
  slyspc+= 5;
  sl.dosl( slnnltb, -60, 0, -12, .1, 1, 0, 1, 1, ztxt.nil ); ///*!ztxt.slnnlt='   -nl thresh (dB)');*/ (!ztxt.slnnlt ?(ztxt.slnnlt=mem(19); ztxt.slnnlt[0]=18; ztxt.slnnlt[1]=($' ');ztxt.slnnlt[2]=($' ');ztxt.slnnlt[3]=($' ');ztxt.slnnlt[4]=($'-');ztxt.slnnlt[5]=($'n');ztxt.slnnlt[6]=($'l');ztxt.slnnlt[7]=($' ');ztxt.slnnlt[8]=($'t');ztxt.slnnlt[9]=($'h');ztxt.slnnlt[10]=($'r');ztxt.slnnlt[11]=($'e');ztxt.slnnlt[12]=($'s');ztxt.slnnlt[13]=($'h');ztxt.slnnlt[14]=($' ');ztxt.slnnlt[15]=($'(');ztxt.slnnlt[16]=($'d');ztxt.slnnlt[17]=($'B');ztxt.slnnlt[18]=($')'););ztxt.slnnlt;));
  slyspc-= 5;
  sl.dosl( slpgainb, -24, 24, 0, .1, 1, 1, 1, 0, ztxt.nil ); ///*!ztxt.slpgain='+ gain (dB)');*/ (!ztxt.slpgain ?(ztxt.slpgain=mem(12); ztxt.slpgain[0]=11; ztxt.slpgain[1]=($'+');ztxt.slpgain[2]=($' ');ztxt.slpgain[3]=($'g');ztxt.slpgain[4]=($'a');ztxt.slpgain[5]=($'i');ztxt.slpgain[6]=($'n');ztxt.slpgain[7]=($' ');ztxt.slpgain[8]=($'(');ztxt.slpgain[9]=($'d');ztxt.slpgain[10]=($'B');ztxt.slpgain[11]=($')'););ztxt.slpgain;));
  slyspc+= 5;
  sl.dosl( slngainb, -24, 24, 0, .1, 1, 1, 1, 0, ztxt.nil ); ///*!ztxt.slngain='- gain (dB)');*/ (!ztxt.slngain ?(ztxt.slngain=mem(12); ztxt.slngain[0]=11; ztxt.slngain[1]=($'-');ztxt.slngain[2]=($' ');ztxt.slngain[3]=($'g');ztxt.slngain[4]=($'a');ztxt.slngain[5]=($'i');ztxt.slngain[6]=($'n');ztxt.slngain[7]=($' ');ztxt.slngain[8]=($'(');ztxt.slngain[9]=($'d');ztxt.slngain[10]=($'B');ztxt.slngain[11]=($')'););ztxt.slngain;));
  sl.dosl( slogainb, -36, 36, 0, .1, 1, 1, 1, 0, ztxt.nil ); ///*!ztxt.slogain='out gain (dB)');*/ (!ztxt.slogain ?(ztxt.slogain=mem(14); ztxt.slogain[0]=13; ztxt.slogain[1]=($'o');ztxt.slogain[2]=($'u');ztxt.slogain[3]=($'t');ztxt.slogain[4]=($' ');ztxt.slogain[5]=($'g');ztxt.slogain[6]=($'a');ztxt.slogain[7]=($'i');ztxt.slogain[8]=($'n');ztxt.slogain[9]=($' ');ztxt.slogain[10]=($'(');ztxt.slogain[11]=($'d');ztxt.slogain[12]=($'B');ztxt.slogain[13]=($')'););ztxt.slogain;));
  gyo-= slysz+2;

  // A & B controls
  slyspc= slysz+slyspc1;
  zhsl.hue();
  sl.doslz( slcrunchcrv, 0, 100, 0, 1, 0, 0, 0, 0, 0, ztxt.off, /*!ztxt.slcrunchcrv='crunch');*/ (!ztxt.slcrunchcrv ?(ztxt.slcrunchcrv=mem(7); ztxt.slcrunchcrv[0]=6; ztxt.slcrunchcrv[1]=($'c');ztxt.slcrunchcrv[2]=($'r');ztxt.slcrunchcrv[3]=($'u');ztxt.slcrunchcrv[4]=($'n');ztxt.slcrunchcrv[5]=($'c');ztxt.slcrunchcrv[6]=($'h'););ztxt.slcrunchcrv;));
):(
  slyspc= slysz+slyspc1;
  zhslbtn.hue();
  //dosl( slnum, min, max, def, rnd, prec, bp, inv, xtr, txt )
  sl.doslbtn( slzb4y, ztxt.no, ztxt.yes, /*!ztxt.slzb4y='mod Z before Y');*/ (!ztxt.slzb4y ?(ztxt.slzb4y=mem(15); ztxt.slzb4y[0]=14; ztxt.slzb4y[1]=($'m');ztxt.slzb4y[2]=($'o');ztxt.slzb4y[3]=($'d');ztxt.slzb4y[4]=($' ');ztxt.slzb4y[5]=($'Z');ztxt.slzb4y[6]=($' ');ztxt.slzb4y[7]=($'b');ztxt.slzb4y[8]=($'e');ztxt.slzb4y[9]=($'f');ztxt.slzb4y[10]=($'o');ztxt.slzb4y[11]=($'r');ztxt.slzb4y[12]=($'e');ztxt.slzb4y[13]=($' ');ztxt.slzb4y[14]=($'Y'););ztxt.slzb4y;));
  sl.doslbtn( slnodrivez, ztxt.no, ztxt.yes, /*!ztxt.slnodrivez='undriven mod Z');*/ (!ztxt.slnodrivez ?(ztxt.slnodrivez=mem(15); ztxt.slnodrivez[0]=14; ztxt.slnodrivez[1]=($'u');ztxt.slnodrivez[2]=($'n');ztxt.slnodrivez[3]=($'d');ztxt.slnodrivez[4]=($'r');ztxt.slnodrivez[5]=($'i');ztxt.slnodrivez[6]=($'v');ztxt.slnodrivez[7]=($'e');ztxt.slnodrivez[8]=($'n');ztxt.slnodrivez[9]=($' ');ztxt.slnodrivez[10]=($'m');ztxt.slnodrivez[11]=($'o');ztxt.slnodrivez[12]=($'d');ztxt.slnodrivez[13]=($' ');ztxt.slnodrivez[14]=($'Z'););ztxt.slnodrivez;));
  sli.doslbtn( slinvert, ztxt.no, ztxt.yes, /*!ztxt.invert='invert output');*/ (!ztxt.invert ?(ztxt.invert=mem(14); ztxt.invert[0]=13; ztxt.invert[1]=($'i');ztxt.invert[2]=($'n');ztxt.invert[3]=($'v');ztxt.invert[4]=($'e');ztxt.invert[5]=($'r');ztxt.invert[6]=($'t');ztxt.invert[7]=($' ');ztxt.invert[8]=($'o');ztxt.invert[9]=($'u');ztxt.invert[10]=($'t');ztxt.invert[11]=($'p');ztxt.invert[12]=($'u');ztxt.invert[13]=($'t'););ztxt.invert;));
  sli.doslbtn( slunlimit, ztxt.no, ztxt.yes, /*!ztxt.unlimit='UNlimited output');*/ (!ztxt.unlimit ?(ztxt.unlimit=mem(17); ztxt.unlimit[0]=16; ztxt.unlimit[1]=($'U');ztxt.unlimit[2]=($'N');ztxt.unlimit[3]=($'l');ztxt.unlimit[4]=($'i');ztxt.unlimit[5]=($'m');ztxt.unlimit[6]=($'i');ztxt.unlimit[7]=($'t');ztxt.unlimit[8]=($'e');ztxt.unlimit[9]=($'d');ztxt.unlimit[10]=($' ');ztxt.unlimit[11]=($'o');ztxt.unlimit[12]=($'u');ztxt.unlimit[13]=($'t');ztxt.unlimit[14]=($'p');ztxt.unlimit[15]=($'u');ztxt.unlimit[16]=($'t'););ztxt.unlimit;));
  zhsl.hue();
  sl.doslz( slostimes,    1, 16, 1, 1, 0, 0, 0, 0, 1, ztxt.off, /*!ztxt.slostimes='oversampling (times)');*/ (!ztxt.slostimes ?(ztxt.slostimes=mem(21); ztxt.slostimes[0]=20; ztxt.slostimes[1]=($'o');ztxt.slostimes[2]=($'v');ztxt.slostimes[3]=($'e');ztxt.slostimes[4]=($'r');ztxt.slostimes[5]=($'s');ztxt.slostimes[6]=($'a');ztxt.slostimes[7]=($'m');ztxt.slostimes[8]=($'p');ztxt.slostimes[9]=($'l');ztxt.slostimes[10]=($'i');ztxt.slostimes[11]=($'n');ztxt.slostimes[12]=($'g');ztxt.slostimes[13]=($' ');ztxt.slostimes[14]=($'(');ztxt.slostimes[15]=($'t');ztxt.slostimes[16]=($'i');ztxt.slostimes[17]=($'m');ztxt.slostimes[18]=($'e');ztxt.slostimes[19]=($'s');ztxt.slostimes[20]=($')'););ztxt.slostimes;));
  sl.dosl( sloscascades, 1, 12, 4, 1, 0, 0, 0, 0, /*!ztxt.sloscascades='os aa filter cascades');*/ (!ztxt.sloscascades ?(ztxt.sloscascades=mem(22); ztxt.sloscascades[0]=21; ztxt.sloscascades[1]=($'o');ztxt.sloscascades[2]=($'s');ztxt.sloscascades[3]=($' ');ztxt.sloscascades[4]=($'a');ztxt.sloscascades[5]=($'a');ztxt.sloscascades[6]=($' ');ztxt.sloscascades[7]=($'f');ztxt.sloscascades[8]=($'i');ztxt.sloscascades[9]=($'l');ztxt.sloscascades[10]=($'t');ztxt.sloscascades[11]=($'e');ztxt.sloscascades[12]=($'r');ztxt.sloscascades[13]=($' ');ztxt.sloscascades[14]=($'c');ztxt.sloscascades[15]=($'a');ztxt.sloscascades[16]=($'s');ztxt.sloscascades[17]=($'c');ztxt.sloscascades[18]=($'a');ztxt.sloscascades[19]=($'d');ztxt.sloscascades[20]=($'e');ztxt.sloscascades[21]=($'s'););ztxt.sloscascades;));
  sl.dosl( slosbw,     .5, 1, 1, .01, 2, 0, 0, 0, /*!ztxt.slosbw='os aa filter bandwidth');*/ (!ztxt.slosbw ?(ztxt.slosbw=mem(23); ztxt.slosbw[0]=22; ztxt.slosbw[1]=($'o');ztxt.slosbw[2]=($'s');ztxt.slosbw[3]=($' ');ztxt.slosbw[4]=($'a');ztxt.slosbw[5]=($'a');ztxt.slosbw[6]=($' ');ztxt.slosbw[7]=($'f');ztxt.slosbw[8]=($'i');ztxt.slosbw[9]=($'l');ztxt.slosbw[10]=($'t');ztxt.slosbw[11]=($'e');ztxt.slosbw[12]=($'r');ztxt.slosbw[13]=($' ');ztxt.slosbw[14]=($'b');ztxt.slosbw[15]=($'a');ztxt.slosbw[16]=($'n');ztxt.slosbw[17]=($'d');ztxt.slosbw[18]=($'w');ztxt.slosbw[19]=($'i');ztxt.slosbw[20]=($'d');ztxt.slosbw[21]=($'t');ztxt.slosbw[22]=($'h'););ztxt.slosbw;));
  zhslbtn.hue();
  sli.doslbtn( slsidechain, ztxt.no, ztxt.yes, /*!ztxt.sidechain='sidechain');*/ (!ztxt.sidechain ?(ztxt.sidechain=mem(10); ztxt.sidechain[0]=9; ztxt.sidechain[1]=($'s');ztxt.sidechain[2]=($'i');ztxt.sidechain[3]=($'d');ztxt.sidechain[4]=($'e');ztxt.sidechain[5]=($'c');ztxt.sidechain[6]=($'h');ztxt.sidechain[7]=($'a');ztxt.sidechain[8]=($'i');ztxt.sidechain[9]=($'n'););ztxt.sidechain;));
  zhsl.hue();
  //dosl( memsl, min, max, def, rnd, prec, bp, inv, xtr, txt )
  sl.doslz( slenv2slim, 1, .1, 1, .0001, 4, 0, 0, 0, 1, ztxt.off, /*!ztxt.env2slim='curve slew limit');*/ (!ztxt.env2slim ?(ztxt.env2slim=mem(17); ztxt.env2slim[0]=16; ztxt.env2slim[1]=($'c');ztxt.env2slim[2]=($'u');ztxt.env2slim[3]=($'r');ztxt.env2slim[4]=($'v');ztxt.env2slim[5]=($'e');ztxt.env2slim[6]=($' ');ztxt.env2slim[7]=($'s');ztxt.env2slim[8]=($'l');ztxt.env2slim[9]=($'e');ztxt.env2slim[10]=($'w');ztxt.env2slim[11]=($' ');ztxt.env2slim[12]=($'l');ztxt.env2slim[13]=($'i');ztxt.env2slim[14]=($'m');ztxt.env2slim[15]=($'i');ztxt.env2slim[16]=($'t'););ztxt.env2slim;));
  sl.dosl( slenvtpow, 1, 5, 2, .1, 1, 0, 0, 1, /*!ztxt.envtpow='transience power');*/ (!ztxt.envtpow ?(ztxt.envtpow=mem(17); ztxt.envtpow[0]=16; ztxt.envtpow[1]=($'t');ztxt.envtpow[2]=($'r');ztxt.envtpow[3]=($'a');ztxt.envtpow[4]=($'n');ztxt.envtpow[5]=($'s');ztxt.envtpow[6]=($'i');ztxt.envtpow[7]=($'e');ztxt.envtpow[8]=($'n');ztxt.envtpow[9]=($'c');ztxt.envtpow[10]=($'e');ztxt.envtpow[11]=($' ');ztxt.envtpow[12]=($'p');ztxt.envtpow[13]=($'o');ztxt.envtpow[14]=($'w');ztxt.envtpow[15]=($'e');ztxt.envtpow[16]=($'r'););ztxt.envtpow;));
  sl.dosl( slenvtoff, -24, 24, 0, .1, 1, 1, 0, 1, /*!ztxt.envtoff='transience offset (dB)');*/ (!ztxt.envtoff ?(ztxt.envtoff=mem(23); ztxt.envtoff[0]=22; ztxt.envtoff[1]=($'t');ztxt.envtoff[2]=($'r');ztxt.envtoff[3]=($'a');ztxt.envtoff[4]=($'n');ztxt.envtoff[5]=($'s');ztxt.envtoff[6]=($'i');ztxt.envtoff[7]=($'e');ztxt.envtoff[8]=($'n');ztxt.envtoff[9]=($'c');ztxt.envtoff[10]=($'e');ztxt.envtoff[11]=($' ');ztxt.envtoff[12]=($'o');ztxt.envtoff[13]=($'f');ztxt.envtoff[14]=($'f');ztxt.envtoff[15]=($'s');ztxt.envtoff[16]=($'e');ztxt.envtoff[17]=($'t');ztxt.envtoff[18]=($' ');ztxt.envtoff[19]=($'(');ztxt.envtoff[20]=($'d');ztxt.envtoff[21]=($'B');ztxt.envtoff[22]=($')'););ztxt.envtoff;));
  sl.doslz( slenvtenv, 0, 10, 0, .01, 2, 0, 0, 0, 0, ztxt.off, /*!ztxt.envtenv='transience decay (ms)');*/ (!ztxt.envtenv ?(ztxt.envtenv=mem(22); ztxt.envtenv[0]=21; ztxt.envtenv[1]=($'t');ztxt.envtenv[2]=($'r');ztxt.envtenv[3]=($'a');ztxt.envtenv[4]=($'n');ztxt.envtenv[5]=($'s');ztxt.envtenv[6]=($'i');ztxt.envtenv[7]=($'e');ztxt.envtenv[8]=($'n');ztxt.envtenv[9]=($'c');ztxt.envtenv[10]=($'e');ztxt.envtenv[11]=($' ');ztxt.envtenv[12]=($'d');ztxt.envtenv[13]=($'e');ztxt.envtenv[14]=($'c');ztxt.envtenv[15]=($'a');ztxt.envtenv[16]=($'y');ztxt.envtenv[17]=($' ');ztxt.envtenv[18]=($'(');ztxt.envtenv[19]=($'m');ztxt.envtenv[20]=($'s');ztxt.envtenv[21]=($')'););ztxt.envtenv;));
  sli.doslz( slenvtlimit, 0, 200, 0, 1, 0, 0, 0, 1, 0, ztxt.off, /*!ztxt.slenvtlimit='transience limit (%)');*/ (!ztxt.slenvtlimit ?(ztxt.slenvtlimit=mem(21); ztxt.slenvtlimit[0]=20; ztxt.slenvtlimit[1]=($'t');ztxt.slenvtlimit[2]=($'r');ztxt.slenvtlimit[3]=($'a');ztxt.slenvtlimit[4]=($'n');ztxt.slenvtlimit[5]=($'s');ztxt.slenvtlimit[6]=($'i');ztxt.slenvtlimit[7]=($'e');ztxt.slenvtlimit[8]=($'n');ztxt.slenvtlimit[9]=($'c');ztxt.slenvtlimit[10]=($'e');ztxt.slenvtlimit[11]=($' ');ztxt.slenvtlimit[12]=($'l');ztxt.slenvtlimit[13]=($'i');ztxt.slenvtlimit[14]=($'m');ztxt.slenvtlimit[15]=($'i');ztxt.slenvtlimit[16]=($'t');ztxt.slenvtlimit[17]=($' ');ztxt.slenvtlimit[18]=($'(');ztxt.slenvtlimit[19]=($'%');ztxt.slenvtlimit[20]=($')'););ztxt.slenvtlimit;));
  sli.dosl( slenvtlimcrv, 0, 100, 25, 1, 0, 0, 0, 1, /*!ztxt.slenvtlimcrv='transience limit hardness');*/ (!ztxt.slenvtlimcrv ?(ztxt.slenvtlimcrv=mem(26); ztxt.slenvtlimcrv[0]=25; ztxt.slenvtlimcrv[1]=($'t');ztxt.slenvtlimcrv[2]=($'r');ztxt.slenvtlimcrv[3]=($'a');ztxt.slenvtlimcrv[4]=($'n');ztxt.slenvtlimcrv[5]=($'s');ztxt.slenvtlimcrv[6]=($'i');ztxt.slenvtlimcrv[7]=($'e');ztxt.slenvtlimcrv[8]=($'n');ztxt.slenvtlimcrv[9]=($'c');ztxt.slenvtlimcrv[10]=($'e');ztxt.slenvtlimcrv[11]=($' ');ztxt.slenvtlimcrv[12]=($'l');ztxt.slenvtlimcrv[13]=($'i');ztxt.slenvtlimcrv[14]=($'m');ztxt.slenvtlimcrv[15]=($'i');ztxt.slenvtlimcrv[16]=($'t');ztxt.slenvtlimcrv[17]=($' ');ztxt.slenvtlimcrv[18]=($'h');ztxt.slenvtlimcrv[19]=($'a');ztxt.slenvtlimcrv[20]=($'r');ztxt.slenvtlimcrv[21]=($'d');ztxt.slenvtlimcrv[22]=($'n');ztxt.slenvtlimcrv[23]=($'e');ztxt.slenvtlimcrv[24]=($'s');ztxt.slenvtlimcrv[25]=($'s'););ztxt.slenvtlimcrv;));
  zhslbtn.hue();
  slt.doslbtn(sldbgraph, ztxt.no, ztxt.yes, /*!ztxt.dbgraph='dB shapes');*/ (!ztxt.dbgraph ?(ztxt.dbgraph=mem(10); ztxt.dbgraph[0]=9; ztxt.dbgraph[1]=($'d');ztxt.dbgraph[2]=($'B');ztxt.dbgraph[3]=($' ');ztxt.dbgraph[4]=($'s');ztxt.dbgraph[5]=($'h');ztxt.dbgraph[6]=($'a');ztxt.dbgraph[7]=($'p');ztxt.dbgraph[8]=($'e');ztxt.dbgraph[9]=($'s'););ztxt.dbgraph;));
  slt.doslbtn(slenvgax, ztxt.no, ztxt.yes, /*!ztxt.envgax='dark envelopes');*/ (!ztxt.envgax ?(ztxt.envgax=mem(15); ztxt.envgax[0]=14; ztxt.envgax[1]=($'d');ztxt.envgax[2]=($'a');ztxt.envgax[3]=($'r');ztxt.envgax[4]=($'k');ztxt.envgax[5]=($' ');ztxt.envgax[6]=($'e');ztxt.envgax[7]=($'n');ztxt.envgax[8]=($'v');ztxt.envgax[9]=($'e');ztxt.envgax[10]=($'l');ztxt.envgax[11]=($'o');ztxt.envgax[12]=($'p');ztxt.envgax[13]=($'e');ztxt.envgax[14]=($'s'););ztxt.envgax;));
  zhsl.hue();
  slt.doslz( slesnapavc, 0, 10, 0, 1, 0, 0, 0, 0, 0, ztxt.off, /*!ztxt.esnapavc='env/wave timescale (spls/pix)' );*/ (!ztxt.esnapavc ?(ztxt.esnapavc=mem(30); ztxt.esnapavc[0]=29; ztxt.esnapavc[1]=($'e');ztxt.esnapavc[2]=($'n');ztxt.esnapavc[3]=($'v');ztxt.esnapavc[4]=($'/');ztxt.esnapavc[5]=($'w');ztxt.esnapavc[6]=($'a');ztxt.esnapavc[7]=($'v');ztxt.esnapavc[8]=($'e');ztxt.esnapavc[9]=($' ');ztxt.esnapavc[10]=($'t');ztxt.esnapavc[11]=($'i');ztxt.esnapavc[12]=($'m');ztxt.esnapavc[13]=($'e');ztxt.esnapavc[14]=($'s');ztxt.esnapavc[15]=($'c');ztxt.esnapavc[16]=($'a');ztxt.esnapavc[17]=($'l');ztxt.esnapavc[18]=($'e');ztxt.esnapavc[19]=($' ');ztxt.esnapavc[20]=($'(');ztxt.esnapavc[21]=($'s');ztxt.esnapavc[22]=($'p');ztxt.esnapavc[23]=($'l');ztxt.esnapavc[24]=($'s');ztxt.esnapavc[25]=($'/');ztxt.esnapavc[26]=($'p');ztxt.esnapavc[27]=($'i');ztxt.esnapavc[28]=($'x');ztxt.esnapavc[29]=($')'););ztxt.esnapavc;) );
  sl.doslz( slesnapthx, 0, 100, 0, 1, 0, 0, 0, 0, 0, ztxt.off, /*!ztxt.esnapthx='freeze thresh (%)' );*/ (!ztxt.esnapthx ?(ztxt.esnapthx=mem(18); ztxt.esnapthx[0]=17; ztxt.esnapthx[1]=($'f');ztxt.esnapthx[2]=($'r');ztxt.esnapthx[3]=($'e');ztxt.esnapthx[4]=($'e');ztxt.esnapthx[5]=($'z');ztxt.esnapthx[6]=($'e');ztxt.esnapthx[7]=($' ');ztxt.esnapthx[8]=($'t');ztxt.esnapthx[9]=($'h');ztxt.esnapthx[10]=($'r');ztxt.esnapthx[11]=($'e');ztxt.esnapthx[12]=($'s');ztxt.esnapthx[13]=($'h');ztxt.esnapthx[14]=($' ');ztxt.esnapthx[15]=($'(');ztxt.esnapthx[16]=($'%');ztxt.esnapthx[17]=($')'););ztxt.esnapthx;) );
  zhslbtn.hue();
);

slyspc= slysz+slyspc1;
zhsl.hue();
sl.dosl( slmgain, -36, 36, 0, .1, 1, 0, 0, 0, /*!ztxt.slmgain='master gain');*/ (!ztxt.slmgain ?(ztxt.slmgain=mem(12); ztxt.slmgain[0]=11; ztxt.slmgain[1]=($'m');ztxt.slmgain[2]=($'a');ztxt.slmgain[3]=($'s');ztxt.slmgain[4]=($'t');ztxt.slmgain[5]=($'e');ztxt.slmgain[6]=($'r');ztxt.slmgain[7]=($' ');ztxt.slmgain[8]=($'g');ztxt.slmgain[9]=($'a');ztxt.slmgain[10]=($'i');ztxt.slmgain[11]=($'n'););ztxt.slmgain;));
sl.dosl( slwetmix, 0, 100, 100, 1, 0, 0, 0, 0, /*!ztxt.slwetmix='wet mix');*/ (!ztxt.slwetmix ?(ztxt.slwetmix=mem(8); ztxt.slwetmix[0]=7; ztxt.slwetmix[1]=($'w');ztxt.slwetmix[2]=($'e');ztxt.slwetmix[3]=($'t');ztxt.slwetmix[4]=($' ');ztxt.slwetmix[5]=($'m');ztxt.slwetmix[6]=($'i');ztxt.slwetmix[7]=($'x'););ztxt.slwetmix;));

graphyx= gyo;
gsz= graphyr*.8-15; //min(graphyb-15, graphyr-15);
gsz > gszmax + 10 ? gsz= gszmax + 10;
graphyb= gsz + 5; //gyo - 10 * (slysz+slyspc); //# of 1st col sliders * y-extent

// mod/env controls
gyo= graphyb+15; gxo= 5+(graphyr-slxsz-15)*.5;
slyspc= slysz+slyspc1;
zhsl.hue();
//dosl( slnum, min, max, def, rnd, prec, bp, inv, xtr, txt )
sl.dosl( slabcurve,   -100, 100, 0, 1, 0, 0, 0, 0, /*!ztxt.slabcurve='A/B curve');*/ (!ztxt.slabcurve ?(ztxt.slabcurve=mem(10); ztxt.slabcurve[0]=9; ztxt.slabcurve[1]=($'A');ztxt.slabcurve[2]=($'/');ztxt.slabcurve[3]=($'B');ztxt.slabcurve[4]=($' ');ztxt.slabcurve[5]=($'c');ztxt.slabcurve[6]=($'u');ztxt.slabcurve[7]=($'r');ztxt.slabcurve[8]=($'v');ztxt.slabcurve[9]=($'e'););ztxt.slabcurve;));
sl.doslz( slabmorphval, -1, 100, -1, 1, 0, 0, 0, 0, -1, ztxt.off, /*!ztxt.slabmorphval='A/B morph');*/ (!ztxt.slabmorphval ?(ztxt.slabmorphval=mem(10); ztxt.slabmorphval[0]=9; ztxt.slabmorphval[1]=($'A');ztxt.slabmorphval[2]=($'/');ztxt.slabmorphval[3]=($'B');ztxt.slabmorphval[4]=($' ');ztxt.slabmorphval[5]=($'m');ztxt.slabmorphval[6]=($'o');ztxt.slabmorphval[7]=($'r');ztxt.slabmorphval[8]=($'p');ztxt.slabmorphval[9]=($'h'););ztxt.slabmorphval;));
zhsla.hue();
sl.dosl( slathresh,  -100, 12, -48, .1, 1, 0, 0, 0, /*!ztxt.slathresh='A threshold (dB)');*/ (!ztxt.slathresh ?(ztxt.slathresh=mem(17); ztxt.slathresh[0]=16; ztxt.slathresh[1]=($'A');ztxt.slathresh[2]=($' ');ztxt.slathresh[3]=($'t');ztxt.slathresh[4]=($'h');ztxt.slathresh[5]=($'r');ztxt.slathresh[6]=($'e');ztxt.slathresh[7]=($'s');ztxt.slathresh[8]=($'h');ztxt.slathresh[9]=($'o');ztxt.slathresh[10]=($'l');ztxt.slathresh[11]=($'d');ztxt.slathresh[12]=($' ');ztxt.slathresh[13]=($'(');ztxt.slathresh[14]=($'d');ztxt.slathresh[15]=($'B');ztxt.slathresh[16]=($')'););ztxt.slathresh;));
zhslb.hue();
sl.dosl( slbthresh,  -100, 12, -48, .1, 1, 0, 0, 0, /*!ztxt.slbthresh='B threshold (dB)');*/ (!ztxt.slbthresh ?(ztxt.slbthresh=mem(17); ztxt.slbthresh[0]=16; ztxt.slbthresh[1]=($'B');ztxt.slbthresh[2]=($' ');ztxt.slbthresh[3]=($'t');ztxt.slbthresh[4]=($'h');ztxt.slbthresh[5]=($'r');ztxt.slbthresh[6]=($'e');ztxt.slbthresh[7]=($'s');ztxt.slbthresh[8]=($'h');ztxt.slbthresh[9]=($'o');ztxt.slbthresh[10]=($'l');ztxt.slbthresh[11]=($'d');ztxt.slbthresh[12]=($' ');ztxt.slbthresh[13]=($'(');ztxt.slbthresh[14]=($'d');ztxt.slbthresh[15]=($'B');ztxt.slbthresh[16]=($')'););ztxt.slbthresh;));
zhsl.hue();
sl.dosl( sltrans,     -100, 100, 0, 1, 0, 0, 0, 1, /*!ztxt.slsltrans='A/B transience');*/ (!ztxt.slsltrans ?(ztxt.slsltrans=mem(15); ztxt.slsltrans[0]=14; ztxt.slsltrans[1]=($'A');ztxt.slsltrans[2]=($'/');ztxt.slsltrans[3]=($'B');ztxt.slsltrans[4]=($' ');ztxt.slsltrans[5]=($'t');ztxt.slsltrans[6]=($'r');ztxt.slsltrans[7]=($'a');ztxt.slsltrans[8]=($'n');ztxt.slsltrans[9]=($'s');ztxt.slsltrans[10]=($'i');ztxt.slsltrans[11]=($'e');ztxt.slsltrans[12]=($'n');ztxt.slsltrans[13]=($'c');ztxt.slsltrans[14]=($'e'););ztxt.slsltrans;));
sl.dosl( slresptm,      1, 100, 23, 1, 0, 0, 0, 1, /*!ztxt.slresptm='response time (ms)');*/ (!ztxt.slresptm ?(ztxt.slresptm=mem(19); ztxt.slresptm[0]=18; ztxt.slresptm[1]=($'r');ztxt.slresptm[2]=($'e');ztxt.slresptm[3]=($'s');ztxt.slresptm[4]=($'p');ztxt.slresptm[5]=($'o');ztxt.slresptm[6]=($'n');ztxt.slresptm[7]=($'s');ztxt.slresptm[8]=($'e');ztxt.slresptm[9]=($' ');ztxt.slresptm[10]=($'t');ztxt.slresptm[11]=($'i');ztxt.slresptm[12]=($'m');ztxt.slresptm[13]=($'e');ztxt.slresptm[14]=($' ');ztxt.slresptm[15]=($'(');ztxt.slresptm[16]=($'m');ztxt.slresptm[17]=($'s');ztxt.slresptm[18]=($')'););ztxt.slresptm;));
sl.dosl( sltranstm,     .1, 32, 4, .1, 1, 0, 0, 1, /*!ztxt.sltranstm='transience time (ratio)');*/ (!ztxt.sltranstm ?(ztxt.sltranstm=mem(24); ztxt.sltranstm[0]=23; ztxt.sltranstm[1]=($'t');ztxt.sltranstm[2]=($'r');ztxt.sltranstm[3]=($'a');ztxt.sltranstm[4]=($'n');ztxt.sltranstm[5]=($'s');ztxt.sltranstm[6]=($'i');ztxt.sltranstm[7]=($'e');ztxt.sltranstm[8]=($'n');ztxt.sltranstm[9]=($'c');ztxt.sltranstm[10]=($'e');ztxt.sltranstm[11]=($' ');ztxt.sltranstm[12]=($'t');ztxt.sltranstm[13]=($'i');ztxt.sltranstm[14]=($'m');ztxt.sltranstm[15]=($'e');ztxt.sltranstm[16]=($' ');ztxt.sltranstm[17]=($'(');ztxt.sltranstm[18]=($'r');ztxt.sltranstm[19]=($'a');ztxt.sltranstm[20]=($'t');ztxt.sltranstm[21]=($'i');ztxt.sltranstm[22]=($'o');ztxt.sltranstm[23]=($')'););ztxt.sltranstm;));
 
zhslbtn.hue();
! ztxt.transbp0 ?(
  /*@ztxt.transbp0='+';*/                         (ztxt.transbp0=mem(2); ztxt.transbp0[0]=1; ztxt.transbp0[1]=($'+');ztxt.transbp0;);
  /*@ztxt.transbp1='-=+';*/                       (ztxt.transbp1=mem(4); ztxt.transbp1[0]=3; ztxt.transbp1[1]=($'-');ztxt.transbp1[2]=($'=');ztxt.transbp1[3]=($'+');ztxt.transbp1;);
  /*@ztxt.transbp2='+/-';*/                       (ztxt.transbp2=mem(4); ztxt.transbp2[0]=3; ztxt.transbp2[1]=($'+');ztxt.transbp2[2]=($'/');ztxt.transbp2[3]=($'-');ztxt.transbp2;);
);
sl.doslbtnval( slbptrans, 3, ztxt.transbp0, /*!ztxt.transbp='transience polarity');*/ (!ztxt.transbp ?(ztxt.transbp=mem(20); ztxt.transbp[0]=19; ztxt.transbp[1]=($'t');ztxt.transbp[2]=($'r');ztxt.transbp[3]=($'a');ztxt.transbp[4]=($'n');ztxt.transbp[5]=($'s');ztxt.transbp[6]=($'i');ztxt.transbp[7]=($'e');ztxt.transbp[8]=($'n');ztxt.transbp[9]=($'c');ztxt.transbp[10]=($'e');ztxt.transbp[11]=($' ');ztxt.transbp[12]=($'p');ztxt.transbp[13]=($'o');ztxt.transbp[14]=($'l');ztxt.transbp[15]=($'a');ztxt.transbp[16]=($'r');ztxt.transbp[17]=($'i');ztxt.transbp[18]=($'t');ztxt.transbp[19]=($'y'););ztxt.transbp;));

slt.doslbtn(sltweaks, ztxt.nil, ztxt.nil, /*!ztxt.tweaks='tweaks');*/ (!ztxt.tweaks ?(ztxt.tweaks=mem(7); ztxt.tweaks[0]=6; ztxt.tweaks[1]=($'t');ztxt.tweaks[2]=($'w');ztxt.tweaks[3]=($'e');ztxt.tweaks[4]=($'a');ztxt.tweaks[5]=($'k');ztxt.tweaks[6]=($'s'););ztxt.tweaks;));
tweaks= slt.sl(sltweaks);

graphyx < gyo ? graphyx= gyo;
graphyx+= 10;

gxo= 5+(graphyr-gsz-15)*.5; 
//gxo > gfx_w-gsz ? gxo= gfx_w-gsz;
gyo= 5; //(graphyb-gsz)*.5;

pp.paneini(gxo, gyo, gsz, gsz, -1, -1, 1, 1);

gsz < 100 ?( 
  hueset(0,0,0,1);
  pp.pxy(-1,1);
  /*puts(':^(');*/                                (putc($':');putc($'^');putc($'('););
):(
//@ gfx mouse

mouse_x > gxo && mouse_x < gxo+gsz && mouse_y > gyo && mouse_y < gyo+gsz ?(
  leftclick ?(
    plainclick ?(
      clickigaina= sla.sl(sligain);
      clickigainb= slb.sl(sligain);
      clickogaina= sla.sl(slogain);
      clickogainb= slb.sl(slogain);
    );
  );
  rightclick ?(
    shiftclick ?(
      optclick ?(
        //paste
        sla.slcopy(slclip.self);
        ii= abslbase; loop ( abslcnt, sl.slx( ii, sla.sl(ii) ); ii+= 1; );
        //setwhackab(); //a();
        slmunge();
      ):(
        //copy
        abmorph ? slclip.slmix(sla.self, slb.self, abcurve.invcurve( abmorphval ))
        : slclip.slcopy(sla.self);
      );
    ): plainclick ?( // swap a/b
      slb.slpush();
      sla.slswap();
      //setwhackab(); //a(); setwhackb();
      slmunge();
    );
  );
  leftdown && plainclick ?(
    abs(mouse_x - clickx) > abs(mouse_y - clicky) ?(
      gainx= clickigaina + (mouse_x-clickx)/gsz*maxigain*2;
      gainx > maxigain ? gainx= maxigain : gainx < -maxigain ? gainx= -maxigain;
      sla.slx(sligain, floor(gainx*10+.5)*.1 );
      gainx= clickigainb + (mouse_x-clickx)/gsz*maxigain*2;
      gainx > maxigain ? gainx= maxigain : gainx < -maxigain ? gainx= -maxigain;
      slb.slx(sligain, floor(gainx*10+.5)*.1 );
      sla.slx(slogain, clickogaina );
      slb.slx(slogain, clickogainb );
    ):(
      gainx= clickogaina - (mouse_y-clicky)/gsz*maxogain*2;
      gainx > maxogain ? gainx= maxogain : gainx < -maxogain ? gainx= -maxogain;
      sla.slx(slogain, floor(gainx*10+.5)*.1 );
      gainx= clickogainb - (mouse_y-clicky)/gsz*maxogain*2;
      gainx > maxogain ? gainx= maxogain : gainx < -maxogain ? gainx= -maxogain;
      slb.slx(slogain, floor(gainx*10+.5)*.1 );
      sla.slx(sligain, clickigaina );
      slb.slx(sligain, clickigainb );
    );
    slmunge();
  );
);

//@ gfx draw

//linking > 0 ? linking-= 1;

// fx bg fill
// zhfxbg.hue();
// gfx_x= 0; gfx_y= gyo; 
// gfxwo != gfx_w || gfxho != gfx_h ? gfx_rectto(gfx_w+1, gfx_h+1)
//                                  : gfx_rectto(gxo+1.2*gsz, gfx_h+1);
// gfxwo= gfx_w; gfxho= gfx_h;

// axes
zhax.hue();
pp.pline(-1, 0, 1, 0); // x axis
pp.pline(0, -1, 0, 1); // y axis
//hueset(1,1,1,1); hueset.huepush(); zhax.huepush(); hueset.huemix(.25); hueset.hue();
pp.pxyo(1, 0, -15, 0); /*puts('in');*/            (putc($'i');putc($'n'););
pp.pxyo(0, 1, 2, 0); /*puts('out');*/             (putc($'o');putc($'u');putc($'t'););
pp.pxyo(-1, -1, 2, txth-5 ); putn(adb < bdb ? adb : bdb, 1);
gxx= !doab ? envtbdb : adb < bdb ? bdb : adb;
pp.pxyo(1, -1, 1-txtw*(3+(gxx<=-10?1:0)+(gxx<0?1:0)), txth-5 ); putn(gxx, 1);

pp.pxyo(1, -1, 0, 17-10);
doabtr ?(
  // b outgain text
  zhtxtb.hue();
  pp.pxo(1, -txtw*11, 10); 
  /*puts('out B:');*/                             (putc($'o');putc($'u');putc($'t');putc($' ');putc($'B');putc($':'););
  abs(whackb0.outgaindb) < 10 ? /*puts(' ');*/    (putc($' '););
  whackb0.outgaindb == 0 ? /*puts(' ');*/         (putc($' '););
  whackb0.outgaindb > 0 ? /*puts('+');*/          (putc($'+'););
  putn(whackb0.outgaindb,1);
);
// a outgain text
zhtxta.hue();
pp.pxo(1, -txtw*11, 10); 
/*puts('out A:');*/                               (putc($'o');putc($'u');putc($'t');putc($' ');putc($'A');putc($':'););
abs(whacka0.outgaindb) < 10 ? /*puts(' ');*/      (putc($' '););
whacka0.outgaindb == 0 ? /*puts(' ');*/           (putc($' '););
whacka0.outgaindb > 0 ? /*puts('+');*/            (putc($'+'););
putn(whacka0.outgaindb,1);
doabtr ?(
  // b ingain text
  zhtxtb.hue();
  pp.pxo(1, -txtw*11, 10); 
  /*puts(' in B:');*/                             (putc($' ');putc($'i');putc($'n');putc($' ');putc($'B');putc($':'););
  abs(whackb0.ingaindb) < 10 ? /*puts(' ');*/     (putc($' '););
  whackb0.ingaindb == 0 ? /*puts(' ');*/          (putc($' '););
  whackb0.ingaindb > 0 ? /*puts('+');*/           (putc($'+'););
  putn(whackb0.ingaindb,1);
);
// a ingain text
zhtxta.hue();
pp.pxo(1, -txtw*11, 10); 
/*puts(' in A:');*/                               (putc($' ');putc($'i');putc($'n');putc($' ');putc($'A');putc($':'););
abs(whacka0.ingaindb) < 10 ? /*puts(' ');*/       (putc($' '););
whacka0.ingaindb == 0 ? /*puts(' ');*/            (putc($' '););
whacka0.ingaindb > 0 ? /*puts('+');*/             (putc($'+'););
putn(whacka0.ingaindb,1);

// shaper options
zhtxt.hue();
sl(slnodrivez) ? ( pp.pxo(1, -txtw*10, 10); /*puts('mod Z + 0X'); );*/ (putc($'m');putc($'o');putc($'d');putc($' ');putc($'Z');putc($' ');putc($'+');putc($' ');putc($'0');putc($'X');); );
sl(slzb4y) ? ( pp.pxo(1, -txtw*9, 10); /*puts('mod Z < Y'); );*/ (putc($'m');putc($'o');putc($'d');putc($' ');putc($'Z');putc($' ');putc($'<');putc($' ');putc($'Y');); );
bptrans == 2 ?( pp.pxo(1, -txtw*9, 10); /*puts('+/- trans'); )*/ (putc($'+');putc($'/');putc($'-');putc($' ');putc($'t');putc($'r');putc($'a');putc($'n');putc($'s');); )
: bptrans ?( pp.pxo(1, -txtw*9, 10); /*puts('-=+ trans'); )*/ (putc($'-');putc($'=');putc($'+');putc($' ');putc($'t');putc($'r');putc($'a');putc($'n');putc($'s');); )
:( pp.pxo(1, -txtw*7, 10); /*puts('+ trans'); );*/ (putc($'+');putc($' ');putc($'t');putc($'r');putc($'a');putc($'n');putc($'s');); );
sidechain ?( pp.pxo(1, -txtw*9, 10); /*puts('sidechain'); );*/ (putc($'s');putc($'i');putc($'d');putc($'e');putc($'c');putc($'h');putc($'a');putc($'i');putc($'n');); );
env2slim ?( pp.pxo(1, -txtw*11, 10); /*puts('s-lim curve'); );*/ (putc($'s');putc($'-');putc($'l');putc($'i');putc($'m');putc($' ');putc($'c');putc($'u');putc($'r');putc($'v');putc($'e');); );
invert ?( pp.pxo(1, -txtw*6, 10); /*puts('invert'); );*/ (putc($'i');putc($'n');putc($'v');putc($'e');putc($'r');putc($'t');); );
unlimit && ! crunchcrvon ?( pp.pxo(1, -txtw*9, 10); /*puts('UNlimited'); ); */ (putc($'U');putc($'N');putc($'l');putc($'i');putc($'m');putc($'i');putc($'t');putc($'e');putc($'d');); ); 
abmorph ?( pp.pxo(1, -txtw*9, 10); /*puts('A/B morph'); );*/ (putc($'A');putc($'/');putc($'B');putc($' ');putc($'m');putc($'o');putc($'r');putc($'p');putc($'h');); );

// a in/outgain bars
zhtxta.hue();
pp.plineo(0, 0, whacka0.ingaindb/maxigain, 0, 0, -2, 0, -2);
pp.plineo(0, 0, 0, whacka0.outgaindb/maxogain, 2, 0, 2, 0);
doabtr ?(
  // b in/outgain bars
  zhtxtb.hue();
  pp.plineo(0, 0, whackb0.ingaindb/maxigain, 0, 0, 2, 0, 2);
  pp.plineo(0, 0, 0, whackb0.outgaindb/maxogain, -2, 0, -2, 0);
);

// edit/options text
dbgraph ?(
  zhtxta.hue(); gfx_a= .3;
  pp.pxyo(0, 0, -2-txtw*5, txth+2 ); putn(gdbmin, 0); /*puts('dB');*/ (putc($'d');putc($'B'););
);

// resize panes for actual graphing
gsz -= 10;
gyo+= 5;
gxo+= 5;
pp.paneini(gxo, gyo, gsz, gsz, -1, -1, 1, 1);
ppc.paneini(gxo, gyo, gsz, gsz, 0, 0, 1, 1);

// grid lines
zhax.hue(); gfx_a= .2;
dbgraph ?(
  gii= -6; while (
    gjj= gii/gdbmin;
    pp.pline(-1, -gjj, 1, -gjj); // x axis
    pp.pline(-gjj, -1, -gjj, 1); // y axis
    pp.pline(-1, gjj, 1, gjj); // x axis
    pp.pline(gjj, -1, gjj, 1); // y axis
    (gii-= 6) > gdbmin;
  );
):(
  gii= -6; while (
    gjj= exp(gii * db2log);
    pp.pline(-1, -gjj, 1, -gjj); // x axis
    pp.pline(-gjj, -1, -gjj, 1); // y axis
    pp.pline(-1, gjj, 1, gjj); // x axis
    pp.pline(gjj, -1, gjj, 1); // y axis
    (gii-= 6) >= -30;
  );
);

// recreate shape graphs if nec
gdirty || (gforce-= 1) < 0 ?(
  abc.gcurveinit(gsz); abc.gcurvemake();
  gwhacka.ga.gshapeinit(gsz, gdbmin); gwhacka.ga.gshapemake(); 
  gwhackb.gb.gshapeinit(gsz, gdbmin); gwhackb.gb.gshapemake(); 
  genvdone && doabtr && abmorph ?(
    gwhacka.whackpush(); gwhackb.whackpush();
    gwhackab.whackmix( abcurve.invcurve( abmorphval ) );
    gwhackab.ingain= gwhackab.outgain= 1;
    gwhackab.gab.gshapeinit(gsz, gdbmin); gwhackab.gab.gshapemake();
  ); 
  gforce= 15;
);

//@ envelope/transience graph
gfx_w != oldgfx_w || gdirty ?( //figure num of 1/30sec @gfx cycles/screen
    esnapskip= (gfx_w * esnapavgcnt / (srate*.0333)) | 0; 
    esnapskip < 1 ? esnapskip= 1; 
);
! doabtr || abmorph || !trans || !esnapavgcnt || gfx_w != oldgfx_w || gfx_h != oldgfx_h ?(
  zhfxbg.hue();
  gfx_x= 0; gfx_y= graphyx; gfx_rectto(gfx_w+1, gfx_h+1);
  oldgfx_w= gfx_w; oldgfx_h= gfx_h;
);

gdirty= 0; //no longer ref'd; allows dirty= 1 below

doabtr && ! abmorph ?(
  gpenvg= 1;
  // draw env curves
  doab ?(
    adb < bdb ? pph.paneini(gxo, gyo, gsz, gsz, adb, 0, bdb, gsz)
              : pph.paneini(gxo, gyo, gsz, gsz, bdb, 0, adb, gsz);
  ):(
    pph.paneini(gxo, gyo, gsz, gsz, adb, 0, envtbdb, gsz);
    ppht.paneini(gxo, gyo, gsz, gsz, 0, 0, envtrng, gsz);
  );
  jj0= ehistndx-gsz; jj0 < 0 ? jj0+= ehistmax; 
  trans ?(
    // peak transience max
    gii= gsz-1; gjj= jj0;
    gpenvg ? hueset(.80, .73, .98, 0) : hueset(.8, .75, .7, 0); //hueset(.65, .55, .9, 0) : hueset(.8, .75, .7, 0);
        //gpenvg ? hueset(.75, .65, .95, 0) : hueset(.8, .75, .7, 0); //hueset(.65, .55, .9, 0) : hueset(.8, .75, .7, 0);
    //trans > 0 ? hueset(.65, .75, .6, 0);
    while (
      doab ?(
        gxx= (doab?ehistenv[gjj]:0) + ehistenvtmax[gjj]; //envgax && gxx > (pph.x0+1.2*pph.xx) ? gxx= (pph.x0+1.2*pph.xx);
        pph.plinetoaa(gxx, gii);
      ):(
        gxx= (doab?ehistenv[gjj]:0) + ehistenvtmax[gjj]; //envgax && gxx > (ppht.x0+1.2*ppht.xx) ? gxx= (ppht.x0+1.2*ppht.xx);
        ppht.plinetoaa(gxx, gii);
      );
      gfx_a= gpenvg ? .3 : .65; gfx_a= gfx_a + (1-gfx_a)*envgax;
      (gjj+= 1) >= ehistmax ? gjj= 0;
      (gii-= 1) >= 0;
    );
    // peak transience min
    //doab || bptrans == 2 ?(
      gii= gsz-1; gjj= jj0;
      gpenvg ? hueset(.65, .8, .85, 0) : hueset(.8, .75, .7, 0);
          //gpenvg ? hueset(.795, .65, .95, 0) : hueset(.8, .75, .7, 0);
      //trans > 0 ? hueset(.65, .75, .6, 0);
      while (
        doab ?(
          gxx= (doab?ehistenv[gjj]:0) + ehistenvtmin[gjj]; //envgax && gxx > (pph.x0+1.2*pph.xx) ? gxx= (pph.x0+1.2*pph.xx);
          pph.plinetoaa(gxx, gii);
        ):(
          gxx= (doab?ehistenv[gjj]:0) + ehistenvtmin[gjj]; //envgax && gxx > (ppht.x0+1.2*ppht.xx) ? gxx= (ppht.x0+1.2*ppht.xx);
          ppht.plinetoaa(gxx, gii);
        );
        gfx_a= gpenvg ? .3 : .65; gfx_a= gfx_a + (1-gfx_a)*envgax;
        (gjj+= 1) >= ehistmax ? gjj= 0;
        (gii-= 1) >= 0;
      );
    //);
  );
  // main response envelope
  gii= gsz-1; gjj= jj0;
  gpenvg ?( trans ? hueset(.8, .78, .73, 0) : hueset(.75, .75, .75, 0); ) : hueset(.6, .7, .8, 0);
      //gpenvg ?( trans ? hueset(.75, .7, .65, 0) : hueset(.7, .7, .7, 0); ) : hueset(.6, .7, .8, 0);
  while (
    gxx= ehistenv[gjj]; //envgax && gxx > (pph.x0+1.2*pph.xx) ? gxx= (pph.x0+1.2*pph.xx);
    pph.plinetoaa(//gii, 
      gxx, gii);
    gfx_a= gpenvg ?( trans ? .45 : .5 ) : .45; gfx_a= gfx_a + (1-gfx_a)*envgax;
    (gjj+= 1) >= ehistmax ? gjj= 0;
    (gii-= 1) >= 0;
  );
  // envt snapshots
  esnapavgcnt && trans ?( //&& (envtfadecnt-= 1) <= 0 ?( envtfadecnt= 2;
    esnapthx ?( 
      //search back for prev transient above thresh
      gjj0= gjj= esnapndx;
      while (
        gjj-= 1; gjj < 0 ? gjj= esnapmax-1;
        gjj != gjj0 && (doab?esnapenv1[gjj]:0)+esnapenvt[gjj] < esnapth;
      );
      gjj != gjj0 ?(
        gjj1= gjj;
        gjj+= 1;
        while (
          gjj-= 1; gjj < 0 ? gjj= esnapmax-1;
          gjj != gjj0 && (doab?esnapenv1[gjj]:0)+esnapenvt[gjj] >= esnapth - 3;
        );
      );
      estrig= gjj != gjj0
        && (gjj != gjj1st 
            || (esnapndx < gjj ? esnapndx <= gjj-gfx_w*esnapavgcnt : esnapndx < gjj+esnapmax-gfx_w*esnapavgcnt));
                // don't trigger close to wraparound of circular buf: avoids visible eob
      estrig && gjj != gjj1st ?(
        gjj1st= gjj;
        gxx= 0; gyy= 0; loop ( 16, //average a few env spls to figure rough gain for wave snap
          gyy+= -esnapenvt0[gjj1]; gxx+= exp(-esnapenvt0[gjj1] * db2log); gjj1-= 23; gjj1 < 0 ? gjj1 += esnapmax; );
        gsplgain= gxx * .015625; //== 1/16 * .25;
        gsplgaindb0= gyy*.0625*.5;
        gsplgaindb= .5/gsplgaindb0;
      );
    ): estrig= 0;
    estrig || ((esnapskipcnt-= 1) <= 0) ?(
      esnapskipcnt= esnapskip;
      //blank or fade
      zhfxbg.hue(); gfx_a= estrig ? 1 : .02;
      gfx_x= 0; gfx_y= graphyx; gfx_rectto(gfx_w+1, gfx_h+1);
      estrig ?( gjj0= gjj - gfx_w*esnapavgcnt*.4; gjj= gfx_w*.4; ) //srate*.005*esnapavgcnt
             : gjj0= esnapndx-(gfx_w*esnapavgcnt); 
      gjj0 < 0 ? gjj0+= esnapmax;
      estrig ?(
        hueset(.8,.8,.8,1); ppt.pline(gjj, ppt.y0, gjj, ppt.y0+ppt.yx);
        ppt.pxyo( ppt.x0+ppt.xx, ppt.y0, -7*txtw, fonth); 
        putn( gfx_w*esnapavgcnt/srate*1000, 0); /*puts('ms');*/ (putc($'m');putc($'s'););
        //wave snapshot
        ppx.paneini(0, graphyx, gfx_w, gfx_h-graphyx, 0, 0, gfx_w, 1 ); //abrng*(gfx_w-(gxo+1.2*gsz))/gsz, gsz, 0, 0 );
        gii= 0; gjj= gjj0; 
        loop( gfx_w, 
          gyy= 0; gee= 0; gtt= 0; loop ( esnapavgcnt, 
            gyy < esnapspl[gjj] ? gyy= esnapspl[gjj];
            gee+= esnapenv1[gjj];
            gtt+= esnapenvt0[gjj];
            (gjj+= 1) > esnapmax ? gjj= 0; 
          ); 
          gyy*= gsplgain;
          gee= 1 + (gsplgaindb0+gee*esnapavgcnti) * gsplgaindb;
          gtt= 1 + (gsplgaindb0+gtt*esnapavgcnti) * gsplgaindb;
          gii ?(
            hueset(.85, .70, .65, .5 + .5*envgax); ppx.plineaa( gii-1, gee0, gii, gee ); 
            hueset(.65, .8, .85, .5 + .5*envgax); ppx.plineaa( gii-1, gtt0, gii, gtt ); 
            hueset(.5, .5, .5, .5 + .5*envgax); ppx.plineaa( gii-1, gyy0, gii, gyy ); 
          );
          gyy0= gyy; gee0= gee; gtt0= gtt;
          gii+= 1; 
        );
      );
      //transient snapshot
      doab ? ppt.paneini(0, graphyx, gfx_w, gfx_h-graphyx, 0, 0, gfx_w, (gfx_h-graphyx)*abrng/gsz )
           : ppt.paneini(0, graphyx, gfx_w, gfx_h-graphyx, 0, 0, gfx_w, (gfx_h-graphyx)*envtrng/gsz );
      gpenvg ? hueset(.53, .42, 1, 0) : hueset(.9, .8, .85, 0);
      gii= 0; gjj= gjj0;
      loop( gfx_w, 
        gxx= 0; loop ( esnapavgcnt, 
          gxx+= esnapenvt[gjj]; //abs(esnapenvt[gjj]); 
          (gjj+= 1) > esnapmax ? gjj= 0; 
        ); 
        gxx*= esnapavgcnti;
        //gxx > ppt.x0 ? gxx= ppt.x0; //+ppt.xx ? gxx= ppt.x0+ppt.xx;
        ppt.plinetoaa( gii, bptrans<2?abs(gxx):gxx ); 
        gfx_a= gpenvg ? .5 : .8; gfx_a= gfx_a + (1-gfx_a)*envgax;
        gii+= 1; 
      );
    );
  );
);

// a/b curve graph
zhcrv.hue();
doabtr ? abc.gcurvedraw();

! genvdone ?(
  doabtr ?(
    gwhacka.whackpush(); gwhackb.whackpush();
    gwhackab.whackmix( genv3 );
    gwhackab.ingain= gwhackab.outgain= 1;
    gwhackab.gab.gshapeinit(gsz, gdbmin); gwhackab.gab.gshapemake();
  );
  // peak bar
  dbgraph ? envmaxx = ( max(log(envmax) * log2db, gdbmin)-gdbmin )/-gdbmin
          : envmaxx = envmax;
  envmaxx > 1 ? envmaxx= 1.001;	
  zhpeakbar.hue();
  pp.plineo( -envmaxx, -1, envmaxx, -1, 0, -4, 0, -4);
  envmaxx <= 1 ?(
    zhpeak.hue();
    pp.plineo(-envmaxx, -1, -envmaxx, -1, 0, -5, 0, -3);
    pp.plineo(-envmaxx, -1, -envmaxx, -1, -1, -4, 2, -4);
    pp.plineo(envmaxx, -1, envmaxx, -1, 0, -5, 0, -3);
    pp.plineo(envmaxx, -1, envmaxx, -1, -2, -4, 1, -4);
    gfx_a= .32;
    pp.precto(-envmaxx, -1, -envmaxx, -1, -1, -6, 2, -3);
    pp.precto(envmaxx, -1, envmaxx, -1, -1, -6, 2, -3);
  );
  doabtr ?( 
    // morphed shape
    zhab.hue(); gwhackab.gab.gshapedraw();
    // env curve ticks
    zhebar.hue();
    ppc.plineo(genv0, 0, genv1, 0, 0, -1, 0, -1); //trans bar
    zhetick.hue();
    ppc.pdia(genv1, 0, 0, -1);
    zhebar.hue(); 
    ppc.pdia(genv1, genv2x, 0, 0);
    zhebar2.hue();
    ppc.pline(0, genv2, 0, genv2x); //unlimited out line
    zhetick.hue();
    ppc.pdia(0, genv2, 0, 0);
  );
  envmaxx <= 1 ?( // peak shape ticks
    zhpeakbar.hue();
    envmaxy= (doabtr?gwhackab.whack(-envmax,0):gwhacka.whack(-envmax,0));
    stack_pop();
    crunchcrvon ? envmaxy= crunchcrv.curvelimit(envmaxy); // * crunchcomp; 
    dbgraph ? envmaxy = -(max( log(-envmaxy) * log2db, gdbmin )-gdbmin)/-gdbmin;
    pp.pline(-envmaxx, -envmaxx, -envmaxx, envmaxy); // line from x==x
    zhpeak2.hue();
    pp.plineo(-envmaxx, envmaxy, -envmaxx, envmaxy, 0, -5, 0, 4); // peak shape tick
    envmaxy*100 | 0 != -envmaxx*100 | 0 ?(
      envmaxy < -envmaxx 
        ?( pp.plineo(-envmaxx, envmaxy, -envmaxx, envmaxy, -1, -4, 1, -4); // peak crosstick
          gfx_a= .32; pp.precto(-envmaxx, envmaxy, -envmaxx, envmaxy, -1, -3, 2, -6); )
        :( pp.plineo(-envmaxx, envmaxy, -envmaxx, envmaxy, -1, 3, 1, 3);
          gfx_a= .32; pp.precto(-envmaxx, envmaxy, -envmaxx, envmaxy, -1, 1, 2, 4); );
    );
    zhpeakbar.hue();
    envmaxy= (doabtr?gwhackab.whack(envmax,0):gwhacka.whack(envmax,0));
    stack_pop();
    crunchcrvon ? envmaxy= crunchcrv.curvelimit(envmaxy); // * crunchcomp; 
    dbgraph ? envmaxy = (max( log(envmaxy) * log2db, gdbmin )-gdbmin)/-gdbmin;
    pp.pline(envmaxx, envmaxx, envmaxx, envmaxy); // line from x==x
    zhpeak2.hue();
    pp.plineo(envmaxx, envmaxy, envmaxx, envmaxy, 0, -4, 0, 5); // peak shape tick
    envmaxy*100 | 0 != envmaxx*100 | 0 ?(
      envmaxy < envmaxx 
        ?( pp.plineo(envmaxx, envmaxy, envmaxx, envmaxy, -1, -3, 1, -3); // peak crosstick
          gfx_a= .32; pp.precto(envmaxx, envmaxy, envmaxx, envmaxy, -1, -2, 2, -5); )
        :( pp.plineo(envmaxx, envmaxy, envmaxx, envmaxy, -1, 4, 1, 4);
          gfx_a= .32; pp.precto(envmaxx, envmaxy, envmaxx, envmaxy, -1, 2, 2, 5); );
    );
  );
  genvdone= 1;
  genvdonecnt= 0;
):(
  //if @sample disabled; duplicates !genvdone/@sample code:
  (genvdonecnt+= 1) > 3 ?( 
    redoslmunge ? slmunge();
    doslmunge1 ?( 
      newwhackpre ?( 
        ! sfadeout ? sfadeout= sfademax= (srate * .1) | 0;
      ):(
        slmunge1();
        newwhack ?(
          whacka0.whackpush(); whacka.whackpop();
          whackb0.whackpush(); whackb.whackpop(); 
          newwhack= 0;
        );
        doslmunge1= 0;
      );
    );
    doabtr && abmorph ?( zhab.hue(); gwhackab.gab.gshapedraw(); );
  );
);

doabtr ?( zhb.hue(); gwhackb.gb.gshapedraw(); );

zha.hue(); gwhacka.ga.gshapedraw();

); // /gfx mouse

hueset(.79,.79,.79,1);
gfx_x = gfx_w-32; gfx_y= graphyx-fonth;
/*puts('pv');*/                                   (putc($'p');putc($'v'););
putn(readserial,0);

/*  copyright 2013 dan mcmullen bang@bangzero.org

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. 
*/
