distortion effect
parent
b0b754a37d
commit
f969aa0d2e
2
notes
2
notes
|
@ -42,7 +42,7 @@ TODO {
|
|||
|
||||
revert-to-saved menu action
|
||||
|
||||
distortion effect
|
||||
- distortion effect
|
||||
|
||||
automation node {
|
||||
listens for one specific param
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
#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);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include "data/node.h"
|
||||
#include "nodelib/param.h"
|
||||
|
||||
namespace Xybrid::Effects {
|
||||
class Distortion : public Data::Node {
|
||||
NodeLib::Param drive = {"Drive", 0.0, 24.0, 0.0};
|
||||
NodeLib::Param shape = {"Shape", -5.0, 5.0, 0.0};
|
||||
NodeLib::Param mix = {"Mix", 0.0, 1.0, 1.0};
|
||||
NodeLib::Param output = {"Output", -12.0, 12.0, 0.0};
|
||||
|
||||
public:
|
||||
Distortion();
|
||||
~Distortion() override = default;
|
||||
|
||||
void init() override;
|
||||
void reset() override;
|
||||
//void release() override;
|
||||
void process() override;
|
||||
|
||||
void saveData(QCborMap&) const override;
|
||||
void loadData(const QCborMap&) override;
|
||||
|
||||
void onGadgetCreated() override;
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue