desc:PC70 [sound module] (GFX Lab)
//tags: instrument rompler sound module piano epiano strings pad bass drums split
//author: JGWizrad / Garden FX (GFX)
//
// Requires gfx-lab-drift, gfx-lab-output, gfx-lab-ui, gfx-lab-panel, gfx-lab-instrument, gfx-lab-voice, gfx-lab-dyn, gfx-lab-faceplate
// (.jsfx-inc) in the same folder.
//
// A late-90s sound module: pick a patch, play it. 90 patches in ten groups, all synthesised (no samples):
//   the Lab80 sounds (synthetic pianos, FM and chorus e-pianos, clav, drawbar organ, bells and glass,
//   the LA guitars, pads, choirs, brass, leads and basses) together with the pick of the PC70 GM voices,
//   and a drum kit on the GM drum map.
// EDIT        TONE (tone, filter, resonance), FILTER ENVELOPE (amount, A D S R) and AMP ENVELOPE (A D S R) move the
//             patch from where it stands (centre = the patch as made); choosing a patch puts them back. The filter
//             envelope works on the analogue and GM-style patches (piano, bells, plucks, organ and drums have none).
// PLAY        VELOCITY, TUNE, BEND range and the MIDI channel. Mod wheel adds vibrato; sustain pedal works.
// MOD RACK    the GFX Mod Rack inside: TREMOLO, CHORUS, VIBE and DELAY, each with L / C / R outputs and tempo SYNC.
// REVERB      the GFX Space engine (ROOM / HALL / PLATE).
//             Every patch carries its own Mod Rack and reverb settings.
// SPLIT       a bass part under the left hand: keys below the split point play one of the twelve basses (patches
//             76 - 87) with its own OCTAVE and LEVEL, keys from the split point up play the patch. The bass is dry: the
//             patch's EDIT knobs, Mod Rack and reverb stay with the patch. Set the split by clicking the keyboard
//             picture or with LEARN (the next key played). SPLIT off = every key plays the patch.
// DRIFT (0 - 100 %, 50 % = standard): two dials, BASS DRIFT and MAIN DRIFT, each moving its own part on its own -
//             the tuning wanders a little, every note lands slightly differently in pitch and brightness.
// MIDI        program change 0 - 89 picks the patch; pitch bend, CC1, CC64, CC120 / 123.

import gfx-lab-drift.jsfx-inc
import gfx-lab-output.jsfx-inc
import gfx-lab-ui.jsfx-inc
import gfx-lab-panel.jsfx-inc
import gfx-lab-instrument.jsfx-inc
import gfx-lab-voice.jsfx-inc
import gfx-lab-dyn.jsfx-inc
import gfx-lab-faceplate.jsfx-inc

slider1:0<0,89,1>-Patch
slider2:0<-24,6,0.1>-Volume (dB)
slider3:1<0,1,1{Off,On}>-Split
slider4:0<0,16,1>-MIDI channel (0 = omni)
slider5:50<0,100,1>-Tone (%)
slider6:0<-6,3,0.01>-Filter (octaves)
slider7:0<0,100,1>-Resonance (%)
slider8:100<10,400,1>-Attack (%)
slider9:100<10,400,1>-Release (%)
slider10:48<24,84,1>-Split point (note)
slider11:70<0,100,1>-Velocity (%)
slider12:0<-50,50,1>-Tune (cents)
slider13:2<0,12,1>-Bend range (st)
slider14:1<0,2,1{Room,Hall,Plate}>-Reverb type
slider15:15<0,150,1>-Reverb pre-delay (ms)
slider16:2.2<0.2,10,0.01>-Reverb decay (s)
slider17:50<0,100,1>-Reverb damping (%)
slider18:25<0,100,1>-Reverb mix (%)
slider19:0.8<0.05,8,0.01>-FX chorus rate (Hz)
slider20:50<0,100,1>-FX chorus depth (%)
slider21:0<0,100,1>-FX chorus mix (%)
slider22:8<0,11,1{Bass Synth,Sub Bass,Acid Bass,Round Bass,Pluck Bass,Hollow Bass,Reese Bass,Acoustic Bass,Finger Bass,Synth Bass 1,Synth Bass 2,Synth Bass 3}>-Bass sound
slider23:5<0,7,1{Off,L,C,L+C,R,L+R,C+R,L+C+R}>-FX chorus outputs
slider24:20<20,500,1>-Mono below (Hz, 20 = off)
slider25:0<0,100,1>-Stereo width (%)
slider26:0<0,3,1{Off,Straight,Dotted,Triplet}>-FX chorus sync
slider27:2<0,7,1{4 Bars,2 Bars,1 Bar,1/2,1/4,1/8,1/16,1/32}>-FX chorus sync rate
slider28:4<0.1,15,0.01>-FX tremolo rate (Hz)
slider29:0<0,100,1>-FX tremolo depth (%)
slider30:0<-2,2,1>-Bass octave
slider31:5<0,7,1{Off,L,C,L+C,R,L+R,C+R,L+C+R}>-FX tremolo outputs
slider32:0<-24,6,0.1>-Bass level (dB)
slider33:50<0,100,1>-Bass drift (%)
slider34:0<0,3,1{Off,Straight,Dotted,Triplet}>-FX tremolo sync
slider35:5<0,7,1{4 Bars,2 Bars,1 Bar,1/2,1/4,1/8,1/16,1/32}>-FX tremolo sync rate
slider36:1.5<0.1,12,0.01>-FX vibe rate (Hz)
slider37:0<0,100,1>-FX vibe depth (%)
slider38:50<0,100,1>-Main drift (%)
slider39:5<0,7,1{Off,L,C,L+C,R,L+R,C+R,L+C+R}>-FX vibe outputs
slider42:0<0,3,1{Off,Straight,Dotted,Triplet}>-FX vibe sync
slider43:4<0,7,1{4 Bars,2 Bars,1 Bar,1/2,1/4,1/8,1/16,1/32}>-FX vibe sync rate
slider44:350<20,1500,1>-FX delay time (ms)
slider45:30<0,95,1>-FX delay feedback (%)
slider46:0<0,100,1>-FX delay mix (%)
slider48:5<0,7,1{Off,L,C,L+C,R,L+R,C+R,L+C+R}>-FX delay outputs
slider51:0<0,3,1{Off,Straight,Dotted,Triplet}>-FX delay sync
slider52:4<0,7,1{4 Bars,2 Bars,1 Bar,1/2,1/4,1/8,1/16,1/32}>-FX delay sync rate
slider53:100<10,400,1>-Amp decay (%)
slider54:0<-100,100,1>-Amp sustain (+/-)
slider55:100<0,200,1>-Filter envelope amount (%)
slider56:100<10,400,1>-Filter attack (%)
slider57:100<10,400,1>-Filter decay (%)
slider58:0<-100,100,1>-Filter sustain (+/-)
slider59:100<10,400,1>-Filter release (%)
slider60:0<0,100,1>-Band sat (%)
slider61:30<0,100,1>-Bias (%)
slider62:120<40,400,1>-Sat low band (Hz)
slider63:6000<2000,16000,10>-Sat high band (Hz)
slider64:-0.3<-24,0,0.1>-Ceiling (dB)

in_pin:none
out_pin:left output
out_pin:right output

@init
fl_ok = 0;
#ui_man = "gfx-lab-g-pc70";
NV = 16; VS = 172; NB = 4;     // 16 voices for the patch, then 4 for the SPLIT bass (VB + (NV + k) * VS)
VB = 1000;                       // voice blocks: VB + v * VS (the GM voices use VB + v * VS + 100 ..)
// field offsets
F_N = 0; F_G = 1; F_S = 2; F_ACT = 3; F_AGE = 4; F_VEL = 5; F_F0 = 6; F_AE = 7; F_AST = 8; F_FE = 9; F_FST = 10;
F_P1 = 11; F_P2 = 12; F_P3 = 13; F_S1 = 14; F_S2 = 15; F_S3 = 16; F_S4 = 17;
F_O1 = 18; F_O2 = 19; F_O3 = 20; F_O4 = 21; F_E1 = 22; F_E2 = 23; F_E3 = 24; F_E4 = 25; F_VT = 26;
F_MS = 27; F_MC = 31; F_MA = 35; F_MD = 39; F_MWS = 43; F_MWC = 47; F_CLK = 51;
F_DCO = 64; F_DCF = 65; F_PY = 66; F_ATK = 67; F_PY2 = 68;   // de-click: offset, flag, last two outputs, fade-in
F_PE = 69; F_HN = 70; F_HL = 71;                              // pitch envelope, hammer / click noise state
P_MS = 72; P_MC = 88; P_MA = 104; P_MD = 120; P_WS = 136; P_WC = 152;   // 16 partials (piano, organ)
F_KW = 55; F_KL = 56; F_KLP = 57; F_KAP = 58; F_KG = 59; F_KPO = 60; F_KHP = 61; F_KX = 62; F_DT = 63;
KSB = 117000 + ceil(1.45 * srate); KSL = 4096;   // string / pluck delay lines, one per voice (above the reverb at any rate)
evq = 4000;                      // MIDI event queue
cbuf = 8192; cmask = 8191;       // chorus delay line
PG = 70000;                      // GM voice programs: 46 x 16
PT = 72000;                      // patches: 90 x 64 (kind, index, chorus, trim, reverb x 3, Mod Rack x 34, group)
MR = KSB + (NV + NB) * KSL + 64;        // Mod Rack lines
NP = 90;
memset(VB, 0, (NV + NB) * VS); memset(KSB, 0, (NV + NB) * KSL); memset(cbuf, 0, 8192);
age = 0; pedal = 0; modw = 0; cwp = 0; cps = 0; cpf = 0; mono_n = -1; mono_f = 0; bend_t = 0; bend_m = 1;

function svf_set(f, q) instance(a1, a2, a3, k) local(g) (
  g = tan($pi * min(f, srate * 0.45) / srate); k = 1 / q;
  a1 = 1 / (1 + g * (g + k)); a2 = g * a1; a3 = g * a2;
);
function svf_bp(x) instance(a1, a2, a3, k, ic1, ic2) local(v1, v2, v3) (
  v3 = x - ic2; v1 = a1 * ic1 + a2 * v3; v2 = ic2 + a2 * ic1 + a3 * v3;
  ic1 = 2 * v1 - ic1; ic2 = 2 * v2 - ic2;
  v1;
);
function tanh_(x) local(e) ( x = min(max(x, -20), 20); e = exp(2 * x); (e - 1) / (e + 1) );
function blep(t, dt) (
  t < dt ? ( t /= dt; t + t - t * t - 1; ) : t > 1 - dt ? ( t = (t - 1) / dt; t * t + t + t + 1; ) : 0;
);
function saw(p, dt) ( 2 * p - 1 - blep(p, dt) );
function sqw(p, dt) local(q) ( q = p + 0.5; q >= 1 ? q -= 1; (p < 0.5 ? 1 : -1) + blep(p, dt) - blep(q, dt) );
function tc(t) ( exp(-1 / (max(t, 0.0005) * srate)) );

// ---------- the sounds: settings used when a key is struck ----------
function patch_set(s) (
  snd = s;
  eng = s == 0 || s == 25 ? 1 : s == 1 ? 2 : s == 2 ? 3 : s == 24 || s == 38 ? 4 : s == 34 ? 5 : 0;
  // 0 analogue, 1 FM, 2 plucked string, 3 metal bar, 4 synthetic piano, 5 drawbar organ
  // analogue defaults
  o2w = 0; det = 0.006; subl = 0; o2l = 1; fbase = 1200; famt = 1.5; fres = 0.2; ktrk = 0.5;
  aA = 0.01; aD = 0.5; aS = 0.8; aR = 0.4; fA = 0.01; fD = 0.6; fS = 0.3; vib = 0; vibd = 0.4; mono = 0; glide = 0;
  chor = 0.3; three = 0; flfo = 0; lvl = 0.5;
  // layers (off by default): bell partials, plucked string, breath + chiff, osc 1 sine, formant "aah"
  bl_lvl = 0; bR0 = 1; bR1 = 2; bR2 = 3; bR3 = 4; bA0 = 1; bA1 = 0.5; bA2 = 0.3; bA3 = 0.15; bD0 = 1; bD1 = 0.5; bD2 = 0.25; bD3 = 0.12;
  ks_lvl = 0; ks_T = 1; ks_br = 0.4; ks_pick = 0; br_lvl = 0; chf = 0; o1w = 0; vamix = 1; form = 0;
  // extras: pitch envelope (semitones, s), velocity to filter, echo (mix, beats, feedback), tremolo, chorus rate,
  // rhythmic loop layer, piano brightness / decay / unison, organ percussion
  pe_amt = 0; pe_t = 0.1; vf = 0; brp = 0; dl_mix = 0; dl_bt = 0.75; dl_fb = 0.35; trem = 0; crate = 0.6; nd = 0;
  pn_hard = 0.6; pn_T = 1; pn_uni = 1; pn_knock = 1; pn_ch = 0.3; org_perc = 0;
  s == 3 ? ( det = 0.009; fbase = 700; famt = 1.6; fres = 0.25; aA = 0.6; aD = 1; aS = 0.85; aR = 1.6; fA = 1.2; fD = 2; fS = 0.5; chor = 0.6; lvl = 0.3; ) :
  s == 4 ? ( det = 0.004; subl = 0.6; o2l = 0.5; fbase = 420; famt = 0.8; fres = 0.12; aA = 0.9; aD = 1; aS = 0.9; aR = 2.2; fA = 1.5; fD = 2; fS = 0.6; chor = 0.9; flfo = 0.35; lvl = 0.32; ) :
  s == 5 ? ( det = 0.003; o2w = 1; o2l = 0.5; subl = 0.8; fbase = 140; famt = 3.2; fres = 0.45; ktrk = 0.3; aA = 0.002; aD = 0.5; aS = 0.75; aR = 0.12; fA = 0.001; fD = 0.28; fS = 0.15; mono = 1; glide = 0.04; chor = 0; lvl = 0.55; ) :
  s == 6 ? ( det = 0.005; fbase = 2200; famt = 0.6; fres = 0.1; ktrk = 0.8; aA = 0.35; aD = 1; aS = 0.9; aR = 0.8; fA = 0.4; fD = 1; fS = 0.7; vib = 5.3; vibd = 0.5; chor = 0.4; lvl = 0.3; ) :
  s == 7 ? ( det = 0.002; fbase = 4500; famt = 0.3; fres = 0.05; ktrk = 0.6; aA = 0.06; aD = 1; aS = 1; aR = 0.9; fA = 0.05; fD = 1; fS = 0.8; chor = 0.55; three = 1; lvl = 0.28; ) :
  s == 8 ? (   // BELL PAD
    det = 0.008; fbase = 800; famt = 1; fres = 0.15; aA = 0.8; aD = 1; aS = 0.85; aR = 2.2; fA = 1; fD = 2; fS = 0.5; chor = 0.9; lvl = 0.3;
    bl_lvl = 0.5; bR0 = 1; bR1 = 3.52; bR2 = 6.01; bR3 = 8.93; bA0 = 1; bA1 = 0.5; bA2 = 0.3; bA3 = 0.15; bD0 = 2.4; bD1 = 1; bD2 = 0.5; bD3 = 0.25;
  ) : s == 9 ? (   // STACCATO CHOIR
    det = 0.006; fbase = 1600; famt = 0.5; fres = 0.1; aA = 0.015; aD = 0.35; aS = 0.45; aR = 0.45; fA = 0.02; fD = 0.4; fS = 0.5; form = 1; chor = 0.8; lvl = 0.12;
    bl_lvl = 0.35; bR0 = 2; bR1 = 4.1; bR2 = 6.8; bR3 = 9.6; bA0 = 1; bA1 = 0.5; bA2 = 0.3; bA3 = 0.15; bD0 = 0.5; bD1 = 0.3; bD2 = 0.2; bD3 = 0.12;
  ) : s == 10 ? (  // PIZZ BELLS
    vamix = 0; aA = 0.001; aD = 0.2; aS = 0; aR = 0.1; chor = 0.5; lvl = 0.6;
    ks_lvl = 1; ks_T = 0.35; ks_br = 0.5; ks_pick = 0;
    bl_lvl = 0.4; bR0 = 1; bR1 = 4; bR2 = 7.2; bR3 = 10.1; bA0 = 1; bA1 = 0.4; bA2 = 0.2; bA3 = 0.1; bD0 = 0.9; bD1 = 0.4; bD2 = 0.2; bD3 = 0.1;
  ) : s == 11 ? (  // GLASS CHOIR
    det = 0.007; fbase = 1300; famt = 0.4; fres = 0.08; aA = 0.7; aD = 1; aS = 0.9; aR = 1.8; fA = 0.8; fD = 1; fS = 0.8; form = 1; br_lvl = 0.12;
    vib = 4.8; vibd = 0.45; chor = 1; lvl = 0.1;
  ) : s == 12 ? (  // NYLON HAZE
    vamix = 0.55; det = 0.007; fbase = 600; famt = 0.6; fres = 0.1; aA = 1.4; aD = 1; aS = 0.9; aR = 2; fA = 1.5; fD = 2; fS = 0.7; chor = 0.8; lvl = 0.34;
    ks_lvl = 1.6; ks_T = 2.2; ks_br = 0.35; ks_pick = 0;
  ) : s == 13 ? (  // SYNTH BRASS
    det = 0.004; fbase = 280; famt = 2.8; fres = 0.15; aA = 0.03; aD = 0.3; aS = 0.85; aR = 0.25; fA = 0.09; fD = 0.55; fS = 0.45; chor = 0.35; lvl = 0.38;
  ) : s == 14 ? (  // CRYSTAL HARP
    vamix = 0.35; det = 0.006; fbase = 4000; famt = 0.2; fres = 0.05; aA = 0.5; aD = 1; aS = 0.8; aR = 1.8; fA = 0.5; fD = 1; fS = 0.8; chor = 1; lvl = 0.32;
    bl_lvl = 0.55; bR0 = 1; bR1 = 2.005; bR2 = 4.02; bR3 = 7.13; bA0 = 1; bA1 = 0.45; bA2 = 0.3; bA3 = 0.12; bD0 = 3; bD1 = 1.6; bD2 = 0.8; bD3 = 0.3;
  ) : s == 15 ? (  // SUB BASS: pure sine
    o1w = 1; o2l = 0; det = 0; fbase = 400; famt = 0.3; fres = 0; ktrk = 0.5; aA = 0.003; aD = 0.5; aS = 0.9; aR = 0.12; fA = 0.001; fD = 0.3; fS = 0.5;
    mono = 1; glide = 0.03; chor = 0; lvl = 0.9;
  ) : s == 16 ? (  // ACID BASS: resonant saw, snappy envelope, slides
    o2l = 0; det = 0; fbase = 180; famt = 3.6; fres = 0.82; ktrk = 0.4; fA = 0.001; fD = 0.18; fS = 0.05; aA = 0.002; aD = 0.4; aS = 0.8; aR = 0.08;
    mono = 1; glide = 0.06; chor = 0; lvl = 0.6;
  ) : s == 17 ? (  // ROUND BASS: saw + square + sub
    det = 0.004; o2w = 1; o2l = 0.7; subl = 0.6; fbase = 220; famt = 1.8; fres = 0.3; fA = 0.001; fD = 0.35; fS = 0.25; aA = 0.002; aD = 0.6; aS = 0.85; aR = 0.1;
    mono = 1; glide = 0.02; chor = 0; lvl = 0.5;
  ) : s == 18 ? (  // PLUCK BASS: short and punchy, polyphonic
    det = 0.003; o2l = 0.6; subl = 0.5; fbase = 160; famt = 3; fres = 0.25; fA = 0.001; fD = 0.12; fS = 0; aA = 0.001; aD = 0.35; aS = 0; aR = 0.1;
    chor = 0; lvl = 0.6;
  ) : s == 19 ? (  // HOLLOW BASS: sine + square
    o1w = 1; o2w = 1; o2l = 1; det = 0; fbase = 600; famt = 0.8; fres = 0.1; fA = 0.001; fD = 0.4; fS = 0.4; aA = 0.002; aD = 0.5; aS = 0.8; aR = 0.1;
    mono = 1; glide = 0.03; chor = 0; lvl = 0.55;
  ) : s == 20 ? (  // REESE BASS: wide detuned saws
    det = 0.018; o2l = 1; subl = 0.4; fbase = 350; famt = 0.5; fres = 0.2; fA = 0.01; fD = 1; fS = 0.8; aA = 0.005; aD = 1; aS = 0.95; aR = 0.15;
    mono = 1; glide = 0.03; chor = 0.2; lvl = 0.5;
  ) : s == 21 ? (  // NATIVE DANCE: a tempo-synced log-drum loop riding a dark resonant sweep
    det = 0.006; fbase = 300; famt = 1.2; fres = 0.55; ktrk = 0.4; aA = 0.4; aD = 1; aS = 0.9; aR = 1.5; fA = 2.5; fD = 3; fS = 0.6; flfo = 0.5;
    chor = 0.6; lvl = 0.26; vamix = 0.7; nd = 1; bl_lvl = 0.9; chf = 0.0; dl_mix = 0.25; dl_bt = 0.75; dl_fb = 0.4;
  ) : s == 22 ? (  // CALLIOPE LEAD: a pipe (sine + a little square an octave up), pitched breath, a short chiff, vibrato
    o1w = 1; o2w = 1; o2l = 0.22; det = 0; fbase = 2200; famt = 0.3; fres = 0.05; ktrk = 0.7; aA = 0.04; aD = 1; aS = 0.95; aR = 0.25; fA = 0.05; fD = 1; fS = 0.9;
    br_lvl = 0.1; brp = 1; chf = 0.12; vib = 5.6; vibd = 0.7; chor = 0.5; lvl = 0.42; dl_mix = 0.18; dl_bt = 0.5; dl_fb = 0.3;
  ) : s == 23 ? (  // SOUNDTRACK PAD: a chime over a slow, warm sweep, with echo
    det = 0.007; subl = 0.3; fbase = 500; famt = 1.4; fres = 0.18; aA = 1.2; aD = 1; aS = 0.9; aR = 2.6; fA = 3; fD = 3; fS = 0.5; flfo = 0.3; chor = 1; lvl = 0.28;
    bl_lvl = 0.45; bR0 = 2; bR1 = 5.03; bR2 = 8.1; bR3 = 11.7; bA0 = 1; bA1 = 0.4; bA2 = 0.25; bA3 = 0.12; bD0 = 2; bD1 = 1; bD2 = 0.5; bD3 = 0.3;
    dl_mix = 0.25; dl_bt = 1; dl_fb = 0.4;
  ) : s == 24 ? (  // SESSION PIANO: warm and even
    pn_hard = 0.55; pn_T = 1; pn_uni = 1; pn_knock = 1; chor = 0.25; lvl = 0.5;
  ) : s == 25 ? (  // CHORUS EP: the FM tine piano with tremolo and a deep chorus
    chor = 0.9; trem = 0.25; lvl = 1;
  ) : s == 26 ? (  // DARK VOX: a low, slow "ooh" choir
    det = 0.006; fbase = 900; famt = 0.4; fres = 0.08; aA = 0.9; aD = 1; aS = 0.95; aR = 1.6; fA = 1; fD = 1; fS = 0.8; form = 2; br_lvl = 0.06;
    vib = 4.6; vibd = 0.35; chor = 0.9; lvl = 0.13;
  ) : s == 27 ? (  // FANTASY VOX: a bright "aah" with a glassy chime on the front
    det = 0.007; fbase = 1800; famt = 0.5; fres = 0.08; aA = 0.5; aD = 1; aS = 0.9; aR = 1.8; fA = 0.6; fD = 1; fS = 0.8; form = 1; br_lvl = 0.08;
    vib = 5; vibd = 0.4; chor = 1; lvl = 0.11;
    bl_lvl = 0.35; bR0 = 2; bR1 = 4.01; bR2 = 6.02; bR3 = 8.97; bA0 = 1; bA1 = 0.45; bA2 = 0.3; bA3 = 0.15; bD0 = 1.6; bD1 = 0.9; bD2 = 0.5; bD3 = 0.25;
  ) : s == 28 ? (  // SPACED VOX: airy "eh" voices, slow filter drift, long echo
    det = 0.008; fbase = 1500; famt = 0.3; fres = 0.1; aA = 1.2; aD = 1; aS = 0.95; aR = 2.4; fA = 1.4; fD = 1; fS = 0.9; form = 3; br_lvl = 0.14; flfo = 0.4;
    vib = 4.4; vibd = 0.3; chor = 1.2; lvl = 0.11; dl_mix = 0.3; dl_bt = 1.5; dl_fb = 0.45;
  ) : s == 29 ? (  // VELO STAB: playing harder opens it right up
    det = 0.008; o2l = 1; subl = 0.3; fbase = 260; famt = 4; fres = 0.35; ktrk = 0.5; aA = 0.002; aD = 0.35; aS = 0; aR = 0.2; fA = 0.001; fD = 0.22; fS = 0;
    vf = 1; chor = 0.4; lvl = 0.5;
  ) : s == 30 ? (  // HOOVER: wide saws and pulses that scoop up into the note
    det = 0.022; o2w = 1; o2l = 0.8; subl = 0.5; fbase = 1400; famt = 1; fres = 0.15; aA = 0.005; aD = 1; aS = 0.95; aR = 0.3; fA = 0.01; fD = 0.6; fS = 0.6;
    pe_amt = -7; pe_t = 0.12; mono = 1; glide = 0.08; chor = 1.2; lvl = 0.36;
  ) : s == 31 ? (  // FAT STRINGS: thick saws into the ensemble
    det = 0.009; subl = 0.25; fbase = 2600; famt = 0.5; fres = 0.08; ktrk = 0.6; aA = 0.25; aD = 1; aS = 1; aR = 1; fA = 0.3; fD = 1; fS = 0.8;
    chor = 0.8; three = 1; lvl = 0.26;
  ) : s == 32 ? (  // ORCHESTRA HIT: a big octave stab that drops in pitch
    det = 0.01; o2w = 1; o2l = 0.8; subl = 0.9; fbase = 1800; famt = 2; fres = 0.1; aA = 0.002; aD = 0.32; aS = 0; aR = 0.25; fA = 0.001; fD = 0.25; fS = 0;
    pe_amt = 3; pe_t = 0.05; chf = 0.9; chor = 0.5; lvl = 0.5;
    bl_lvl = 0.4; bR0 = 1; bR1 = 2; bR2 = 3; bR3 = 4.02; bA0 = 1; bA1 = 0.7; bA2 = 0.5; bA3 = 0.3; bD0 = 0.35; bD1 = 0.25; bD2 = 0.18; bD3 = 0.12;
  ) : s == 33 ? (  // BRASS SECTION: swelling filter, a little rise into the note, delayed vibrato
    det = 0.006; o2l = 0.9; fbase = 330; famt = 2.6; fres = 0.12; aA = 0.06; aD = 0.6; aS = 0.85; aR = 0.3; fA = 0.12; fD = 0.8; fS = 0.55;
    pe_amt = -0.6; pe_t = 0.06; vib = 5.2; vibd = 0.3; vf = 0.5; chor = 0.4; lvl = 0.36;
  ) : s == 34 ? (  // DRAWBAR ORGAN: 888 with third-harmonic percussion, fast rotary
    org_perc = 0.5; chor = 0.7; crate = 6.2; lvl = 0.3;
  ) : s == 35 ? (  // PAN FLUTE: sine with its breath tuned to the note, a soft chiff, vibrato
    o1w = 1; o2l = 0; det = 0; fbase = 3000; famt = 0.3; fres = 0; aA = 0.08; aD = 1; aS = 0.9; aR = 0.35; fA = 0.1; fD = 1; fS = 0.9;
    br_lvl = 0.16; brp = 1; chf = 0.15; vib = 5.2; vibd = 0.5; chor = 0.4; lvl = 0.5;
  ) : s == 36 ? (  // HARP: a long, round pluck
    vamix = 0; aA = 0.001; aD = 0.2; aS = 0; aR = 0.6; chor = 0.35; lvl = 0.7;
    ks_lvl = 1; ks_T = 3.2; ks_br = 0.3; ks_pick = 0;
  ) : s == 37 ? (  // SQUARE LEAD: two squares an octave apart, glide
    o1w = 2; o2w = 1; o2l = 0.5; det = 0.003; fbase = 2400; famt = 0.8; fres = 0.15; ktrk = 0.6; aA = 0.005; aD = 0.5; aS = 0.9; aR = 0.2; fA = 0.005; fD = 0.5; fS = 0.7;
    vib = 5.5; vibd = 0.5; mono = 1; glide = 0.05; chor = 0.3; lvl = 0.3; dl_mix = 0.15; dl_bt = 0.75; dl_fb = 0.3;
  ) : s == 38 ? (  // BRIGHT PIANO: harder hammers, more shimmer
    pn_hard = 0.85; pn_T = 0.85; pn_uni = 1.6; pn_knock = 1.3; chor = 0.45; lvl = 0.42;
  ) : s == 39 ? (  // LA NYLON: a round pluck with a soft pick, over a quiet sine body that swells in
    o1w = 1; o2l = 0; det = 0; fbase = 900; famt = 0.3; fres = 0; aA = 0.35; aD = 2; aS = 0.5; aR = 0.6; fA = 0.3; fD = 1; fS = 0.8;
    vamix = 0.18; chf = 0.08; chor = 0.45; lvl = 0.6;
    ks_lvl = 1.1; ks_T = 2.6; ks_br = 0.32; ks_pick = 0;
  ) : s == 40 ? (  // LA STEEL: a bright steel-string pick with a shimmering synth body
    det = 0.004; o2l = 0.5; fbase = 1500; famt = 0.6; fres = 0.05; aA = 0.25; aD = 2; aS = 0.4; aR = 0.7; fA = 0.2; fD = 1.5; fS = 0.5;
    vamix = 0.12; chf = 0.14; chor = 0.7; lvl = 0.5;
    ks_lvl = 1; ks_T = 3.2; ks_br = 0.78; ks_pick = 0;
  ) : s == 41 ? (  // LA CLEAN: a chorused electric (pickup near the bridge), with echo
    o1w = 1; o2l = 0; det = 0; fbase = 1200; famt = 0.2; fres = 0; aA = 0.2; aD = 2; aS = 0.4; aR = 0.5; fA = 0.2; fD = 1; fS = 0.7;
    vamix = 0.1; chf = 0.06; chor = 1; lvl = 0.55; dl_mix = 0.2; dl_bt = 0.75; dl_fb = 0.3;
    ks_lvl = 1; ks_T = 2.4; ks_br = 0.55; ks_pick = 1;
  ) : s == 42 ? (  // LA HARMONICS: glassy string harmonics over a soft pluck, with echo
    vamix = 0; aA = 0.001; aD = 0.2; aS = 0; aR = 0.8; chor = 0.7; lvl = 0.55; dl_mix = 0.25; dl_bt = 0.75; dl_fb = 0.4;
    ks_lvl = 0.5; ks_T = 1.8; ks_br = 0.45; ks_pick = 0;
    bl_lvl = 0.55; bR0 = 2; bR1 = 3; bR2 = 4; bR3 = 6; bA0 = 1; bA1 = 0.45; bA2 = 0.3; bA3 = 0.12; bD0 = 2.2; bD1 = 1.4; bD2 = 0.9; bD3 = 0.4;
  );
  // LA retunes: closer to the classic layered presets
  s == 9 ? ( dl_mix = 0.3; dl_bt = 0.75; dl_fb = 0.4; );                       // STACCATO GLASS: its echo
  s == 10 ? ( ks_br = 0.65; bl_lvl = 0.3; dl_mix = 0.12; dl_bt = 0.5; dl_fb = 0.25; );   // PIZZ FLOW: brighter pluck
  s == 12 ? ( dl_mix = 0.15; dl_bt = 1; dl_fb = 0.3; );                         // NYLON ATMOS
  // the choir's vowels
  form == 1 ? ( fA1.svf_set(730, 5); fA2.svf_set(1090, 7); fA3.svf_set(2440, 9); ) :
  form == 2 ? ( fA1.svf_set(320, 5); fA2.svf_set(800, 6); fA3.svf_set(2300, 8); ) :
  form == 3 ? ( fA1.svf_set(530, 5); fA2.svf_set(1840, 7); fA3.svf_set(2480, 9); );
);

// ---------- plucked string: set up and run (clav and the pluck layers) ----------
function ks_setup(v, b, f0, vg, h, Ts, bright, pick) local(L, x, j, rr, x2_) (
  L = srate / f0;
  b[F_KL] = L; b[F_KW] = floor(L); b[F_KLP] = 0; b[F_KAP] = 0; b[F_KHP] = 0; b[F_KX] = 0; b[F_O3] = 1;
  b[F_KG] = 10 ^ (-3 / (Ts * f0));
  b[F_KPO] = pick ? max(floor(L * 0.13), 1) : 0;
  x = 0; x2_ = 0; j = 0;
  loop(min(ceil(L) + 2, KSL),
    rr = rand(2) - 1; x += (rr - x) * (bright * (0.3 + 0.7 * h));   // softer pluck when played gently
    x2_ += (x - x2_) * 0.6;
    KSB[v * KSL + j] = x2_ * vg * 0.45 * sin($pi * min(j / L, 1)) * (j < L * 0.5 ? 1 : 0.7);
    j += 1;
  );
);
function ks_tick(av, b, pick, bite) local(lc_, L, Li, fr, w_, ofs, rp, sv, ac, ap, lpv, gk, pq, y) (
  lc_ = 0.72 + 0.26 * tone;                                   // loop brightness
  L = b[F_KL] / pdrift - (1 - lc_) / lc_;                     // minus the loop filter delay
  Li = floor(L); fr = L - Li; fr < 0.1 ? ( Li -= 1; fr += 1; );
  w_ = b[F_KW]; ofs = av * KSL;
  rp = w_ - Li; rp < 0 ? rp += KSL;
  sv = KSB[ofs + rp];
  ac = (1 - fr) / (1 + fr);                                   // fractional delay (first-order allpass)
  ap = ac * sv + b[F_KX] - ac * b[F_KAP];
  b[F_KX] = sv; b[F_KAP] = ap;
  lpv = b[F_KLP] + (ap - b[F_KLP]) * lc_;
  b[F_KLP] = lpv;
  gk = held ? b[F_KG] : b[F_KG] * ks_rd;                     // the damper: a fast stop when the key lifts (RELEASE)
  KSB[ofs + w_] = lpv * gk;
  b[F_KW] = (w_ + 1) % KSL;
  pick ? ( pq = w_ - b[F_KPO]; pq < 0 ? pq += KSL; y = sv - KSB[ofs + pq]; ) : y = sv;
  b[F_KHP] += (y - b[F_KHP]) * 0.02; y -= b[F_KHP];
  y = bite ? tanh_(y * 1.5) * 3.5 : y * 2.2;
  b[F_O3] = b[F_O3] * 0.9995 + abs(y) * 0.0005;              // level tracker
  y;
);
// bell partials (glockenspiel and the bell layers)
function bell_set(b, f0, vg, h, ratio, amp, dk, k) local(w) (
  w = 2 * $pi * min(f0 * ratio, srate * 0.45) / srate;
  b[F_MS + k] = 0; b[F_MC + k] = 1; b[F_MWS + k] = sin(w); b[F_MWC + k] = cos(w);
  b[F_MA + k] = f0 * ratio < srate * 0.45 ? amp : 0; b[F_MD + k] = tc(dk);
);
function bell_tick(b, rel) local(k, s_, y) (
  k = 0; y = 0; bell_amp = 0;
  loop(4,
    s_ = b[F_MS + k] * b[F_MWC + k] + b[F_MC + k] * b[F_MWS + k];
    b[F_MC + k] = b[F_MC + k] * b[F_MWC + k] - b[F_MS + k] * b[F_MWS + k];
    b[F_MS + k] = s_;
    b[F_MA + k] *= b[F_MD + k] * rel;
    y += s_ * b[F_MA + k]; bell_amp += b[F_MA + k];
    k += 1;
  );
  y;
);

// 16-partial bank (synthetic piano, drawbar organ)
function pn_set(b, k, f, amp, T) local(w) (
  w = 2 * $pi * min(f, srate * 0.45) / srate;
  b[P_MS + k] = 0; b[P_MC + k] = 1; b[P_WS + k] = sin(w); b[P_WC + k] = cos(w);
  b[P_MA + k] = f < srate * 0.45 ? amp : 0; b[P_MD + k] = T > 0 ? tc(T) : 1;
);
function pn_tick(b, rel) local(k, s_, y) (
  k = 0; y = 0; pn_amp = 0;
  loop(16,
    b[P_MA + k] > 0.00001 ? (
      s_ = b[P_MS + k] * b[P_WC + k] + b[P_MC + k] * b[P_WS + k];
      b[P_MC + k] = b[P_MC + k] * b[P_WC + k] - b[P_MS + k] * b[P_WS + k];
      b[P_MS + k] = s_;
      b[P_MA + k] *= b[P_MD + k] * rel;
      y += s_ * b[P_MA + k]; pn_amp += b[P_MA + k];
    );
    k += 1;
  );
  y;
);
// the oscillator pairs drift in amplitude after many cycles: renormalise once a block
function pn_norm(b) local(k, m) (
  k = 0; loop(16, m = sqrt(sqr(b[P_MS + k]) + sqr(b[P_MC + k])); m > 0 ? ( b[P_MS + k] /= m; b[P_MC + k] /= m; ); k += 1; );
);

// ---------- voices ----------
function vfree() local(v, best, ba) (
  best = -1; v = 0;
  loop(NV, best < 0 && !VB[v * VS + F_ACT] ? best = v; v += 1; );
  best < 0 ? ( ba = 1000000000; v = 0; loop(NV, (VB[v * VS + F_AGE] + (VB[v * VS + F_G] ? 100000000 : 0)) < ba ? ( ba = VB[v * VS + F_AGE] + (VB[v * VS + F_G] ? 100000000 : 0); best = v; ); v += 1; ); );
  best;
);

function pg(i, a, b, c, d, e, f, g, h, k, l, m, n, o, p, q, r) local(z) (
  z = PG + i*16;
  z[0] = a; z[1] = b; z[2] = c; z[3] = d; z[4] = e; z[5] = f; z[6] = g; z[7] = h;
  z[8] = k; z[9] = l; z[10] = m; z[11] = n; z[12] = o; z[13] = p; z[14] = q; z[15] = r;
);
// ---------- the GM voices (type, octave, cutoff, resonance, filter env, key track, A, D, S, R,
//            detune 2nd osc, p1, p2, p3, vibrato, level) and their names ----------
pg(0, 4, 0, 5000, 0.1, 0.5, 0.5, 1, 3000, 0.1, 600, 0, 1, 1.6, 400, 0, 0.5);
strcpy(200 + 0, "E.Piano1");
pg(1, 4, 0, 8000, 0.1, 1.5, 0.5, 1, 2500, 0.05, 500, 0, 14, 1.2, 300, 0, 0.5);
strcpy(200 + 1, "E.Piano2");
pg(2, 5, 0, 6000, 0.2, 1.5, 0.5, 1, 1500, 0, 300, 0, 0.5, 0, 0.996, 0, 4.5);
strcpy(200 + 2, "Harpsi.");
pg(3, 3, 0, 1800, 0.4, 2, 0.5, 1, 500, 0, 100, 0, 0.15, 0, 300, 0, 0);
strcpy(200 + 3, "Clavi.");
pg(4, 4, 12, 9000, 0.1, 1.5, 0.5, 1, 1500, 0, 500, 0, 3.5, 1.5, 200, 0, 1);
strcpy(200 + 4, "Celesta");
pg(5, 4, 12, 9000, 0.1, 1.5, 0.5, 1, 1200, 0, 600, 0, 5, 1.2, 150, 0, 1.5);
strcpy(200 + 5, "MusicBox");
pg(6, 4, 0, 8000, 0.1, 1.5, 0.5, 1, 3000, 0, 900, 0, 4, 0.8, 300, 0, -0.5);
strcpy(200 + 6, "Vibes");
pg(7, 4, 0, 6000, 0.1, 1.5, 0.5, 1, 500, 0, 200, 0, 4, 1.5, 60, 0, 4.5);
strcpy(200 + 7, "Marimba");
pg(8, 4, 12, 9000, 0.1, 1.5, 0.5, 1, 350, 0, 150, 0, 3, 2, 40, 0, 4.5);
strcpy(200 + 8, "Xylophon");
pg(9, 4, 0, 9000, 0.1, 1.5, 0.5, 1, 5000, 0, 1500, 0, 3.5, 2.5, 900, 0, -3.5);
strcpy(200 + 9, "TubulBel");
pg(10, 5, 0, 7000, 0.1, 1.5, 0.5, 1, 2000, 0, 500, 0, 0.5, 0, 0.998, 0, 4.5);
strcpy(200 + 10, "Dulcimer");
pg(11, 5, 0, 3000, 0.1, 0.5, 0.5, 1, 3000, 0, 250, 0, 0.5, 0, 0.995, 0, 7.5);
strcpy(200 + 11, "NylonGtr");
pg(12, 5, 0, 5000, 0.1, 0.5, 0.5, 1, 3000, 0, 250, 0, 0.5, 0, 0.997, 0, 6);
strcpy(200 + 12, "SteelGtr");
pg(13, 5, 0, 5000, 0.1, 0.5, 0.5, 1, 300, 0, 250, 0, 0.5, 0, 0.985, 0, 7);
strcpy(200 + 13, "Mute.Gtr");
pg(14, 8, 0, 2500, 0.3, 1, 0.5, 2, 2000, 0.6, 200, 6, 0.5, 0, 300, 0, 2);
strcpy(200 + 14, "Ovrdrive");
pg(15, 1, -12, 1200, 0.2, 0.5, 0.5, 1, 1500, 0.2, 150, 0, 0.5, 0, 300, 0, 1.5);
strcpy(200 + 15, "Aco.Bass");
pg(16, 4, -12, 1500, 0.2, 1.5, 0.5, 1, 800, 0.5, 150, 0, 1, 1.2, 300, 0, 0.5);
strcpy(200 + 16, "FngrBass");
pg(17, 2, -12, 500, 0.6, 3, 0.5, 1, 300, 0.3, 150, 0, 0.5, 0, 300, 0, 5.5);
strcpy(200 + 17, "SynBass1");
pg(18, 3, -12, 700, 0.5, 2.5, 0.5, 1, 350, 0.4, 150, 0, 0.3, 0, 300, 0, -0.5);
strcpy(200 + 18, "SynBass2");
pg(19, 2, -24, 500, 0.15, 2.2, 0.6, 40, 600, 0.75, 180, 0, 0.5, 0, 300, 5, 0);
strcpy(200 + 19, "SynBass3");
pg(20, 8, 0, 3500, 0.05, 0.3, 0.5, 80, 500, 1, 500, 4, 0.5, 0, 300, 14, 0.5);
strcpy(200 + 20, "Violin");
pg(21, 8, 0, 2800, 0.05, 0.3, 0.5, 90, 500, 1, 500, 4, 0.5, 0, 300, 12, 1);
strcpy(200 + 21, "Viola");
pg(22, 8, -12, 2200, 0.05, 0.3, 0.5, 90, 500, 1, 500, 4, 0.5, 0, 300, 10, -2);
strcpy(200 + 22, "Cello");
pg(23, 8, 0, 3500, 0.05, 0.3, 0.5, 180, 500, 1, 500, 7, 0.5, 0, 300, 6, 2.5);
strcpy(200 + 23, "Strings1");
pg(24, 8, 0, 4500, 0.05, 0.3, 0.5, 150, 500, 1, 500, 12, 0.5, 0, 300, 0, 1.5);
strcpy(200 + 24, "Syn Str1");
pg(25, 3, 0, 1300, 0.2, 1, 0.5, 30, 400, 0.8, 120, 0, 0.5, 0, 300, 8, -3.5);
strcpy(200 + 25, "SynReed");
pg(26, 0, 12, 6000, 0, 0, 0.5, 60, 300, 0.9, 150, 0, 0.5, 0, 300, 10, -3.5);
strcpy(200 + 26, "Whistle");
pg(27, 1, 0, 6000, 0, 0, 0.5, 60, 300, 0.9, 150, 0, 0.5, 0.05, 300, 4, 0);
strcpy(200 + 27, "Ocarina");
pg(28, 3, 0, 4000, 0.25, 1, 0.5, 3, 500, 0.8, 150, 0, 0.5, 0, 300, 8, -4.5);
strcpy(200 + 28, "SquareLd");
pg(29, 2, 0, 4000, 0.25, 1, 0.5, 3, 500, 0.8, 150, 6, 0.5, 0, 300, 8, 1.5);
strcpy(200 + 29, "Saw.Lead");
pg(30, 1, 0, 4000, 0.25, 1, 0.5, 3, 500, 0.8, 150, 0, 0.5, 0.1, 300, 8, 0.5);
strcpy(200 + 30, "CaliopLd");
pg(31, 3, 0, 4000, 0.25, 2, 0.5, 3, 200, 0.6, 150, 0, 0.3, 0, 300, 8, -1.5);
strcpy(200 + 31, "Chiff Ld");
pg(32, 8, 0, 3000, 0.5, 1, 0.5, 3, 500, 0.8, 150, 10, 0.5, 0, 300, 8, 1.5);
strcpy(200 + 32, "CharanLd");
pg(33, 1, 0, 1800, 0.35, 0.2, 0.5, 40, 500, 1, 600, 8, 0.5, 0, 300, 10, 1.5);
strcpy(200 + 33, "Voice Ld");
pg(34, 2, 0, 4000, 0.25, 1, 0.5, 3, 500, 0.8, 150, 702, 0.5, 0, 300, 8, -1);
strcpy(200 + 34, "Fifth Ld");
pg(35, 2, -12, 1500, 0.4, 1, 0.5, 3, 500, 0.8, 150, 1200, 0.5, 0, 300, 8, -1);
strcpy(200 + 35, "Bass &Ld");
pg(36, 8, 0, 2400, 0.15, 1.5, 0.5, 40, 1500, 1, 1500, 9, 0.5, 0, 300, 0, 0.5);
strcpy(200 + 36, "PolySyPd");
pg(37, 1, 0, 1300, 0.35, 0.2, 0.5, 600, 500, 1, 1500, 8, 0.5, 0, 300, 10, 5.5);
strcpy(200 + 37, "ChoirPad");
pg(38, 3, 0, 1500, 0.15, 0.5, 0.5, 800, 1500, 1, 1500, 9, 0.4, 0, 300, 0, 4);
strcpy(200 + 38, "BowedPad");
pg(39, 4, 0, 6000, 0.15, 0.5, 0.5, 600, 1500, 1, 1500, 9, 3.5, 1.5, 3000, 0, 0);
strcpy(200 + 39, "MetalPad");
pg(40, 8, 0, 900, 0.6, 3, 0.5, 1500, 4000, 0.4, 1500, 9, 0.5, 0, 300, 0, 12);
strcpy(200 + 40, "SweepPad");
pg(41, 5, 0, 5000, 0.1, 1.5, 0.5, 1, 2500, 0, 400, 0, 0.5, 0, 0.996, 0, 4.5);
strcpy(200 + 41, "Koto");
pg(42, 4, 0, 6000, 0.1, 1.5, 0.5, 1, 900, 0, 300, 0, 4.5, 1.2, 80, 0, 4);
strcpy(200 + 42, "Kalimba");
pg(43, 4, 12, 9000, 0.1, 1.5, 0.5, 1, 1500, 0, 500, 0, 5.4, 1.5, 400, 0, 1.5);
strcpy(200 + 43, "TnklBell");
pg(44, 4, 12, 6000, 0.1, 1.5, 0.5, 1, 400, 0, 200, 0, 2.3, 2, 80, 0, 5.5);
strcpy(200 + 44, "Agogo");
pg(45, 4, 12, 5000, 0.1, 1.5, 0.5, 1, 120, 0, 80, 0, 3.1, 3, 20, 0, 7);
strcpy(200 + 45, "WoodBlok");

function ms2c(ms) ( exp(-1/(max(ms, 0.1)*0.001*srate)); );
function dset(b, f, pe, pt, td, ta, na, nd_, nf, hp, lv) local(g, k) (
  b[42] = f; b[43] = pe; b[44] = ms2c(pt); b[45] = ms2c(td); b[8] = ta; b[46] = na; b[47] = ms2c(nd_); b[48] = hp;
  g = tan($pi*min(nf, srate*0.45)/srate); k = hp ? 1.4 : 0.9;
  b[20] = k; b[50] = 1/(1 + g*(g + k)); b[51] = g*b[50]; b[52] = g*b[51];
  b[38] = 1; b[39] = 1; b[40] = 1; b[62] *= lv;
);
function drum_setup(b, n) (
  n == 35 || n == 36 ? dset(b, 50, 2.2, 35, 320, 1, 0.08, 15, 3000, 0, 1.1) :
  n == 37 ? dset(b, 420, 0.3, 5, 40, 0.6, 0.4, 30, 2500, 0, 0.7) :
  n == 38 ? dset(b, 190, 0.5, 15, 110, 0.5, 0.75, 170, 3500, 1, 0.9) :
  n == 40 ? dset(b, 210, 0.5, 12, 90, 0.4, 0.85, 150, 5000, 1, 0.9) :
  n == 39 ? dset(b, 0, 0, 1, 1, 0, 1, 160, 1200, 0, 1) :
  n == 42 ? dset(b, 0, 0, 1, 1, 0, 0.6, 45, 8000, 1, 0.6) :
  n == 44 ? dset(b, 0, 0, 1, 1, 0, 0.55, 65, 7500, 1, 0.5) :
  n == 46 ? dset(b, 0, 0, 1, 1, 0, 0.55, 380, 7500, 1, 0.55) :
  n == 41 || n == 43 || n == 45 || n == 47 || n == 48 || n == 50 ?
    dset(b, n == 41 ? 80 : n == 43 ? 95 : n == 45 ? 110 : n == 47 ? 135 : n == 48 ? 155 : 180, 0.5, 60, 350, 1, 0.08, 40, 2000, 0, 0.9) :
  n == 49 || n == 57 || n == 52 ? dset(b, 0, 0, 1, 1, 0, 0.5, 1300, 5500, 1, 0.55) :
  n == 55 ? dset(b, 0, 0, 1, 1, 0, 0.5, 600, 6500, 1, 0.5) :
  n == 51 || n == 59 ? dset(b, 3100, 0, 1, 900, 0.12, 0.3, 1100, 7000, 1, 0.55) :
  n == 53 ? dset(b, 2300, 0, 1, 700, 0.5, 0.15, 600, 6000, 1, 0.55) :
  n == 54 ? dset(b, 0, 0, 1, 1, 0, 0.5, 160, 9000, 1, 0.5) :
  n == 56 ? dset(b, 560, 0, 1, 250, 0.6, 0.1, 80, 800, 0, 0.6) :
  n >= 60 && n <= 64 ? dset(b, n == 60 ? 300 : n == 61 ? 220 : n == 62 ? 200 : n == 63 ? 170 : 140, 0.3, 20, 180, 1, 0.1, 30, 2000, 0, 0.8) :
  n == 69 || n == 70 ? dset(b, 0, 0, 1, 1, 0, 0.45, 70, 7000, 1, 0.45) :
  n == 75 ? dset(b, 2500, 0, 1, 60, 0.8, 0, 1, 1000, 0, 0.6) :
  n == 76 || n == 77 ? dset(b, n == 76 ? 1700 : 1300, 0, 1, 70, 0.8, 0.05, 20, 2000, 0, 0.6) :
  dset(b, 600, 0.2, 10, 80, 0.4, 0.4, 60, 3000, 0, 0.5);
);

// one GM voice or drum on its own block (pb = the voice block + 100): set up at the key
// the GM voices' amp and filter envelopes, from the patch and the EDIT knobs (at note-on and while a note plays)
function p_env(pb, q) (
  pb[28] = 1/max(1, max(q[6]*atk_k + max(0, atk_k - 1)*150, 1)*0.001*srate); pb[29] = 1 - exp(-4.6/(max(q[7]*dec_k, 1)*0.001*srate));
  pb[30] = min(max(q[8] + sus_o, 0), 1); pb[31] = 1 - exp(-4.6/(max(q[9]*rel_k, 1)*0.001*srate));
  pb[5] = 1/max(1, max(q[6]*fatk_k + max(0, fatk_k - 1)*150, 1)*0.001*srate); pb[6] = 1 - exp(-4.6/(max(q[7]*fdec_k, 1)*0.001*srate));
  pb[7] = min(max(q[8] + fsus_o, 0), 1); pb[9] = 1 - exp(-4.6/(max(q[9]*frel_k, 1)*0.001*srate));
);
function p_on(v, b, n, vg) local(pb, q, at, de, re, f, len, j, lp, k) (
  pb = b + 100;
  memset(pb, 0, 64);
  pb[3] = n; pb[37] = (rand(2) - 1)*drift*3;            // drift: a tiny tuning scatter per note
  eng == 7 ? (
    n == 42 || n == 44 ? ( k = 0; loop(NV, VB[k*VS + F_ACT] && VB[k*VS + 103] == 46 ? ( VB[k*VS + F_ACT] = 0; VB[k*VS + 100] = 0; ); k += 1; ); );   // hats choke the open hat
    pb[49] = -1; pb[62] = vg*vg*1.6; pb[0] = 2; pb[1] = 1;
    drum_setup(pb, n);
  ) : (
    q = PG + gprog*16;
    pb[49] = q[0]; pb[10] = n;
    p_env(pb, q);                                       // the filter envelope starts as the patch's amp shape
    pb[55] = q[10] > 0 ? 2^(q[10]/1200) : 0; pb[56] = q[11]; pb[57] = q[12]; pb[58] = q[13];
    pb[59] = q[4]; pb[60] = q[5];
    pb[61] = min(max(q[2]*2^(fl_fo + fl_to), 30), srate*0.45);
    pb[20] = 2*(1 - min(max(q[3] + fl_rs*(0.95 - q[3]), 0), 0.95));
    pb[62] = vg*10^(q[15]/20)*0.5; pb[63] = q[14];
    pb[54] = q[12]; pb[53] = q[0] == 4 ? exp(-1/(max(q[13], 5)*0.001*srate)) : 1; pb[16] = q[12];
    pb[0] = 1; pb[1] = 0; pb[24] = 0; pb[22] = rand(1); pb[4] = 1; pb[2] = 0;
    q[0] == 5 ? (                                       // pluck: fill the line with a noise burst
      f = 440*2^((n + q[1] - 69)/12);
      len = min(max(floor(srate/f), 2), 4090); pb[26] = len; pb[25] = 0;
      lp = 0; j = 0; loop(len, lp += (rand(2) - 1 - lp)*min(1, q[2]/8000 + 0.2); KSB[v*KSL + j] = lp*2; j += 1; );
    );
  );
);
// the output filter's coefficients and the analogue voices' resonance, from the glided FILTER / RESONANCE
function fl_gf() (
  gf_g = tan($pi * min(18000 * 2 ^ fl_fo, srate * 0.45) / srate); gf_k = 2 - 1.9 * fl_rs;
  gf_a1 = 1 / (1 + gf_g * (gf_g + gf_k)); gf_a2 = gf_g * gf_a1; gf_a3 = gf_g * gf_a2;
  va_res = fres + fl_rs * (1.02 - fres);
);
// control rate (every 32 samples): pitch, vibrato, mod wheel, filter
function p_ctl(pb) local(q, vib, st, f, oct, g, k) (
  q = PG + gprog*16;
  p_env(pb, q);
  pb[22] += 5.5*32/srate; pb[22] -= floor(pb[22]);
  vib = sin(2*$pi*pb[22]);
  st = pb[10] + q[1] + (vib*(pb[63] + modw*50) + pb[37])/100;
  f = 440*2^((st - 69)/12)*tune*pdrift;
  pb[11] = min(f/srate, 0.45);
  pb[12] = pb[55] > 0 ? min(pb[11]*pb[55], 0.45) : 0;
  oct = (pb[59]*fl_fa + max(0, fl_fa - 1)*1.5)*(pb[2] - 1) + pb[60]*(pb[10] - 60)/12 + ins_cut;
  f = min(max(pb[61]*2^oct, 30), srate*0.45);
  g = tan($pi*f/srate); k = pb[20];
  pb[50] = 1/(1 + g*(g + k)); pb[51] = g*pb[50]; pb[52] = g*pb[51];
);
// one sample
function p_run(v, pb, held) local(t, y, ph, s, p2, nz, v1, v2, v3, k, a1, a2, a3, i0, i1, o) (
  y = 0;
  pb[49] < 0 ? (
    // drum
    pb[38] *= pb[44]; pb[39] *= pb[45]; pb[40] *= pb[47];
    pb[42] > 0 ? ( pb[13] += pb[42]*(1 + pb[43]*pb[38])/srate; pb[13] -= floor(pb[13]); y = sin(2*$pi*pb[13])*pb[39]*pb[8]; );
    pb[46] > 0 ? (
      nz = rand(2) - 1;
      k = pb[20]; a1 = pb[50]; a2 = pb[51]; a3 = pb[52];
      v3 = nz - pb[18]; v1 = a1*pb[17] + a2*v3; v2 = pb[18] + a2*pb[17] + a3*v3; pb[17] = 2*v1 - pb[17]; pb[18] = 2*v2 - pb[18];
      y += (pb[48] ? nz - k*v1 - v2 : k*v1)*pb[40]*pb[46];
    );
    pb[39] < 0.0001 && pb[40] < 0.0001 ? pb[0] = 0;
    y *= pb[62]*0.9;
  ) : (
    !held && pb[0] > 0 && pb[0] < 3 ? ( pb[0] = 3; pb[4] = 3; );
    pb[4] == 1 ? ( pb[2] += pb[5]; pb[2] >= 1 ? ( pb[2] = 1; pb[4] = 2; ); ) :
    pb[4] == 2 ? ( pb[2] += (pb[7] - pb[2])*pb[6]; ) :
    ( pb[2] += (0 - pb[2])*pb[9]; );
    pb[0] == 1 ? ( pb[1] += pb[28]; pb[1] >= 1 ? ( pb[1] = 1; pb[0] = 2; ); ) :
    pb[0] == 2 ? ( pb[1] += (pb[30] - pb[1])*pb[29]; ) :
    ( pb[1] += (0 - pb[1])*pb[31]; pb[1] < 0.0001 ? pb[0] = 0; );
    (pb[24] -= 1) <= 0 ? ( pb[24] = 32; p_ctl(pb); );
    t = pb[49];
    pb[13] += pb[11]; pb[13] -= floor(pb[13]); ph = pb[13];
    t == 0 ? ( y = sin(2*$pi*ph); pb[57] > 0 ? ( pb[27] += (rand(2) - 1 - pb[27])*0.3; y += pb[57]*pb[27]*2; ); ) :
    t == 1 ? ( y = 1 - 4*abs(ph - 0.5); pb[12] > 0 ? ( pb[14] += pb[12]; pb[14] -= floor(pb[14]); y = (y + 1 - 4*abs(pb[14] - 0.5))*0.6; ); ) :
    t == 2 || t == 8 ? (
      y = 2*ph - 1 - vo_blep(ph, pb[11]);
      pb[12] > 0 ? ( pb[14] += pb[12]; pb[14] -= floor(pb[14]); y = (y + 2*pb[14] - 1 - vo_blep(pb[14], pb[12]))*0.6; );
    ) :
    t == 3 ? (
      p2 = ph + 1 - pb[56]; p2 -= floor(p2);
      y = (2*ph - 1 - vo_blep(ph, pb[11])) - (2*p2 - 1 - vo_blep(p2, pb[11]));
      pb[12] > 0 ? ( pb[14] += pb[12]; pb[14] -= floor(pb[14]); p2 = pb[14] + 1 - pb[56]; p2 -= floor(p2);
                    y = (y + (2*pb[14] - 1 - vo_blep(pb[14], pb[12])) - (2*p2 - 1 - vo_blep(p2, pb[12])))*0.6; );
    ) :
    t == 4 ? (
      pb[15] += pb[11]*pb[56]; pb[15] -= floor(pb[15]);
      pb[16] = pb[16]*pb[53] + pb[54]*0.15*(1 - pb[53]);       // the index falls towards 15 % of its start
      y = sin(2*$pi*ph + pb[16]*sin(2*$pi*pb[15]));
    ) :
    t == 5 ? (
      o = KSB + v*KSL; i0 = pb[25]; i1 = i0 + 1; i1 >= pb[26] ? i1 = 0;
      y = o[i0]; o[i0] = (o[i0] + o[i1])*0.5*pb[58]; pb[25] = i1;
    ) :
    t == 6 ? ( y = rand(2) - 1; ) :
    t == 7 ? ( y = (sin(2*$pi*ph) + pb[56]*sin(4*$pi*ph) + pb[57]*sin(6*$pi*ph) + 0.35*sin(8*$pi*ph))*0.5; );
    // 12 dB state-variable low-pass
    a1 = pb[50]; a2 = pb[51]; a3 = pb[52];
    v3 = y - pb[18]; v1 = a1*pb[17] + a2*v3; v2 = pb[18] + a2*pb[17] + a3*v3; pb[17] = 2*v1 - pb[17]; pb[18] = 2*v2 - pb[18];
    y = v2*pb[1]*pb[62];
  );
  y;
);

function note_on(n, vel) local(v, b, f0, vg, h, Tn, j, k, L, x, rr, ratio, amp, dk, w, was, hd, Bc) (
  f0 = 440 * 2 ^ ((n - 69) / 12) * tune;
  vg = (1 - sens) + sens * (vel / 127) ^ 1.3;
  h = vel / 127;
  mono && eng == 0 ? (
    v = 0;                                   // mono: always voice 0, glide from the last note
    b = VB;
    b[F_DCF] = 1; !b[F_ACT] ? ( b[F_PY] = 0; b[F_PY2] = 0; b[F_DCO] = 0; ); b[F_ATK] = 1;
    mono_n >= 0 && b[F_ACT] && b[F_AE] > 0.01 ? ( b[F_F0] = f0; b[F_G] = 1; b[F_N] = n; b[F_VEL] = vg; mono_n = n; ) : (
      was = b[F_ACT];                        // still ringing: rise from where it is
      b[F_N] = n; b[F_G] = 1; b[F_S] = 0; b[F_ACT] = 1; b[F_VEL] = vg; b[F_F0] = f0; mono_f = f0;
      b[F_DT] = 1; b[F_VT] = 0; !was ? ( b[F_AE] = 0; b[F_FE] = 0; );
      b[F_AST] = 0; b[F_FST] = 0; mono_n = n;
    );
  ) : (
  // re-strike the same key on the same voice, else a free / old one
  v = -1; k = 0; loop(NV, VB[k * VS + F_N] == n && VB[k * VS + F_ACT] ? v = k; k += 1; );
  v < 0 ? v = vfree();
  b = VB + v * VS;
  age += 1; b[F_AGE] = age;
  was = b[F_ACT];                                          // re-struck / reused while still sounding?
  b[F_DCF] = 1; !was ? ( b[F_PY] = 0; b[F_PY2] = 0; b[F_DCO] = 0; );
  b[F_ATK] = eng == 0 && ks_lvl == 0 && bl_lvl == 0 ? 1 : 0;   // struck / plucked sounds get a short fade-in
  b[F_N] = n; b[F_G] = 1; b[F_S] = 0; b[F_ACT] = 1; b[F_VEL] = vg; b[F_F0] = f0;
  b[F_DT] = ins_note_detune();                              // each note slightly out (GFX drift)
  b[F_E1] = (rand(2) - 1) * drift * 0.35;                   // ... and slightly brighter / darker
  b[F_AST] = 0; b[F_FST] = 0; b[F_VT] = 0; !was ? b[F_FE] = 0;
  eng >= 6 ? (
    // the GM voices and the drum kit (the PC70 engine)
    p_on(v, b, n, vg);
    b[F_ATK] = eng == 7 ? 1 : 0;
  ) : eng == 0 ? (
    // a sounding voice keeps its oscillators and rises from where it is; a fresh one starts clean
    !was ? ( b[F_P1] = rand(1); b[F_P2] = rand(1); b[F_P3] = rand(1); b[F_AE] = 0; b[F_O1] = 0; b[F_O2] = 0; b[F_O3] = 0; );
    // attack / extra layers
    Tn = 2 ^ (-(n - 72) / 24) * dec_k;
    k = 0; loop(4, b[F_MA + k] = 0; k += 1; );
    bl_lvl > 0 && !nd ? (
      bell_set(b, f0, vg, h, bR0, vg * bl_lvl * bA0,              bD0 * Tn, 0);
      bell_set(b, f0, vg, h, bR1, vg * bl_lvl * bA1 * (0.5 + h), bD1 * Tn, 1);
      bell_set(b, f0, vg, h, bR2, vg * bl_lvl * bA2 * (0.4 + h), bD2 * Tn, 2);
      bell_set(b, f0, vg, h, bR3, vg * bl_lvl * bA3 * (0.3 + h), bD3 * Tn, 3);
    );
    ks_lvl > 0 ? ks_setup(v, b, f0, vg * ks_lvl, h, ks_T * 2 ^ (-(n - 60) / 24) * dec_k, ks_br, ks_pick);
    b[F_CLK] = chf * vg;
    b[F_PE] = pe_amt;
  ) : eng == 4 ? (
    // synthetic piano: stretched partials, two strings each (a quick prompt string and a slower, detuned
    // after-ring one); velocity sets the hammer: brightness, loudness, knock and how fast the top fades
    Tn = 7 * pn_T * 2 ^ (-(n - 40) / 17) * dec_k;
    hd = min(max(pn_hard * (0.15 + 1.15 * h ^ 1.2) + (tone - 0.5) * 0.5, 0.05), 1.15);
    vg = (1 - min(sens * 1.3, 1)) + min(sens * 1.3, 1) * h * h;     // a wider dynamic range than the synths
    Bc = 0.00025 * 2 ^ ((n - 60) / 20);
    k = 0;
    loop(8,
      j = k + 1;
      ratio = j * sqrt(1 + Bc * j * j);
      amp = vg * j ^ -0.85 * hd ^ ((j - 1) * 0.75) * (0.35 + 0.65 * abs(sin($pi * j * 0.13)) );
      dk = Tn / (1 + 0.45 * (j - 1) * (0.6 + 0.8 * h));
      pn_set(b, k * 2,     f0 * ratio,                                   amp * 0.72, dk * 0.42);
      pn_set(b, k * 2 + 1, f0 * ratio * 2 ^ ((0.9 + 0.5 * k) * pn_uni / 1200), amp * 0.38, dk * 1.5);
      k += 1;
    );
    b[F_CLK] = pn_knock * (0.05 + 0.3 * h * h) * vg;       // the hammer's knock
    b[F_HN] = 0; b[F_HL] = 0; b[F_AE] = 1;
  ) : eng == 5 ? (
    // drawbar organ: 16' 8' 5 1/3' 4' + a little 2 2/3' and 2', third-harmonic percussion on fresh chords
    k = 0;
    loop(9,
      ratio = k == 0 ? 0.5 : k == 1 ? 1 : k == 2 ? 1.5 : k == 3 ? 2 : k == 4 ? 3 : k == 5 ? 4 : k == 6 ? 5 : k == 7 ? 6 : 8;
      amp = k == 0 ? 0.8 : k == 1 ? 0.8 : k == 2 ? 0.8 : k == 3 ? 0.45 : k == 4 ? 0.25 : k == 5 ? 0.2 : 0.06;
      pn_set(b, k, f0 * ratio, amp * vg * 0.5, 0);
      k += 1;
    );
    pn_set(b, 9, f0 * 3, org_perc * (nact == 0 ? 1 : 0.3) * vg * 0.6, 0.35);
    b[F_CLK] = 0.15 * vg;                                 // key click
    b[F_AE] = 1; b[F_HN] = 0; b[F_HL] = 0;
  ) :
  eng == 1 ? (
    // FM e-piano: carriers C1 (body) and C3 (tine), modulators M2 (ratio 1) and M4 (ratio 14)
    !was ? ( b[F_O1] = 0; b[F_O2] = 0; b[F_O3] = 0; b[F_O4] = 0; );
    Tn = 4.5 * 2 ^ (-(n - 48) / 20);
    b[F_E1] = vg; b[F_E2] = 0.9 + 1.6 * h; b[F_E3] = vg * 0.55; b[F_E4] = 0.6 + 2.2 * h * h;
    b[F_MD] = tc(Tn * dec_k); b[F_MD + 1] = tc(Tn * 0.35 * dec_k); b[F_MD + 2] = tc(Tn * 0.4 * dec_k); b[F_MD + 3] = tc(0.09 + 0.05 * (1 - h));
    b[F_AE] = 1;
  ) : eng == 2 ? (
    // clav: a bright pluck, pickup near the string's end
    ks_setup(v, b, f0, vg, h, 4 * 2 ^ (-(n - 48) / 24) * dec_k, 0.4, 1);
    b[F_AE] = 1;
  ) : (
    // glockenspiel bar: 4 inharmonic partials
    Tn = 3.2 * 2 ^ (-(n - 72) / 24) * dec_k;
    k = 0;
    loop(4,
      ratio = k == 0 ? 1 : k == 1 ? 2.756 : k == 2 ? 5.404 : 8.933;
      amp = vg * (k == 0 ? 1 : k == 1 ? 0.22 + 0.25 * h : k == 2 ? 0.08 + 0.15 * h : 0.04 + 0.08 * h);
      dk = Tn * (k == 0 ? 1 : k == 1 ? 0.35 : k == 2 ? 0.14 : 0.07);
      bell_set(b, f0, vg, h, ratio, amp, dk, k);
      k += 1;
    );
    b[F_CLK] = vg * (0.1 + 0.15 * h);                      // mallet click (soft)
    b[F_AE] = 1;
  );
  );
);
function note_off(n) local(v, b) (
  v = 0; loop(NV, b = VB + v * VS; b[F_N] == n && b[F_G] ? ( b[F_G] = 0; b[F_S] = pedal; ); v += 1; );
  mono && n == mono_n ? mono_n = -1;
);
function pedal_set(on) local(v) ( pedal = on; !on ? ( v = 0; loop(NV + NB, VB[v * VS + F_S] = 0; v += 1; ); ); );
function all_off() local(v) ( v = 0; loop(NV + NB, VB[v * VS + F_G] = 0; VB[v * VS + F_S] = 0; v += 1; ); pedal = 0; );
function kill_all() ( memset(VB, 0, NV * VS); memset(KSB, 0, NV * KSL); pedal = 0; mono_n = -1; );

// ---------- SPLIT: the bass part under the left hand ----------
// Voices NV .. NV + NB - 1 (their strings at KSB + v * KSL). One of the twelve basses of the bank (patches 76 - 87):
// the analogue ones run their own copy of the analogue voice (bs_voice), the GM ones the GM voice (p_on / p_run)
// inside bs_ctx_in / bs_ctx_out, which lend it the bass part's drift and neutral EDIT settings. No EDIT knobs, effects
// or reverb on the bass: it joins the patch just before the output stage.
function bs_set(i) local(o, s) (
  o = PT + (75 + i) * 64;
  bs_trim = o[3];
  o[0] == 0 ? (
    bs_eng = 0; s = o[1];
    bs_o1w = 0; bs_o2w = 0; bs_det = 0.006; bs_subl = 0; bs_o2l = 1; bs_fbase = 1200; bs_famt = 1.5; bs_res = 0.2; bs_ktrk = 0.5;
    bs_aA = 0.01; bs_aD = 0.5; bs_aS = 0.8; bs_aR = 0.4; bs_fA = 0.01; bs_fD = 0.6; bs_fS = 0.3; bs_mono = 0; bs_glide = 0; bs_lvl = 0.5;
    s == 5 ? (         // BASS SYNTH
      bs_det = 0.003; bs_o2w = 1; bs_o2l = 0.5; bs_subl = 0.8; bs_fbase = 140; bs_famt = 3.2; bs_res = 0.45; bs_ktrk = 0.3; bs_aA = 0.002; bs_aD = 0.5; bs_aS = 0.75; bs_aR = 0.12;
      bs_fA = 0.001; bs_fD = 0.28; bs_fS = 0.15; bs_mono = 1; bs_glide = 0.04; bs_lvl = 0.55;
    ) : s == 15 ? (    // SUB BASS
      bs_o1w = 1; bs_o2l = 0; bs_det = 0; bs_fbase = 400; bs_famt = 0.3; bs_res = 0; bs_ktrk = 0.5; bs_aA = 0.003; bs_aD = 0.5; bs_aS = 0.9; bs_aR = 0.12;
      bs_fA = 0.001; bs_fD = 0.3; bs_fS = 0.5; bs_mono = 1; bs_glide = 0.03; bs_lvl = 0.9;
    ) : s == 16 ? (    // ACID BASS
      bs_o2l = 0; bs_det = 0; bs_fbase = 180; bs_famt = 3.6; bs_res = 0.82; bs_ktrk = 0.4; bs_fA = 0.001; bs_fD = 0.18; bs_fS = 0.05; bs_aA = 0.002; bs_aD = 0.4; bs_aS = 0.8; bs_aR = 0.08;
      bs_mono = 1; bs_glide = 0.06; bs_lvl = 0.6;
    ) : s == 17 ? (    // ROUND BASS
      bs_det = 0.004; bs_o2w = 1; bs_o2l = 0.7; bs_subl = 0.6; bs_fbase = 220; bs_famt = 1.8; bs_res = 0.3; bs_fA = 0.001; bs_fD = 0.35; bs_fS = 0.25; bs_aA = 0.002; bs_aD = 0.6; bs_aS = 0.85; bs_aR = 0.1;
      bs_mono = 1; bs_glide = 0.02; bs_lvl = 0.5;
    ) : s == 18 ? (    // PLUCK BASS (polyphonic)
      bs_det = 0.003; bs_o2l = 0.6; bs_subl = 0.5; bs_fbase = 160; bs_famt = 3; bs_res = 0.25; bs_fA = 0.001; bs_fD = 0.12; bs_fS = 0; bs_aA = 0.001; bs_aD = 0.35; bs_aS = 0; bs_aR = 0.1;
      bs_lvl = 0.6;
    ) : s == 19 ? (    // HOLLOW BASS
      bs_o1w = 1; bs_o2w = 1; bs_o2l = 1; bs_det = 0; bs_fbase = 600; bs_famt = 0.8; bs_res = 0.1; bs_fA = 0.001; bs_fD = 0.4; bs_fS = 0.4; bs_aA = 0.002; bs_aD = 0.5; bs_aS = 0.8; bs_aR = 0.1;
      bs_mono = 1; bs_glide = 0.03; bs_lvl = 0.55;
    ) : s == 20 ? (    // REESE BASS
      bs_det = 0.018; bs_o2l = 1; bs_subl = 0.4; bs_fbase = 350; bs_famt = 0.5; bs_res = 0.2; bs_fA = 0.01; bs_fD = 1; bs_fS = 0.8; bs_aA = 0.005; bs_aD = 1; bs_aS = 0.95; bs_aR = 0.15;
      bs_mono = 1; bs_glide = 0.03; bs_lvl = 0.5;
    );
  ) : ( bs_eng = 6; bs_prog = o[1]; bs_lvl = 0.4; bs_mono = 0; );
);
// envelope and glide coefficients (once a block)
function bs_coef() (
  bs_ainc = 1 / max(max(bs_aA, 0.003) * srate, 1); bs_finc = 1 / max(max(bs_fA, 0.002) * srate, 1);
  bs_adec = tc(bs_aD); bs_arel = tc(bs_aR); bs_fdec = tc(bs_fD); bs_frel = tc(bs_aR);
  bs_glc = bs_glide > 0 ? 1 - exp(-1 / (bs_glide * srate)) : 1;
);
// the GM voice reads the patch's settings from globals: lend it the bass part's for a moment
function bs_ctx_in() (
  bx_gprog = gprog; bx_eng = eng; bx_fo = fl_fo; bx_to = fl_to; bx_rs = fl_rs; bx_fa = fl_fa; bx_dr = drift; bx_cut = ins_cut; bx_pd = pdrift;
  bx_atk = atk_k; bx_dec = dec_k; bx_sus = sus_o; bx_rel = rel_k; bx_fatk = fatk_k; bx_fdec = fdec_k; bx_fsus = fsus_o; bx_frel = frel_k;
  gprog = bs_prog; eng = 6; fl_fo = 0; fl_to = 0; fl_rs = 0; fl_fa = 1; drift = bs_amt; ins_cut = bs_cut; pdrift = bs_pd;
  atk_k = 1; dec_k = 1; sus_o = 0; rel_k = 1; fatk_k = 1; fdec_k = 1; fsus_o = 0; frel_k = 1;
);
function bs_ctx_out() (
  gprog = bx_gprog; eng = bx_eng; fl_fo = bx_fo; fl_to = bx_to; fl_rs = bx_rs; fl_fa = bx_fa; drift = bx_dr; ins_cut = bx_cut; pdrift = bx_pd;
  atk_k = bx_atk; dec_k = bx_dec; sus_o = bx_sus; rel_k = bx_rel; fatk_k = bx_fatk; fdec_k = bx_fdec; fsus_o = bx_fsus; frel_k = bx_frel;
);
// a key below the split: key = the key played (note-offs find the voice by it), the bass sounds BASS OCTAVE from it
function bs_note_on(key, vel) local(v, b, n, f0, vg, k, was, ba, a_) (
  n = min(max(key + 12 * bs_oct, 0), 127);
  f0 = 440 * 2 ^ ((n - 69) / 12) * tune;
  vg = (1 - sens) + sens * (vel / 127) ^ 1.3;
  bs_act = 1;
  bs_eng == 0 && bs_mono ? (
    b = VB + NV * VS;                        // mono: always the first bass voice, glide from the last note
    b[F_DCF] = 1; !b[F_ACT] ? ( b[F_PY] = 0; b[F_PY2] = 0; b[F_DCO] = 0; ); b[F_ATK] = 1;
    bs_mn >= 0 && b[F_ACT] && b[F_AE] > 0.01 ? ( b[F_F0] = f0; b[F_G] = 1; b[F_N] = key; b[F_VEL] = vg; bs_mn = key; ) : (
      was = b[F_ACT];
      b[F_N] = key; b[F_G] = 1; b[F_S] = 0; b[F_ACT] = 1; b[F_VEL] = vg; b[F_F0] = f0; bs_mf = f0;
      b[F_DT] = 2 ^ ((rand(2) - 1) * bs_amt * 0.06 / 12);            // BASS DRIFT: each note slightly out ...
      b[F_E1] = (rand(2) - 1) * bs_amt * 0.35;                        // ... and slightly brighter / darker
      !was ? ( b[F_AE] = 0; b[F_FE] = 0; b[F_P1] = rand(1); b[F_P2] = rand(1); b[F_P3] = rand(1); );
      b[F_AST] = 0; b[F_FST] = 0; bs_mn = key;
    );
  ) : (
    v = -1; k = NV; loop(NB, VB[k * VS + F_N] == key && VB[k * VS + F_ACT] ? v = k; k += 1; );
    k = NV; loop(NB, v < 0 && !VB[k * VS + F_ACT] ? v = k; k += 1; );
    v < 0 ? (
      ba = 1000000000; k = NV;
      loop(NB, a_ = VB[k * VS + F_AGE] + (VB[k * VS + F_G] ? 100000000 : 0); a_ < ba ? ( ba = a_; v = k; ); k += 1; );
    );
    b = VB + v * VS;
    age += 1; b[F_AGE] = age;
    was = b[F_ACT];
    b[F_DCF] = 1; !was ? ( b[F_PY] = 0; b[F_PY2] = 0; b[F_DCO] = 0; );
    b[F_ATK] = 1;
    b[F_N] = key; b[F_G] = 1; b[F_S] = 0; b[F_ACT] = 1; b[F_VEL] = vg; b[F_F0] = f0;
    b[F_DT] = 2 ^ ((rand(2) - 1) * bs_amt * 0.06 / 12);
    b[F_E1] = (rand(2) - 1) * bs_amt * 0.35;
    b[F_AST] = 0; b[F_FST] = 0; b[F_VT] = 0; !was ? b[F_FE] = 0;
    bs_eng == 6 ? (
      bs_ctx_in(); p_on(v, b, n, vg); bs_ctx_out();
      b[F_ATK] = 0;
    ) : (
      !was ? ( b[F_P1] = rand(1); b[F_P2] = rand(1); b[F_P3] = rand(1); b[F_AE] = 0; );
    );
  );
);
function bs_note_off(key) local(v, b) (
  v = NV; loop(NB, b = VB + v * VS; b[F_N] == key && b[F_G] ? ( b[F_G] = 0; b[F_S] = pedal; ); v += 1; );
  key == bs_mn ? bs_mn = -1;
);
// one sample of an analogue bass voice (the patch's analogue voice, with the bass part's settings)
function bs_voice(b, held) local(f, dt, x, fc, g, gG, u, v_, y1, y2, y3, y4) (
  bs_mono ? ( bs_mf += (b[F_F0] - bs_mf) * bs_glc; f = bs_mf; ) : f = b[F_F0];
  f *= b[F_DT] * bs_pd * (1 + modw * 0.008 * sin(2 * $pi * vph));
  dt = f / srate;
  b[F_P1] += dt * (1 + bs_det); b[F_P1] >= 1 ? b[F_P1] -= 1;
  b[F_P2] += dt * (1 - bs_det); b[F_P2] >= 1 ? b[F_P2] -= 1;
  b[F_P3] += dt * 0.5;          b[F_P3] >= 1 ? b[F_P3] -= 1;
  x = (bs_o1w == 2 ? sqw(b[F_P1], dt * (1 + bs_det)) : bs_o1w ? 1.2 * sin(2 * $pi * b[F_P1]) : saw(b[F_P1], dt * (1 + bs_det)))
    + bs_o2l * (bs_o2w ? sqw(b[F_P2], dt) : saw(b[F_P2], dt * (1 - bs_det))) + bs_subl * sqw(b[F_P3], dt * 0.5);
  held ? (
    b[F_AST] == 0 ? ( b[F_AE] += bs_ainc; b[F_AE] >= 1 ? ( b[F_AE] = 1; b[F_AST] = 1; ); ) : b[F_AE] = bs_aS + (b[F_AE] - bs_aS) * bs_adec;
    b[F_FST] == 0 ? ( b[F_FE] += bs_finc; b[F_FE] >= 1 ? ( b[F_FE] = 1; b[F_FST] = 1; ); ) : b[F_FE] = bs_fS + (b[F_FE] - bs_fS) * bs_fdec;
  ) : ( b[F_AE] *= bs_arel; b[F_FE] *= bs_frel; );
  fc = bs_fbase * 2 ^ (bs_famt * b[F_FE] * (0.6 + 0.4 * b[F_VEL]) + b[F_E1] + bs_cut + bs_ktrk * log(f / 261.6) / log(2));
  g = tan($pi * min(fc, srate * 0.42) / srate); gG = g / (1 + g);
  u = tanh_(x * 0.5 - bs_res * 3.9 * b[F_S4]);
  v_ = (u - b[F_S1]) * gG; y1 = v_ + b[F_S1]; b[F_S1] = y1 + v_;
  v_ = (y1 - b[F_S2]) * gG; y2 = v_ + b[F_S2]; b[F_S2] = y2 + v_;
  v_ = (y2 - b[F_S3]) * gG; y3 = v_ + b[F_S3]; b[F_S3] = y3 + v_;
  v_ = (y3 - b[F_S4]) * gG; y4 = v_ + b[F_S4]; b[F_S4] = y4 + v_;
  !held && b[F_AE] < 0.0003 ? b[F_ACT] = 0;
  y4 * b[F_AE] * b[F_VEL] * 2 * (1 + 0.8 * bs_res);
);

// ---------- reverb (GFX Space engine) ----------
rv_a = 96000;                                 // small arrays: 8 per field
rlw = rv_a; rlz = rv_a + 10; rlph = rv_a + 20; rlrt = rv_a + 30; rllen = rv_a + 40; rlga = rv_a + 50; rlgb = rv_a + 60;
rapw = rv_a + 70; rapl = rv_a + 80; rbl = rv_a + 90; rtmp = rv_a + 100; rmix = rv_a + 110;
memset(rv_a, 0, 120);
rbl[0] = 31.7; rbl[1] = 37.1; rbl[2] = 41.3; rbl[3] = 47.9; rbl[4] = 53.3; rbl[5] = 61.1; rbl[6] = 70.7; rbl[7] = 79.3;
rapl[0] = 142; rapl[1] = 107; rapl[2] = 379; rapl[3] = 277;
i = 0; loop(8, rlrt[i] = 0.31 + 0.11 * i; rlph[i] = rand(1); i += 1; );
RBLK = ceil(0.16 * srate) + 16;
rpre_b = 100000; rpre_len = ceil(0.16 * srate) + 8;
rap_b = rpre_b + rpre_len;                    // 4 diffusers, rings of 4096
rln_b = rap_b + 4 * 4096;                     // 8 lines
memset(rpre_b, 0, rln_b + 8 * RBLK - rpre_b);
rpre_w = 0; rv_on = 0;
bt_pos = 0; nd_last = -1;
function rv_update() local(i, sz, L, gl, gh, a, t60) (
  rtyp = floor(slider14 + 0.5);
  sz = rtyp == 0 ? 0.42 : rtyp == 1 ? 1 : 0.55;
  rdiff = rtyp == 2 ? 0.95 : 0.75;
  rpre = slider15 * 0.001 * srate;
  t60 = slider16 * 1.11;
  rmod = rtyp == 2 ? 0.0004 : 0.0008;
  i = 0;
  loop(8,
    L = min(rbl[i] * sz * 0.001 * srate, RBLK - 64);
    rllen[i] = L;
    gl = 10 ^ (-3 * L / (t60 * srate));
    gh = 10 ^ (-3 * L / (t60 * (1 - 0.9 * slider17 / 100) * srate * (rtyp == 2 ? 1.4 : 1)));
    a = (gl - gh) / (gl + gh); rlga[i] = a; rlgb[i] = gl * (1 - a);
    i += 1;
  );
  rv_wet = slider18 / 100;
  rv_on = rv_wet > 0.001;
);

// ---------- MOD RACK (the GFX Mod Rack inside): chorus, tremolo, vibe, delay in parallel on the voices ----------
// each module adds only its change ("delta") to the dry signal; L / C / R pick left, mono centre, right
mrCHN = 16384; mrDLN = floor(srate*2.2) + 8;
mrChA = MR; mrChB = MR + mrCHN; mrChC = MR + 2*mrCHN;
mrDlA = MR + 3*mrCHN; mrDlB = mrDlA + mrDLN; mrDlC = mrDlB + mrDLN;
mrVsC = mrDlC + mrDLN; mrVsT = mrVsC + 48; mrVsV = mrVsT + 48; mrPre = mrVsV + 48; mrDls = mrPre + 4; mrRg = mrDls + 8; mrVbF = mrRg + 24;
memset(MR, 0, mrVbF + 4 - MR);
mrVsT[0] = mrVsT[16] = mrVsT[32] = 1;
mrVbF[0] = 60; mrVbF[1] = 180; mrVbF[2] = 480; mrVbF[3] = 1300;
mrCw = 1 - exp(-1/(0.15*srate)); mrCs = 1 - exp(-1/(3*srate)); mrCd = 1 - exp(-1/(0.8*srate)); mrCdr = 1 - exp(-1/(3*srate));
function mr_opc(fc) ( 1 - exp(-2*$pi*min(fc, srate*0.45)/srate); );
function mr_tanh(v) ( v = max(-20, min(20, v)); 1 - 2/(exp(2*v) + 1); );
mrVbLp = mr_opc(160); mrVbAt = 1 - exp(-1/(0.008*srate));
mrDlLc = mr_opc(3500); mrDlHc = mr_opc(70); mrDlTs = 1 - exp(-1/(0.25*srate)); mrDlT = 350;
function mr_div(i, md) (
  (i == 0 ? 4*mrBar : i == 1 ? 2*mrBar : i == 2 ? mrBar : i == 3 ? 2 : i == 4 ? 1 : i == 5 ? 0.5 : i == 6 ? 0.25 : 0.125)*(md == 2 ? 1.5 : md == 3 ? 2/3 : 1);
);
function mr_hread(buf, n, pos) local(i, f, xm1, x0, x1, x2, c1, c2, c3) (
  pos < 0 ? pos += n; pos >= n ? pos -= n;
  i = floor(pos); f = pos - i;
  xm1 = buf[(i - 1 + n) % n]; x0 = buf[i]; x1 = buf[(i + 1) % n]; x2 = buf[(i + 2) % n];
  c1 = 0.5*(x1 - xm1); c2 = xm1 - 2.5*x0 + 2*x1 - 0.5*x2; c3 = 0.5*(x2 - xm1) + 1.5*(x0 - x1);
  ((c3*f + c2)*f + c1)*f + x0;
);
function mr_rgen(q, period, coef) ( q[0] -= 1; q[0] <= 0 ? ( q[0] = period*srate; q[1] = rand(2) - 1; ); q[2] += coef*(q[1] - q[2]); q[2]; );
function mr_ch(buf, phoff, vs) local(lf, dms, y) (
  lf = sin(2*$pi*(mrChPh + phoff));
  dms = mrChBase + mrChDep*lf + mrWarb;
  y = mr_hread(buf, mrCHN, mrChW - max(1, dms)*srate*0.001);
  mrClkOn ? ( vs[0] += mrClkInc; vs[0] >= 1 ? ( vs[0] -= 1; vs[1] = y; ); y = vs[1]; );
  vs[2] += mrChPc*(y - vs[2]); vs[3] += mrChPc*(vs[2] - vs[3]);
  vs[3];
);
function mr_tr(phoff, vs) local(sv, sh, g) (
  sv = sin(2*$pi*(mrTrPh + phoff));
  sh = mrTrK > 1.01 ? mr_tanh(mrTrK*sv)/mrTrTk : sv;
  g = 1 - mrTrDep*(0.5 - 0.5*sh);
  vs[0] += mrTrLag*(g - vs[0]); vs[0];
);
function mr_vb(x, phoff, vs) local(q, pw, lf, c, rr, oc, k, y, f, t, a1, xi) (
  q = mrVbPh + phoff; q -= floor(q);
  pw = q < mrVbSk ? 0.5*q/mrVbSk : 0.5 + 0.5*(q - mrVbSk)/(1 - mrVbSk);
  lf = 0.5 - 0.5*cos(2*$pi*pw);
  c = lf > vs[8] ? mrVbAt : mrVbRl; vs[8] += c*(lf - vs[8]); rr = vs[8];
  oc = mrVbOct*rr; y = x; k = 0;
  loop(4, f = min(srate*0.45, mrVbF[k]*2^oc); t = tan($pi*f/srate); a1 = (t - 1)/(t + 1);
    xi = y; y = a1*xi + vs[k*2] - a1*vs[k*2 + 1]; vs[k*2] = xi; vs[k*2 + 1] = y; k += 1; );
  vs[9] += mrVbLp*(x - vs[9]);
  mrVbWet*(0.5*(y - x) + mrVbTh*(2*rr - 1)*vs[9]);
);
function mr_loop(y, q) local(v) ( q[0] += mrDlLc*(y - q[0]); q[1] += mrDlHc*(q[0] - q[1]); v = q[0] - q[1]; mr_tanh(v*mrFbE*1.15)/1.15; );
// the controls (each block)
function mr_update() local(fclk) (
  // L / C / R as one slider per unit (1 = L, 2 = C, 4 = R): the Lab copy keeps to 64 sliders for REAPER 6
  mrChLo = (slider23 & 1) > 0; mrChCo = (slider23 & 2) > 0; mrChRo = (slider23 & 4) > 0;
  mrTrLo = (slider31 & 1) > 0; mrTrCo = (slider31 & 2) > 0; mrTrRo = (slider31 & 4) > 0;
  mrVbLo = (slider39 & 1) > 0; mrVbCo = (slider39 & 2) > 0; mrVbRo = (slider39 & 4) > 0;
  mrDlLo = (slider48 & 1) > 0; mrDlCo = (slider48 & 2) > 0; mrDlRo = (slider48 & 4) > 0;
  mrChBase = 7; mrChDep = slider20/100*3;
  fclk = 40000; mrClkOn = fclk < srate*0.98; mrClkInc = fclk/srate;
  mrChPc = mr_opc(min(14000, fclk*0.42)); mrChMix = slider21/100;
  mrTrK = 1; mrTrTk = mr_tanh(mrTrK); mrTrDep = slider29/100;
  mrTrLag = 1 - exp(-1/(6*0.001*srate));
  mrVbSk = 0.5; mrVbRl = 1 - exp(-1/(0.04*srate));
  mrVbTh = 0; mrVbOct = 3*slider37/100; mrVbWet = min(1, 2*slider37/100);
  mrFbE = 0.95*slider45/95; mrDlMix = slider46/100;
);
// tempo (each block)
function mr_block() (
  mrBar = ts_denom > 0 ? ts_num*4/ts_denom : 4;
  mrPlay = play_state & 1; mrBpos = beat_position; mrBpInc = tempo/(60*srate);
  mrChSy = slider26 > 0.5; mrChQn = mr_div(slider27, slider26);
  mrTrSy = slider34 > 0.5; mrTrQn = mr_div(slider35, slider34);
  mrVbSy = slider42 > 0.5; mrVbQn = mr_div(slider43, slider42);
  mrDlTgt = slider51 > 0.5 && tempo > 0 ? min(1500, mr_div(slider52, slider51)*60000/tempo) : slider44;
  mrOn = mrChMix > 0 || mrTrDep > 0 || mrVbWet > 0 || mrDlMix > 0;
);
// one sample: in mrL / mrR, out mrL / mrR
function mr_run() local(xl, xr, m, dl, dr, y, sp, kc, ws, wc, dsm, ya, yb, yc) (
  xl = mrL; xr = mrR; m = 0.5*(xl + xr); dl = dr = 0;
  mrBpos += mrBpInc;
  mrChSy ? mrChPh = (mrPlay ? mrBpos/mrChQn : mrChPh + mrBpInc/mrChQn) : mrChPh += slider19*(1 + 0.2*drift*mr_rgen(mrRg, 2.5, mrCdr))/srate;
  mrTrSy ? mrTrPh = (mrPlay ? mrBpos/mrTrQn : mrTrPh + mrBpInc/mrTrQn) : mrTrPh += slider28*(1 + 0.2*drift*mr_rgen(mrRg + 3, 2.5, mrCdr))/srate;
  mrVbSy ? mrVbPh = (mrPlay ? mrBpos/mrVbQn : mrVbPh + mrBpInc/mrVbQn) : mrVbPh += slider36*(1 + 0.2*drift*mr_rgen(mrRg + 6, 2.5, mrCdr))/srate;
  mrChPh -= floor(mrChPh); mrTrPh -= floor(mrTrPh); mrVbPh -= floor(mrVbPh);
  // chorus
  mrPre[0] += mrChPc*(xl - mrPre[0]); mrPre[1] += mrChPc*(xr - mrPre[1]); mrPre[2] += mrChPc*(m - mrPre[2]);
  mrChA[mrChW] = mrPre[0]; mrChB[mrChW] = mrPre[1]; mrChC[mrChW] = mrPre[2];
  mrChMix > 0 ? (
    sp = mrChCo && (mrChLo || mrChRo); kc = (mrChLo || mrChRo) ? 0.707 : 1;
    mrChLo ? dl += mrChMix*mr_ch(mrChA, 0, mrVsC);
    mrChRo ? dr += mrChMix*mr_ch(mrChB, sp ? 2/3 : 0.25, mrVsC + 16);
    mrChCo ? ( y = mrChMix*kc*mr_ch(mrChC, sp ? 1/3 : 0, mrVsC + 32); dl += y; dr += y; );
  );
  // tremolo
  mrTrDep > 0 ? (
    sp = mrTrCo && (mrTrLo || mrTrRo); ws = mrTrCo ? 0.5 : 1; wc = (mrTrLo || mrTrRo) ? 0.5 : 1;
    mrTrLo ? dl += ws*xl*(mr_tr(0, mrVsT) - 1);
    mrTrRo ? dr += ws*xr*(mr_tr(sp ? 2/3 : 0, mrVsT + 16) - 1);
    mrTrCo ? ( y = wc*m*(mr_tr(sp ? 1/3 : 0, mrVsT + 32) - 1); dl += y; dr += y; );
  );
  // vibe
  mrVbWet > 0 ? (
    sp = mrVbCo && (mrVbLo || mrVbRo); kc = (mrVbLo || mrVbRo) ? 0.707 : 1;
    mrVbLo ? dl += mr_vb(xl, 0, mrVsV);
    mrVbRo ? dr += mr_vb(xr, sp ? 2/3 : 0, mrVsV + 16);
    mrVbCo ? ( y = kc*mr_vb(m, sp ? 1/3 : 0, mrVsV + 32); dl += y; dr += y; );
  );
  // delay
  mrDlT += mrDlTs*(mrDlTgt - mrDlT);
  dsm = max(2, min(mrDLN*0.55, mrDlT*srate*0.001));
  sp = mrDlCo && (mrDlLo || mrDlRo); kc = (mrDlLo || mrDlRo) ? 0.707 : 1;
  mrDlLo && mrDlMix > 0 ? ( ya = mr_hread(mrDlA, mrDLN, mrDlW - dsm*(sp ? 0.75 : 1)); mrDlA[mrDlW] = xl + mr_loop(ya, mrDls); dl += mrDlMix*ya; ) : mrDlA[mrDlW] = 0;
  mrDlRo && mrDlMix > 0 ? ( yb = mr_hread(mrDlB, mrDLN, mrDlW - dsm*(sp ? 1.25 : 1)); mrDlB[mrDlW] = xr + mr_loop(yb, mrDls + 2); dr += mrDlMix*yb; ) : mrDlB[mrDlW] = 0;
  mrDlCo && mrDlMix > 0 ? ( yc = mr_hread(mrDlC, mrDLN, mrDlW - dsm); mrDlC[mrDlW] = m + mr_loop(yc, mrDls + 4); y = mrDlMix*kc*yc; dl += y; dr += y; ) : mrDlC[mrDlW] = 0;
  mrChW += 1; mrChW >= mrCHN ? mrChW = 0;
  mrDlW += 1; mrDlW >= mrDLN ? mrDlW = 0;
  mrL = xl + dl; mrR = xr + dr;
);

// ---------- the patches ----------
function pt(i, j, a, b, c, d, e, f, g, h, k, l, m, n, o, q) local(z) (
  z = PT + i*64 + j;
  z[0] = a; z[1] = b; z[2] = c; z[3] = d; z[4] = e; z[5] = f; z[6] = g; z[7] = h; z[8] = k; z[9] = l; z[10] = m; z[11] = n; z[12] = o; z[13] = q;
);
pt(0, 0, 0, 24, 0, 1.129, 1, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(0, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(0, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 0);
strcpy(400 + 0, "Session Piano");
pt(1, 0, 0, 38, 0, 1.103, 1, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(1, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(1, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 0);
strcpy(400 + 1, "Bright Piano");
pt(2, 0, 0, 25, 0, 0.58, 1, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(2, 14, 0, 2, 4.6, 50, 0, 1, 1, 1, 0, 5, 1.5, 0, 0, 1);
pt(2, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 0);
strcpy(400 + 2, "Chorus EP");
pt(3, 0, 0, 0, 0, 0.957, 1, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(3, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(3, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 0);
strcpy(400 + 3, "FM E-Piano");
pt(4, 0, 1, 0, 0.5, 1.235, 1, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(4, 14, 0, 2, 4.2, 30, 0, 1, 1, 1, 0, 5, 1.5, 0, 0, 1);
pt(4, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 0);
strcpy(400 + 4, "E.Piano 1");
pt(5, 0, 1, 1, 0.5, 1.405, 1, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(5, 14, 0, 2, 4.2, 30, 0, 1, 1, 1, 0, 5, 1.5, 0, 0, 1);
pt(5, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 0);
strcpy(400 + 5, "E.Piano 2");
pt(6, 0, 0, 1, 0, 0.957, 1, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(6, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(6, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 0);
strcpy(400 + 6, "Clav");
pt(7, 0, 1, 3, 0.2, 0.789, 1, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(7, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(7, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 0);
strcpy(400 + 7, "Clavi");
pt(8, 0, 1, 2, 0.25, 0.878, 1, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(8, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(8, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 0);
strcpy(400 + 8, "Harpsichord");
pt(9, 0, 0, 34, 0, 0.46, 0, 1.4, 14, 0.8, 50, 0, 0, 1, 0, 1);
pt(9, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(9, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 0);
strcpy(400 + 9, "Drawbar Organ");
pt(10, 0, 0, 2, 0, 0.443, 1, 2.4, 25, 0.8, 50, 0, 0, 1, 0, 1);
pt(10, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(10, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 1);
strcpy(400 + 10, "Glockenspiel");
pt(11, 0, 0, 8, 0, 0.691, 1, 2.4, 25, 0.8, 50, 0, 0, 1, 0, 1);
pt(11, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(11, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 1);
strcpy(400 + 11, "Fantasy Bells");
pt(12, 0, 0, 14, 0, 0.861, 1, 2.4, 25, 0.8, 50, 0, 0, 1, 0, 1);
pt(12, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(12, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 1);
strcpy(400 + 12, "Crystal Harp");
pt(13, 0, 0, 9, 0, 0.579, 1, 2.4, 25, 0.8, 50, 0, 0, 1, 0, 1);
pt(13, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(13, 28, 0, 1, 0, 4, 350, 40, 42, 0, 1, 1, 1, 2, 5, 1);
strcpy(400 + 13, "Staccato Glass");
pt(14, 0, 1, 4, 0.3, 1.065, 1, 2.4, 25, 0.8, 50, 0, 0, 1, 0, 1);
pt(14, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(14, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 1);
strcpy(400 + 14, "Celesta");
pt(15, 0, 1, 5, 0.3, 1.223, 1, 2.4, 25, 0.8, 50, 0, 0, 1, 0, 1);
pt(15, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(15, 28, 0, 1, 0, 4, 320, 25, 15, 0, 1, 1, 1, 1, 4, 1);
strcpy(400 + 15, "Music Box");
pt(16, 0, 1, 6, 0.3, 1.183, 1, 2.4, 25, 0.8, 50, 0, 0, 1, 0, 1);
pt(16, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(16, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 1);
strcpy(400 + 16, "Vibes");
pt(17, 0, 1, 7, 0.3, 0.785, 1, 2.4, 25, 0.8, 50, 0, 0, 1, 0, 1);
pt(17, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(17, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 1);
strcpy(400 + 17, "Marimba");
pt(18, 0, 1, 8, 0.3, 0.884, 1, 2.4, 25, 0.8, 50, 0, 0, 1, 0, 1);
pt(18, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(18, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 1);
strcpy(400 + 18, "Xylophone");
pt(19, 0, 1, 9, 0.3, 1.423, 1, 2.4, 25, 0.8, 50, 0, 0, 1, 0, 1);
pt(19, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(19, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 1);
strcpy(400 + 19, "Tubular Bells");
pt(20, 0, 1, 10, 0.3, 0.776, 1, 2.4, 25, 0.8, 50, 0, 0, 1, 0, 1);
pt(20, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(20, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 1);
strcpy(400 + 20, "Dulcimer");
pt(21, 0, 1, 43, 0.3, 1.127, 1, 2.4, 25, 0.8, 50, 0, 0, 1, 0, 1);
pt(21, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(21, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 1);
strcpy(400 + 21, "Tinkle Bell");
pt(22, 0, 0, 39, 0, 1.391, 2, 1.8, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(22, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(22, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 2);
strcpy(400 + 22, "LA Nylon");
pt(23, 0, 0, 40, 0, 1.906, 2, 1.8, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(23, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(23, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 2);
strcpy(400 + 23, "LA Steel");
pt(24, 0, 0, 41, 0, 1.237, 2, 1.8, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(24, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(24, 28, 0, 1, 0, 4, 350, 30, 28, 0, 1, 1, 1, 2, 5, 2);
strcpy(400 + 24, "LA Clean");
pt(25, 0, 0, 42, 0, 0.638, 2, 1.8, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(25, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(25, 28, 0, 1, 0, 4, 350, 40, 35, 0, 1, 1, 1, 2, 5, 2);
strcpy(400 + 25, "LA Harmonics");
pt(26, 0, 0, 12, 0, 1.839, 2, 1.8, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(26, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(26, 28, 0, 1, 0, 4, 350, 30, 21, 0, 1, 1, 1, 1, 4, 2);
strcpy(400 + 26, "Nylon Atmos");
pt(27, 0, 0, 10, 0, 1.479, 2, 1.8, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(27, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(27, 28, 0, 1, 0, 4, 350, 25, 17, 0, 1, 1, 1, 1, 5, 2);
strcpy(400 + 27, "Pizz Flow");
pt(28, 0, 0, 36, 0, 1.495, 2, 1.8, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(28, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(28, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 2);
strcpy(400 + 28, "Harp");
pt(29, 0, 1, 11, 0.25, 1.074, 2, 1.8, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(29, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(29, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 2);
strcpy(400 + 29, "Nylon Gtr");
pt(30, 0, 1, 12, 0.25, 0.847, 2, 1.8, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(30, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(30, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 2);
strcpy(400 + 30, "Steel Gtr");
pt(31, 0, 1, 13, 0.25, 0.866, 2, 1.8, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(31, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(31, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 2);
strcpy(400 + 31, "Muted Gtr");
pt(32, 0, 1, 14, 0.25, 0.825, 2, 1.8, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(32, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(32, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 2);
strcpy(400 + 32, "Overdrive Gtr");
pt(33, 0, 1, 41, 0.25, 1.174, 2, 1.8, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(33, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(33, 28, 0, 1, 0, 4, 320, 25, 15, 0, 1, 1, 1, 1, 4, 2);
strcpy(400 + 33, "Koto");
pt(34, 0, 1, 42, 0.25, 0.889, 2, 1.8, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(34, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(34, 28, 0, 1, 0, 4, 320, 25, 15, 0, 1, 1, 1, 1, 4, 2);
strcpy(400 + 34, "Kalimba");
pt(35, 0, 0, 6, 0, 0.591, 1, 2.6, 28, 0.8, 50, 0, 0, 1, 0, 1);
pt(35, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(35, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 3);
strcpy(400 + 35, "Strings");
pt(36, 0, 0, 7, 0, 0.496, 1, 2.6, 28, 0.8, 50, 0, 0, 1, 0, 1);
pt(36, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(36, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 3);
strcpy(400 + 36, "String Ensemble");
pt(37, 0, 0, 31, 0, 0.577, 1, 2.6, 28, 0.8, 50, 0, 0, 1, 0, 1);
pt(37, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(37, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 3);
strcpy(400 + 37, "Fat Strings");
pt(38, 0, 0, 32, 0, 0.357, 1, 2.6, 28, 0.8, 50, 0, 0, 1, 0, 1);
pt(38, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(38, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 3);
strcpy(400 + 38, "Orchestra Hit");
pt(39, 0, 1, 20, 0.7, 0.958, 1, 2.6, 28, 0.8, 50, 0, 0, 1, 0, 1);
pt(39, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(39, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 3);
strcpy(400 + 39, "Violin");
pt(40, 0, 1, 21, 0.7, 0.795, 1, 2.6, 28, 0.8, 50, 0, 0, 1, 0, 1);
pt(40, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(40, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 3);
strcpy(400 + 40, "Viola");
pt(41, 0, 1, 22, 0.7, 1.044, 1, 2.6, 28, 0.8, 50, 0, 0, 1, 0, 1);
pt(41, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(41, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 3);
strcpy(400 + 41, "Cello");
pt(42, 0, 1, 23, 0.7, 0.673, 1, 2.6, 28, 0.8, 50, 0, 0, 1, 0, 1);
pt(42, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(42, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 3);
strcpy(400 + 42, "Strings 1");
pt(43, 0, 1, 24, 0.7, 0.804, 1, 2.6, 28, 0.8, 50, 0, 0, 1, 0, 1);
pt(43, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(43, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 3);
strcpy(400 + 43, "Syn Strings");
pt(44, 0, 0, 3, 0, 0.817, 1, 3.4, 30, 0.8, 50, 0, 0, 1, 0, 1);
pt(44, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(44, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 4);
strcpy(400 + 44, "Synth Pad");
pt(45, 0, 0, 4, 0, 0.821, 1, 3.4, 30, 0.8, 50, 0, 0, 1, 0, 1);
pt(45, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(45, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 4);
strcpy(400 + 45, "Warm Pad");
pt(46, 0, 0, 23, 0, 0.887, 1, 3.4, 30, 0.8, 50, 0, 0, 1, 0, 1);
pt(46, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(46, 28, 0, 1, 0, 4, 350, 40, 35, 0, 1, 1, 1, 1, 4, 4);
strcpy(400 + 46, "Soundtrack Pad");
pt(47, 0, 0, 21, 0, 1.349, 1, 3.4, 30, 0.8, 50, 0, 0, 1, 0, 1);
pt(47, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(47, 28, 0, 1, 0, 4, 350, 40, 35, 0, 1, 1, 1, 2, 5, 4);
strcpy(400 + 47, "Native Dance");
pt(48, 0, 1, 36, 0.8, 0.856, 1, 3.4, 30, 0.8, 50, 0, 0, 1, 0, 1);
pt(48, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(48, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 4);
strcpy(400 + 48, "Poly Synth");
pt(49, 0, 1, 38, 0.8, 0.53, 1, 3.4, 30, 0.8, 50, 0, 0, 1, 0, 1);
pt(49, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(49, 28, 0, 1, 0, 4, 450, 40, 18, 0, 1, 1, 1, 2, 4, 4);
strcpy(400 + 49, "Bowed Pad");
pt(50, 0, 1, 39, 0.8, 0.799, 1, 3.4, 30, 0.8, 50, 0, 0, 1, 0, 1);
pt(50, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(50, 28, 0, 1, 0, 4, 450, 40, 18, 0, 1, 1, 1, 2, 4, 4);
strcpy(400 + 50, "Metal Pad");
pt(51, 0, 1, 40, 0.8, 0.566, 1, 3.4, 30, 0.8, 50, 0, 0, 1, 0, 1);
pt(51, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(51, 28, 0, 1, 0, 4, 450, 40, 18, 0, 1, 1, 1, 2, 4, 4);
strcpy(400 + 51, "Sweep Pad");
pt(52, 0, 0, 11, 0, 0.688, 1, 3, 30, 0.8, 50, 0, 0, 1, 0, 1);
pt(52, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(52, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 5);
strcpy(400 + 52, "Glass Voices");
pt(53, 0, 0, 26, 0, 0.471, 1, 3, 30, 0.8, 50, 0, 0, 1, 0, 1);
pt(53, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(53, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 5);
strcpy(400 + 53, "Dark Voice");
pt(54, 0, 0, 27, 0, 0.432, 1, 3, 30, 0.8, 50, 0, 0, 1, 0, 1);
pt(54, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(54, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 5);
strcpy(400 + 54, "Fantasy Voice");
pt(55, 0, 0, 28, 0, 0.58, 1, 3, 30, 0.8, 50, 0, 0, 1, 0, 1);
pt(55, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(55, 28, 0, 1, 0, 4, 350, 45, 42, 0, 1, 1, 1, 2, 4, 5);
strcpy(400 + 55, "Spaced Voice");
pt(56, 0, 1, 37, 0.9, 0.604, 1, 3, 30, 0.8, 50, 0, 0, 1, 0, 1);
pt(56, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(56, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 5);
strcpy(400 + 56, "Choir Pad");
pt(57, 0, 0, 33, 0, 0.918, 1, 2, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(57, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(57, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 6);
strcpy(400 + 57, "Brass Section");
pt(58, 0, 0, 13, 0, 0.901, 1, 2, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(58, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(58, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 6);
strcpy(400 + 58, "Synth Brass");
pt(59, 0, 0, 29, 0, 0.925, 1, 2, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(59, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(59, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 6);
strcpy(400 + 59, "Velo Stab");
pt(60, 0, 0, 30, 0, 0.76, 1, 2, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(60, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(60, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 6);
strcpy(400 + 60, "Hoover");
pt(61, 0, 0, 35, 0, 0.413, 1, 2, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(61, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(61, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 6);
strcpy(400 + 61, "Pan Flute");
pt(62, 0, 1, 25, 0.3, 1.679, 1, 2, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(62, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(62, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 6);
strcpy(400 + 62, "Syn Reed");
pt(63, 0, 1, 26, 0.3, 1.778, 1, 2, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(63, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(63, 28, 0, 1, 0, 4, 350, 30, 22, 0, 1, 0, 1, 2, 5, 6);
strcpy(400 + 63, "Whistle");
pt(64, 0, 1, 27, 0.3, 1.663, 1, 2, 20, 0.8, 50, 0, 0, 1, 0, 1);
pt(64, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(64, 28, 0, 1, 0, 4, 350, 30, 22, 0, 1, 0, 1, 2, 5, 6);
strcpy(400 + 64, "Ocarina");
pt(65, 0, 0, 37, 0, 0.745, 2, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(65, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(65, 28, 0, 1, 0, 4, 350, 30, 21, 0, 1, 1, 1, 2, 5, 7);
strcpy(400 + 65, "Square Lead");
pt(66, 0, 0, 22, 0, 0.535, 2, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(66, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(66, 28, 0, 1, 0, 4, 350, 30, 25, 0, 1, 1, 1, 1, 5, 7);
strcpy(400 + 66, "Calliope Lead");
pt(67, 0, 1, 28, 0.3, 1.606, 2, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(67, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(67, 28, 0, 1, 0, 4, 350, 30, 22, 0, 1, 0, 1, 2, 5, 7);
strcpy(400 + 67, "Square Wave");
pt(68, 0, 1, 29, 0.3, 1.48, 2, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(68, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(68, 28, 0, 1, 0, 4, 350, 30, 22, 0, 1, 0, 1, 2, 5, 7);
strcpy(400 + 68, "Saw Lead");
pt(69, 0, 1, 30, 0.3, 1.565, 2, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(69, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(69, 28, 0, 1, 0, 4, 350, 30, 22, 0, 1, 0, 1, 2, 5, 7);
strcpy(400 + 69, "Calliope");
pt(70, 0, 1, 31, 0.3, 1.665, 2, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(70, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(70, 28, 0, 1, 0, 4, 350, 30, 22, 0, 1, 0, 1, 2, 5, 7);
strcpy(400 + 70, "Chiff Lead");
pt(71, 0, 1, 32, 0.3, 1.624, 2, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(71, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(71, 28, 0, 1, 0, 4, 350, 30, 22, 0, 1, 0, 1, 2, 5, 7);
strcpy(400 + 71, "Charang");
pt(72, 0, 1, 33, 0.3, 1.403, 2, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(72, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(72, 28, 0, 1, 0, 4, 350, 30, 22, 0, 1, 0, 1, 2, 5, 7);
strcpy(400 + 72, "Voice Lead");
pt(73, 0, 1, 34, 0.3, 2.171, 2, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(73, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(73, 28, 0, 1, 0, 4, 350, 30, 22, 0, 1, 0, 1, 2, 5, 7);
strcpy(400 + 73, "Fifth Lead");
pt(74, 0, 1, 35, 0.3, 1.817, 2, 1.8, 18, 0.8, 50, 0, 0, 1, 0, 1);
pt(74, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(74, 28, 0, 1, 0, 4, 350, 30, 22, 0, 1, 0, 1, 2, 5, 7);
strcpy(400 + 74, "Bass & Lead");
pt(75, 0, 0, 5, 0, 0.588, 0, 1, 6, 0.8, 50, 0, 0, 1, 0, 1);
pt(75, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(75, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 8);
strcpy(400 + 75, "Bass Synth");
pt(76, 0, 0, 15, 0, 0.306, 0, 1, 6, 0.8, 50, 0, 0, 1, 0, 1);
pt(76, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(76, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 8);
strcpy(400 + 76, "Sub Bass");
pt(77, 0, 0, 16, 0, 0.911, 0, 1, 6, 0.8, 50, 0, 0, 1, 0, 1);
pt(77, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(77, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 8);
strcpy(400 + 77, "Acid Bass");
pt(78, 0, 0, 17, 0, 0.565, 0, 1, 6, 0.8, 50, 0, 0, 1, 0, 1);
pt(78, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(78, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 8);
strcpy(400 + 78, "Round Bass");
pt(79, 0, 0, 18, 0, 0.801, 0, 1, 6, 0.8, 50, 0, 0, 1, 0, 1);
pt(79, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(79, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 8);
strcpy(400 + 79, "Pluck Bass");
pt(80, 0, 0, 19, 0, 0.265, 0, 1, 6, 0.8, 50, 0, 0, 1, 0, 1);
pt(80, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(80, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 8);
strcpy(400 + 80, "Hollow Bass");
pt(81, 0, 0, 20, 0, 0.738, 0, 1, 6, 0.8, 50, 0, 0, 1, 0, 1);
pt(81, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(81, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 8);
strcpy(400 + 81, "Reese Bass");
pt(82, 0, 1, 15, 0, 1.546, 0, 1, 6, 0.8, 50, 0, 0, 1, 0, 1);
pt(82, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(82, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 8);
strcpy(400 + 82, "Acoustic Bass");
pt(83, 0, 1, 16, 0, 1.738, 0, 1, 6, 0.8, 50, 0, 0, 1, 0, 1);
pt(83, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(83, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 8);
strcpy(400 + 83, "Finger Bass");
pt(84, 0, 1, 17, 0, 1.422, 0, 1, 6, 0.8, 50, 0, 0, 1, 0, 1);
pt(84, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(84, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 8);
strcpy(400 + 84, "Synth Bass 1");
pt(85, 0, 1, 18, 0, 1.536, 0, 1, 6, 0.8, 50, 0, 0, 1, 0, 1);
pt(85, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(85, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 8);
strcpy(400 + 85, "Synth Bass 2");
pt(86, 0, 1, 19, 0, 1.868, 0, 1, 6, 0.8, 50, 0, 0, 1, 0, 1);
pt(86, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(86, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 8);
strcpy(400 + 86, "Synth Bass 3");
pt(87, 0, 2, 0, 0, 0.698, 0, 1.2, 12, 0.8, 50, 0, 0, 1, 0, 1);
pt(87, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(87, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 9);
strcpy(400 + 87, "Drum Kit");
pt(88, 0, 1, 44, 0.2, 1.19, 0, 1.2, 12, 0.8, 50, 0, 0, 1, 0, 1);
pt(88, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(88, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 9);
strcpy(400 + 88, "Agogo");
pt(89, 0, 1, 45, 0.2, 2.139, 0, 1.2, 12, 0.8, 50, 0, 0, 1, 0, 1);
pt(89, 14, 0, 2, 4, 0, 0, 1, 0, 1, 0, 5, 1.5, 0, 0, 1);
pt(89, 28, 0, 1, 0, 4, 350, 30, 0, 0, 1, 0, 1, 0, 4, 9);
strcpy(400 + 89, "Woodblock");
function grp_name(k) ( k == 0 ? "Pianos & Keys" : k == 1 ? "Mallets & Bells" : k == 2 ? "Guitars & Plucks" : k == 3 ? "Strings & Orchestra" : k == 4 ? "Pads" : k == 5 ? "Choirs & Voices" : k == 6 ? "Brass & Winds" : k == 7 ? "Leads" : k == 8 ? "Basses" : "Drums & Perc"; );
function grp_start(k) ( k == 0 ? 0 : k == 1 ? 10 : k == 2 ? 22 : k == 3 ? 35 : k == 4 ? 44 : k == 5 ? 52 : k == 6 ? 57 : k == 7 ? 65 : k == 8 ? 75 : k == 9 ? 87 : 90; );
function pname(p) ( 400 + min(max(floor(p + 0.5), 0), NP - 1); );
function pgrp(p) ( PT[min(max(floor(p + 0.5), 0), NP - 1)*64 + 41]; );

function update() (
  tone = slider5/100; filt_oct = slider6; reso = slider7/100;
  atk_k = slider8/100; rel_k = slider9/100; chor_k = 1; dec_k = slider53/100; sus_o = slider54/100;
  fam_k = slider55/100; fatk_k = slider56/100; fdec_k = slider57/100; fsus_o = slider58/100; frel_k = slider59/100;
  sens = slider11/100; tune = 2^(slider12/1200);
  drift = 0.1 * slider38 / 50; chan = slider4;   // MAIN DRIFT: 50 % = the Stable PC70's fixed amount
  bs_on = slider3 > 0.5; split = floor(slider10 + 0.5); bs_oct = floor(slider30 + 0.5);
  bs_gain = 10 ^ (slider32 / 20); bs_amt = 0.1 * slider33 / 50;        // BASS DRIFT, the same scale
  out_t = 10^(slider2/20);
  ins_output_setup(60); ins_stereo_setup(24);   // output stage: CLIP, always on
  rv_update(); mr_update();
);
// the sound engine for a patch (no sliders touched)
function patch_engine(p) local(o) (
  p = min(max(floor(p + 0.5), 0), NP - 1);
  o = PT + p*64;
  kill_all();
  o[0] == 0 ? patch_set(o[1]) : (
    patch_set(-1);                                    // neutral analogue settings, then the GM voice / drums
    eng = o[0] == 1 ? 6 : 7; gprog = o[1];
    chor = o[2]; lvl = 0.4; mono = 0;
  );
  ptr_t = o[3]; cur_p = p;
);
// choose a patch: its engine, its Mod Rack and reverb, and the EDIT knobs back to centre
function load_patch(p) local(o, i, k) (
  p = min(max(floor(p + 0.5), 0), NP - 1);
  o = PT + p*64;
  slider1 = p;
  slider5 = 50; slider6 = 0; slider7 = 0; slider8 = 100; slider9 = 100;
  slider53 = 100; slider54 = 0; slider55 = 100; slider56 = 100; slider57 = 100; slider58 = 0; slider59 = 100;
  slider14 = o[4]; slider16 = o[5]; slider18 = o[6];
  // the patch table keeps the Stable layout (slider 19 + i = o[7 + i]); its L / C / R triples pack into one slider each
  i = 0; loop(34, k = 19 + i; (k >= 19 && k <= 21) || k == 26 || k == 27 || k == 28 || k == 29 || (k >= 34 && k <= 37) || (k >= 42 && k <= 46) || k == 51 || k == 52 ? slider(k) = o[7 + i]; i += 1; );
  slider23 = o[11] + 2 * o[12] + 4 * o[13]; slider31 = o[19] + 2 * o[20] + 4 * o[21];
  slider39 = o[27] + 2 * o[28] + 4 * o[29]; slider48 = o[36] + 2 * o[37] + 4 * o[38];
  ui_auto(1); i = 5; loop(5, ui_auto(i); i += 1; ); ui_auto(14); ui_auto(16); ui_auto(18);
  i = 53; loop(7, ui_auto(i); i += 1; );
  i = 19; loop(34, ui_auto(i); i += 1; );
  patch_engine(p);
  update();
);

// ---------- state ----------
ins_drift_init();
bdP.drift_init(0.8 + rand(1) * 0.5); bdC.drift_init(0.8 + rand(1) * 0.5);   // the bass part's own drift
bs_pitch = 1; bs_cut = 0; bs_pd = 1; bs_cur = -1; bs_g = 1; bs_gt = 1; bs_mn = -1; bs_mf = 0; bs_act = 0; lrn_dirty = 0; splt_d = -1;
ost_init(90000); ostL.ost_ch_init(); ostR.ost_ch_init();
fA1.svf_set(730, 5); fA2.svf_set(1090, 7); fA3.svf_set(2440, 9);
sm = 1 - exp(-1 / (0.03 * srate));
pkL = 0; pkR = 0; nact = 0; vph = 0; flph = 0;
!ui_dflt ? ( ui_sz = 2; p70_page = 0; );
patch_engine(slider1); ptr_s = ptr_t;
update();
out_s = out_t; bs_gs = bs_gain;
last_p = -1;                                    // the first block adopts the saved patch without reloading it
ui_dflt = 1;

@slider
update();

@block
last_p < 0 ? last_p = slider1 : slider1 != last_p ? ( load_patch(slider1); last_p = slider1; );
update();                                       // knobs turned on the GUI take effect here
evn = 0; pc_req = -1;
while (midirecv(mofs, m1, m2, m3)) (
  stt = m1 & 0xF0; mch = (m1 & 0x0F) + 1;
  (chan == 0 || mch == chan) ? (
    stt == 0xE0 ? bend_t = ((m3*128 + m2) - 8192)/8192*slider13 :
    stt == 0xC0 ? pc_req = m2 :
    evn < 512 ? ( evq[evn * 4] = mofs; evq[evn * 4 + 1] = stt; evq[evn * 4 + 2] = m2; evq[evn * 4 + 3] = m3; evn += 1; );
  );
);
// transport stop: release whatever is still held (as an all-notes-off would; a safety net if the stop's note-offs go missing)
gfx_pst = play_state == 1 || play_state == 5;
gfx_pst_prev && !gfx_pst ? ( all_off(); );
gfx_pst_prev = gfx_pst;
pc_req >= 0 && pc_req < NP ? ( load_patch(pc_req); last_p = slider1; );
evi = 0; spos = 0;
panic_req ? ( all_off(); panic_req = 0; );
ins_drift_block(drift, samplesblock);            // GFX instrument drift (MAIN DRIFT)
bs_inc = 0.35 * samplesblock / srate;            // BASS DRIFT: its own wander, apart from the patch's
bs_pitch = 2 ^ (bdP.drift_tick(bs_inc) * bs_amt * 0.2 / 12);
bs_cut = bdC.drift_tick(bs_inc) * bs_amt * 0.45;
// BASS sound: a change fades the bass part out (about 10 ms), swaps, and comes back
bs_req = min(max(floor(slider22 + 0.5), 0), 11);
bs_req != bs_cur ? (
  !bs_act || bs_g < 0.001 ? (
    memset(VB + NV * VS, 0, NB * VS); memset(KSB + NV * KSL, 0, NB * KSL); bs_mn = -1; bs_act = 0;
    bs_set(bs_req); bs_cur = bs_req; bs_gt = 1;
  ) : bs_gt = 0;
);
bs_coef(); bs_fk = 1 - exp(-1 / (0.002 * srate)); dc_r = exp(-2 * $pi * 5 / srate);
eng_d = eng;                                     // for the panel (the bass part borrows eng for a moment)
bend_c = 1 - exp(-1/(0.004*srate));
// envelope coefficients (with the ATTACK / RELEASE macros)
a_inc = 1 / max(max(aA * atk_k + max(0, atk_k - 1) * 0.15, 0.003) * srate, 1);      // never faster than 3 ms (no click)
fi_step = 1 / ((eng == 1 ? 0.003 : 0.002) * srate); dc_k = exp(-1 / (0.002 * srate));
f_inc = 1 / max(max(fA * fatk_k + max(0, fatk_k - 1) * 0.15, 0.002) * srate, 1);
a_dec = tc(aD * dec_k); a_rel = tc(aR * rel_k);
f_dec = tc(fD * fdec_k); f_rel = tc(aR * frel_k); ks_rd = 0.8 ^ (1 / (rel_k * rel_k));
aS_e = min(max(aS + sus_o, 0), 1); fS_e = min(max(fS + fsus_o, 0), 1);   // SUSTAIN moves the patch's level
gl_c = glide > 0 ? 1 - exp(-1 / (glide * srate)) : 1;
fm_rel = tc(0.28 * rel_k); ks_damp = 0.6; gl_rel = tc(1.5 * rel_k); chf_d = tc(0.03);
tone_oct = (tone - 0.5) * 3;                     // TONE: +/- 1.5 octaves on filters / brightness
fl_k = 1 - exp(-1 / (0.015 * srate));
// output filter for the FM / string / bar / piano / organ sounds (FILTER 0 and no RESONANCE = bypassed)
gf_on = eng >= 1 && eng <= 5 && (filt_oct < -0.01 || reso > 0.005);
// analogue sounds: the knobs move each note's filter (the output filter and va_res: fl_gf, from the glides)
fl_ok ? fl_gf();
pe_c = tc(pe_t); pn_damp = tc(0.18 * rel_k) ^ 0.5; pn_kd = tc(0.012); org_rel = tc(0.03 * rel_k); org_ck = tc(0.004);
(eng == 4 || eng == 5) ? ( pv = 0; loop(NV, VB[pv * VS + F_ACT] ? pn_norm(VB + pv * VS); pv += 1; ); );
// tempo: the host's when playing, else free-running at its tempo
bt_inc = tempo / 60 / srate;
(play_state & 1) ? bt_pos = beat_position;
mr_block();

@serialize
file_var(0, ui_sz);
file_var(0, p70_page);

@sample
while (evi < evn && (evq[evi * 4] <= spos || spos >= samplesblock - 1)) (   // (an event stamped at / past the block end: handled at its last sample)
  e1 = evq[evi * 4 + 1]; e2 = evq[evi * 4 + 2]; e3 = evq[evi * 4 + 3];
  e1 == 0x90 && e3 > 0 ? (
    lrn_dirty == 1 ? ( splt_d = e2; lrn_dirty = 2; ) :              // LEARN: this key becomes the split point
    bs_on && e2 < split ? bs_note_on(e2, e3) : note_on(e2, e3);
    ins_midi_hit();
  ) :
  e1 == 0x80 || e1 == 0x90 ? ( note_off(e2); bs_note_off(e2); ) :
  e1 == 0xB0 ? (
    e2 == 64 ? pedal_set(e3 >= 64);
    e2 == 1 ? modw = e3 / 127;
    e2 == 120 || e2 == 123 ? all_off();
  );
  evi += 1;
);
spos += 1;
// FILTER, RESONANCE, TONE and the filter envelope's AMOUNT glide (two 15 ms stages on the octaves, 15 ms on the rest),
// so a turned knob never steps; the output filter and the analogue voices' resonance follow every 16 samples
!fl_ok ? ( fl_f1 = fl_fo = filt_oct; fl_t1 = fl_to = tone_oct; fl_rs = reso; fl_fa = fam_k; fl_ok = 1; );
fl_f1 += (filt_oct - fl_f1) * fl_k; fl_fo += (fl_f1 - fl_fo) * fl_k; fl_t1 += (tone_oct - fl_t1) * fl_k; fl_to += (fl_t1 - fl_to) * fl_k;
fl_rs += (reso - fl_rs) * fl_k; fl_fa += (fam_k - fl_fa) * fl_k;
(fl_n -= 1) <= 0 ? ( fl_n = 16; fl_gf(); );
bend_m += (2^(bend_t/12) - bend_m)*bend_c;
pdrift = ins_pitch*bend_m;
nz = rand(2) - 1;
vph += (vib > 0 ? vib : 5.5) / srate; vph >= 1 ? vph -= 1;
flph += 0.13 / srate; flph >= 1 ? flph -= 1;
// NATIVE DANCE: a 16-step log-drum pattern, retuned to each held note
nd ? (
  ndst = floor(bt_pos * 4) & 15;
  ndst != nd_last ? (
    nd_last = ndst;
    ndh = ndst == 0 || ndst == 3 || ndst == 6 || ndst == 8 || ndst == 10 || ndst == 11 || ndst == 14;
    ndh ? (
      ndr = ndst == 6 || ndst == 14 ? 1.5 : ndst == 10 ? 2 : ndst == 11 ? 0.75 : 1;
      nda = ndst == 0 || ndst == 8 ? 1 : 0.6;
      av = 0;
      loop(NV,
        b = VB + av * VS;
        b[F_ACT] && (b[F_G] || b[F_S]) ? (
          bell_set(b, b[F_F0] * 0.5, 1, 1, ndr,        b[F_VEL] * bl_lvl * nda, 0.22, 0);
          bell_set(b, b[F_F0] * 0.5, 1, 1, ndr * 2.76, b[F_VEL] * bl_lvl * nda * 0.35, 0.07, 1);
          bell_set(b, b[F_F0] * 0.5, 1, 1, ndr * 4.1,  b[F_VEL] * bl_lvl * nda * 0.15, 0.04, 2);
          b[F_CLK] = b[F_VEL] * 0.12 * nda;
        );
        av += 1;
      );
    ) : ndst % 2 == 1 ? (
      av = 0; loop(NV, b = VB + av * VS; b[F_ACT] && (b[F_G] || b[F_S]) ? b[F_CLK] = b[F_VEL] * 0.05; av += 1; );   // shaker ticks
    );
  );
);
bt_pos += bt_inc;
mix = 0; nact = 0;
av = 0;
loop(NV,
  b = VB + av * VS;
  b[F_ACT] ? (
    nact += 1;
    held = b[F_G] || b[F_S];
    y = 0;
    eng >= 6 ? (
      // ---------- GM voice / drum kit ----------
      y = p_run(av, b + 100, held);
      b[100] == 0 ? b[F_ACT] = 0;
    ) : eng == 0 ? (
      // ---------- analogue voice ----------
      mono ? ( mono_f += (b[F_F0] - mono_f) * gl_c; f = mono_f; ) : f = b[F_F0];
      b[F_VT] = min(b[F_VT] + 1 / (0.6 * srate), 1);                         // delayed vibrato
      f *= b[F_DT] * pdrift * (1 + (vibd * 0.006 * b[F_VT] * (vib > 0) + modw * 0.008) * sin(2 * $pi * vph));
      b[F_PE] != 0 ? ( f *= 2 ^ (b[F_PE] / 12); b[F_PE] *= pe_c; abs(b[F_PE]) < 0.001 ? b[F_PE] = 0; );   // pitch envelope
      dt = f / srate;
      b[F_P1] += dt * (1 + det); b[F_P1] >= 1 ? b[F_P1] -= 1;
      b[F_P2] += dt * (1 - det); b[F_P2] >= 1 ? b[F_P2] -= 1;
      b[F_P3] += dt * 0.5;       b[F_P3] >= 1 ? b[F_P3] -= 1;
      x = (o1w == 2 ? sqw(b[F_P1], dt * (1 + det)) : o1w ? 1.2 * sin(2 * $pi * b[F_P1]) : saw(b[F_P1], dt * (1 + det))) + o2l * (o2w ? sqw(b[F_P2], dt) : saw(b[F_P2], dt * (1 - det))) + subl * sqw(b[F_P3], dt * 0.5);
      // envelopes
      held ? (
        b[F_AST] == 0 ? ( b[F_AE] += a_inc; b[F_AE] >= 1 ? ( b[F_AE] = 1; b[F_AST] = 1; ); ) : b[F_AE] = aS_e + (b[F_AE] - aS_e) * a_dec;
        b[F_FST] == 0 ? ( b[F_FE] += f_inc; b[F_FE] >= 1 ? ( b[F_FE] = 1; b[F_FST] = 1; ); ) : b[F_FE] = fS_e + (b[F_FE] - fS_e) * f_dec;
      ) : ( b[F_AE] *= a_rel; b[F_FE] *= f_rel; );
      // 4-pole filter
      fc = fbase * 2 ^ ((famt * fl_fa + max(0, fl_fa - 1) * 1.5) * b[F_FE] * (vf > 0 ? (1 - vf) * (0.6 + 0.4 * b[F_VEL]) + vf * b[F_VEL] * b[F_VEL] * 1.2 : 0.6 + 0.4 * b[F_VEL]) + fl_to + fl_fo + b[F_E1] + ins_cut + ktrk * log(f / 261.6) / log(2) + flfo * sin(2 * $pi * flph));
      g = tan($pi * min(fc, srate * 0.42) / srate); gG = g / (1 + g);
      u = tanh_(x * 0.5 - va_res * 3.9 * b[F_S4]);
      v_ = (u - b[F_S1]) * gG; y1 = v_ + b[F_S1]; b[F_S1] = y1 + v_;
      v_ = (y1 - b[F_S2]) * gG; y2 = v_ + b[F_S2]; b[F_S2] = y2 + v_;
      v_ = (y2 - b[F_S3]) * gG; y3 = v_ + b[F_S3]; b[F_S3] = y3 + v_;
      v_ = (y3 - b[F_S4]) * gG; y4 = v_ + b[F_S4]; b[F_S4] = y4 + v_;
      y = y4 * b[F_AE] * b[F_VEL] * 2 * (1 + 0.8 * va_res) * vamix;
      // attack / extra layers
      bl_lvl > 0 ? y += 0.6 * bell_tick(b, held ? 1 : gl_rel) : bell_amp = 0;
      ks_lvl > 0 ? y += ks_tick(av, b, ks_pick, 0) : b[F_O3] = 0;
      br_lvl > 0 || b[F_CLK] > 0.0005 ? (
        b[F_O1] += (nz - b[F_O1]) * 0.35; b[F_O2] += (b[F_O1] - b[F_O2]) * 0.03;      // breath band
        brp ? (
          // the pipes: breath through a narrow band an octave above the note (it sounds with the pipe, not as hiss);
          // the broad band only for the brief chiff
          bfc = 2 * sin($pi * min(f * 2, 6000) / srate);
          b[F_KLP] += bfc * b[F_KAP]; bfh = nz * br_lvl * b[F_AE] * b[F_VEL] - b[F_KLP] - 0.3 * b[F_KAP]; b[F_KAP] += bfc * bfh;
          y += b[F_KAP] * 0.8 + (b[F_O1] - b[F_O2]) * b[F_CLK];
        ) : y += (b[F_O1] - b[F_O2]) * (br_lvl * b[F_AE] * b[F_VEL] + b[F_CLK]);
        b[F_CLK] *= chf_d;
      );
      !held && b[F_AE] < 0.0003 && bell_amp < 0.0003 && b[F_O3] < 0.0002 ? (
        b[F_ACT] = 0; ks_lvl > 0 ? memset(KSB + av * KSL, 0, KSL);
      );
    ) : eng == 1 ? (
      // ---------- FM e-piano ----------
      f = b[F_F0] * pdrift * (1 + modw * 0.008 * sin(2 * $pi * vph));
      b[F_O1] += f / srate;          b[F_O1] -= floor(b[F_O1]);
      b[F_O2] += f / srate;          b[F_O2] -= floor(b[F_O2]);
      b[F_O3] += f * 1.0017 / srate; b[F_O3] -= floor(b[F_O3]);
      b[F_O4] += f * 14 / srate;     b[F_O4] -= floor(b[F_O4]);
      br = 2 ^ (tone_oct * 0.5);
      m2 = sin(2 * $pi * b[F_O2]) * b[F_E2] * br;
      m4 = sin(2 * $pi * b[F_O4]) * b[F_E4] * br;
      y = (0.62 * sin(2 * $pi * b[F_O1] + m2) * b[F_E1] + 0.42 * sin(2 * $pi * b[F_O3] + m4) * b[F_E3]);
      rm = held ? 1 : fm_rel;
      b[F_E1] *= b[F_MD] * rm; b[F_E2] *= b[F_MD + 1]; b[F_E3] *= b[F_MD + 2] * rm; b[F_E4] *= b[F_MD + 3];
      y *= 0.6;
      b[F_E1] + b[F_E3] < 0.0003 ? b[F_ACT] = 0;
    ) : eng == 4 ? (
      // ---------- synthetic piano ----------
      rm = held ? 1 : pn_damp;
      y = pn_tick(b, rm) * 0.5;
      b[F_CLK] > 0.0003 ? (                                    // knock: a low thud and a short click
        b[F_HN] += (nz - b[F_HN]) * 0.08; b[F_HL] += (b[F_HN] - b[F_HL]) * 0.02;
        y += (b[F_HN] - b[F_HL] * 0.6) * b[F_CLK]; b[F_CLK] *= pn_kd;
      );
      pn_amp < 0.0003 && b[F_CLK] < 0.0003 ? b[F_ACT] = 0;
    ) : eng == 5 ? (
      // ---------- drawbar organ ----------
      held ? b[F_AE] = 1 : b[F_AE] *= org_rel;
      y = pn_tick(b, 1) * b[F_AE];
      b[F_CLK] > 0.0003 ? ( b[F_HN] += (nz - b[F_HN]) * 0.5; y += (nz - b[F_HN]) * b[F_CLK]; b[F_CLK] *= org_ck; );
      !held && b[F_AE] < 0.0003 ? b[F_ACT] = 0;
    ) : eng == 2 ? (
      // ---------- clav string ----------
      y = ks_tick(av, b, 1, 1);
      !held && b[F_O3] < 0.0002 ? ( b[F_ACT] = 0; memset(KSB + av * KSL, 0, KSL); );
    ) : (
      // ---------- glockenspiel bar ----------
      y = bell_tick(b, held ? 1 : gl_rel); amp = bell_amp;
      b[F_CLK] > 0.0005 ? ( b[F_KHP] += (nz - b[F_KHP]) * 0.45; y += (nz - b[F_KHP]) * b[F_CLK]; b[F_CLK] *= 0.993; );
      y *= 0.6;
      amp < 0.0003 && b[F_CLK] < 0.0005 ? b[F_ACT] = 0;
    );
    // de-click: fade-in for struck sounds, and any jump at a (re)start is smoothed over ~2 ms
    b[F_ATK] < 1 ? ( b[F_ATK] = min(b[F_ATK] + fi_step, 1); y *= b[F_ATK]; );
    b[F_DCF] ? ( b[F_DCO] = 2 * b[F_PY] - b[F_PY2] - y; b[F_DCF] = 0; );   // continue the waveform's own slope
    y += b[F_DCO]; b[F_DCO] *= dc_k;
    b[F_PY2] = b[F_PY]; b[F_PY] = y;
    mix += y;
  );
  av += 1;
);
// ---------- the SPLIT bass part ----------
bsy = 0;
bs_g += (bs_gt - bs_g) * bs_fk; bs_gs += (bs_gain - bs_gs) * sm;
bs_act ? (
  bs_pd = bs_pitch * bend_m; bs_cx = 0; bs_act = 0;
  av = NV;
  loop(NB,
    b = VB + av * VS;
    b[F_ACT] ? (
      bs_act = 1;
      held = b[F_G] || b[F_S];
      bs_eng == 6 ? (
        !bs_cx ? ( bs_ctx_in(); bs_cx = 1; );
        y = p_run(av, b + 100, held);
        b[100] == 0 ? b[F_ACT] = 0;
      ) : y = bs_voice(b, held);
      b[F_ATK] < 1 ? ( b[F_ATK] = min(b[F_ATK] + fi_step, 1); y *= b[F_ATK]; );
      b[F_DCF] ? ( b[F_DCO] = 2 * b[F_PY] - b[F_PY2] - y; b[F_DCF] = 0; );
      y += b[F_DCO]; b[F_DCO] *= dc_k;
      b[F_PY2] = b[F_PY]; b[F_PY] = y;
      bsy += y;
    );
    av += 1;
  );
  bs_cx ? bs_ctx_out();
  bsy *= bs_lvl * bs_trim * bs_g * bs_gs;
);
mix *= lvl;
// 5 Hz DC blockers: the analogue voices' resonant ladder (tanh in its feedback) leaves a small offset that grows with
// pitch - Synth Pad played across the keys put about -27 dBFS of DC on the output
dcm_y = mix - dcm_x + dc_r * dcm_y; dcm_x = mix; mix = dcm_y;
dcb_y = bsy - dcb_x + dc_r * dcb_y; dcb_x = bsy; bsy = dcb_y;
form ? (
  // "aah": three vocal formants
  fo1 = fA1.svf_bp(mix); fo2 = fA2.svf_bp(mix); fo3 = fA3.svf_bp(mix);
  mix = 0.25 * mix + 1.6 * fo1 + 1.1 * fo2 + 0.7 * fo3;
);
gf_on ? (
  gv3 = mix - gf2; gv1 = gf_a1 * gf1 + gf_a2 * gv3; gv2 = gf2 + gf_a2 * gf1 + gf_a3 * gv3;
  gf1 = 2 * gv1 - gf1; gf2 = 2 * gv2 - gf2;
  mix = gv2;
) : ( gf1 = 0; gf2 = 0; );

// chorus / three-phase ensemble
cbuf[cwp] = mix;
ca = chor * chor_k;
ca > 0.001 ? (
  cps += crate * (1 + 0.15 * ins_fx) / srate; cps >= 1 ? cps -= 1;
  cpf += 5.5 / srate; cpf >= 1 ? cpf -= 1;
  aj = 0; t0 = 0; t1 = 0; t2 = 0;
  loop(3,
    d_ = (0.007 + ((crate > 2 ? 0.0006 : 0.0017) * sin(2 * $pi * cps + aj * 2.0944) + (three ? 0.0004 * sin(2 * $pi * cpf + aj * 2.0944) : 0)) * min(ca, 1.5)) * srate;
    rp2 = cwp - d_; ri = floor(rp2); rf = rp2 - ri;
    tv = cbuf[ri & cmask] * (1 - rf) + cbuf[(ri + 1) & cmask] * rf;
    aj == 0 ? t0 = tv : aj == 1 ? t1 = tv : t2 = tv;
    aj += 1;
  );
  wet = min(ca, 1);
  oL = mix * (1 - 0.5 * wet) + wet * (t0 + 0.5 * t1) * 0.7;
  oR = mix * (1 - 0.5 * wet) + wet * (t2 + 0.5 * t1) * 0.7;
) : ( oL = mix; oR = mix; );
cwp = (cwp + 1) & cmask;

// ---------- the Mod Rack ----------
mrL = oL; mrR = oR;
mrOn ? mr_run();
oL = mrL; oR = mrR;

// ---------- reverb send ----------
// the reverb sleeps once its input has been below -140 dB for longer than its lines and its tail has died away
// below -140 dB too; asleep, only its write positions and LFOs tick on, so it wakes exactly in step
rin = 0.5 * (oL + oR) * (rv_on ? 1 : 0);
abs(rin) > 0.0000001 ? rv_z = 0 : rv_z += 1;
(rv_on || rv_tail > 0.00001) && (rv_z < rpre_len + RBLK || rv_tail > 0.0000001) ? (
  rpre_b[rpre_w] = rin;
  rq = rpre_w - floor(rpre); rq < 0 ? rq += rpre_len;
  rd = rpre_b[rq];
  rpre_w += 1; rpre_w >= rpre_len ? rpre_w = 0;
  ak = 0;
  loop(4,
    rn = floor(rapl[ak] * srate / 48000 * (0.6 + 0.4 * rdiff));
    ro = rap_b + ak * 4096; rw = rapw[ak];
    rr = rw - rn; rr < 0 ? rr += 4096;
    rbv = ro[rr]; ryv = -rdiff * 0.75 * rd + rbv; ro[rw] = rd + rdiff * 0.75 * ryv; rd = ryv;
    rapw[ak] = (rw + 1) % 4096;
    ak += 1;
  );
  ak = 0;
  loop(8,
    rlph[ak] += rlrt[ak] / srate; rlph[ak] >= 1 ? rlph[ak] -= 1;
    rm = rmod * srate * sin(2 * $pi * rlph[ak]);
    rp3 = rlw[ak] - rllen[ak] - rm; rp3 < 0 ? rp3 += RBLK;
    ri3 = floor(rp3); rf3 = rp3 - ri3; ro = rln_b + ak * RBLK;
    rv3 = ro[ri3 % RBLK] * (1 - rf3) + ro[(ri3 + 1) % RBLK] * rf3;
    rlz[ak] = rlgb[ak] * rv3 + rlga[ak] * rlz[ak];
    rtmp[ak] = rlz[ak];
    ak += 1;
  );
  ra0 = rtmp[0]; ra1 = rtmp[1]; ra2 = rtmp[2]; ra3 = rtmp[3]; ra4 = rtmp[4]; ra5 = rtmp[5]; ra6 = rtmp[6]; ra7 = rtmp[7];
  rb0 = ra0 + ra1; rb1 = ra0 - ra1; rb2 = ra2 + ra3; rb3 = ra2 - ra3; rb4 = ra4 + ra5; rb5 = ra4 - ra5; rb6 = ra6 + ra7; rb7 = ra6 - ra7;
  rc0 = rb0 + rb2; rc1 = rb1 + rb3; rc2 = rb0 - rb2; rc3 = rb1 - rb3; rc4 = rb4 + rb6; rc5 = rb5 + rb7; rc6 = rb4 - rb6; rc7 = rb5 - rb7;
  rmix[0] = (rc0 + rc4) * 0.35355339; rmix[1] = (rc1 + rc5) * 0.35355339; rmix[2] = (rc2 + rc6) * 0.35355339; rmix[3] = (rc3 + rc7) * 0.35355339;
  rmix[4] = (rc0 - rc4) * 0.35355339; rmix[5] = (rc1 - rc5) * 0.35355339; rmix[6] = (rc2 - rc6) * 0.35355339; rmix[7] = (rc3 - rc7) * 0.35355339;
  ak = 0;
  loop(8,
    ro = rln_b + ak * RBLK;
    ro[rlw[ak]] = rmix[ak] + rd * (ak & 1 ? -0.5 : 0.5);
    rlw[ak] += 1; rlw[ak] >= RBLK ? rlw[ak] = 0;
    ak += 1;
  );
  rvL = (ra0 - ra2 + ra4 - ra6 + 0.5 * (ra1 + ra5)) * 0.5;
  rvR = (ra1 - ra3 + ra5 - ra7 + 0.5 * (ra2 - ra6)) * 0.5;
  rv_tail = max(abs(rvL), abs(rvR)) * 0.001 + rv_tail * 0.999;
  oL += rvL * rv_wet * 2.4; oR += rvR * rv_wet * 2.4;      // +12 dB: the wet level now sits where it can be heard
) : rv_on || rv_tail > 0.00001 ? (
  rpre_w += 1; rpre_w >= rpre_len ? rpre_w = 0;
  ak = 0; loop(4, rapw[ak] = (rapw[ak] + 1) % 4096; ak += 1; );
  ak = 0; loop(8, rlph[ak] += rlrt[ak] / srate; rlph[ak] >= 1 ? rlph[ak] -= 1; rlw[ak] += 1; rlw[ak] >= RBLK ? rlw[ak] = 0; ak += 1; );
  rv_tail *= 0.999;
);

out_s += (out_t - out_s) * sm;
ptr_s = ptr_t;
oL = ostL.ost_band(oL * ptr_s + bsy) * out_s;      // the bass joins dry, centred
oR = ostR.ost_band(oR * ptr_s + bsy) * out_s;
ins_stereo(oL, oR); ost_out(ins_sl, ins_sr);           // mono-maker / widener, then the output stage
spl0 = ost_l;
spl1 = ost_r;

@gfx 960 653
// =====================================================================
// GUI - a top bar with the backlit LCD, then page 1 (LIST: every patch by group, click a name to play it) or
// page 2 (EDIT: TONE, FILTER and AMP ENVELOPES, PLAY, REVERB and the patch's MOD RACK), with the SPLIT strip between
// them (always shown). Design space 1280 x 870 at qs = 0.75 * sc; the pages are drawn yo = 110 lower than they were.
// =====================================================================
ui_begin(960, 653);
qs = sc*0.75;
gfx_setfont(8, "Trebuchet MS", 13*qs, 'b');
gfx_setfont(9, "Courier New", 28*qs, 'b');
gfx_setfont(10, "Courier New", 17*qs, 'b');
gfx_setfont(11, "Trebuchet MS", 15*qs, 'b');
gfx_setfont(12, "Trebuchet MS", 40*qs, 'b');
gfx_setfont(13, "Trebuchet MS", 17*qs, 'b');
gfx_setfont(14, "Trebuchet MS", 19*qs, 'b');
gfx_setfont(15, "Courier New", 20*qs, 'b');
// patch-list names: the largest size (21 to 25) at which every name fits its row - worked out once per window size
sc != p70_lsc ? (
  p70_lsc = sc; p70_lfs = 25; fit_ = 0;
  loop(5,
    !fit_ ? (
      gfx_setfont(16, "Trebuchet MS", p70_lfs*qs, 'b');
      mw_ = 0; i_ = 0; loop(NP, gfx_measurestr(pname(i_), w_, h_); mw_ = max(mw_, w_); i_ += 1; );
      mw_ <= 158*qs ? fit_ = 1 : p70_lfs -= 1;
    );
  );
);
gfx_setfont(16, "Trebuchet MS", p70_lfs*qs, 'b');
BG = 0xB9BDC1; BG2 = 0xC9CCCF; BG3 = 0xA7ABB0; INK = 0x22262A; INK2 = 0x51575D; ACC = 0x2F6FB8;
LB = 0xBFD0C4; LK = 0x16201C; KC = 0x6A6F76; AMB = 0xFFB030;
FP3 = 0xB0B4B8;

function R(x, y, w, h) ( gfx_rect(x*qs, (y + yo)*qs, max(1, w*qs), max(1, h*qs)); );
function RR(x, y, w, h, r) ( rd_rr(x*qs, (y + yo)*qs, w*qs, h*qs, r*qs); );
function TX(x, y, t) ( gfx_x = x*qs; gfx_y = (y + yo)*qs; gfx_drawstr(t); );
function TXC(cx, y, t) local(w, h) ( gfx_measurestr(t, w, h); gfx_x = cx*qs - w*0.5; gfx_y = (y + yo)*qs; gfx_drawstr(t); );
function inbox(x, y, w, h) ( mouse_x >= x*qs && mouse_x < (x + w)*qs && mouse_y >= (y + yo)*qs && mouse_y < (y + yo + h)*qs; );
function hitbox(x, y, w, h) local(h_) ( h_ = pressed && drag_id == 0 && inbox(x, y, w, h); h_ ? drag_id = -1; h_; );
function setmsg(n, v) ( strcpy(#lcdn, n); strcpy(#lcdv, v); lcd_t = time_precise(); );
function setv(idx, v) ( slider(idx) = v; ui_auto(idx); );
function tog(idx) ( slider(idx) = slider(idx) < 0.5; ui_auto(idx); );
function touch(idx, name, val) ( drag_id == 1600 + idx ? setmsg(name, val); );
function sect(x, y, w, h, t) (
  ui_col(BG3); RR(x, y, w, h, 6); ui_col(BG2); RR(x + 2, y + 2, w - 4, h - 4, 5);
  gfx_setfont(13); ui_col(ACC); TX(x + 12, y + 8, t);
);
// knob on a slider: value on hover / drag only (house style); its name and value go to the LCD while turning
function knob(idx, cx, cy, r, lo, hi, def, lg, cap, label, val) (
  dy_kst = 7; dy_ink = INK; dy_ntick = 11;
  dy_knob(cx*0.75, (cy + yo)*0.75, r*0.75, idx, lo, hi, def, lg, cap, label, val);
  touch(idx, label, val);
);
function sknob(idx, cx, cy, r, lo, hi, def, cap, label, val) (
  knob(idx, cx, cy, r, lo, hi, def, 0, cap, label, val);
  slider(idx) != floor(slider(idx) + 0.5) ? slider(idx) = floor(slider(idx) + 0.5);
);
// a small lit switch with its text inside
function chip(x, y, w, h, t, on) local(hov) (
  hov = inbox(x, y, w, h);
  ui_col(on ? ACC : 0xE6E8EA); RR(x, y, w, h, 4);
  ui_cola(INK, hov ? 0.6 : 0.3); gfx_rect(x*qs, (y + yo)*qs, w*qs, h*qs, 0);
  gfx_setfont(11); ui_col(on ? 0xFFFFFF : INK); TXC(x + w*0.5, y + h*0.5 - 8, t);
  hitbox(x, y, w, h);
);
function fms(v) ( v >= 1000 ? sprintf(#vt, "%.2f s", v/1000) : sprintf(#vt, "%d ms", floor(v + 0.5)); #vt; );
function fpc(v) ( sprintf(#vt, "%d%%", floor(v + 0.5)); #vt; );
function fdiv(i, md) (
  strcpy(#dv, i == 0 ? "4 BARS" : i == 1 ? "2 BARS" : i == 2 ? "1 BAR" : i == 3 ? "1/2" : i == 4 ? "1/4" : i == 5 ? "1/8" : i == 6 ? "1/16" : "1/32");
  md == 2 ? strcat(#dv, " D") : md == 3 ? strcat(#dv, " T"); #dv;
);
// one Mod Rack module; kind 0 tremolo, 1 chorus, 2 vibe, 3 delay (chorus and delay have a MIX knob)
function mrmod(mx, kind) local(b, hm, md, k, on, x_, i_l, i_sy, i_dv, cap, bt, vv) (
  b = kind == 0 ? 28 : kind == 1 ? 19 : kind == 2 ? 36 : 44;
  hm = kind == 1 || kind == 3;
  i_l = b + 3 + hm;                              // the L / C / R slider (bits 1 / 2 / 4) i_sy = b + 6 + hm; i_dv = b + 7 + hm;
  cap = kind == 0 ? 0xC8A23A : kind == 1 ? 0x2FB3A8 : kind == 2 ? 0x9A6A3C : 0x5A8FD0;
  ui_col(FP3); RR(mx, 548, 304, 142, 6);
  ui_col(cap); RR(mx, 548, 304, 5, 2);
  gfx_setfont(13); ui_col(INK); TX(mx + 12, 562, kind == 0 ? "TREMOLO" : kind == 1 ? "CHORUS" : kind == 2 ? "VIBE" : "DELAY");
  md = floor(slider(i_sy) + 0.5);
  chip(mx + 110, 558, 76, 26, md <= 1 ? "SYNC" : md == 2 ? "SYNC D" : "SYNC T", md > 0) ? (
    setv(i_sy, (md + 1) % 4);
    setmsg(kind == 3 ? "DELAY TIME" : "RATE", md == 0 ? "SYNC STRAIGHT" : md == 1 ? "SYNC DOTTED" : md == 2 ? "SYNC TRIPLET" : kind == 3 ? "IN MS" : "IN HZ");
  );
  k = 0;
  loop(3,
    bt = k == 0 ? 1 : k == 1 ? 2 : 4; vv = floor(slider(i_l) + 0.5); on = (vv & bt) > 0;
    chip(mx + 196 + k*35, 558, 31, 26, k == 0 ? "L" : k == 1 ? "C" : "R", on) ? setv(i_l, on ? vv - bt : vv + bt);
    k += 1;
  );
  x_ = mx + 152 - (hm ? 80 : 40);                // the knobs sit centred in the module
  md > 0 ? (
    sknob(i_dv, x_, 626, 22, 0, 7, 4, cap, kind == 3 ? "TIME" : "RATE", fdiv(slider(i_dv), md));
  ) : kind == 3 ? (
    knob(b, x_, 626, 22, 20, 1500, 350, 1, cap, "TIME", fms(slider(b)));
  ) : (
    sprintf(#mr0, "%.2f Hz", slider(b)); knob(b, x_, 626, 22, kind == 1 ? 0.05 : 0.1, kind == 1 ? 8 : kind == 0 ? 15 : 12, 1, 1, cap, "RATE", #mr0);
  );
  kind == 3 ? knob(b + 1, x_ + 80, 626, 22, 0, 95, 30, 0, cap, "FDBK", fpc(slider(b + 1)))
            : knob(b + 1, x_ + 80, 626, 22, 0, 100, 50, 0, cap, "DEPTH", fpc(slider(b + 1)));
  hm ? knob(b + 2, x_ + 160, 626, 22, 0, 100, 0, 0, cap, "MIX", fpc(slider(b + 2)));
);

// ---------------------------------------------------------------------
ui_col(BG); gfx_rect(0, 0, gfx_w, gfx_h);
cp_ = floor(slider1 + 0.5); yo = 0;

// ---- top bar ----
ui_col(0x2A2E33); R(0, 0, 1280, 150);
gfx_gradrect(0, 0, 1280*qs, 60*qs, 1, 1, 1, 0.05, 0, 0, 0, 0, 0, 0, 0, -0.05/(60*qs));
ui_col(ACC); gfx_circle(48*qs, 56*qs, 22*qs, 1, 1);
gfx_setfont(2); ui_col(0xFFFFFF); ui_text(48*qs, 49*qs, "GFX");
gfx_setfont(12); ui_col(0xEDEDEA); TX(82, 30, "PC70");
gfx_setfont(11); ui_col(0xA6ACB2); TX(84, 82, "SOUND MODULE  -  90 PATCHES");
// the backlit LCD: group, patch number and name (a knob's name and value while it turns)
ui_col(0x101214); R(360, 18, 470, 114);
ui_col(LB); R(366, 24, 458, 102);
gfx_gradrect(366*qs, 24*qs, 458*qs, 102*qs, 1, 1, 1, 0.08, 0, 0, 0, 0, 0, 0, 0, -0.08/(102*qs));
ui_col(LK);
time_precise() - lcd_t < 1.5 ? (
  gfx_setfont(10); TX(380, 34, #lcdn); gfx_setfont(9); TX(380, 66, #lcdv);
) : (
  gfx_setfont(10); strcpy(#l1, grp_name(pgrp(cp_))); TX(380, 34, #l1);
  gfx_setfont(9); sprintf(#l2, "%02d ", cp_ + 1); strcat(#l2, pname(cp_)); TX(380, 66, #l2);
);
ui_button(842*qs, 24*qs, 42*qs, 102*qs, "<", 0, 1) ? ( setv(1, (cp_ + NP - 1) % NP); );
ui_button(888*qs, 24*qs, 42*qs, 102*qs, ">", 0, 1) ? ( setv(1, (cp_ + 1) % NP); );
rd_sqbg = 0x55595E;
hitbox(360, 18, 470, 114) ? p70_page = 0;                         // click the LCD for the patch list
ui_button(952*qs, 24*qs, 110*qs, 50*qs, "EDITOR", p70_page != 0, 1) ? p70_page = !p70_page;   // lit while open; again for the list
rd_led(964*0.75, 104*0.75, 5*0.75, ins_midi_lit(), 0x46D86A);
gfx_setfont(11); ui_col(0xA6ACB2); TX(978, 96, "MIDI IN");
dy_kst = 7; dy_ink = 0xD8D8D2; dy_ntick = 11;
sprintf(#mv, "%+.1f dB", slider2); dy_knob(1172*0.75, 58*0.75, 24*0.75, 2, -24, 6, 0, 0, 0x9DA2A8, "VOLUME", #mv);
ui_size_picker(1180*qs, 124*qs);

// ---- the SPLIT strip: SPLIT / LEARN keys, the keyboard picture (click a key to split there), BASS sound and OCTAVE,
//      BASS LEVEL, BASS DRIFT and MAIN DRIFT ----
function nname(n) local(k) (
  k = n % 12;
  strcpy(#nn, k == 0 ? "C" : k == 1 ? "C#" : k == 2 ? "D" : k == 3 ? "D#" : k == 4 ? "E" : k == 5 ? "F" : k == 6 ? "F#" : k == 7 ? "G" : k == 8 ? "G#" : k == 9 ? "A" : k == 10 ? "A#" : "B");
  sprintf(#no, "%d", floor(n/12) - 1); strcat(#nn, #no); #nn;
);
function blk(n) local(k) ( k = n % 12; k == 1 || k == 3 || k == 6 || k == 8 || k == 10; );
lrn_dirty == 2 ? ( setv(10, min(max(splt_d, 24), 84)); lrn_dirty = 0; );
sp_ = floor(slider10 + 0.5); son_ = slider3 > 0.5;
ui_col(BG3); RR(10, 156, 1260, 106, 7); ui_col(BG2); RR(12, 158, 1256, 102, 6);
chip(24, 170, 104, 36, "SPLIT", son_) ? tog(3);
chip(24, 214, 104, 32, lrn_dirty == 1 ? "PLAY A KEY" : "LEARN", lrn_dirty == 1) ? lrn_dirty = lrn_dirty == 1 ? 0 : 1;
// keyboard C1 - C6 (61 keys): the bass keys tinted the bass colour, an amber line at the split
KX = 148; KY = 192; KW = 12.4; KH = 56;
gfx_setfont(13); ui_col(INK);
son_ ? ( strcpy(#st, "BASS BELOW "); strcat(#st, nname(sp_)); strcat(#st, "  -  PATCH FROM "); strcat(#st, nname(sp_)); strcat(#st, " UP"); )
     : strcpy(#st, "SPLIT OFF  -  EVERY KEY PLAYS THE PATCH");
TX(KX, 166, #st);
ui_col(0x16181A); R(KX - 2, KY - 2, 36*KW + 4, KH + 4);
n_ = 24; wi_ = 0;
loop(61,
  !blk(n_) ? (
    ui_col(son_ && n_ < sp_ ? 0xD9B48C : 0xF2F2EE); R(KX + wi_*KW + 0.6, KY, KW - 1.2, KH);
    wi_ += 1;
  );
  n_ += 1;
);
n_ = 24; wi_ = 0;
loop(61,
  blk(n_) ? ( ui_col(son_ && n_ < sp_ ? 0x6A4626 : 0x1C1C1E); R(KX + wi_*KW - KW*0.32, KY, KW*0.64, KH*0.6); ) : wi_ += 1;
  n_ += 1;
);
son_ ? (
  n_ = 24; wi_ = 0; loop(sp_ - 24, !blk(n_) ? wi_ += 1; n_ += 1; );
  sx_ = blk(sp_) ? KX + wi_*KW - KW*0.32 : KX + wi_*KW;
  ui_col(AMB); R(sx_ - 1.5, KY - 6, 3, KH + 12);
);
hitbox(KX, KY, 36*KW, KH) ? (
  mx_ = mouse_x/qs - KX; my_ = mouse_y/qs - yo - KY; k_ = -1;
  n_ = 24; wi_ = 0;
  loop(61,
    blk(n_) ? ( my_ < KH*0.6 && mx_ >= wi_*KW - KW*0.32 && mx_ < wi_*KW + KW*0.32 ? k_ = n_; ) : wi_ += 1;
    n_ += 1;
  );
  k_ < 0 ? ( wi_ = floor(mx_/KW); n_ = 24; loop(61, !blk(n_) ? ( wi_ == 0 ? k_ = n_; wi_ -= 1; ); n_ += 1; ); );
  k_ >= 24 ? ( setv(10, k_); slider3 < 0.5 ? setv(3, 1); );
);
// BASS sound (click for the list) and OCTAVE (click for a menu): backlit like the patch LCD
gfx_setfont(13); ui_col(INK2); TX(624, 166, "BASS SOUND"); TX(876, 166, "OCTAVE");
ui_col(0x101214); R(624, 190, 232, 46); R(876, 190, 86, 46);
ui_col(LB); R(627, 193, 226, 40); R(879, 193, 80, 40);
gfx_setfont(15); ui_col(LK);
bsel_ = floor(slider22 + 0.5); TX(638, 202, pname(75 + bsel_));
bo_ = floor(slider30 + 0.5); sprintf(#bo, bo_ > 0 ? "+%d" : "%d", bo_); TXC(919, 202, #bo);
hitbox(624, 190, 232, 46) ? (
  strcpy(#bm, ""); i_ = 0;
  loop(12, i_ > 0 ? strcat(#bm, "|"); i_ == bsel_ ? strcat(#bm, "!"); strcat(#bm, pname(75 + i_)); i_ += 1; );
  gfx_x = 624*qs; gfx_y = 236*qs; k_ = gfx_showmenu(#bm); k_ > 0 ? setv(22, k_ - 1);
);
hitbox(876, 190, 86, 46) ? (
  gfx_x = 876*qs; gfx_y = 236*qs;
  k_ = gfx_showmenu(bo_ == 2 ? "!+2|+1|0|-1|-2" : bo_ == 1 ? "+2|!+1|0|-1|-2" : bo_ == 0 ? "+2|+1|!0|-1|-2" : bo_ == -1 ? "+2|+1|0|!-1|-2" : "+2|+1|0|-1|!-2");
  k_ > 0 ? setv(30, 3 - k_);
);
sprintf(#q82, "%+.1f dB", slider32); knob(32, 1026, 198, 22, -24, 6, 0, 0, 0xC08850, "BASS LEVEL", #q82);
knob(33, 1124, 198, 22, 0, 100, 50, 0, 0xC08850, "BASS DRIFT", fpc(slider33));
knob(38, 1222, 198, 22, 0, 100, 50, 0, ACC, "MAIN DRIFT", fpc(slider38));
!son_ ? ( ui_cola(BG2, 0.55); RR(140, 160, 1032, 98, 5); );    // greyed while SPLIT is off (MAIN DRIFT stays live)
yo = 110;

p70_page == 0 ? (
  // ---- page 1: every patch, by group, in six recessed column cards - click a name to play it ----
  c_ = 0; loop(6, tx_ = 8 + c_*212; ui_col(BG3); RR(tx_ - 2, 156, 208, 594, 7); ui_col(BG2); RR(tx_, 158, 204, 590, 6); c_ += 1; );
  e_ = 0; p_ = 0; g_ = 0;
  loop(NP + 10,
    col_ = floor(e_/18); row_ = e_ % 18;
    tx_ = 8 + col_*212; ty_ = 160 + row_*32.6;
    p_ == grp_start(g_) && g_ < 10 ? (
      row_ == 17 ? ( e_ += 1; col_ = floor(e_/18); row_ = 0; tx_ = 8 + col_*212; ty_ = 160; );   // no heading at a column's foot
      // group heading: a dark label bar with a blue tab
      ui_col(0x3A3E43); RR(tx_ + 3, ty_ + 2, 198, 28, 4);
      ui_col(ACC); RR(tx_ + 3, ty_ + 2, 5, 28, 2);
      gfx_setfont(14); gfx_measurestr(grp_name(g_), w_, h_); w_ > 180*qs ? ( gfx_setfont(13); gfx_measurestr(grp_name(g_), w_, h_); );
      ui_col(0xFFFFFF); gfx_x = (tx_ + 15)*qs; gfx_y = (ty_ + 16 + yo)*qs - h_*0.5; gfx_drawstr(grp_name(g_));
      g_ += 1;
    ) : (
      on_ = p_ == cp_; hv_ = inbox(tx_, ty_, 204, 31);
      // zebra rows, hover and the selected patch
      on_ ? ( ui_col(ACC); RR(tx_ + 3, ty_ + 1, 198, 30, 4); )
          : hv_ ? ( ui_col(BG3); RR(tx_ + 3, ty_ + 1, 198, 30, 4); )
          : row_ % 2 ? ( ui_cola(0xFFFFFF, 0.25); R(tx_ + 3, ty_ + 1, 198, 30); );
      gfx_setfont(15); ui_col(on_ ? 0xFFFFFF : INK2); sprintf(#pe, "%02d", p_ + 1);
      gfx_measurestr(#pe, w_, h_); gfx_x = (tx_ + 8)*qs; gfx_y = (ty_ + 16 + yo)*qs - h_*0.5; gfx_drawstr(#pe);
      gfx_setfont(16); ui_col(on_ ? 0xFFFFFF : INK);
      gfx_measurestr(pname(p_), w_, h_); gfx_x = (tx_ + 38)*qs; gfx_y = (ty_ + 16 + yo)*qs - h_*0.5; gfx_drawstr(pname(p_));
      hitbox(tx_, ty_, 204, 31) ? setv(1, p_);
      p_ += 1;
    );
    e_ += 1;
  );
) : (
  // ---- page 2: EDIT ----
  ui_col(0x3A3E43); RR(12, 160, 1256, 44, 6);
  gfx_setfont(14); ui_col(0xFFFFFF); sprintf(#et, "%02d  ", cp_ + 1); strcat(#et, pname(cp_)); TX(28, 171, #et);
  gfx_setfont(11); ui_col(0xA6ACB2); strcpy(#eg, grp_name(pgrp(cp_))); TX(420, 174, #eg);

  gfx_setfont(11); ui_col(0xA6ACB2); TX(760, 174, "Centre = the patch as made - choosing a patch resets these");

  // TONE, FILTER ENVELOPE, AMP ENVELOPE
  sect(12, 214, 310, 168, "TONE");
  sprintf(#q5, "%+d", floor(slider5 - 50 + 0.5)); knob(5, 73, 290, 26, 0, 100, 50, 0, 0x3D70CC, "TONE", #q5);
  sprintf(#q6, "%+.2f oct", slider6); knob(6, 167, 290, 26, -6, 3, 0, 0, 0x3D70CC, "FILTER", #q6);
  knob(7, 261, 290, 26, 0, 100, 0, 0, 0x3D70CC, "RESONANCE", fpc(slider7));
  sect(344, 214, 498, 168, "FILTER ENVELOPE");
  knob(55, 405, 290, 26, 0, 200, 100, 0, 0x3D70CC, "AMOUNT", fpc(slider55));
  knob(56, 499, 290, 26, 10, 400, 100, 1, 0x3D70CC, "ATTACK", fpc(slider56));
  knob(57, 593, 290, 26, 10, 400, 100, 1, 0x3D70CC, "DECAY", fpc(slider57));
  sprintf(#q58, "%+d", slider58); knob(58, 687, 290, 26, -100, 100, 0, 0, 0x3D70CC, "SUSTAIN", #q58);
  knob(59, 781, 290, 26, 10, 400, 100, 1, 0x3D70CC, "RELEASE", fpc(slider59));
  (eng_d >= 1 && eng_d <= 5) || eng_d == 7 ? (                // this patch has no filter envelope: dim the row
    ui_cola(BG2, 0.7); RR(346, 236, 494, 144, 5);
    gfx_setfont(11); ui_col(INK2); TX(560, 222, "(not on this patch)");
  );
  sect(864, 214, 404, 168, "AMP ENVELOPE");
  knob(8, 925, 290, 26, 10, 400, 100, 1, 0x33A052, "ATTACK", fpc(slider8));
  knob(53, 1019, 290, 26, 10, 400, 100, 1, 0x33A052, "DECAY", fpc(slider53));
  sprintf(#q54, "%+d", slider54); knob(54, 1113, 290, 26, -100, 100, 0, 0, 0x33A052, "SUSTAIN", #q54);
  knob(9, 1207, 290, 26, 10, 400, 100, 1, 0x33A052, "RELEASE", fpc(slider9));
  ui_cola(BG2, 0.7);                                    // dim what this patch type has no use for
  (eng_d >= 1 && eng_d <= 5) || eng_d == 7 ? ( RR(881, 252, 88, 120, 6); RR(1069, 252, 88, 120, 6); );   // ATTACK, SUSTAIN
  eng_d == 5 || eng_d == 7 ? RR(975, 252, 88, 120, 6);                                                // DECAY
  eng_d == 7 ? RR(1163, 252, 88, 120, 6);                                                           // RELEASE

  sect(12, 390, 490, 144, "PLAY");
  knob(11, 80, 460, 22, 0, 100, 70, 0, KC, "VELOCITY", fpc(slider11));
  sprintf(#q12, "%+d c", slider12); knob(12, 180, 460, 22, -50, 50, 0, 0, KC, "TUNE", #q12);
  sprintf(#q13, "%d st", slider13); sknob(13, 280, 460, 22, 0, 12, 2, KC, "BEND", #q13);
  gfx_setfont(11); ui_col(INK); TX(352, 428, "MIDI CH");
  chip(352, 448, 120, 32, slider4 < 0.5 ? "OMNI" : sprintf(#ch, "%d", slider4), 0) ? (
    gfx_x = 352*qs; gfx_y = (480 + yo)*qs; k_ = gfx_showmenu("Omni|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16"); k_ > 0 ? setv(4, k_ - 1); );

  sect(512, 390, 756, 144, "REVERB");
  k_ = 0; loop(3, chip(640 + k_*112, 396, 104, 26, k_ == 0 ? "ROOM" : k_ == 1 ? "HALL" : "PLATE", floor(slider14 + 0.5) == k_) ? setv(14, k_); k_ += 1; );
  sprintf(#q15, "%d ms", slider15); knob(15, 700, 462, 24, 0, 150, 15, 0, 0xC8862A, "PRE", #q15);
  sprintf(#q16, "%.1f s", slider16); knob(16, 840, 462, 24, 0.2, 10, 2.2, 1, 0xC8862A, "DECAY", #q16);
  knob(17, 980, 462, 24, 0, 100, 50, 0, 0xC8862A, "DAMP", fpc(slider17));
  knob(18, 1120, 462, 24, 0, 100, 25, 0, 0xC8862A, "MIX", fpc(slider18));

  // the patch's MOD RACK
  sect(12, 542, 1256, 152, "");
  mrmod(20, 0); mrmod(332, 1); mrmod(644, 2); mrmod(956, 3);

  // output
  ui_col(BG3); R(0, 700, 1280, 60);
  gfx_setfont(13); ui_col(ACC); TX(24, 720, "OUTPUT");
  ins_io(110*0.75, (708 + yo)*0.75, 60, INK);
  sprintf(#q76, "%d Hz", slider24); knob(24, 760, 730, 14, 20, 500, 20, 1, KC, "", #q76); gfx_setfont(11); ui_col(INK); TX(620, 722, "MONO BELOW");
  knob(25, 960, 730, 14, 0, 100, 0, 0, KC, "", fpc(slider25)); gfx_setfont(11); ui_col(INK); TX(860, 722, "WIDTH");
);

pk_end();
ui_end();
