144 lines
3.4 KiB
C++
144 lines
3.4 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 "util/strings.h"
|
|
|
|
#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>
|
|
|
|
// clazy:excludeall=non-pod-global-static
|
|
RegisterPlugin(SVF, {
|
|
i->id = "fx:svf";
|
|
i->oldIds = {"gadget:svf"};
|
|
i->displayName = "Filter";
|
|
i->category = "Effect";
|
|
})
|
|
|
|
SVF::SVF() { }
|
|
|
|
void SVF::init() {
|
|
addPort(Port::Input, Port::Audio, 0);
|
|
addPort(Port::Output, Port::Audio, 0);
|
|
|
|
//addPort(Port::Input, Port::Parameter, 0);
|
|
//auto p = Param("Cutoff", 0.0, 16000.0, 0.0);
|
|
cutoff.makePort(this);
|
|
}
|
|
|
|
void SVF::reset() {
|
|
filter.reset();
|
|
}
|
|
|
|
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();
|
|
|
|
auto r = filter.scaledResonance(resonance);
|
|
auto c = cutoff.start();
|
|
|
|
size_t ts = audioEngine->curTickSize();
|
|
for (size_t f = 0; f < ts; f++) {
|
|
AudioFrame inp = (*in)[f];
|
|
|
|
filter.process(inp, c.next(), r);
|
|
|
|
switch (mode) {
|
|
case Low:
|
|
(*out)[f] = filter.low;
|
|
break;
|
|
case High:
|
|
(*out)[f] = filter.high;
|
|
break;
|
|
case Band:
|
|
(*out)[f] = filter.band;
|
|
break;
|
|
case Notch:
|
|
(*out)[f] = filter.notch;
|
|
break;
|
|
default:
|
|
(*out)[f] = inp;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SVF::saveData(QCborMap& m) const {
|
|
//m[qs("cutoff")] = cutoff;
|
|
cutoff.save(m);
|
|
m[qs("resonance")] = resonance;
|
|
m[qs("mode")] = mode;
|
|
}
|
|
|
|
void SVF::loadData(const QCborMap& m) {
|
|
cutoff.load(m, "frequency");
|
|
cutoff.load(m);
|
|
//cutoff = m.value("cutoff").toDouble(m.value("frequency").toDouble(cutoff));
|
|
resonance = m.value("resonance").toDouble(resonance);
|
|
mode = static_cast<FilterMode>(m.value("mode").toInteger(mode));
|
|
}
|
|
|
|
namespace {
|
|
std::unordered_map<SVF::FilterMode, QString> modeNames = [] {
|
|
std::unordered_map<SVF::FilterMode, QString> m;
|
|
m[SVF::Off] = "off";
|
|
m[SVF::Low] = "low";
|
|
m[SVF::High] = "high";
|
|
m[SVF::Band] = "band";
|
|
m[SVF::Notch] = "notch";
|
|
return m;
|
|
}();
|
|
}
|
|
|
|
void SVF::onGadgetCreated() {
|
|
if (!obj) return;
|
|
auto l = new LayoutGadget(obj);
|
|
|
|
auto modetxt = [](double inp) {
|
|
if (auto f = modeNames.find(static_cast<FilterMode>(inp)); f != modeNames.end()) return f->second;
|
|
return qs("?");
|
|
};
|
|
|
|
KnobGadget::autoCutoff(l, cutoff);
|
|
(new KnobGadget(l))->bind(resonance)->setLabel(qs("Res"))->setTextFunc(KnobGadget::textPercent)->setRange(0.0, 1.0, 0.01)->setDefault(0.0);
|
|
(new KnobGadget(l))->bind(mode)->setLabel(qs("Mode"))->setTextFunc(modetxt)->setRange(0, Notch, 1, KnobGadget::BigStep)->setDefault(0);
|
|
}
|