/* * 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 #include #define qs QStringLiteral #define MIN(a,b) (a(); i->id = "gadget:svf"; i->displayName = "Filter"; i->category = "Effect"; i->createInstance = []{ return std::make_shared(); }; 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(port(Port::Input, Port::Audio, 0)); auto out = std::static_pointer_cast(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); }