xybrid/xybrid/nodes/effect/distortion.cpp

100 lines
2.4 KiB
C++

#include "distortion.h"
using Xybrid::Effects::Distortion;
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(Distortion, {
i->id = "fx:distortion";
i->displayName = "Distortion";
i->category = "Effect";
})
Distortion::Distortion() = default;
void Distortion::init() {
addPort(Port::Input, Port::Audio, 0);
addPort(Port::Output, Port::Audio, 0);
}
void Distortion::reset() {
//
}
namespace {
inline double sxp(double v, double e) {
double s = v < 0 ? -1.0 : 1.0;
return std::pow(std::abs(v), e) * s;
}
inline AudioFrame sxp(AudioFrame v, double e) { return {sxp(v.l, e), sxp(v.r, e)}; }
}
void Distortion::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 ts = audioEngine->curTickSize();
auto d = drive.start(), s = shape.start(), m = mix.start(), o = output.start();
for (size_t f = 0; f < ts; f++) {
AudioFrame inp = (*in)[f];
auto g = inp.gainBalance(d.next());
auto pv = s.next();
auto exp = pv > 0.0 ? 1.0 / (1.0 + pv) : -pv + 1.0;
(*out)[f] = AudioFrame::lerp(inp, sxp(g.clamp(), exp), m.next()).gainBalance(o.next());
}
}
void Distortion::saveData(QCborMap& m) const {
drive.save(m);
shape.save(m);
mix.save(m);
output.save(m);
}
void Distortion::loadData(const QCborMap& m) {
drive.load(m);
shape.load(m);
mix.load(m);
output.load(m);
}
void Distortion::onGadgetCreated() {
if (!obj) return;
auto l = new LayoutGadget(obj);
KnobGadget::autoGain(l, drive);
(new KnobGadget(l))->setRange(0, 0, 0.1)->bind(shape)->setTextFunc(KnobGadget::textOffset);
KnobGadget::autoPercent(l, mix);
KnobGadget::autoGain(l, output);
}