New modern C++ library for fast decramped modulable filters
-
- KVRer
- 16 posts since 16 Apr, 2025
Hello,
I present a very small (200 loc) recursive first and second order filter library written in modern C++20. The filters are based on my two papers on the matter. This is the very first library that efficiently solves decramping for all filter types and puts them into an optimised recursive structure suited for audio rate modulation. The filter types include [LowPass, HighPass, BandPass, AllPass, Notch, LowShelf, HighShelf, Peaking]. The filters have been tested under extreme conditions: with a resonance Q=100 and the cutoff frequency being heavily modulated from 10^-5Hz to infinityHz (it in fact can accept infinity). The ::Linear namespace also hints at a future update; again, based only on novelties.
https://github.com/yIvantsov/ivantsov-filters
I present a very small (200 loc) recursive first and second order filter library written in modern C++20. The filters are based on my two papers on the matter. This is the very first library that efficiently solves decramping for all filter types and puts them into an optimised recursive structure suited for audio rate modulation. The filter types include [LowPass, HighPass, BandPass, AllPass, Notch, LowShelf, HighShelf, Peaking]. The filters have been tested under extreme conditions: with a resonance Q=100 and the cutoff frequency being heavily modulated from 10^-5Hz to infinityHz (it in fact can accept infinity). The ::Linear namespace also hints at a future update; again, based only on novelties.
https://github.com/yIvantsov/ivantsov-filters
-
Music Engineer Music Engineer https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=15959
- KVRAF
- 4389 posts since 8 Mar, 2004 from Berlin, Germany
Very nice! Thank you for sharing your research results and code! I have a question. In your code, some "magic numbers" appear - like for example:
It would be nice to know where these numbers come from, even without studying the attached papers (which are also very much appreciated!) in detail. Maybe by documenting the formulas that were used to computing them or maybe even better by letting the code itself compute them (perhaps at compile time as constexpr?). This would also make the numbers appropriately precise when using the code with double precision (or even with extended precision someday). Anyway, good work.
Thanks again.
Code: Select all
sigma = (T {0.519355108} * w * w - T {0.2251345831}) / (w * w - T {0.5514625429});- KVRAF
- 8503 posts since 12 Feb, 2006 from Helsinki, Finland
The responses in "paper1" with sigma sqrt(2/3)pi actually look fairly similar to MZTi (which is based on Chebychev fitting) which is nice and I guess the coefficients here are probably a bit faster to compute.
As for "paper2" ... I'm very bad at this signal flow graphs, but I wonder if you've compared this to the trapezoidal SVF (using TDF2 integrators as an optimization) which is sort of the "gold standard" when it comes to biquad structures that "just works" with modulation?
As for "paper2" ... I'm very bad at this signal flow graphs, but I wonder if you've compared this to the trapezoidal SVF (using TDF2 integrators as an optimization) which is sort of the "gold standard" when it comes to biquad structures that "just works" with modulation?
-
- KVRer
- Topic Starter
- 16 posts since 16 Apr, 2025
Those magic numbers are in fact not ideal, thank you for the suggestion. I'll wrap them inside a function. Regarding what it does, it's actually a simple scaled approximation of Eq(2.11) from paper1. That way, you can exactly match the cutoff frequency, although it's not very "vital" in my opinion.
I'm not familiar at all with MZTi. But it appears that it's mapping the poles by exponentials and then fitting, as you said. If the filter coefficients are static, then it's a good method. But I dislike it, because you are trying to fix something by doing measurements, similarly to an iterative algorithm. In the engineering field, this is acceptable; even encouraged I think. But in mathematics, this is seen as a hack. I'd nevertheless be interested in comparing the results if I can somehow grab an implementation of it.
The trapezoidal SVF is a very good solution and there is no reason to not use it. It has been the "gold standard" because it was the only child for a while. Now there is a contender and people can compare the two variants. On my side, I've measured a better quantization noise, although it's very minimal. Also having the ability to modulate the cutoff frequency past Nyquist is a nice feature. And the cpu usage is very good. Regarding the signal flow diagrams, I agree that there is no real intuition on understanding them. But at least, they expose the simplicity as well as the symmetry of the structures; which electronic circuits don't do (that's why dislike them and can't even read them).
I'm not familiar at all with MZTi. But it appears that it's mapping the poles by exponentials and then fitting, as you said. If the filter coefficients are static, then it's a good method. But I dislike it, because you are trying to fix something by doing measurements, similarly to an iterative algorithm. In the engineering field, this is acceptable; even encouraged I think. But in mathematics, this is seen as a hack. I'd nevertheless be interested in comparing the results if I can somehow grab an implementation of it.
The trapezoidal SVF is a very good solution and there is no reason to not use it. It has been the "gold standard" because it was the only child for a while. Now there is a contender and people can compare the two variants. On my side, I've measured a better quantization noise, although it's very minimal. Also having the ability to modulate the cutoff frequency past Nyquist is a nice feature. And the cpu usage is very good. Regarding the signal flow diagrams, I agree that there is no real intuition on understanding them. But at least, they expose the simplicity as well as the symmetry of the structures; which electronic circuits don't do (that's why dislike them and can't even read them).
- KVRAF
- 8503 posts since 12 Feb, 2006 from Helsinki, Finland
Hold on. I must object here. Any general biquad structure (including the trapezoidal SVF) can implement any response. You can't move poles past Nyquist, but nothing says you must use BLT to choose your coefficients. MZTi, your coefficient formula, a few other similar approaches can all take "cutoff" above Nyquist and all of these can be realized using the trapezoidal SVF (or trapezoidal SK, or digital lattice-ladder, or even the direct forms if you really wanted to).Ivantsov wrote: Mon Dec 08, 2025 4:08 amAlso having the ability to modulate the cutoff frequency past Nyquist is a nice feature.
-
- KVRer
- Topic Starter
- 16 posts since 16 Apr, 2025
You're right. I was just comparing against the dominant SVF done with the bilinear transform and the tan pre warp. In that case, you're limited below Nyquist.
- KVRist
- 191 posts since 31 Oct, 2017
Very nice indeed!Ivantsov wrote: Sun Dec 07, 2025 9:50 am Hello,
I present a very small (200 loc) recursive first and second order filter library written in modern C++20. The filters are based on my two papers on the matter. This is the very first library that efficiently solves decramping for all filter types and puts them into an optimised recursive structure suited for audio rate modulation. The filter types include [LowPass, HighPass, BandPass, AllPass, Notch, LowShelf, HighShelf, Peaking]. The filters have been tested under extreme conditions: with a resonance Q=100 and the cutoff frequency being heavily modulated from 10^-5Hz to infinityHz (it in fact can accept infinity). The ::Linear namespace also hints at a future update; again, based only on novelties.
https://github.com/yIvantsov/ivantsov-filters
Couple of things regarding the source...where's peaking? Is that midshelf?
Also, in general, anyone adopting your code for anything commercial where they can't use GPL is going to have to reference your papers (which they arguably should) then probably cross correlate with the code you've written without actually copying any of it. Seems a bit of an unnecessary hassle given its size and brevity - maybe you could have gone with an MIT license for the code.
-
- KVRer
- Topic Starter
- 16 posts since 16 Apr, 2025
Peaking is mid shelf. That's an unfortunate inconsistency, indeed.
If anyone wants to use the code for commercial use without wasting time reading my papers, they can contact me via email to find an easy licensing solution. And if I ever see a wide adoption of my filters in the future, I might MIT it.
Nevertheless, I'm very open to critics and if more people think that MIT is more appropriate, I will rethink it.
If anyone wants to use the code for commercial use without wasting time reading my papers, they can contact me via email to find an easy licensing solution. And if I ever see a wide adoption of my filters in the future, I might MIT it.
Nevertheless, I'm very open to critics and if more people think that MIT is more appropriate, I will rethink it.
- KVRian
- 800 posts since 16 May, 2014 from Germany
Thanks for sharing the document and the source code.
Unfortunately, the implementation (at least the SecondOrder LowPass plus sigma warp) is not suitable for modulating FC at audio rate because the sigma function {sigma = (0.7344790372 * w * w - 0.3183883807) / (w * w - 0.5514625429)} has a pole for w=0.749. FC changes near the pole result in audible distortion of the audio signal.
Unfortunately, the implementation (at least the SecondOrder LowPass plus sigma warp) is not suitable for modulating FC at audio rate because the sigma function {sigma = (0.7344790372 * w * w - 0.3183883807) / (w * w - 0.5514625429)} has a pole for w=0.749. FC changes near the pole result in audible distortion of the audio signal.
-
- KVRer
- Topic Starter
- 16 posts since 16 Apr, 2025
Thank you for testing the code and seeing the bug.
I have indeed incorrectly written the polynomial formulae; w has to be mapped to 1/w. I'll fix it asap.
I have indeed incorrectly written the polynomial formulae; w has to be mapped to 1/w. I'll fix it asap.
-
Guillaume Piolat Guillaume Piolat https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=366815
- KVRist
- 308 posts since 21 Sep, 2015 from Grenoble
Also waiting for the fix for the sigma mapping.
For now using a constant as a workaround (ie using Warp::None)
Very interesting filters.
For now using a constant as a workaround (ie using Warp::None)
Very interesting filters.
Checkout our plug-ins here.
-
Guillaume Piolat Guillaume Piolat https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=366815
- KVRist
- 308 posts since 21 Sep, 2015 from Grenoble
Test plugin for anyone intersted.
You do not have the required permissions to view the files attached to this post.
Checkout our plug-ins here.
-
- KVRer
- Topic Starter
- 16 posts since 16 Apr, 2025
I've uploaded the fix for the warping and changed the license to MIT.
I do plan to update this library to include nonlinear filters as well as other interesting kind of filters.
I do plan to update this library to include nonlinear filters as well as other interesting kind of filters.
- KVRian
- 1320 posts since 3 May, 2005 from Victoria, BC
Do you plan to add a method to calculate filter response at a given frequency? i.e. to draw the curve in the ui?
-
- KVRer
- Topic Starter
- 16 posts since 16 Apr, 2025
