What's the difference with dimtass/DSP-Cpp-filters?
Filters are classified into 5 types depending on a set of parameters:
- BiquadSimple (
fc
andfs
only) - BiquadShelf (
gain_db
,fc
andfs
) - BiquadQ (
Q
,fc
andfs
) - BiquadBand (
bw
,fc
andfs
) - BiquadParametric (
gain_db
,Q
,fc
andfs
)
fc
is corner frequency, fs
is sample rate, bw
is bandwidth, Q
is quality factor.
Filter parameters are now set in the constructor. You need to call calculate_coeffs() function (which has been made virtual) only when you want to change them all at the same time. Added set_param(), set_fc(), set_fs(), set_gain(), set_Q(), set_bw() functions for the case when you want to change only one parameter.
Example of usage from my Android MIDI library:
template<class FilterClass> requires(is_base_of<BiquadSimple, FilterClass>() == true)
void Filter::activateFilter() {
mActiveFilter = make_unique<FilterClass>(mFrequency, AudioEngine::getSampleRate());
}
float Filter::process(float sample) {
return mActiveFilter->process(sample);
}
This repo contains some DSP biquad filters used in audio. I've extracted those
filters from the Designing Audio Effect Plug-Ins in C++: With Digital Audio Signal Processing Theory
book that you can find here.
I've also implemented a real-time testing on a Cortex-M4 MCU, using the on-chip ADC and DAC. You can find the post here.
This is the formula I'm using for the digital biquad filter in the source code:
y(n) = a0*x(n) + a1*x(n-1) + a2*x(n-2) - b*y(n-1) + b2*y(n-2)
- First order all-pass filter (fo_apf)
- First order high-pass filter (fo_hpf)
- First order low-pass filter (fo_lpf)
- First order high-shelving filter (fo_shelving_high)
- First order low-shelving filter (fo_shelving_low)
- Second order all-pass filter (so_apf)
- Second order band-pass filter (so_bpf)
- Second order band-stop filter (so_bsf)
- Second order Butterworth band-pass filter (so_butterworth_bpf)
- Second order Butterworth band-stop filter (so_butterworth_bsf)
- Second order Butterworth high-pass filter (so_butterworth_hpf)
- Second order Butterworth low-pass filter (so_butterworth_lpf)
- Second order high-pass filter (so_hpf)
- Second order Linkwitz-Riley high-pass filter (so_linkwitz_riley_hpf)
- Second order Linkwitz-Riley low-pass filter (so_linkwitz_riley_lpf)
- Second order Low-pass filter (so_lpf)
- Second order parametric/peaking boost filter with constant-Q (so_parametric_cq_boost)
- Second order parametric/peaking cut filter with constant-Q (so_parametric_cq_cut)
- Second order parametric/peaking filter with non-constant-Q (so_parametric_ncq)
All the filters are now header files and they are located in the lib/
folder.
In order to use them just copy the lib/
folder (and rename it if needed) into
your project folder. There's an example how to build later in the README.
You can use cmake to build the tests. On Linux, you can just run this:
./build_tests.sh
The above command will build the tests and run them.
Note: Tests are a bit naive in this case, since it doesn't make much sense for testing using unit-tests, but anyways, I've added them
The filters can be used in your C++ code in the part where the audio sample is about to be processed. You need to include the filter_includes.h file and create an object with filter you want to apply. Filter parameters can be changed with calculate_coeffs() function. Then in the sample processing function run the filter() function with the current sample as a parameter.
I've used RackAFX to test these filters.
For example, to use the so-LPF filter then first create a main.cpp
file
in the top directory of this repo.
touch main.cpp
Then add this code inside:
#include <iostream>
#include <memory>
#include "filter_includes.h"
int main() {
auto filter = std::make_unique<SO_LPF>(1.0, 5000, 96000);
auto coeffs = filter->get_coeffs();
auto yn = filter->process(0.303);
std::cout << "Coeffs: " << std::endl;
std::cout << "a0: " << coeffs.a0 << std::endl;
std::cout << "a1: " << coeffs.a1 << std::endl;
std::cout << "a2: " << coeffs.a2 << std::endl;
std::cout << "b1: " << coeffs.b1 << std::endl;
std::cout << "b2: " << coeffs.b2 << std::endl;
std::cout << "yn: " << yn << std::endl;
return 0;
}
Now to build the file run:
g++ main.cpp -I./lib
And then run the executable:
./a.out
This is will print the filter coefficients and then will process
a sample with the value 0.303
. You should see an output similar
to this:
Coeffs:
a0: 0.0228608
a1: 0.0457215
a2: 0.0228608
b1: -1.63163
b2: 0.723069
yn: 0.00692681