SVF resonant?

Hi,

I’m looking for a SVF resonant, inspired by this “old” filter by Paul Kellet: Resonant filter — Musicdsp.org documentation

Is it possible with Juce native SVF filter JUCE/modules/juce_dsp/processors/juce_StateVariableFilter.h at master · juce-framework/JUCE · GitHub doing something similar?

Thanks

No one? :slight_smile:

Not sure what you’re asking. The SVF filter from JUCE gives you the frequency response of a second-order filter, which is resonant. But it’s not going to give the same frequency response as that Paul Kellet filter.

For “resonant” I mean it will produce “a sine wave” near the cutoff, at higher res value…

I wrong term probably, meaning “Self-Oscillate”, which seems more appropriate :slight_smile:

IIRC that SVF filter indeed self-oscillates with high values or Q. But you can always verify this for yourself by writing a few lines of code. :wink:

I don’t think the SVF does self-oscillate. IIRC, the ladder (Moog style) filter does, but not the SVF.

My recollection is that the Cytomic SVF does self-oscillate. I haven’t tried this with the TPT version that’s built into JUCE. I was under the impression both have the exact same frequency response, but perhaps they diverge when driving Q very hard.

Andy’s SVF’s don’t self-oscillate. They’re pretty much a drop in replacement for RBJ biquads which don’t self-oscillate either. FWIW, the TPT ones don’t as well. Filters that can self-oscillate generally require non-linearities.

1 Like

Ok, so for what I see won’t be that easy to enable self oscillate (at least you are very strong in math).
Maybe I’ll start with one which already got this property by nature.

Excluding Ladder (which seems only LP), which one (with LP/HP/BP) do you know which self oscillate?

I’m willing to be wrong on this, but in that case I do want to understand why I am wrong. :slight_smile: Perhaps I don’t understand the meaning of “self-oscillation”, but I thought it was this:

After exciting the filter by a short noise pulse or an impulse (or any other kind of signal), it creates a sine wave at the cutoff frequency.

Is that indeed the behavior we’re discussing here? Because if so, I have no problems getting the Cytomic SVF to do this. I’m using this filter in the synth from my book and even describe how to change Q to get it to self-oscillate.

If I feed the filter with nothing but some low-level noise (like you’d have in an analog synth) or even a pure impulse, it outputs a sine wave at the cutoff point.

(I’m perfectly happy to be corrected on this if I’m misunderstanding, since I’d want to update the book if this is a mistake.)

1 Like

Which Cytomic SVF implementation are you considering? Could you post the sources?

You can find the complete source code to the book here: GitHub - hollance/synth-plugin-book: Source code for the book Code Your Own Synth Plug-Ins With C++ and JUCE

The filter code is in Finished Project/Source/Filter.h

1 Like

Thanks, but that seems “only” a lowpass filter, not a complete SVF (with simultaneous LP/HP/BP)…

Yep, that’s pretty much the one I’m using. I might well be wrong on this. I’m sure I read some while (years) ago that they didn’t self-oscillate and TBH until very recently I’ve only employed them in a synth as local filters to the oscillators so I’ve never actually tried. If you’ve managed to get them to self-oscillate then I’ll defer to your empirical result.

Take a look at the last page here: https://cytomic.com/files/dsp/SvfLinearTrapOptimised2.pdf

You’ll see all filter derivations including HP&BP using the same technique.

Yeah, I mean “quickly” from the @kerfuffle code, so I can test it faster :slight_smile:
The low pass seems to works nice, just miss the HP/BP part.

From the Cytomic paper (last page) and kerfuffle’s filter source code, something like:

// Resonant low-pass filter based on Cytomic SVF.
class Filter {
public:
  float sampleRate;

  void updateCoefficientsLP(float cutoff, float Q) {
    g = std::tan(PI * cutoff / sampleRate);
    k = 1.0f / Q;
    a1 = 1.0f / (1.0f + g * (g + k));
    a2 = g * a1;
    a3 = g * a2;
    m0 = 0;
    m1 = 0;
    m2 = 1;
  }

  void updateCoefficientsBP(float cutoff, float Q) {
    g = std::tan(PI * cutoff / sampleRate);
    k = 1.0f / Q;
    a1 = 1.0f / (1.0f + g * (g + k));
    a2 = g * a1;
    a3 = g * a2;
    m0 = 0;
    m1 = 1;
    m2 = 0;
  }

  void updateCoefficientsHP(float cutoff, float Q) {
    g = std::tan(PI * cutoff / sampleRate);
    k = 1.0f / Q;
    a1 = 1.0f / (1.0f + g * (g + k));
    a2 = g * a1;
    a3 = g * a2;
    m0 = 1;
    m1 = -k;
    m2 = -1;
  }

  void reset() {
    g = 0.0f;
    k = 0.0f;
    a1 = 0.0f;
    a2 = 0.0f;
    a3 = 0.0f;
    m0 = 0.f;
    m1 = 0.f;
    m2 = 0.f;

    ic1eq = 0.0f;
    ic2eq = 0.0f;
  }

  float render(float x) {
    float v3 = x - ic2eq;
    float v1 = a1 * ic1eq + a2 * v3;
    float v2 = ic2eq + a2 * ic1eq + a3 * v3;
    ic1eq = 2.0f * v1 - ic1eq;
    ic2eq = 2.0f * v2 - ic2eq;
    return m0 * x + m1 * v1 + m2 * v2;
  }

private:
  const float PI = 3.1415926535897932f;

  float g, k, a1, a2, a3; // filter coefficients
  float m0, m1, m2;       // filter mixers
  float ic1eq, ic2eq;     // internal state
};

But that’s move away from original “concept” of SVF (i.e. having multi response at the same time, lp/hp/bp simultaneous).

If I want one at time, I’ve already the RBJ’s Biquad for that.

You can get multiple outputs at the same time, something like this (warning: I didn’t test it):

void render(float x, float& lp, float& bp, float& hp) {
    float v3 = x - ic2eq;
    float v1 = a1 * ic1eq + a2 * v3;
    float v2 = ic2eq + a2 * ic1eq + a3 * v3;
    ic1eq = 2.0f * v1 - ic1eq;
    ic2eq = 2.0f * v2 - ic2eq;

    lp = v2;
    bp = v1;
    hp = x - k * v1 - v2;
}

The coefficients are the same for LP, BP, and HP, only the “mix” amounts m change.

1 Like

Oh right! Nice :slight_smile:
I’ll try it out, and test self oscillation, and let you know :slight_smile: meanwhile, lots of thanks to both, very kind!