; Zero Delay Feedback Filters ; ; Based on code by Will Pirkle, presented in: ; ; http://www.willpirkle.com/Downloads/AN-4VirtualAnalogFilters.2.0.pdf ; ; and in his book "Designing software synthesizer plug-ins in C++ : for ; RackAFX, VST3, and Audio Units" ; ; ZDF using Trapezoidal integrator by Vadim Zavalishin, presented in "The Art ; of VA Filter Design" (https://www.native-instruments.com/fileadmin/ni_media/ ; downloads/pdf/VAFilterDesign_1.1.1.pdf) ; ; UDO versions by Steven Yi (2016.xx.xx) ;; 1-pole (6dB) lowpass/highpass filter ;; takes in a a-rate signal and cutoff value in frequency opcode zdf_1pole, aa, ak ain, kcf xin ; pre-warp the cutoff- these are bilinear-transform filters kwd = 2 * $M_PI * kcf iT = 1/sr kwa = (2/iT) * tan(kwd * iT/2) kg = kwa * iT/2 ; big combined value kG = kg / (1.0 + kg) ahp init 0 alp init 0 ;; state for integrators kz1 init 0 kindx = 0 while kindx < ksmps do ; do the filter, see VA book p. 46 ; form sub-node value v(n) kin = ain[kindx] kv = (kin - kz1) * kG ; form output of node + register klp = kv + kz1 khp = kin - klp ; z1 register update kz1 = klp + kv alp[kindx] = klp ahp[kindx] = khp kindx += 1 od xout alp, ahp endop ;; 1-pole (6dB) lowpass/highpass filter ;; takes in a a-rate signal and cutoff value in frequency opcode zdf_1pole, aa, aa ain, acf xin ; pre-warp the cutoff- these are bilinear-transform filters iT = 1/sr ahp init 0 alp init 0 ;; state for integrators kz1 init 0 kindx = 0 while kindx < ksmps do ; pre-warp the cutoff- these are bilinear-transform filters kwd = 2 * $M_PI * acf[kindx] kwa = (2/iT) * tan(kwd * iT/2) kg = kwa * iT/2 ; big combined value kG = kg / (1.0 + kg) ; do the filter, see VA book p. 46 ; form sub-node value v(n) kin = ain[kindx] kv = (kin - kz1) * kG ; form output of node + register klp = kv + kz1 khp = kin - klp ; z1 register update kz1 = klp + kv alp[kindx] = klp ahp[kindx] = khp kindx += 1 od xout alp, ahp endop ;; 1-pole allpass filter ;; takes in an a-rate signal and corner frequency where input ;; phase is shifted -90 degrees opcode zdf_allpass_1pole, a, ak ain, kcf xin alp, ahp zdf_1pole ain, kcf aout = alp - ahp xout aout endop ;; 1-pole allpass filter ;; takes in an a-rate signal and corner frequency where input ;; phase is shifted -90 degrees opcode zdf_allpass_1pole, a, aa ain, acf xin alp, ahp zdf_1pole ain, acf aout = alp - ahp xout aout endop ;; 2-pole (12dB) lowpass/highpass/bandpass filter ;; takes in a a-rate signal, cutoff value in frequency, and ;; Q factor for resonance opcode zdf_2pole,aaa,aKK ain, kcf, kQ xin ; pre-warp the cutoff- these are bilinear-transform filters kwd = 2 * $M_PI * kcf iT = 1/sr kwa = (2/iT) * tan(kwd * iT/2) kG = kwa * iT/2 kR = 1 / (2 * kQ) ;; output signals alp init 0 ahp init 0 abp init 0 ;; state for integrators kz1 init 0 kz2 init 0 ;; kindx = 0 while kindx < ksmps do khp = (ain[kindx] - (2 * kR + kG) * kz1 - kz2) / (1 + (2 * kR * kG) + (kG * kG)) kbp = kG * khp + kz1 klp = kG * kbp + kz2 ; z1 register update kz1 = kG * khp + kbp kz2 = kG * kbp + klp alp[kindx] = klp ahp[kindx] = khp abp[kindx] = kbp kindx += 1 od xout alp, abp, ahp endop ;; 2-pole (12dB) lowpass/highpass/bandpass filter ;; takes in a a-rate signal, cutoff value in frequency, and ;; Q factor for resonance opcode zdf_2pole,aaa,aaa ain, acf, aQ xin iT = 1/sr ;; output signals alp init 0 ahp init 0 abp init 0 ;; state for integrators kz1 init 0 kz2 init 0 ;; kindx = 0 while kindx < ksmps do ; pre-warp the cutoff- these are bilinear-transform filters kwd = 2 * $M_PI * acf[kindx] kwa = (2/iT) * tan(kwd * iT/2) kG = kwa * iT/2 kR = 1 / (2 * aQ[kindx]) khp = (ain[kindx] - (2 * kR + kG) * kz1 - kz2) / (1 + (2 * kR * kG) + (kG * kG)) kbp = kG * khp + kz1 klp = kG * kbp + kz2 ; z1 register update kz1 = kG * khp + kbp kz2 = kG * kbp + klp alp[kindx] = klp ahp[kindx] = khp abp[kindx] = kbp kindx += 1 od xout alp, abp, ahp endop ;; 2-pole (12dB) lowpass/highpass/bandpass/notch filter ;; takes in a a-rate signal, cutoff value in frequency, and ;; Q factor for resonance opcode zdf_2pole_notch,aaaa,aKK ain, kcf, kQ xin ; pre-warp the cutoff- these are bilinear-transform filters kwd = 2 * $M_PI * kcf iT = 1/sr kwa = (2/iT) * tan(kwd * iT/2) kG = kwa * iT/2 kR = 1 / (2 * kQ) ;; output signals alp init 0 ahp init 0 abp init 0 anotch init 0 ;; state for integrators kz1 init 0 kz2 init 0 ;; kindx = 0 while kindx < ksmps do kin = ain[kindx] khp = (kin - (2 * kR + kG) * kz1 - kz2) / (1 + (2 * kR * kG) + (kG * kG)) kbp = kG * khp + kz1 klp = kG * kbp + kz2 knotch = kin - (2 * kR * kbp) ; z1 register update kz1 = kG * khp + kbp kz2 = kG * kbp + klp alp[kindx] = klp ahp[kindx] = khp abp[kindx] = kbp anotch[kindx] = knotch kindx += 1 od xout alp, abp, ahp, anotch endop ;; 2-pole (12dB) lowpass/highpass/bandpass/notch filter ;; takes in a a-rate signal, cutoff value in frequency, and ;; Q factor for resonance opcode zdf_2pole_notch,aaaa,aaa ain, acf, aQ xin iT = 1/sr ;; output signals alp init 0 ahp init 0 abp init 0 anotch init 0 ;; state for integrators kz1 init 0 kz2 init 0 ;; kindx = 0 while kindx < ksmps do ; pre-warp the cutoff- these are bilinear-transform filters kwd = 2 * $M_PI * acf[kindx] kwa = (2/iT) * tan(kwd * iT/2) kG = kwa * iT/2 kR = 1 / (2 * aQ[kindx]) kin = ain[kindx] khp = (kin - (2 * kR + kG) * kz1 - kz2) / (1 + (2 * kR * kG) + (kG * kG)) kbp = kG * khp + kz1 klp = kG * kbp + kz2 knotch = kin - (2 * kR * kbp) ; z1 register update kz1 = kG * khp + kbp kz2 = kG * kbp + klp alp[kindx] = klp ahp[kindx] = khp abp[kindx] = kbp anotch[kindx] = knotch kindx += 1 od xout alp, abp, ahp, anotch endop ;; moog ladder opcode zdf_ladder, a, akk ain, kcf, kres xin aout init 0 kR = limit(1 - kres, 0.025, 1) kQ = 1 / (2 * kR) kwd = 2 * $M_PI * kcf iT = 1/sr kwa = (2/iT) * tan(kwd * iT/2) kg = kwa * iT/2 kk = 4.0*(kQ - 0.707)/(25.0 - 0.707) kg_2 = kg * kg kg_3 = kg_2 * kg ; big combined value ; for overall filter kG = kg_2 * kg_2 ; for individual 1-poles kG_pole = kg/(1.0 + kg) ;; state for each 1-pole's integrator kz1 init 0 kz2 init 0 kz3 init 0 kz4 init 0 kindx = 0 while kindx < ksmps do ;; processing kin = ain[kindx] kS = kg_3 * kz1 + kg_2 * kz2 + kg * kz3 + kz4 ku = (kin - kk * kS) / (1 + kk * kG) ;; 1st stage kv = (ku - kz1) * kG_pole klp = kv + kz1 kz1 = klp + kv ;; 2nd stage kv = (klp - kz2) * kG_pole klp = kv + kz2 kz2 = klp + kv ;; 3rd stage kv = (klp - kz3) * kG_pole klp = kv + kz3 kz3 = klp + kv ;; 4th stage kv = (klp - kz4) * kG_pole klp = kv + kz4 kz4 = klp + kv aout[kindx] = klp kindx += 1 od xout aout endop opcode zdf_ladder, a, aaa ain, acf, ares xin aout init 0 iT = 1/sr ;; state for each 1-pole's integrator kz1 init 0 kz2 init 0 kz3 init 0 kz4 init 0 kindx = 0 while kindx < ksmps do kR = limit(1 - ares[kindx], 0.025, 1) kQ = 1 / (2 * kR) kwd = 2 * $M_PI * acf[kindx] kwa = (2/iT) * tan(kwd * iT/2) kg = kwa * iT/2 kk = 4.0*(kQ - 0.707)/(25.0 - 0.707) kg_2 = kg * kg kg_3 = kg_2 * kg ; big combined value ; for overall filter kG = kg_2 * kg_2 ; for individual 1-poles kG_pole = kg/(1.0 + kg) ;; processing kin = ain[kindx] kS = kg_3 * kz1 + kg_2 * kz2 + kg * kz3 + kz4 ku = (kin - kk * kS) / (1 + kk * kG) ;; 1st stage kv = (ku - kz1) * kG_pole klp = kv + kz1 kz1 = klp + kv ;; 2nd stage kv = (klp - kz2) * kG_pole klp = kv + kz2 kz2 = klp + kv ;; 3rd stage kv = (klp - kz3) * kG_pole klp = kv + kz3 kz3 = klp + kv ;; 4th stage kv = (klp - kz4) * kG_pole klp = kv + kz4 kz4 = klp + kv aout[kindx] = klp kindx += 1 od xout aout endop ;; 4-pole opcode zdf_4pole, aaaaaa, akk ain, kcf, kres xin alp2, abp2, ahp2 zdf_2pole ain, kcf, kres abp4 init 0 abl4 init 0 alp4 init 0 xout alp2, abp2, ahp2, alp4, abl4, abp4 endop opcode zdf_4pole, aaaaaa, aaa ain, acf, ares xin alp2, abp2, ahp2 zdf_2pole ain, acf, ares abp4 init 0 abl4 init 0 alp4 init 0 xout alp2, abp2, ahp2, alp4, abl4, abp4 endop opcode zdf_4pole_hp, aaaaaa, akk ain, kcf, kres xin alp2, abp2, ahp2 zdf_2pole ain, kcf, kres ahp4 init 0 abh4 init 0 abp4 init 0 xout alp2, abp2, ahp2, abp4, abh4, ahp4 endop opcode zdf_4pole_hp, aaaaaa, aaa ain, acf, ares xin alp2, abp2, ahp2 zdf_2pole ain, acf, ares ahp4 init 0 abh4 init 0 abp4 init 0 xout alp2, abp2, ahp2, abp4, abh4, ahp4 endop ;; TODO - implement opcode zdf_peak_eq, a, akkk ain, kcf, kres, kdB xin aout init 0 xout aout endop opcode zdf_high_shelf_eq, a, akk ain, kcf, kdB xin ;; TODO - convert db to K, check if reusing zdf_1pole is sufficient kK init 0 alp, ahp zdf_1pole ain, kcf aout = ain + kK * ahp xout aout endop opcode zdf_low_shelf_eq, a, akk ain, kcf, kdB xin ;; TODO - convert db to K, check if reusing zdf_1pole is sufficient kK init 0 alp, ahp zdf_1pole ain, kcf aout = ain + kK * alp xout aout endop