135 lines
3.6 KiB
C++
135 lines
3.6 KiB
C++
#include "capaxitor.h"
|
|
using Xybrid::Instruments::Capaxitor;
|
|
using namespace Xybrid::NodeLib;
|
|
using Note = InstrumentCore::Note;
|
|
using namespace Xybrid::Data;
|
|
|
|
#include "nodelib/commandreader.h"
|
|
#include "nodelib/resampler.h"
|
|
|
|
#include "data/project.h"
|
|
#include "data/sample.h"
|
|
|
|
#include "data/porttypes.h"
|
|
#include "config/pluginregistry.h"
|
|
using namespace Xybrid::Config;
|
|
#include "audio/audioengine.h"
|
|
using namespace Xybrid::Audio;
|
|
|
|
#include "ui/waveformpreviewwidget.h"
|
|
|
|
#include "ui/patchboard/nodeobject.h"
|
|
#include "ui/gadgets/layoutgadget.h"
|
|
#include "ui/gadgets/knobgadget.h"
|
|
#include "ui/gadgets/selectorgadget.h"
|
|
#include "ui/gadgets/sampleselectorgadget.h"
|
|
using namespace Xybrid::UI;
|
|
|
|
#include "ui/patchboard/nodeuiscene.h"
|
|
#include "uisocket.h"
|
|
|
|
#include "util/ext.h"
|
|
#include "util/strings.h"
|
|
|
|
#include <cmath>
|
|
|
|
#include <QDebug>
|
|
#include <QCborMap>
|
|
#include <QCborValue>
|
|
#include <QCborArray>
|
|
|
|
#include <QMenu>
|
|
#include <QGraphicsProxyWidget>
|
|
|
|
// clazy:excludeall=non-pod-global-static
|
|
RegisterPlugin(Capaxitor, {
|
|
i->id = "plug:capaxitor";
|
|
i->displayName = "CapaXitor";
|
|
i->category = "Sampler";
|
|
})
|
|
|
|
Capaxitor::Capaxitor() {
|
|
|
|
}
|
|
|
|
void Capaxitor::init() {
|
|
addPort(Port::Input, Port::Command, 0);
|
|
addPort(Port::Output, Port::Audio, 0);
|
|
|
|
core.onNoteOn = [this](Note& note) {
|
|
auto& data = *hard_cast<NoteData*>(¬e.scratch);
|
|
new (&data) NoteData(); // construct in-place
|
|
|
|
note.adsr = adsr;
|
|
};
|
|
|
|
core.onDeleteNote = [](Note& note) {
|
|
auto& data = *hard_cast<NoteData*>(¬e.scratch);
|
|
data.~NoteData(); // destroy
|
|
};
|
|
|
|
core.processNote = [this](Note& note, AudioPort* p) {
|
|
auto& data = *hard_cast<NoteData*>(¬e.scratch);
|
|
auto smp = this->smp.lock();
|
|
if (!smp) return core.deleteNote(note);
|
|
|
|
double rate = static_cast<double>(smp->sampleRate) / static_cast<double>(audioEngine->curSampleRate());
|
|
double baseNote = smp->getNote();
|
|
|
|
bool loop = smp->loopStart >= 0;
|
|
auto len = static_cast<double>(smp->length());
|
|
|
|
size_t ts = p->size;
|
|
for (size_t i = 0; i < ts; i++) {
|
|
core.advanceNote(note);
|
|
|
|
double n = note.effectiveNote();
|
|
double fr = std::pow(SEMI, n - baseNote);
|
|
|
|
// actual sample pos
|
|
double sp = data.sampleTime * rate;
|
|
if (!loop && sp >= len) return core.deleteNote(note);
|
|
|
|
auto out = NodeLib::resamp(smp.get(), sp, rate*fr);
|
|
|
|
(*p)[i] += out.gainBalance(0, note.pan) * note.ampMult();
|
|
data.sampleTime += fr;
|
|
}
|
|
};
|
|
}
|
|
|
|
void Capaxitor::reset() { core.reset(); }
|
|
void Capaxitor::release() { core.release(); }
|
|
void Capaxitor::process() { core.process(this); }
|
|
|
|
void Capaxitor::saveData(QCborMap& m) const {
|
|
if (auto smp = this->smp.lock(); smp) {
|
|
m[qs("sample")] = QCborValue(smp->uuid);
|
|
smp->markForExport();
|
|
}
|
|
m[qs("adsr")] = adsr;
|
|
}
|
|
|
|
void Capaxitor::loadData(const QCborMap& m) {
|
|
auto id = m.value("sample").toUuid();
|
|
if (auto f = project->samples.find(id); f != project->samples.end()) {
|
|
smp = f.value();
|
|
}
|
|
adsr = m.value("adsr");
|
|
}
|
|
|
|
void Capaxitor::onGadgetCreated() {
|
|
if (!obj) return;
|
|
|
|
auto l = new LayoutGadget(obj);
|
|
auto sampleSelector = new SampleSelectorGadget(project, l);
|
|
sampleSelector->setSize(128, 48);
|
|
sampleSelector->setSample(smp.lock(), false);
|
|
|
|
KnobGadget::autoCreate(l, adsr);
|
|
|
|
QObject::connect(sampleSelector, &SampleSelectorGadget::sampleSelected, [=](auto smp) { this->smp = smp; });
|
|
}
|
|
|
|
void Capaxitor::onDoubleClick() { emit project->socket->openNodeUI(this); }
|