electro-smith / DaisySP

A Powerful DSP Library in C++
https://www.electro-smith.com/daisy
Other
882 stars 139 forks source link

Problems with the SVF Filter at high cutoff frequencies #145

Open makingsoundmachines opened 3 years ago

makingsoundmachines commented 3 years ago

I keep having problems with the SVF filter crashing at cutoff frequencies higher than 2500 hz, especially when using more than one instance. When setting the cutoff with a knob and sweeping the frequency, over a frequency in about that range, the filter just crashes and sound from daisy doesn't recover. Whereas using more than one instance of other filters is fine (e.g. the moogladder).

I can't exactly pinpoint why - would it make sense to try and implement the filter with mat approximations and without the doublesampling, to get better performance out of it? It's a shame because as far as I can see it's the only highpass filter in DaisySP right now.

stephenhensley commented 3 years ago

@makingsoundmachines There is a single-pole highpass filter available. (ATone)

I have not seen the behavior you're mentioning, but I also don't think I've used very many of these at once. Are you connecting them in series or are they in parallel or processing different things?

The previous issues that (I thought) were resolved were related to low resonance/high drive along with higher cut off frequencies. If these instabilities were not resolved then I would guess that the internal filter values are getting set to NaN and that is infecting the rest of your audio path.

I can look into fixing this, but I agree that creating a more generic SVF that's as lightweight as possible (i.e. no double sampling, etc.) would be very handy. We recently added a few MI ports that use the current Svf module that would definitely be a bit more efficient without the double sampling.

makingsoundmachines commented 3 years ago

I'm using them in a serial hp -> lp setting, using two different instances of the filter so I can set an upper and lower cutoff with resonance (a bit like an MS20 filter).

ATone will help me out in one instance though, that is great already! Thank you!

erikformella commented 3 years ago

I've been experiencing the same issue, running 4 instances in parallel on my Versio.

It seems to happen when the resonance is low and the default drive is unchanged, so maybe related to the previous issue @stephenhensley described?

I haven't written a digital filter since college, but I am happy to get out my debugger and help where I can 😆.

makingsoundmachines commented 3 years ago

I've been researching a little but for now all I have are clues. I'll still leave them here.

I asked a friend whos been working in audio DSP for a long time and he described the issue with Chamberlin SVF and derivates (which this is) like this: "it'll blow up at high freqs if you don't use a high enough q - it's more stable when it resonates than when it's damped", accoding to damping factor < 2 / F1 - F1 / 2.

This is exactly describing my experience. My workaround for now has been implementing another filter model (state variable biquad) where I needed it, which works fine on noise but the Andrew Simper SVF here sounds better on synthesized tones.

I found the original musicDSP source here https://www.musicdsp.org/en/latest/Filters/92-state-variable-filter-double-sampled-stable.html

and a thread about it here that has an erratum https://music-dsp.music.columbia.narkive.com/SzijmwZo/andrew-simper-s-state-variable-filter

`My fault, I put the MIN in the wrong place when re-typing the code to submit it to the archive.

freq = 2.0sin(PIMIN(0.25, fc/(fs*2)));

or equivalently (for those that didn't understand the 0.25):

freq = 2.0sin(PI0.5*MIN(0.5, fc/fs));

Thanks for picking up the error, and everyone else who has used it and didn't notice, well at least someone was paying attention ;)

For stability you just have to increase your resonance. This is taken account of in the calculation:

damp = MIN(2.0(1.0 - pow(res, 0.25)), MIN(2.0, 2.0/freq - freq0.5));

which descreases damping (increase resonance) with increased frequency.

Others prefer to limit your frequency depending on damping, but I prefer to have a wide frequency range.

--andy`

Haven't found the time to properly dive into it but maybe that will help solve the bug.

stephenhensley commented 3 years ago

@makingsoundmachines nice! Good find! That should totally help sort it out! I should be able to work in a patch sometime over the next few days!

Thanks for the sleuth work!

TheSlowGrowth commented 3 years ago

It could be worth checking out the topology preserving transform (TPT) version of the SVF: https://www.native-instruments.com/fileadmin/ni_media/downloads/pdf/VAFilterDesign_2.1.0.pdf Pages 110 and following. From my experience the TPT version it doesn't have any instability at high frequencies. I'm implementing this as part of a commercial EQ right now, and haven't seen anything weird so far for frequencies up to 0.9*Fs/2.

stephenhensley commented 3 years ago

Thanks for sharing that @TheSlowGrowth it looks like a hearty resource for sure. Once I dig into it a bit I may rework this filter (or add another one if it makes sense/sounds any different) with the TPT structure.

Hmm, went to go patch up the freq setting, and I think the fixes are applied to the current version on the archive, and in DaisySP. Though, I could just be missing something silly.

For a sanity check here are some side-by-sides:

For Freq:

// In DaisySP:
freq_ = 2.0f * sinf(PI_F * MIN(0.25f, fc_ / (sr_ * 2.0f)));
// copy/pasted from above (with * added for multiplies)
freq = 2.0 * sin(PI * MIN(0.25, fc/(fs*2)));

For Damp:

// In DaisySP
damp_  = MIN(2.0f * (1.0f - powf(res_, 0.25f)), MIN(2.0f, 2.0f / freq_ - freq_ * 0.5f));
// copy/pasted from above (with * added for multiplies)
damp = MIN(2.0*(1.0 - pow(res, 0.25)), MIN(2.0, 2.0/freq - freq*0.5));