96 lines
2.6 KiB
C++
96 lines
2.6 KiB
C++
#include "autopan.h"
|
|
|
|
using Xybrid::Effects::AutoPan;
|
|
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(AutoPan, {
|
|
i->id = "fx:autopan";
|
|
i->displayName = "Auto Pan";
|
|
i->category = "Effect";
|
|
})
|
|
|
|
AutoPan::AutoPan() { }
|
|
|
|
void AutoPan::init() {
|
|
addPort(Port::Input, Port::Audio, 0);
|
|
addPort(Port::Output, Port::Audio, 0);
|
|
}
|
|
|
|
void AutoPan::reset() {
|
|
cyc = 0.0;
|
|
}
|
|
|
|
void AutoPan::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 sr = audioEngine->curSampleRate();
|
|
auto ts = audioEngine->curTickSize();
|
|
|
|
auto eRate = rate;
|
|
if (bpmRelative) eRate *= audioEngine->curTempo() / 60.0;
|
|
|
|
auto tl = static_cast<double>(ts) / static_cast<double>(sr); // tick length
|
|
for (size_t f = 0; f < ts; f++) {
|
|
AudioFrame fCurrent = (*in)[f];
|
|
auto cc = cyc+phase + (static_cast<double>(f) / static_cast<double>(sr)) * eRate;
|
|
|
|
(*out)[f] = fCurrent.gainBalance(0.0, level * std::sin(cc * 2*PI));
|
|
}
|
|
|
|
cyc = std::fmod(cyc + tl*eRate, 1.0);
|
|
}
|
|
|
|
void AutoPan::saveData(QCborMap& m) const {
|
|
m[qs("level")] = level;
|
|
m[qs("rate")] = rate;
|
|
m[qs("phase")] = phase;
|
|
m[qs("bpmRelative")] = bpmRelative;
|
|
}
|
|
|
|
void AutoPan::loadData(const QCborMap& m) {
|
|
level = m.value("level").toDouble(level);
|
|
rate = m.value("rate").toDouble(rate);
|
|
phase = m.value("phase").toDouble(phase);
|
|
bpmRelative = m.value("bpmRelative").toBool(bpmRelative);
|
|
}
|
|
|
|
void AutoPan::onGadgetCreated() {
|
|
if (!obj) return;
|
|
auto l = new LayoutGadget(obj);
|
|
l->setMetrics(-1, 2);
|
|
|
|
(new KnobGadget(l))->bind(rate)->setLabel(qs("Rate"))->setRange(0.0, 8.0, 0.01, -1, 0.001)->setDefault(1.0);
|
|
auto l2 = (new LayoutGadget(l, true))->setMetrics(0, 2);
|
|
(new ToggleGadget(l2))->bind(bpmRelative)->setColor({191, 127, 255})->setToolTip(qs("BPM-relative"));
|
|
KnobGadget::autoPercent(l2, phase)->setLabel(qs("Phase"))->setSize(22);
|
|
KnobGadget::autoBalance(l, level)->setLabel(qs("Level"));
|
|
}
|