desc:GFX VB30 //tags: compressor limiter fet diode-bridge gate expander freeze pumping parallel //author: JGWizrad / Garden FX (GFX) // // Requires gfx-drift, gfx-input, gfx-output, gfx-ui, gfx-panel, gfx-instrument and gfx-dyn (.jsfx-inc) in the same folder. // // VB30: an aggressive, characterful programme limiter in the spirit of early broadcast modules and high-ratio // industrial limiters (personal use; the sound is designed from scratch). Made for room mics, shouty vocals and // parallel drum buses. // LIMITER (upper row) // THRESHOLD, RATIO (1.5:1 - LIMIT), ATTACK (fast, FET-style), RELEASE. // MEMORY - the "capacitor memory": the release follows how much gain reduction there has been over the last // half second or so. Short peaks snap straight back; sustained squashing clamps down and lets go // slowly, with a long, musical suck-back. 0 = a plain fixed release. // COLOUR - the diode-bridge gain cell: a soft, slightly lopsided saturation that thickens as the gain // reduction deepens. 0 = clean. // GAIN - make-up gain. // GATE / FREEZE (lower row) // FREEZE - a fast background detector: when the signal falls below its threshold (a pause, the gap between // hits) the release stops and the gain reduction is held where it is, so the noise floor and the // room do not pump up in the gaps. The HOLD lamp lights while it is frozen. // GATE THRESHOLD, RANGE, RELEASE, GATE / EXP - a gate or gentle 1:2 expander before the limiter. // SC HPF - high-pass filter on the limiter's detector (fully left = off): less pumping from the bass. // MIX - parallel blend with the dry signal. // LINK - both sides share one gain; IN switches the limiter and the gate. // Order: gate > limiter (diode-bridge cell) > make-up > mix. PRESETS. import gfx-drift.jsfx-inc import gfx-input.jsfx-inc import gfx-output.jsfx-inc import gfx-ui.jsfx-inc import gfx-panel.jsfx-inc import gfx-instrument.jsfx-inc import gfx-dyn.jsfx-inc slider1:1<0,1,1{Out,In}>-Limiter in slider2:-18<-40,0,0.1>-Threshold (dB) slider3:4<1.5,20,0.1>-Ratio (20 = limit) slider4:0.8<0.05,20,0.01>-Attack (ms) slider5:200<30,1500,1>-Release (ms) slider6:50<0,100,1>-Memory (%) slider7:40<0,100,1>-Colour (%) slider8:0<-6,24,0.1>-Gain (dB) slider9:1<0,1,1{Off,On}>-Freeze slider10:-50<-70,-25,0.1>-Freeze threshold (dB) slider11:0<0,1,1{Out,In}>-Gate in slider12:-60<-80,-20,0.1>-Gate threshold (dB) slider13:15<0,60,0.1>-Gate range (dB) slider14:250<20,2000,1>-Gate release (ms) slider15:1<0,1,1{Gate,Expander}>-Gate mode slider16:20<20,300,1>-SC high-pass (Hz, 20 = off) slider17:1<0,1,1{Off,On}>-Link slider18:100<0,100,1>-Mix (%) slider19:0<-24,12,0.1>-Input trim (dB) slider20:1<0,1,1{Off,On}>-Input guard slider21:0<0,100,1>-Band sat (%) slider22:30<0,100,1>-Bias (%) slider23:120<40,400,1>-Sat low band (Hz) slider24:6000<2000,16000,10>-Sat high band (Hz) slider25:-0.3<-24,0,0.1>-Ceiling / limit threshold (dB) slider26:1<0,2,1{Off,Clip,Limit}>-Output stage in_pin:left input in_pin:right input out_pin:left output out_pin:right output @init #ui_man = "gfx-vb30"; // the ? pop-up links to this manual // fast tanh (exact +-1 beyond +-3) function th(x) ( x = min(max(x, -3), 3); x * (27 + x * x) / (27 + 9 * x * x); ); // one channel: detectors, gate, limiter envelope with capacitor memory and freeze function ch_init() instance(lg) ( lg = 1; ); function ch_det(x, xs) instance(pk, gms, fms) local(a) ( a = abs(xs); pk = a > pk ? a : pk * pk_rel; // FET-style peak detector (instant charge) gms += (x * x - gms) * gdet_c; fms += (x * x - fms) * fdet_c; // freeze sense: a quick RMS ); function ch_gate(lv) instance(ge) local(t, o) ( g_on ? ( o = lv - gthr; t = gmode ? max(min(o, 0), -grange) : (o < 0 ? -grange : 0); ge += (t - ge) * (t > ge ? gatt_c : grel_c); ) : ge = 0; ge; ); function ch_lim(lv, frz) instance(e, mem) local(t, f, rms_, c) ( c_on ? ( t = -slp * dy_curve(lv - thr, 4); t < e ? e += (t - e) * ac : ( !frz ? ( f = min(mem / 10, 1); rms_ = rel_ms * ((1 - memo) + memo * (0.25 + 5.75 * f * sqrt(f))); e += (t - e) / (1 + rms_ * 0.001 * srate); ); ); mem += (-e - mem) * (-e > mem ? mem_up : mem_dn); // dual-rate leaky integrator of the gain reduction ) : ( e = 0; mem = 0; ); e; ); // diode-bridge cell: gain, then a lopsided tanh whose drive follows the gain reduction (level compensated) function cell(x, e) local(amt, d, b, tb, u) ( u = x * 10 ^ (e / 20); col_on ? ( amt = colr * (0.15 + 0.85 * min(-e / 18, 1)); d = 1 + amt * 3; b = amt * 0.3; tb = th(b); u = (th(d * u + b) - tb) / (d * (1 - tb * tb)); ); u; ); function update() ( c_on = slider1; thr = slider2; slp = slider3 >= 19.95 ? 1 : 1 - 1 / slider3; ac = dy_ms(slider4); rel_ms = slider5; memo = slider6 / 100; colr = slider7 / 100; col_on = colr > 0.001; mk = 10 ^ (slider8 / 20); f_on = slider9; fthr = slider10; g_on = slider11; gthr = slider12; grange = slider13; grel_c = dy_ms(slider14); gmode = slider15; hp_on = slider16 > 20.5; hp_on ? ( hpL.bq_set(1, slider16, 0.707, 0); hpR.bq_set(1, slider16, 0.707, 0); ); lnk = slider17; mix_t = slider18 / 100; in_setup(0, slider20); ost_setup(0, 0, 120, 6000, -0.3, 0); // no GFX output stage on this unit: its own character does that job ); // ---------- presets (leave INPUT and OUTPUT alone) ---------- function pl(t, r, a, rl, m, c, g) ( slider1 = 1; slider2 = t; slider3 = r; slider4 = a; slider5 = rl; slider6 = m; slider7 = c; slider8 = g; ); function pg(fz, ft, gi, gt, gr, grl, gm, hp, lk, mx) ( slider9 = fz; slider10 = ft; slider11 = gi; slider12 = gt; slider13 = gr; slider14 = grl; slider15 = gm; slider16 = hp; slider17 = lk; slider18 = mx; ); function load_preset(p) ( p == 1 ? ( pl(-24, 20, 0.2, 120, 70, 70, 10); pg(1, -50, 0, -60, 15, 250, 1, 90, 1, 100); ) : // Room Mic Smash p == 2 ? ( pl(-28, 12, 0.5, 250, 80, 60, 12); pg(1, -45, 0, -60, 15, 250, 1, 120, 1, 40); ) : // Parallel Drum Crush p == 3 ? ( pl(-20, 6, 1.5, 180, 50, 45, 6); pg(1, -55, 1, -55, 12, 300, 1, 60, 1, 100); ) : // Shouty Vocal p == 4 ? ( pl(-22, 8, 0.3, 300, 100, 40, 7); pg(0, -50, 0, -60, 15, 250, 1, 20, 1, 100); ) : // Big Suck-back p == 5 ? ( pl(-14, 20, 0.05, 80, 30, 25, 3); pg(1, -50, 0, -60, 15, 250, 1, 20, 1, 100); ) : // Brick Wall Peaks p == 6 ? ( pl(-16, 3, 4, 250, 40, 30, 3); pg(1, -55, 0, -60, 15, 250, 1, 60, 1, 100); ) : // Bass Grab p == 7 ? ( pl(-26, 10, 0.4, 150, 60, 85, 9); pg(1, -40, 1, -45, 30, 120, 0, 150, 0, 100); ) : // Snare Grit (gated) p == 8 ? ( pl(-18, 4, 2, 400, 40, 20, 4); pg(1, -50, 0, -60, 15, 250, 1, 90, 1, 100); ) : // Gentle Glue Pump p == 9 ? ( pl(-40, 20, 0.1, 60, 90, 100, 18); pg(0, -50, 0, -60, 15, 250, 1, 60, 1, 30); ) : // Destroy (blend in) p == 10 ? ( pl(-18, 1.5, 20, 1500, 0, 60, 0); pg(0, -50, 0, -60, 15, 250, 1, 20, 1, 100); ); // Colour Only p >= 1 && p <= 10 ? slider_automate(262143); // sliders 1-18 p == 11 ? ( // Reset all to defaults slider1 = 1; slider2 = -18; slider3 = 4; slider4 = 0.8; slider5 = 200; slider6 = 50; slider7 = 40; slider8 = 0; pg(1, -50, 0, -60, 15, 250, 1, 20, 1, 100); slider19 = 0; slider20 = 1; slider21 = 0; slider22 = 30; slider23 = 120; slider24 = 6000; slider25 = -0.3; slider26 = 1; slider_automate(67108863); // sliders 1-26 ); ); in_init(); ost_init(20000); ostL.ost_ch_init(); ostR.ost_ch_init(); pk_rel = exp(-1 / (0.01 * srate)); // peak detector lets go in ~10 ms gdet_c = 1 - exp(-1 / (0.006 * srate)); fdet_c = 1 - exp(-1 / (0.004 * srate)); gatt_c = 1 - exp(-1 / (0.0005 * srate)); mem_up = 1 - exp(-1 / (0.5 * srate)); // memory charges over ~500 ms ... mem_dn = 1 - exp(-1 / (1.5 * srate)); // ... and drains more slowly sm = 1 - exp(-1 / (0.03 * srate)); L.ch_init(); R.ch_init(); !ui_dflt ? ui_thm = 5; !ui_dflt ? ui_hw = 1; // fixed faceplate PNL = 0x3A3E41; RAIL = 0x2A2D2F; OWH = 0xE2DDCE; BLKC = 0x101112; SORG = 0xF26B1D; NEON = 0xFF6A2A; PTR = 0xE4542A; AORG = 0xF0702A; update(); mix_s = mix_t; ui_dflt = 1; // theme defaults above apply once: @init re-runs (playback start, device reset) must not undo the saved theme @slider update(); @block update(); @serialize file_var(0, ui_sz); file_avail(0) != 0 ? file_var(0, pr_cur); // the preset in use (older projects end before it) @sample in_process(spl0, spl1); dl = in_l; dr = in_r; sl_ = hp_on ? hpL.bq_run(dl) : dl; sr_ = hp_on ? hpR.bq_run(dr) : dr; L.ch_det(dl, sl_); R.ch_det(dr, sr_); // freeze: a pause in the audio holds the gain reduction (3 dB hysteresis) flv = 10 * log10(max(L.fms, R.fms) + 0.0000000001) + 3; frz = f_on && (frz ? flv < fthr + 3 : flv < fthr); // gate gvL = 10 * log10(L.gms + 0.0000000001) + 3; gvR = 10 * log10(R.gms + 0.0000000001) + 3; lnk ? ( gvL = gvR = max(gvL, gvR); ); gL = L.ch_gate(gvL); gR = R.ch_gate(gvR); xl = dl * 10 ^ (gL / 20); xr = dr * 10 ^ (gR / 20); // limiter (its detector hears the gated, filtered signal) cvL = 20 * log10(L.pk * 10 ^ (gL / 20) + 0.0000000001); cvR = 20 * log10(R.pk * 10 ^ (gR / 20) + 0.0000000001); lnk ? ( eL = eR = L.ch_lim(max(cvL, cvR), frz); memL = memR = L.mem; ) : ( eL = L.ch_lim(cvL, frz); eR = R.ch_lim(cvR, frz); ); yl = cell(xl, eL); yr = cell(xr, eR); c_on ? ( yl *= mk; yr *= mk; ); grm = min(grm, min(eL, eR)); grlm = min(grlm, eL); grrm = min(grrm, eR); gtm = min(gtm, min(gL, gR)); frzm = max(frzm, frz); // mix + output stage mix_s += (mix_t - mix_s) * sm; oL = dl + (yl - dl) * mix_s; oR = dr + (yr - dr) * mix_s; oL = ostL.ost_band(oL * in_comp); oR = ostR.ost_band(oR * in_comp); ost_out(oL, oR); spl0 = ost_l; spl1 = ost_r; pkI = max(pkI, max(abs(dl), abs(dr))); pkOL = max(pkOL, abs(spl0)); pkOR = max(pkOR, abs(spl1)); @gfx 1000 376 ui_begin(1000, 376); dy_ink = OWH; dy_bg = PNL; dy_kst = 33; dy_num = 1; dy_numc = OWH; // off-white label plate (black lettering), or signal orange for a threshold function plate(cx, y, w, s, hot) ( ui_col(hot ? SORG : OWH); gfx_rect((cx - w * 0.5) * sc, y * sc, w * sc, 16 * sc); ui_cola(0x000000, 0.35); gfx_rect((cx - w * 0.5) * sc, (y + 15) * sc, w * sc, 1 * sc); gfx_setfont(4); ui_col(BLKC); ui_keytext(cx * sc, (y + 8) * sc, s); ); // a knob on the grid with its plate function knob(slot, row, idx, lo, hi, def, lg, s, hot, val) local(cx, cy) ( cx = 96 + slot * 84; cy = row ? 288 : 128; dy_knob(cx, cy, 17, idx, lo, hi, def, lg, PTR, "", ""); plate(cx, cy + 27, 66, s, hot); dy_act ? dy_lbl(cx, cy + 50, val, 1); // value on hover / drag only ); // orange heading with fine bracket lines down to the knobs it covers function bracket(x0, x1, y, s) local(tw, th, cx) ( gfx_setfont(6, "Arial", 11 * sc, 'b'); gfx_measurestr(s, tw, th); cx = (x0 + x1) * 0.5 * sc; ui_col(AORG); gfx_x = cx - tw * 0.5; gfx_y = y * sc - th * 0.5; gfx_drawstr(s); ui_cola(OWH, 0.6); gfx_line(x0 * sc, y * sc, cx - tw * 0.5 - 5 * sc, y * sc, 1); gfx_line(cx + tw * 0.5 + 5 * sc, y * sc, x1 * sc, y * sc, 1); gfx_line(x0 * sc, y * sc, x0 * sc, (y + 6) * sc, 1); gfx_line(x1 * sc, y * sc, x1 * sc, (y + 6) * sc, 1); ); function divider(x, y0, y1) ( ui_cola(OWH, 0.45); gfx_rect(x * sc, y0 * sc, 1 * sc, (y1 - y0) * sc); ); // a row: a tall off-white tab with its name stacked down it, an etched outline function row(y, h, s) local(i, n, c) ( ui_col(RAIL); gfx_rect(18 * sc, y * sc, 742 * sc, h * sc); ui_cola(0xFFFFFF, 0.07); gfx_rect(18 * sc, y * sc, 742 * sc, 1 * sc); ui_cola(0x000000, 0.5); gfx_rect(18 * sc, (y + h - 1) * sc, 742 * sc, 1 * sc); ui_col(OWH); gfx_rect(18 * sc, y * sc, 26 * sc, h * sc); gfx_setfont(6, "Arial", 11 * sc, 'b'); ui_col(BLKC); n = strlen(s); i = 0; loop(n, c = str_getchar(s, i); strcpy_substr(#rc, s, i, 1); gfx_measurestr(#rc, rw_, rh_); gfx_x = 31 * sc - rw_ * 0.5; gfx_y = (y + h * 0.5 + (i - n * 0.5) * 11) * sc; gfx_drawstr(#rc); i += 1; ); ); // a neon gas bar (glass tube), lit from the bottom by v = 0..1 function neon(x, y, h, v) local(t, gy) ( ui_col(0x0A0A0B); ui_rrect((x - 2) * sc, (y - 2) * sc, 18 * sc, (h + 4) * sc, 7 * sc); ui_col(0x1C1412); ui_rrect(x * sc, y * sc, 14 * sc, h * sc, 6 * sc); ui_cola(NEON, 0.12); gfx_rect((x + 6) * sc, y * sc, 2 * sc, h * sc); // the unlit cathode wire v = min(max(v, 0), 1); t = h * v; t > 0.5 ? ( gy = y + h - t; ui_cola(NEON, 0.25); ui_rrect((x - 1) * sc, (gy - 2) * sc, 16 * sc, (t + 2) * sc, 7 * sc); ui_cola(NEON, 0.85); ui_rrect((x + 2) * sc, gy * sc, 10 * sc, t * sc, 4 * sc); ui_cola(0xFFD2A0, 0.8); gfx_rect((x + 5) * sc, gy * sc, 4 * sc, t * sc); ui_cola(0xFFFFFF, 0.6); gfx_rect((x + 3) * sc, (gy - 1) * sc, 8 * sc, 2 * sc); ); ui_cola(0xFFFFFF, 0.1); gfx_rect((x + 2) * sc, (y + 2) * sc, 2 * sc, (h - 4) * sc); ); // high-density LED column: 24 segments, -36 .. +3 dBFS function ledcol(x, y, h, pk) local(i, sh, db, d, c) ( db = 20 * log10(max(pk, 0.0000001)); sh = h / 24; i = 0; loop(24, d = 3 - i * (39 / 23); c = d > -1 ? 0xFF3A2A : d > -9 ? 0xFFB030 : 0x9BE36A; ui_col(0x070708); gfx_rect(x * sc, (y + i * sh) * sc, 12 * sc, (sh - 1) * sc); ui_col(db >= d ? c : ui_mix(c, 0x000000, 0.86)); gfx_rect((x + 1) * sc, (y + i * sh + 1) * sc, 10 * sc, (sh - 2.5) * sc); i += 1; ); ); function lamp(x, y, on, s) ( ui_col(0x0A0A0B); gfx_circle(x * sc, y * sc, 6 * sc, 1, 1); ui_col(on ? NEON : 0x3A2A22); gfx_circle(x * sc, y * sc, 4.5 * sc, 1, 1); on ? ( ui_cola(NEON, 0.3); gfx_circle(x * sc, y * sc, 9 * sc, 1, 1); ui_cola(0xFFFFFF, 0.5); gfx_circle((x - 1.5) * sc, (y - 1.5) * sc, 1.5 * sc, 1, 1); ); dy_lbl(x, y + 10, s, 0.85); ); // ---------- panel ---------- fh = 368; ui_col(0x0B0B0C); gfx_rect(0, 0, gfx_w, gfx_h); pk_chassis(8 * sc, 4 * sc, 984 * sc, fh * sc, PNL); ui_col(OWH); gfx_circle(40 * sc, 34 * sc, 14 * sc, 1, 1); gfx_setfont(4); ui_col(BLKC); ui_text(40 * sc, 29 * sc, "GFX"); gfx_setfont(6, "Arial", 30 * sc, 'bi'); gi = 0; loop(8, ui_col(AORG); gfx_x = (64 + (gi == 0 || gi == 4 ? 1.3 : gi == 1 || gi == 5 ? -1.3 : 0) + (gi == 6 ? 1 : gi == 7 ? -1 : 0)) * sc; gfx_y = (16 + (gi == 2 || gi == 4 || gi == 5 ? 1.3 : gi == 3 ? -1.3 : 0) + (gi == 6 || gi == 7 ? -1 : 0)) * sc; gfx_drawstr("VB30"); gi += 1; ); ui_col(PNL); gfx_x = 64 * sc; gfx_y = 16 * sc; gfx_drawstr("VB30"); ui_col(OWH); gfx_rect(160 * sc, 26 * sc, 236 * sc, 15 * sc); gfx_setfont(4); ui_col(BLKC); gfx_x = 166 * sc; gfx_y = 29 * sc; gfx_drawstr("DIODE-BRIDGE PROGRAMME LIMITER"); pk_led(420 * sc, 34 * sc, 4.5 * sc, slider1, 0xFF3A2A); gfx_setfont(4); ui_cola(OWH, 0.7); gfx_x = 430 * sc; gfx_y = 29 * sc; gfx_drawstr("POWER"); pk_pextra = "Reset all to defaults"; // the house preset display: PRESETS, prev / next, LCD (click it for the list) k_ = pk_preset(500 * sc, 14 * sc, 320 * sc, 36 * sc, pr_cur, "Room Mic Smash|Parallel Drum Crush|Shouty Vocal|Big Suck-back|Brick Wall Peaks|Bass Grab|Snare Grit (gated)|Gentle Glue Pump|Destroy (blend in)|Colour Only"); k_ > 0 ? ( load_preset(k_); pr_cur = k_ > 10 ? 0 : k_; ); ui_size_picker(832 * sc, 22 * sc); ui_cola(0x000000, 0.4); gfx_rect(14 * sc, 60 * sc, 972 * sc, 1 * sc); ui_cola(0xFFFFFF, 0.08); gfx_rect(14 * sc, 61 * sc, 972 * sc, 1 * sc); // ---------- upper row: LIMITER ---------- row(68, 144, "LIMITER"); sprintf(#v, "%.1f dB", slider2); knob(0, 0, 2, -40, 0, -18, 0, "THRESHOLD", 1, #v); slider3 >= 19.95 ? strcpy(#v, "LIMIT") : sprintf(#v, "%.1f:1", slider3); knob(1, 0, 3, 1.5, 20, 4, 1, "RATIO", 0, #v); sprintf(#v, slider4 < 1 ? "%.0f us" : "%.1f ms", slider4 < 1 ? slider4 * 1000 : slider4); knob(2, 0, 4, 0.05, 20, 0.8, 1, "ATTACK", 0, #v); sprintf(#v, "%.0f ms", slider5); knob(3, 0, 5, 30, 1500, 200, 1, "RELEASE", 0, #v); sprintf(#v, "%.0f%%", slider6); knob(4, 0, 6, 0, 100, 50, 0, "MEMORY", 0, #v); sprintf(#v, "%.0f%%", slider7); knob(5, 0, 7, 0, 100, 40, 0, "COLOUR", 0, #v); sprintf(#v, "%+.1f dB", slider8); knob(6, 0, 8, -6, 24, 0, 0, "GAIN", 0, #v); bracket(66, 352, 78, "DYNAMICS"); bracket(402, 610, 78, "CHARACTER"); divider(380, 74, 206); dy_btn(656, 80, slider1, NEON, "IN") ? ( slider1 = 1 - slider1; ui_auto(1); ); dy_btn(706, 80, slider17, NEON, "LINK") ? ( slider17 = 1 - slider17; ui_auto(17); ); // memory charge: how much the release is being stretched right now memd = L.mem; dy_lbl(706, 158, "MEMORY CHARGE", 0.75); ui_col(0x070708); gfx_rect(658 * sc, 170 * sc, 96 * sc, 10 * sc); gi = 0; loop(12, ui_col(gi < memd / 10 * 12 ? NEON : 0x2A1E18); gfx_rect((659 + gi * 8) * sc, 171 * sc, 6 * sc, 8 * sc); gi += 1; ); dy_lbl(662, 186, "SNAP", 0.55); dy_lbl(748, 186, "SUCK", 0.55); // ---------- lower row: GATE / FREEZE ---------- row(218, 144, "GATE"); bracket(66, 352, 228, "GATE / FREEZE"); bracket(402, 526, 228, "SIDECHAIN / MIX"); divider(380, 224, 356); sprintf(#v, "%.0f dB", slider10); knob(0, 1, 10, -70, -25, -50, 0, "FREEZE THR", 1, #v); sprintf(#v, "%.0f dB", slider12); knob(1, 1, 12, -80, -20, -60, 0, "GATE THR", 1, #v); sprintf(#v, "%.0f dB", slider13); knob(2, 1, 13, 0, 60, 15, 0, "RANGE", 0, #v); sprintf(#v, "%.0f ms", slider14); knob(3, 1, 14, 20, 2000, 250, 1, "RELEASE", 0, #v); slider16 <= 20.5 ? strcpy(#v, "OFF") : sprintf(#v, "%.0f Hz", slider16); dy_kf = 1; knob(4, 1, 16, 20, 300, 20, 1, "SC HPF", 0, #v); sprintf(#v, "WET %.0f", slider18); knob(5, 1, 18, 0, 100, 100, 0, "MIX", 0, #v); dy_btn(554, 240, slider15 == 0, NEON, "GATE") ? ( slider15 = 0; ui_auto(15); ); dy_btn(600, 240, slider15 == 1, NEON, "EXP") ? ( slider15 = 1; ui_auto(15); ); frzd = frzm; frzm = 0; gtd = min(gtm, gtd * 0.8); gtm = 0; lamp(577, 320, slider11 && gtd > -1, "OPEN"); dy_btn(656, 240, slider9, NEON, "FREEZE") ? ( slider9 = 1 - slider9; ui_auto(9); ); dy_btn(706, 240, slider11, NEON, "GATE IN") ? ( slider11 = 1 - slider11; ui_auto(11); ); lamp(676, 320, slider9 && frzd, "HOLD"); sprintf(#v, "GATE %.0f dB", gtd); dy_lbl(730, 336, slider11 ? #v : "GATE OUT", 0.7); // ---------- meter bay ---------- ui_col(0x141516); gfx_rect(770 * sc, 68 * sc, 212 * sc, 294 * sc); ui_cola(0xFFFFFF, 0.06); gfx_rect(770 * sc, 361 * sc, 212 * sc, 1 * sc); grLd = min(grlm, grLd * 0.86); grRd = min(grrm, grRd * 0.86); grlm = 0; grrm = 0; grm = 0; neon(790, 96, 230, -grLd / 30); neon(812, 96, 230, -grRd / 30); gi = 0; loop(7, gd_ = gi * 5; gy_ = 96 + 230 - gd_ / 30 * 230; ui_cola(OWH, 0.5); gfx_rect(830 * sc, gy_ * sc, 5 * sc, 1 * sc); sprintf(#gl, "%d", gd_); gfx_setfont(4); ui_cola(OWH, 0.7); gfx_x = 838 * sc; gfx_y = (gy_ - 5) * sc; gfx_drawstr(#gl); gi += 1; ); ledcol(900, 96, 230, pkOL); ledcol(916, 96, 230, pkOR); gi = 0; loop(5, gd_ = gi == 0 ? 0 : gi == 1 ? -6 : gi == 2 ? -12 : gi == 3 ? -24 : -36; gy_ = 96 + (3 - gd_) / 39 * 230; sprintf(#gl, "%d", gd_); gfx_setfont(4); ui_cola(OWH, 0.7); gfx_x = 934 * sc; gfx_y = (gy_ - 2) * sc; gfx_drawstr(#gl); gi += 1; ); pkOL *= 0.85; pkOR *= 0.85; pkI *= 0.85; plate(812, 74, 64, "GAIN RED.", 0); plate(916, 74, 64, "OUTPUT", 0); dy_lbl(797, 332, "L", 0.7); dy_lbl(819, 332, "R", 0.7); dy_lbl(906, 332, "L", 0.7); dy_lbl(922, 332, "R", 0.7); sprintf(#v, "%.1f dB", min(grLd, grRd)); dy_lbl(812, 346, #v, 0.85); pk_end(); ui_end();