K35 Filter

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

This filter from the OG MS-20 is my favoriter filter, so I'm trying to implement it. Of course, the code is so ridiculously unreadable. From Pirkle:

Code: Select all

// prewarp for BZT
double wd = 2*pi*m_dFc;
double T = 1/(double)m_nSampleRate;
double wa = (2/T)*tan(wd*T/2);
double g = wa*T/2;
float G = g/(1.0 + g);

// set betas all are in the form of <something>/((1 + g)
m_LPF2.m_fBeta = (m_dK - m_dK*G)/(1.0 + g);
m_HPF1.m_fBeta = -1.0/(1.0 + g);

// set m_dAlpha0 variable
m_dAlpha0 = 1.0/(1.0 - m_dK*G + m_dK*G*G); 
It seems to expect the samplre rate in Hz, cutoff in Hz, and as far as I can tell, resonance in 0..3, but 3 is NO resonance, so using the magic of VST 0..1 ranging:

Code: Select all

g = tan(cutoff * .4999 * M_PI);
G = g / (1.0 + g);

// adjust K to never be zero and use a cube to help with the fine tuning at hi rez
K = clamp((1.0 - cube(resonance)) * 3.0, .0001, 2.97);
			
lpf2_beta = (K - K * G) / (1.0 + g);
hpf1_beta = -1.0 / (1.0 + g);
alpha = 1.0 / (1.0 - K * G + K * G * G);
I also checked the code from SurgeXT and it also slavishly follows Pirkle with the *2/T -> *T/2 nonsense.

Anyway, the resonance works, although it needs some fine tuning on the upper end. g properly falls into the range of 0..inf (actually, ~3183.1, avoiding the NaN at .5), and G follows a nice tanh curve. All well and good.

However, the cutoff does not work at all. I've checked my code against Pirkle and Surge and it appears correct.

Code: Select all

// i = input sample
// LPF1
double v1 = (i - z1) * G;
double lp1 = v1 + z1;
z1 = v1 + lp1;
		
double S35 = (lpf2_beta * z2) + (hpf1_beta * z3);
double u = alpha * (z1 + S35);	
// Using 2.0 as a temp saturation value until we get cutoff working	
u = tanh(u * 2.0);
		
// LPF2
double v2 = (v1 - z2) * G;
double lp2 = v2 + z2;
z2 = v2 + lp2;
				
// HPF
double v3 = (v2 - z3) * G;
double hp1 = i - v3 + z3;
z3 = v3 + hp1;
		
return z3/K;
This is the weirdest filter I've seen as it adds in the fitered sample twice and applies the resonance to the first LPF, then filters it through the second.

Can anybody explain this to me ... slowly? :lol:
I've glanced over the whole paper, but the math in turning electronic components into formulae still makes my eyes and brain glaze over. :?
I started on Logic 5 with a PowerBook G4 550Mhz. I now have a MacBook Air M1 and it's ~165x faster! So, why is my music not proportionally better? :(

Post

syntonica wrote: Fri Jun 23, 2023 4:29 pm It seems to expect the samplre rate in Hz, cutoff in Hz,
Does not matter what the units are as long as they are consistent. The BLT prewarping constant is tan(pi*f/fs) and the code here just computes it in an overly complicated way: let T=1/fs be the timestep, let w=2*pi*f be the angular frequency, then prewarp is tan(w*T/2)=tan(2*pi*f*(1/fs)/2), the factors of 2 cancel out and we're left with tan(pi*f/fs).

The filter code itself looks more or less like traditional "manual" ZDF solver. The code you posted doesn't appear to be complete though.
and as far as I can tell, resonance in 0..3, but 3 is NO resonance, so using the magic of VST 0..1 ranging:
In a Sallen-Key filter the Q is quite sensitive (especially at higher values) to small variations of feedback and since you need some non-linearity in the loop to prevent blowup if you want to take it to self-oscillation (and what's the point of MS20 if you don't?), the exact point where you start getting something fun can vary somewhat depending on the non-linearity.. so I'd just figure out the range by trial and error.
Can anybody explain this to me ... slowly? :lol:
I've glanced over the whole paper, but the math in turning electronic components into formulae still makes my eyes and brain glaze over. :?
It's a bit non-intuive and the fact that people seem to prefer somewhat non-systematic methods when possible can help to confuse things further.. but the basic idea is that you formulate the circuit as a system of linear equations following Kirchoff current law (mostly; for MNA we sometimes also need Kirchoffs voltage law) and then you numerically integrate it using the trapezoidal method. Since trapezoidal is an implicit method, this involves solving the system of linear equations once per timestep (assuming we're not also doing Newton, in which case we'd solve once per inner iteration). Such code does not necessarily make any sense if you're trying to think about it as traditional digital signal-flow, because it really isn't that.

The trapezoidal integration as written using TDF2 integrators can be a bit confusing though. Trapezoidal solves forward for the current timestep, then average with the previous timestep (and multiplies by length of timestep, but with BLT we treat timestep as unity and compensate with the tuning coefficient). Since we need both the state and the previous "input" value, this seemingly requires two state variables per integrator, but we can avoid that by adding the contribution of the previous input into the state early (at previous timestep) if we don't care that the state now stores the actual computed integral + the contribution of the current timestep to the next timestep. This is why we solve for the output (of each integrator) and state-update separately, even though in regular text-book trapezoidal they would be the same.

For all intents and purposes, this stuff is mathematics rather than code. The final code is there just to compute the numerical integration and it's not really going to make sense except in terms of what it's computing. Focus on understanding the math and you'll get there faster.

Post

Faust implements both K35 filters and here's an implementation based of them.

K-Brown has shared his SynthMaker/FlowStone projects and Korg MS-20 is included but named as Chorg PS-20.
Last edited by juha_p on Wed Jun 28, 2023 6:56 am, edited 1 time in total.

Post

juha_p wrote: Sat Jun 24, 2023 8:59 am Faust implements both K35 filters and here's an implementation based of them.
Thanks, Juha. I glanced at the code and it seems to break the filters apart into discrete components. However, the K35 chip is a full circuit of 4 transistors, an op amp and a handful of other stuff (and a very weird diode configuration which makes me wish I was an electrical engineer so that I could understand it better). I'm not sure if LP+LP+HP could get me too the same place as an all-in-one configuration. The feedback in the code relies on the previous LP+HP values.

Anyway, I'll study it later when I'm in the filter zone...
I started on Logic 5 with a PowerBook G4 550Mhz. I now have a MacBook Air M1 and it's ~165x faster! So, why is my music not proportionally better? :(

Post

It seems that all of these implementations are linear? In that case I think the most straight forward and easiest to understand version is Andy's here:

https://cytomic.com/files/dsp/SkfLinear ... mised2.pdf

Post

syntonica wrote: Sat Jun 24, 2023 2:54 pm(and a very weird diode configuration which makes me wish I was an electrical engineer so that I could understand it better).
Are you talking about the diodes in the loop of the opamp?

That's actually not complicated if you understand how a basic opamp buffer works. What happens with diodes is that they have a forward voltage drop which means that they don't really start conducting significant current as soon as the voltage is positive, but rather when the voltage is something like .6V to .7V or so... so at voltages close to zero, the resistor alone is passing feedback current so the gain is higher.. but as we reach the forward "knee" of either diode the feedback increases and the amplifier gain drops to unity.

In practice, the opamp construct with diodes like this is approximate a tanh() + a bit of dry signal.

Post

mystran wrote: Sat Jun 24, 2023 8:11 am
The filter code itself looks more or less like traditional "manual" ZDF solver. The code you posted doesn't appear to be complete though.
I did find a *K missing on one computation, but it didn't help. My wave display of a filtered saw is basically all clipped, positive values creating a weird square wave. As long as I can be sure I have K, g, and G all calculated properly, I can tackle the filter.
In a Sallen-Key filter the Q is quite sensitive (especially at higher values) to small variations of feedback
I've noticed. :lol: Surge uses .1..1.96, IIRC, which I find awfully conservative. It'll get tuned to a nice sweet spot by ear once I get the cutoff working.
It's a bit non-intuive...
I was with you until just after this part... :lol:

I would love to solve this with Newton, but that math is a bit beyond my reach for the moment. I think Andy Cytomic has a paper on Sallen-Key that I can study as well.

I vaguely understood the rest. There are a couple of new terms for me, but at least I have a running start at this. Thank you very much!
I started on Logic 5 with a PowerBook G4 550Mhz. I now have a MacBook Air M1 and it's ~165x faster! So, why is my music not proportionally better? :(

Post

mystran wrote: Sat Jun 24, 2023 3:15 pm
syntonica wrote: Sat Jun 24, 2023 2:54 pm(and a very weird diode configuration which makes me wish I was an electrical engineer so that I could understand it better).
Are you talking about the diodes in the loop of the opamp?

That's actually not complicated if you understand how a basic opamp buffer works. What happens with diodes is that they have a forward voltage drop which means that they don't really start conducting significant current as soon as the voltage is positive, but rather when the voltage is something like .6V to .7V or so... so at voltages close to zero, the resistor alone is passing feedback current so the gain is higher.. but as we reach the forward "knee" of either diode the feedback increases and the amplifier gain drops to unity.

In practice, the opamp construct with diodes like this is approximate a tanh() + a bit of dry signal.
Yeah, that's the one with two diodes facing opposite directions in parallel. My limited understanding was diodes prevented ALL flow in one direction. At least, that's what my electronics kit from when I was 8 implied. After all these years, still learning. I may have to jettison my memories of kindergarten to make room.
I started on Logic 5 with a PowerBook G4 550Mhz. I now have a MacBook Air M1 and it's ~165x faster! So, why is my music not proportionally better? :(

Post

syntonica wrote: Sat Jun 24, 2023 4:02 pm Yeah, that's the one with two diodes facing opposite directions in parallel. My limited understanding was diodes prevented ALL flow in one direction. At least, that's what my electronics kit from when I was 8 implied. After all these years, still learning. I may have to jettison my memories of kindergarten to make room.
Ignoring reverse breakdown voltage (which is something you avoid with regular diodes), they do prevent "all" (neglecting tiny leakage currents) flow in one direction, but the point is that when we look at the current curve in the forward direction where they do pass current, the current increases exponentially with voltage and it's somewhere around .6-.7V for silicon diodes where it becomes high enough that we can consider the diode as actually conducting... but even then it's not truly a switch, it turns on gradually so we get soft knees.

So passes current in forward direction is the most simple model. Passes current above .6-.7V in the forward direction is a slightly better model. I=Is*(exp(V/nvt)-1) is an even better model. In this case we need the last one.

Post

Code: Select all

// LPF1
double v1 = (i - z1) * G;
double lp1 = v1 + z1;
z1 = v1 + lp1;
As the others explained, this is a trapezoidal integrator.

There is a great video by Aaron Lanterman going over the MS-20 filter:For instance, 7 minutes in you see why the resonance is 0..3.

Post

Antti Huovilainen's Master’s Thesis - Design of a Scalable Polyphony-MIDI Synthesizer for a Low Cost DSP (PDF).
References mentioned in text:
[55] - Vesa Välimäki and Antti Huovilainen. Oscillator and filter algorithms for virtual analog synthesis. Computer Music Journal, 30(2):19–31, 2006.
[59] - David T. Yeh, Jonathan S. Abel, and Julius O. Smith. Simplified, physically-informed models of distortion and overdrive guitar effect pedals. In Proceedings of the 10th International Conference on Digital Audio Effects (DAFx-07), 2007).
Last edited by juha_p on Tue Jun 27, 2023 7:27 pm, edited 4 times in total.

Post

nevermind

(I remembered something differently, it still is odd but it isn't nearly as odd as I remembered it)

Post

Okay, I found my mistake(s). I just royally messed up the HPF. Mostly, stupid muscle memory made me subtracr from the original input and not the LPF2 output. :x

Now, high resonances are scratchy when sweeping the cutoff. I don't think smoothing will help. I can see why Surge used the smaller resonance range. But I can play with it now.

Thanks for everybody's help! I got tons of stuff to study and read now and it's starting to sink in.
I started on Logic 5 with a PowerBook G4 550Mhz. I now have a MacBook Air M1 and it's ~165x faster! So, why is my music not proportionally better? :(

Post

Urs wrote: Sun Jun 25, 2023 5:16 am nevermind

(I remembered something differently, it still is odd but it isn't nearly as odd as I remembered it)
That's okay. I had a question about Diva's Bite filter and realized that I already know the answer. :lol:
I started on Logic 5 with a PowerBook G4 550Mhz. I now have a MacBook Air M1 and it's ~165x faster! So, why is my music not proportionally better? :(

Post

Urs wrote: Sat Jun 24, 2023 3:11 pm It seems that all of these implementations are linear? In that case I think the most straight forward and easiest to understand version is Andy's here:

https://cytomic.com/files/dsp/SkfLinear ... mised2.pdf
Hope you don't mind me asking Urs but you and your team have a done a stellar job of modelling this one in Diva:

Is it possible to get the 'screaming' aspect of this filter without non-linearities? If not, can you get this aspect with usual non-linearities (tanh etc) or is it something that really comes with an iterative method like Raphson-Newton?

Post Reply

Return to “DSP and Plugin Development”