sensorium / Mozzi

sound synthesis library for Arduino
https://sensorium.github.io/Mozzi/
GNU Lesser General Public License v2.1
1.07k stars 186 forks source link

StateVariable centre frequency depends on Q #164

Closed tomcombriat closed 1 year ago

tomcombriat commented 1 year ago

Hi, Playing a bit with all the filters I found out a few limitations. The StateVariable in mozzi is good fun, it actually is able to display quite high resonance (way bigger than LowPassFilter at high frequencies) and, for low resonance (Q=255) is quite spot on on the desired cutoff frequency as long as one does not push to far toward Nyquist (not a problem in my opinion).

However, when pushing the resonance, the effective centre_frequency of the filter decreases. Here is an example with a set centre_frequency of 1000 Hz:

Q Effective centre frequency
255 1000
128 846
64 702
32 591
16 498
8 416
4 355
2 292
1 248

By fiddling around a bit, I found that one can renormalise the centre_frequency to achieve the correct output: centre_frequency = 4* centre_frequency / (Q^(1/4))

However correcting this is not completely trivial: it implies recalculating the centre_frequency every time the resonance is changed (just like the LowPassFilter is doing). Also the normalisation factor is not trivial to compute. So I am asking for opinions:

On the other end, I also found that the LowPassFilter can also be used as a statevariable using:

//return buf1;    // LP
 //return in-buf0;  // HP
 return buf0 - buf1;  // BP 
 //return in - buf0 + buf1; // notch

And this filter is not impeded by the shift with Q (and is slightly faster). As it is not as resonant as StateVariable, and not scaled, I think it is worth keeping both, and adding the other outputs to LowPassFilter to make it "another" StateVariable. What would be the best strategy then?

Let me know your opinions! Cheers, Tom

tfry-git commented 1 year ago

Regarding the StateVariable filter, I guess it will be a good idea to keep old code working as before. Arguably, the center frequency shift is a bug, but there may well be existing code where the frequency shift is not an issue, while additional computation might be. Suggested procedure: Create a new StateVariableFilter which will have two well-documented functions: setResonance() and setResonanceQuick() (or something). StateVariable could become deprecated with a note on the available choice.

As for a more generic LowPassFilter, FrequencyFilter or ResonantFilter might be suitable names for a template?

tfry-git commented 1 year ago

This can be closed, right?

tomcombriat commented 1 year ago

Well, this is not resolved, but I guess it won't be as this would change the behavior of all existing sketches using the stateVariable. Additionnally, the ResonantFilter class offers filters with stable Q. So I would say yes.