Skip to content

Instantly share code, notes, and snippets.

@spencersalazar
Created September 20, 2021 04:43
Show Gist options
  • Save spencersalazar/40109d20cac7446b4851386e6cb7522b to your computer and use it in GitHub Desktop.
Save spencersalazar/40109d20cac7446b4851386e6cb7522b to your computer and use it in GitHub Desktop.
Virtual Analog filters in ChucK
// ChucK implementation of Pirkle's Korg35 filter digitization
// see https://www.willpirkle.com/app-notes/virtual-analog-korg35-lpf/
// Virtual Analog one-pole filter
class VAOnePole extends Chugen
{
1 => float a;
1 => float b;
0 => float z1;
1 => int isLPF;
fun void set(float freq)
{
second/samp => float srate;
if (freq > srate/2) srate/2 => freq;
if (freq < 10) 10 => freq;
1.0/srate => float T;
2*pi*freq => float wd;
(2/T)*Math.tan(wd*T/2) => float wa;
wa*T/2 => float g;
g/(1.0 + g) => a;
}
fun float getFeedback()
{
return z1*b;
}
fun float tick(float xn)
{
// calculate v(n)
(xn - z1)*a => float vn;
// form LP output
vn + z1 => float lpf;
// update memory
vn + lpf => z1;
// do the HPF
xn - lpf => float hpf;
if(isLPF)
return lpf;
else
return hpf;
}
};
// virtual analog Korg35 filter
class Korg35Filter extends Chugen
{
VAOnePole lpf1;
VAOnePole lpf2;
VAOnePole hpf;
1 => float a0;
1 => float K;
1 => float KNorm;
1 => float saturation;
0 => int nonLinear;
fun void set(float freq, float _K)
{
second/samp => float srate;
if (freq > srate/2) srate/2 => freq;
if (freq < 10) 10 => freq;
_K => K;
1.0/srate => float T;
2*pi*freq => float wd;
(2/T)*Math.tan(wd*T/2) => float wa;
wa*T/2 => float g;
g/(1.0 + g) => float G;
G => lpf1.a => lpf2.a => hpf.a;
(K - K*G)/(1.0 + g) => lpf2.b;
-1.0/(1.0 + g) => hpf.b;
1.0/(1.0-K*G+K*G*G) => a0;
if (K > 0) 1.0/K => KNorm;
else 1.0 => KNorm;
}
fun float tick(float xn)
{
lpf1.tick(xn) => float y1;
hpf.getFeedback() + lpf2.getFeedback() => float S35;
a0*(y1+S35) => float u;
if (nonLinear) {
Math.tanh(saturation*u) => u;
}
K*lpf2.tick(u) => float y;
hpf.tick(y);
KNorm*y => y;
return y;
}
};
/*
// test code if desired
MAUI_Slider slider;
slider.display();
BlitSaw saw => Korg35Filter kf => dac;
0.5 => saw.gain;
440 => saw.freq;
20 => saw.harmonics;
while(true) {
100*Math.pow(10, slider.value()*2) => float val;
kf.set(val, 1.5);
20::ms => now;
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment