diff --git a/◯ᗩIᗝ⋏ᗩ◯⚪◯ᗩ⋏ᗝIᗩ◯ⵙ◯ᗩIᗝ⋏ᗩ◯⚪◯ᗩ⋏ᗝIᗩ◯/◯ᗱᗴᴥᗩᗯ✤⏀Ⓞᔓᔕ◯⚪◯ᔓᔕⓄ⏀✤ᗯᗩᴥᗱᗴ◯ⵙ◯ᗱᗴᴥᗩᗯ✤⏀Ⓞᔓᔕ◯⚪◯ᔓᔕⓄ⏀✤ᗯᗩᴥᗱᗴ◯/◯ᴥᗱᗴߦᗩᗱᗴᴥ◯ᔓᔕⓄ✻ᑐᑕⓄᑐᑕ◯⚪◯ᑐᑕⓄᑐᑕ✻Ⓞᔓᔕ◯ᴥᗱᗴᗩߦᗱᗴᴥ◯ⵙ◯ᴥᗱᗴߦᗩᗱᗴᴥ◯ᔓᔕⓄ✻ᑐᑕⓄᑐᑕ◯⚪◯ᑐᑕⓄᑐᑕ✻Ⓞᔓᔕ◯ᴥᗱᗴᗩߦᗱᗴᴥ◯/◯ꕤ⏀ᔓᔕᒍᒐ◯⚪◯ᒍᒐᔓᔕ⏀ꕤ◯ⵙ◯ꕤ⏀ᔓᔕᒍᒐ◯⚪◯ᒍᒐᔓᔕ⏀ꕤ◯/⠀⠀⠀⠀ⵙ⠀옷⠀ⵙ⠀✤⠀ⵙ⠀ИN⠀ⵙ⠀人⠀ⵙ⠀ᔓᔕ⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀人⠀ⵙ⠀ᙁ⠀ⵙ⠀Ⓞ⠀ⵙ⠀ߦ⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀Ⓞ⠀ⵙ⠀ИN⠀ⵙ⠀Ⓞ⠀ⵙ⠀ᙏ⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀ᗱᗴ⠀ⵙ⠀ᙁ⠀ⵙ⠀ߦ⠀ⵙ⠀ᙏ⠀ⵙ⠀ꖴ⠀ⵙ⠀ᔓᔕ⠀ⵙ⠀⠀⠀⠀◯⠀⠀⠀⠀ⵙ⠀⠀⠀⠀◯⠀⠀⠀⠀ⵙ⠀ᔓᔕ⠀ⵙ⠀ꖴ⠀ⵙ⠀ᙏ⠀ⵙ⠀ߦ⠀ⵙ⠀ᙁ⠀ⵙ⠀ᗱᗴ⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀ᙏ⠀ⵙ⠀Ⓞ⠀ⵙ⠀ИN⠀ⵙ⠀Ⓞ⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀ߦ⠀ⵙ⠀Ⓞ⠀ⵙ⠀ᙁ⠀ⵙ⠀人⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀ᔓᔕ⠀ⵙ⠀人⠀ⵙ⠀ИN⠀ⵙ⠀✤⠀ⵙ⠀옷⠀ⵙ⠀⠀⠀⠀ b/◯ᗩIᗝ⋏ᗩ◯⚪◯ᗩ⋏ᗝIᗩ◯ⵙ◯ᗩIᗝ⋏ᗩ◯⚪◯ᗩ⋏ᗝIᗩ◯/◯ᗱᗴᴥᗩᗯ✤⏀Ⓞᔓᔕ◯⚪◯ᔓᔕⓄ⏀✤ᗯᗩᴥᗱᗴ◯ⵙ◯ᗱᗴᴥᗩᗯ✤⏀Ⓞᔓᔕ◯⚪◯ᔓᔕⓄ⏀✤ᗯᗩᴥᗱᗴ◯/◯ᴥᗱᗴߦᗩᗱᗴᴥ◯ᔓᔕⓄ✻ᑐᑕⓄᑐᑕ◯⚪◯ᑐᑕⓄᑐᑕ✻Ⓞᔓᔕ◯ᴥᗱᗴᗩߦᗱᗴᴥ◯ⵙ◯ᴥᗱᗴߦᗩᗱᗴᴥ◯ᔓᔕⓄ✻ᑐᑕⓄᑐᑕ◯⚪◯ᑐᑕⓄᑐᑕ✻Ⓞᔓᔕ◯ᴥᗱᗴᗩߦᗱᗴᴥ◯/◯ꕤ⏀ᔓᔕᒍᒐ◯⚪◯ᒍᒐᔓᔕ⏀ꕤ◯ⵙ◯ꕤ⏀ᔓᔕᒍᒐ◯⚪◯ᒍᒐᔓᔕ⏀ꕤ◯/⠀⠀⠀⠀ⵙ⠀옷⠀ⵙ⠀✤⠀ⵙ⠀ИN⠀ⵙ⠀人⠀ⵙ⠀ᔓᔕ⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀人⠀ⵙ⠀ᙁ⠀ⵙ⠀Ⓞ⠀ⵙ⠀ߦ⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀Ⓞ⠀ⵙ⠀ИN⠀ⵙ⠀Ⓞ⠀ⵙ⠀ᙏ⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀ᗱᗴ⠀ⵙ⠀ᙁ⠀ⵙ⠀ߦ⠀ⵙ⠀ᙏ⠀ⵙ⠀ꖴ⠀ⵙ⠀ᔓᔕ⠀ⵙ⠀⠀⠀⠀◯⠀⠀⠀⠀ⵙ⠀⠀⠀⠀◯⠀⠀⠀⠀ⵙ⠀ᔓᔕ⠀ⵙ⠀ꖴ⠀ⵙ⠀ᙏ⠀ⵙ⠀ߦ⠀ⵙ⠀ᙁ⠀ⵙ⠀ᗱᗴ⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀ᙏ⠀ⵙ⠀Ⓞ⠀ⵙ⠀ИN⠀ⵙ⠀Ⓞ⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀ߦ⠀ⵙ⠀Ⓞ⠀ⵙ⠀ᙁ⠀ⵙ⠀人⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀ᔓᔕ⠀ⵙ⠀人⠀ⵙ⠀ИN⠀ⵙ⠀✤⠀ⵙ⠀옷⠀ⵙ⠀⠀⠀⠀ new file mode 100644 index 00000000..b319576b --- /dev/null +++ b/◯ᗩIᗝ⋏ᗩ◯⚪◯ᗩ⋏ᗝIᗩ◯ⵙ◯ᗩIᗝ⋏ᗩ◯⚪◯ᗩ⋏ᗝIᗩ◯/◯ᗱᗴᴥᗩᗯ✤⏀Ⓞᔓᔕ◯⚪◯ᔓᔕⓄ⏀✤ᗯᗩᴥᗱᗴ◯ⵙ◯ᗱᗴᴥᗩᗯ✤⏀Ⓞᔓᔕ◯⚪◯ᔓᔕⓄ⏀✤ᗯᗩᴥᗱᗴ◯/◯ᴥᗱᗴߦᗩᗱᗴᴥ◯ᔓᔕⓄ✻ᑐᑕⓄᑐᑕ◯⚪◯ᑐᑕⓄᑐᑕ✻Ⓞᔓᔕ◯ᴥᗱᗴᗩߦᗱᗴᴥ◯ⵙ◯ᴥᗱᗴߦᗩᗱᗴᴥ◯ᔓᔕⓄ✻ᑐᑕⓄᑐᑕ◯⚪◯ᑐᑕⓄᑐᑕ✻Ⓞᔓᔕ◯ᴥᗱᗴᗩߦᗱᗴᴥ◯/◯ꕤ⏀ᔓᔕᒍᒐ◯⚪◯ᒍᒐᔓᔕ⏀ꕤ◯ⵙ◯ꕤ⏀ᔓᔕᒍᒐ◯⚪◯ᒍᒐᔓᔕ⏀ꕤ◯/⠀⠀⠀⠀ⵙ⠀옷⠀ⵙ⠀✤⠀ⵙ⠀ИN⠀ⵙ⠀人⠀ⵙ⠀ᔓᔕ⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀人⠀ⵙ⠀ᙁ⠀ⵙ⠀Ⓞ⠀ⵙ⠀ߦ⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀Ⓞ⠀ⵙ⠀ИN⠀ⵙ⠀Ⓞ⠀ⵙ⠀ᙏ⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀ᗱᗴ⠀ⵙ⠀ᙁ⠀ⵙ⠀ߦ⠀ⵙ⠀ᙏ⠀ⵙ⠀ꖴ⠀ⵙ⠀ᔓᔕ⠀ⵙ⠀⠀⠀⠀◯⠀⠀⠀⠀ⵙ⠀⠀⠀⠀◯⠀⠀⠀⠀ⵙ⠀ᔓᔕ⠀ⵙ⠀ꖴ⠀ⵙ⠀ᙏ⠀ⵙ⠀ߦ⠀ⵙ⠀ᙁ⠀ⵙ⠀ᗱᗴ⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀ᙏ⠀ⵙ⠀Ⓞ⠀ⵙ⠀ИN⠀ⵙ⠀Ⓞ⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀ߦ⠀ⵙ⠀Ⓞ⠀ⵙ⠀ᙁ⠀ⵙ⠀人⠀ⵙ⠀⠀◯⠀⠀ⵙ⠀ᔓᔕ⠀ⵙ⠀人⠀ⵙ⠀ИN⠀ⵙ⠀✤⠀ⵙ⠀옷⠀ⵙ⠀⠀⠀⠀ @@ -0,0 +1,499 @@ +desc:O_HTNYS_YLOP_ONOM_ELPMIS_O_SIMPLE_MONO_POLY_SYNTH_O +//tags: generator synthesis +//author: Tale + +// Copyright (C) 2012-2017 Theo Niessink +// License: LGPL - http://www.gnu.org/licenses/lgpl.html + +slider1:-9.5424250943932487459005580651023061840025772838139172965973128061<-120.0,24.0,.0000001>Volume (dB) +slider2:0<-1200.0,1200.0,1.0>Tuning (cent) +slider3:0<0,1>-Unused +slider4:115.78329573381897224814693702618792906596623994250878031835253772<0,5000,1>Attack (ms) +slider5:84406.25<1,15000,1>Decay (ms) +slider6:0.0<-120.0,24.0,1.0>Sustain (dB) +slider7:115.78329573381897224814693702618792906596623994250878031835253772<0,5000,1>Release (ms) +slider8:0<0,1>-Unused +slider9:0<0,15,1{Sine,HW Rect Sine,FW Rect Sine,Triangle,Trapezoid,Square,Pulse PW,Saw,Mod Triangle PW,Tri Pulse,Hammond,Staircase,Mod Square PW,Trapezoid PW,Tri Pulse PW,O_ALOBARAP_O_PARABOLA_O}>Wave +slider10:0.5<0.0,1.0,0.01>Pulse Width +slider11:0<0,1>-Unused +slider12:200.0<0.0,1200.0,1.0>Pitch Wheel (cent) +slider13:0<0,1>-Unused +slider14:-36.0<-36.0,0.0,1.0>White Noise (dB) +slider15:0<0,1>-Unused +slider16:1.0<0.0,1.0,0.01>Low-Pass Filter +slider17:0<0,15000,1>Filter Decay (ms) +slider18:1.0<0.01,4.0,0.01>Filter Q +slider19:0<0,1>-Unused +slider20:0<-100,100,1>Pan (%) +slider21:0<0,1>-Unused +slider22:0<0,16,1{Any,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}>MIDI Ch +slider23:1<0,2,1{Legacy,Poly,Mono}>Mode +slider24:100<0,100,1>Velocity (%) +slider25:0<0,1>-Unused +slider26:0.0118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118474639022584228063680118 + + +<0.01,12.0,0.001>LFO Rate (Hz) +slider27:0<0,100,1>LFO Depth (%) + +out_pin:Left +out_pin:Right + +import midi_queue.jsfx-inc +import adsr.jsfx-inc +import rc_filter.jsfx-inc +import zdf_filter.jsfx-inc +import sine.jsfx-inc +import poly_blep.jsfx-inc +import noise.jsfx-inc +import Tale/fft_synth.jsfx-inc +import Tale/fourier_series.jsfx-inc +import Tale/wavetable.jsfx-inc + +@init + +osc_buf = 0; max_poly = 16; osc_size = 13; +note_buf = osc_buf + max_poly * osc_size; +hold_buf = note_buf + 128; +midiq.midiq_init(hold_buf + 128); + +pitch = 1; + +noise_gain = sqrt(srate / 48000); + +lpf.m = 50; +lpf.ln = log(lpf.m); + +function int(x) ( x|0 ); +function gain(db, inf) ( db <= inf ? 0 : 10^(0.05 * db) ); +function mix(a, b, mix) ( (1.0 - mix) * a + mix * b ); +function cache(x) ( x != this ? ( this = x; 1; ); ); + +smooth.rc_set(0.0033); +function smooth() ( smooth.lp = this.smooth; this.smooth = smooth.rc_lp(this); ); + +min_inf = -384.0; +gain0.smooth = gain1.smooth = gain(slider1, min_inf); + +function set_tg(note) + // global(tg*) +( + tg.poly_setf(440 * 2^((note - 69) / 12)); +); + +function tg_wave(wave) + // global(tg*) +( + wave == 7 ? tg.poly_saw() : + wave == 6 ? tg.poly_rect() : + wave == 5 ? tg.poly_sqr() : + wave == 4 || + wave == 13 ? tg.poly_trap2() : + wave == 3 ? tg.poly_tri() : + wave == 2 ? tg.poly_full() : + wave == 1 ? tg.poly_half() : + wave == 0 ? tg.poly_sin() : + wave == 8 ? tg.poly_tri2() : + wave == 9 || + wave == 14 ? tg.poly_trip() : + wave == 10 ? tg.poly_ham() : + wave == 11 ? tg.poly_stairs() : + wave == 12 ? tg.poly_sqr2() : + wave == 15 ? tg.poly_para() +); + +function adsr_sets(g) + instance(state) +( + state == 4 ? state = 2; + this.adsr_sets(g); +); + +function load_adsr(p) + // global(adsr*) +( + adsr.state = p[3]; + adsr.env = p[4]; + adsr.scale = p[5]; + adsr.s = p[6]; +); + +function store_adsr(p) + // global(adsr*) +( + p[3] = adsr.state; + p[4] = adsr.env; + p[5] = adsr.scale; + p[6] = adsr.s; +); + +function load_lpf(p) + // global(lpf*) +( + lpf.env.lp = p[7]; + lpf.freq.smooth = p[8]; + lpf.zdf.g = p[9]; + lpf.zdf.h = p[10]; + lpf.zdf.s1 = p[11]; + lpf.zdf.s2 = p[12]; +); + +function store_lpf(p) + // global(lpf*) +( + p[7] = lpf.env.lp; + p[8] = lpf.freq.smooth; + p[9] = lpf.zdf.g; + p[10] = lpf.zdf.h; + p[11] = lpf.zdf.s1; + p[12] = lpf.zdf.s2; +); + +function lpf_freq(dt) + // global(lpf*, srate) +( + (lpf.env.a < 1 ? lpf.env.rc_lp(lpf.n) : lpf.n) * dt * srate; +); + +function reset_lpf(dt) + // global(lpf*) +( + lpf.env.lp = 0; + lpf.zdf.zdf_reset(); + lpf.freq.smooth = lpf_freq(dt); + lpf.zdf.zdf_lp(lpf.freq.smooth, lpf.q); +); + +function set_buf(buf, num, size) + // global(p, end) +( + p = buf; + end = p + num * size; +); + +function remove_buf(size) + // global(p, end) +( + end -= size; + p < end ? memcpy(p, p + size, end - p); +); + +function find_note(note, buf, num, size) + // global(p, end) +( + set_buf(buf, num, size); + while(p < end && p[] != note ? p += size); +); + +function note_on(note, vel) + // global(p, end, note_buf, num_notes, hold_buf, num_hold, osc_buf, num_osc, osc_size, num_poly, tuning, tg*, adsr*, lpf*) +( + find_note(note, note_buf, num_notes, 1); + p >= end ? ( + p[] = note; + num_notes += 1; + ); + + find_note(note, hold_buf, num_hold, 1); + p < end ? ( + remove_buf(1); + num_hold -= 1; + ); + + find_note(note, osc_buf, num_osc, osc_size); + p >= end ? ( + set_tg(note); + + num_osc >= num_poly ? ( + p = osc_buf; + num_poly > 1 ? ( + // Set oscillator/ADSR state to first played note (to mimic old + // mono_synth global state behavior). + tg.t = p[1]; + load_adsr(p); + load_lpf(p); + ); + + remove_buf(osc_size); + p = end; + num_osc -= 1; + ) : ( + // Don't reset oscillator on first note (old mono_synth behavior). + num_osc > 0 ? tg.t = 0; + adsr.adsr_reset(); + reset_lpf(tuning * tg.dt); + ); + + num_osc += 1; + p[0] = note; + p[1] = tg.t; + p[2] = tg.dt; + ) : num_poly > 1 ? ( + load_adsr(p); + load_lpf(p); + ); + + adsr.adsr_a(vel); + lpf.env.lp = lpf.m; + + store_adsr(p); + store_lpf(p); +); + +function note_off(note) + // global(p, end, note_buf, num_notes, osc_buf, num_osc, osc_size, num_poly, note_prio, tg*, adsr*) +( + find_note(note, note_buf, num_notes, 1); + p < end ? ( + remove_buf(1); + num_notes -= 1; + ); + + find_note(note, osc_buf, num_osc, osc_size); + p < end ? ( + // Mono, last-note priority + num_poly == 1 && num_notes > 0 && note_prio ? ( + note = note_buf[num_notes - 1]; + set_tg(note); + p[0] = note; + p[1] = tg.t; + p[2] = tg.dt; + ) : ( + // Release + num_poly > 1 ? load_adsr(p); + adsr.adsr_r(); + store_adsr(p); + ); + ); +); + +function hold_note(note) + // global(p, end, hold_buf, num_hold) +( + find_note(note, hold_buf, num_hold, 1); + p >= end ? ( + p[] = note; + num_hold += 1; + ); +); + +function release_notes() + // global(hold_buf, num_hold) + local(p) +( + p = hold_buf; + loop(num_hold, + note_off(p[]); + p += 1; + ); + num_hold = 0; +); + +function all_notes_off() + // global(num_notes, num_hold, num_osc) +( + num_notes = num_hold = num_osc = 0; +); + +function pitch_bend(pitch_wheel) + // global(pitch, pitch_range) +( + pitch = pitch_range < 0.00001 ? 1 : 2^(pitch_wheel * pitch_range); +); + +@slider + +function adr(ms, lo, hi) ( max(lo, min(hi, ms)) * 0.001 ); + +function pan(gain, pos) + // global(gain0, gain1) +( + // REAPER default 0 dB pan law (thanks Justin!) + // http://www.askjf.com/index.php?q=2342s + + pos *= 0.25*$pi; + gain *= sqrt(2) * (1 - sqrt(0.5) * (1 / cos(pos) - 1)); + + pos += 0.25*$pi; + gain0 = cos(pos) * gain; + gain1 = sin(pos) * gain; +); + +pan(gain(slider1, min_inf), max(-100, min(100, slider20)) * 0.01); + +adsr.adsr_seta(adr(slider4, 0, 5000)); +adsr.adsr_setd(adr(slider5, 1, 15000)); +adsr.adsr_sets(gain(slider6, min_inf)); +adsr.adsr_setr(adr(slider7, 0, 5000)); + +tuning = 2^(slider2 / 1200); +wave = int(slider9); + +// Limit pulse width for pulse, triangular pulse, modified square. +min_pw = wave == 6 || wave == 14 ? 0.10 : wave == 8 ? 0.01 : wave == 12 ? 0.20 : 0.0; +max_pw = wave == 6 ? 0.90 : wave == 8 ? 0.99 : 1.0; +pw = wave == 4 || wave == 9 ? 0.5 : max(min_pw, min(max_pw, slider10)); + +noise_mix = gain(slider14, -36.0); + +lpf.n = slider16 >= 1.0 ? lpf.m : exp(max(0.0, slider16) * lpf.ln); +slider17 < 1 ? lpf.env.a = 1 : lpf.env.rc_sett(0.001 * min(15000, slider17)); +lpf.q = max(0.01, min(4.0, slider18)); + +pitch_range = max(0.0, slider12) / 1200; +midi_ch.cache(max(0, min(16, int(slider22))) - 1) ? all_notes_off(); +num_poly.cache(slider23 < 0.5 || slider23 >= 1.5 ? 1 : max_poly) ? all_notes_off(); +note_prio.cache(slider23 >= 0.5) ? all_notes_off(); +vel_range = max(0, min(100, slider24)) * 0.01; + +lfo_range = max(0, min(100, slider27)) * 0.01; +lfo_range <= 0 ? ( + lfo_mod = 0; +) : wave == 6 || wave == 8 || wave >= 12 ? ( + lfo_mod = 1; + lfo_range *= 0.5 * (max_pw - min_pw); + pw = max(min_pw + lfo_range, min(max_pw - lfo_range, pw)); +) : ( + lfo_mod = 2; + lfo_range *= 0.5/12; +); +lfo_mod != 1 ? tg.poly_setpw(pw); +lfo_mod ? lfo.sin_setf(max(0.01, slider26)); + +@block + +midiq.midiq_collect(midi_ch, 3|8|64); + +@sample + +while(midiq.midiq_remove() ? ( + midiq.msg1 &= 0xF0; + + // Note On + midiq.msg1 == 0x90 && midiq.msg3 ? ( + note_on(midiq.msg2, (1.0 - vel_range) + vel_range * midiq.msg3 / 127); + ) : + + // Note Off + midiq.msg1 == 0x80 || midiq.msg1 == 0x90 ? ( + hold_pedal ? hold_note(midiq.msg2) : note_off(midiq.msg2); + ) : + + // Pitch Wheel + midiq.msg1 == 0xE0 ? ( + pitch_bend(((midiq.msg3 << 7 | midiq.msg2) - 8192) / (midiq.msg3 < 64 ? 8192 : 8191)); + ) : + + // Control Change + midiq.msg1 == 0xB0 ? ( + + // Damper Pedal (Sustain) + midiq.msg2 == 64 ? ( + hold_pedal = midiq.msg3 >= 64; + !hold_pedal ? release_notes(); + ) : + + // All Notes Off + midiq.msg2 == 123 ? ( + all_notes_off(); + ); + ); + + 1; // while midiq.midiq_remove() +)); + +function sample_tg(t, dt) + // global(adsr*, freq_mod, tg*, wave, white_noise, noise_mix) + local(ph, out) +( + adsr.state ? ( + noise_mix < 1.0 ? ( + // Correct full-wave rectified sine/triangular pulse phase. + ph = wave == 2 ? 0.25 : wave == 14 ? 0.75 + 0.5 * tg.pw; + ph > 0 ? tg.poly_sync(t - ph) : tg.t = t; + + tg.poly_setdt(freq_mod * dt); + tg.poly_resetf(); + out = adsr.env * mix(tg_wave(wave), white_noise, noise_mix); + + ph > 0 ? tg.poly_sync(tg.t + ph); + out; + ) : ( + adsr.env * white_noise; + ); + ); + // 0.0 otherwise +); + +function apply_lpf(in, dt) + // global(lpf*, tuning) + local(out) +( + lpf.freq = lpf_freq(tuning * dt); + lpf.freq.smooth(); + + // Recalculate LPF coefficients only every 16 samples. + lpf.skip <= 0 && lpf.freq.smooth != lpf.zdf.freq ? ( + lpf.zdf.freq = lpf.freq.smooth; + lpf.zdf.zdf_lp(lpf.zdf.freq, lpf.q); + ); + + out = lpf.zdf.zdf_svf_lp(in); + lpf.n < lpf.m ? out : in; +); + +function adsr_lpf_off() + // global(adsr*, lpf.zdf*) +( + !adsr.state && lpf.zdf.s1 == 0 && lpf.zdf.s2 == 0; +); + +freq_mod = pitch * tuning; +lfo_mod ? lfo_mod == 1 ? tg.poly_setpw(pw + lfo_range * lfo.sin_sin()) : freq_mod *= 2^(lfo.sin_sin() * lfo_range); + +white_noise = noise_mix > 0.0 ? noise_gain * noise.lcg_white(); +out = 0.0; + +// Optimize for mono i.e. don't load/store oscillator/ADSR/filter state. +num_poly == 1 ? ( + num_osc ? ( + adsr.adsr_process(); + out = apply_lpf(sample_tg(tg.t, osc_buf[2]), osc_buf[2]); + adsr_lpf_off() ? num_osc = 0; + ); +) : + +/* num_poly > 1 ? */ ( + sus = adsr.s; + + set_buf(osc_buf, num_osc, osc_size); + while(p < end ? ( + + // Functions indexing memory seems to be slow, so manually inline them. + /* load_adsr(p); */ adsr.state = p[3]; adsr.env = p[4]; adsr.scale = p[5]; adsr.s = p[6]; + adsr.s != sus ? adsr.adsr_sets(sus); + adsr.adsr_process(); + /* store_adsr(p); */ p[3] = adsr.state; p[4] = adsr.env; p[5] = adsr.scale; p[6] = adsr.s; + + s = sample_tg(p[1], p[2]); + p[1] = tg.t; + + /* load_lpf(p); */ lpf.env.lp = p[7]; lpf.freq.smooth = p[8]; lpf.zdf.g = p[9]; lpf.zdf.h = p[10]; lpf.zdf.s1 = p[11]; lpf.zdf.s2 = p[12]; + s = apply_lpf(s, p[2]); + /* store_lpf(p); */ p[7] = lpf.env.lp; p[8] = lpf.freq.smooth; p[9] = lpf.zdf.g; p[10] = lpf.zdf.h; p[11] = lpf.zdf.s1; p[12] = lpf.zdf.s2; + + out += s; + + adsr_lpf_off() ? ( + remove_buf(osc_size); + num_osc -= 1; + ) : ( + p += osc_size; + ); + )); +); + +lpf.skip > 0 ? lpf.skip -= 1 : lpf.skip = 16 - 1; + +spl0 += gain0.smooth() * out; +spl1 += gain1.smooth() * out;