Adjustable filter parameters
This is an example of a more complex use of the GUI as a controller. The GUI here is used to set a filter's parameters and display its frequency response.
This example uses four libraries:
- the Biquad library is used to create the low pass filter which is applied to the audio input
- the Pipe library is used for sending information to the GUI
- the GUI library is used for creating the GUI itself
- the FFT library is used to calculate the frequency response of the filter
The best way to exerience this example is to play some audio into Bela's audio inputs. A low pass filter is applied to the audio input. If you press the GUI button you will find a control interface which allows you to control the Cutoff frequency (in Hertz) and Q (or resonance) of the filter applied to the audio input. You will hear the effect of the filter.
There are also various controls which allow you to adjust the visualisation of the filter's frequency response. The audio filter is applied in render()
and we listen for changes to the settings of the GUI with the guiCallback
function.
#include <vector>
#include <libraries/Fft/Fft.h>
#include <libraries/Gui/Gui.h>
#include <libraries/Biquad/Biquad.h>
#include <libraries/Pipe/Pipe.h>
#include <stdexcept>
std::vector<Biquad> gAudioBiquads;
unsigned int kFftLen = 2048;
static bool existsAndIsNumber(JSONObject& json, const std::wstring& str)
{
return (json.find(str) != json.end() && json[str]->IsNumber());
}
static double retrieveAsNumber(JSONObject& json, const std::string& str)
{
std::wstring ws = JSON::s2ws(str);
if(existsAndIsNumber(json, ws))
{
double ret = json[ws]->AsNumber();
printf("Received parameter \"%s\": %f\n", str.c_str(), ret);
return ret;
}
else
throw(std::runtime_error("Value " + str + "not found\n"));
}
bool guiCallback(JSONObject& json, void*)
{
settings.
type = Biquad::lowpass;
try {
settings.
cutoff = retrieveAsNumber(json,
"cutoff");
} catch (std::exception& e) {}
try {
settings.
q = retrieveAsNumber(json,
"q");
} catch (std::exception& e) {}
try {
settings.
peakGainDb = retrieveAsNumber(json,
"peakGainDb");
} catch (std::exception& e) {}
static std::vector<float> ir(kFftLen);
static std::vector<float> buf(kFftLen / 2);
fft.setup(kFftLen);
Biquad analysisBiquad(settings);
for(unsigned int n = 0; n < ir.size(); ++n)
{
ir[n] = analysisBiquad.process(0 == n ? 1 : 0);
}
fft.fft(ir);
float mx = -100000;
for(unsigned int n = 0; n < buf.size(); ++n)
{
buf[n] = fft.fda(n);
mx = mx < buf[n] ? buf[n] : mx;
}
return false;
}
{
gPipe.
setup(
"guiToLoop");
gAudioBiquads.resize(
.type = Biquad::lowpass,
.cutoff = 6000,
.q = 0.707,
.peakGainDb = 6,
})
);
return true;
}
{
bool newSettingsReceived = false;
while(1 == gPipe.
readRt(settings))
{
newSettingsReceived = true;
continue;
}
if(newSettingsReceived) {
for(auto& b : gAudioBiquads)
{
b.setup(settings);
b.clean();
}
}
{
for(unsigned int c = 0; c < gAudioBiquads.size(); ++c)
{
float out = gAudioBiquads[c].process(in);
}
}
}
{
}