181 lines
4.5 KiB
C++
181 lines
4.5 KiB
C++
/*
|
|
* Filename: svf.cpp
|
|
*
|
|
* Description: State Variable Filter
|
|
*
|
|
*
|
|
* Version:
|
|
* Created: Fri Nov 1 23:36:50 2019
|
|
* Revision: None
|
|
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
|
|
*
|
|
*/
|
|
|
|
|
|
#include "svf.h"
|
|
using Xybrid::Effects::SVF;
|
|
using namespace Xybrid::Data;
|
|
|
|
#include "nodelib/basics.h"
|
|
using namespace Xybrid::NodeLib;
|
|
|
|
#include "data/audioframe.h"
|
|
#include "data/porttypes.h"
|
|
|
|
#include "config/pluginregistry.h"
|
|
using namespace Xybrid::Config;
|
|
|
|
#include "audio/audioengine.h"
|
|
using namespace Xybrid::Audio;
|
|
|
|
#include "ui/patchboard/nodeobject.h"
|
|
#include "ui/gadgets/layoutgadget.h"
|
|
#include "ui/gadgets/togglegadget.h"
|
|
#include "ui/gadgets/knobgadget.h"
|
|
using namespace Xybrid::UI;
|
|
|
|
#include <cmath>
|
|
|
|
#include <QCborMap>
|
|
|
|
#define qs QStringLiteral
|
|
|
|
#define MIN(a,b) (a<b?a:b)
|
|
|
|
namespace {
|
|
bool _ = PluginRegistry::enqueueRegistration([] {
|
|
auto i = std::make_shared<PluginInfo>();
|
|
i->id = "gadget:svf";
|
|
i->displayName = "Filter";
|
|
i->category = "Effect";
|
|
i->createInstance = []{ return std::make_shared<SVF>(); };
|
|
PluginRegistry::registerPlugin(i);
|
|
});
|
|
}
|
|
|
|
SVF::SVF() { }
|
|
|
|
void SVF::init() {
|
|
auto sr = audioEngine->curSampleRate();
|
|
this->max_freq = ((float)sr / 4.0);
|
|
this->frequency = 12000;
|
|
this->resonance = 65;
|
|
addPort(Port::Input, Port::Audio, 0);
|
|
addPort(Port::Output, Port::Audio, 0);
|
|
}
|
|
|
|
void SVF::reset() {
|
|
release();
|
|
auto sr = audioEngine->curSampleRate();
|
|
}
|
|
|
|
void SVF::release() {
|
|
|
|
}
|
|
|
|
void SVF::process() {
|
|
|
|
|
|
|
|
auto in = std::static_pointer_cast<AudioPort>(port(Port::Input, Port::Audio, 0));
|
|
auto out = std::static_pointer_cast<AudioPort>(port(Port::Output, Port::Audio, 0));
|
|
in->pull();
|
|
out->pull();
|
|
if (this->fm != _off)
|
|
if (this->frequency > 0) { this->frequency-=0.1; }
|
|
size_t ts = audioEngine->curTickSize();
|
|
for (size_t f = 0; f < ts; f++) {
|
|
AudioFrame fCurrent = (*in)[f];
|
|
AudioFrame fOut;
|
|
if (this->fm == _off) {
|
|
(*out)[f] = fCurrent;
|
|
continue;
|
|
}
|
|
|
|
double res = this->resonance;
|
|
//double damp = MIN(2.0*(1.0 - pow(res, 0.25)), MIN(2.0, 2.0/freq - freq*0.5));
|
|
double q = sqrt(1.0 - atan(sqrt(res)) * 2.0 / PI);
|
|
double damp = sqrt(q);
|
|
|
|
//double freq = 2.0*sin(M_PI * MIN(0.25, this->frequency/audioEngine->curSampleRate()));
|
|
double freq = this->frequency / (audioEngine->curSampleRate() * 2 );
|
|
double in_l, in_r;
|
|
double low_l, low_r;
|
|
double band_l, band_r;
|
|
double high_l, high_r;
|
|
double notch_l, notch_r;
|
|
|
|
in_l = fCurrent.l;
|
|
in_r = fCurrent.r;
|
|
low_l=low.l;
|
|
low_r=low.r;
|
|
band_l=band.l;
|
|
band_r=band.r;
|
|
high_l=high.l;
|
|
high_r=high.r;
|
|
notch_l=notch.l;
|
|
notch_r=notch.r;
|
|
|
|
|
|
low_l = low_l + freq * band_l;
|
|
high_l = damp * in_l - low_l - q * band_l;
|
|
band_l = freq * high_l + band_l;
|
|
notch_l = high_l + low_l;
|
|
low_r = low_r + freq * band_r;
|
|
high_r = damp * in_r - low_r - q * band_r;
|
|
band_r = freq * high_r + band_r;
|
|
notch_r = high_r + low_r;
|
|
low_l = low_l + freq * band_l;
|
|
high_l = damp * in_l - low_l - q * band_l;
|
|
band_l = freq * high_l + band_l;
|
|
notch_l = high_l + low_l;
|
|
low_r = low_r + freq * band_r;
|
|
high_r = damp * in_r - low_r - q * band_r;
|
|
band_r = freq * high_r + band_r;
|
|
notch_r = high_r + low_r;
|
|
|
|
low = {low_l, low_r};
|
|
band = {band_l, band_r};
|
|
high = {high_l, high_r};
|
|
notch = {notch_l, notch_r};
|
|
|
|
|
|
switch (fm) {
|
|
case _low:
|
|
(*out)[f] = this->low;
|
|
break;
|
|
case _band:
|
|
(*out)[f] = this->band;
|
|
break;
|
|
case _high:
|
|
(*out)[f] = this->high;
|
|
break;
|
|
case _notch:
|
|
(*out)[f] = this->notch;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SVF::saveData(QCborMap& m) const {
|
|
//m[qs("frequency")] = QCborValue(frequency);
|
|
//m[qs("resonance")] = QCborValue(resonance);
|
|
}
|
|
|
|
void SVF::loadData(const QCborMap& m) {
|
|
//frequency = m.value("frequency").toDouble(frequency);
|
|
//resonance = m.value("resonance").toDouble(resonance);
|
|
}
|
|
|
|
void SVF::onGadgetCreated() {
|
|
if (!obj) return;
|
|
auto l = new LayoutGadget(obj);
|
|
|
|
//(new KnobGadget(l))->bind(freq)->setLabel(qs("Frequency Step"))->setRange(0.0, 10, 0.5)->setDefault(1.0);
|
|
(new KnobGadget(l))->bind(frequency)->setLabel(qs("Frequency"))->setRange(0.0, this->max_freq, 10.0)->setDefault(6440.0);
|
|
l->addSpacer();
|
|
(new KnobGadget(l))->bind(resonance)->setLabel(qs("Resonance"))->setRange(0.0, 100.0, 0.1)->setDefault(0.0);
|
|
l->addSpacer();
|
|
(new KnobGadget(l))->bind(fm)->setLabel(qs("Filter Mode"))->setRange(0,4,1)->setDefault(0);
|
|
}
|