145 lines
3.8 KiB
C++
145 lines
3.8 KiB
C++
#include "testsynth.h"
|
|
using Xybrid::Instruments::TestSynth;
|
|
using namespace Xybrid::Data;
|
|
|
|
#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/patchboard/nodeobject.h"
|
|
#include "ui/gadgets/knobgadget.h"
|
|
using namespace Xybrid::UI;
|
|
|
|
#include <cmath>
|
|
|
|
#include <QDebug>
|
|
|
|
#include "nodelib/resampler.h"
|
|
|
|
RegisterPlugin(TestSynth, {
|
|
i->id = "plug:testsynth";
|
|
i->displayName = "The Testron";
|
|
i->category = "Instrument";
|
|
i->hidden = true;
|
|
})
|
|
|
|
namespace {
|
|
const double PI = std::atan(1)*4;
|
|
const double SEMI = std::pow(2.0, 1.0/12.0);
|
|
|
|
[[maybe_unused]] double fOsc(double& time) {
|
|
time = std::fmod(time, 2.0);
|
|
|
|
auto a = 0.0;
|
|
a += std::sin(time * PI*2);
|
|
a += std::sin(time * PI) * std::pow(.75, 4);
|
|
a += std::sin(time * PI*4) * std::pow(.75, 4);
|
|
a += std::sin(time * PI*8) * std::pow(.25, 4);
|
|
|
|
return a;
|
|
}
|
|
}
|
|
|
|
TestSynth::TestSynth() {
|
|
//
|
|
}
|
|
|
|
void TestSynth::init() {
|
|
addPort(Port::Input, Port::Command, 0);
|
|
addPort(Port::Output, Port::Audio, 0);
|
|
}
|
|
|
|
void TestSynth::reset() {
|
|
osc = 0.0;
|
|
cvol = 0.0;
|
|
tvol = 0.0;
|
|
noteId = 0;
|
|
}
|
|
|
|
void TestSynth::process() {
|
|
auto cp = std::static_pointer_cast<CommandPort>(port(Port::Input, Port::Command, 0));
|
|
cp->pull();
|
|
auto p = std::static_pointer_cast<AudioPort>(port(Port::Output, Port::Audio, 0));
|
|
p->pull();
|
|
|
|
if (!project) return;
|
|
if (project->samples.empty()) return;
|
|
auto smp = *(project->samples.begin());
|
|
|
|
size_t mi = 0;
|
|
while (cp->size >= mi+5) {
|
|
uint16_t id = reinterpret_cast<uint16_t&>(cp->data[mi]);
|
|
int16_t n = reinterpret_cast<int16_t&>(cp->data[mi+2]);
|
|
if (n > -1) {
|
|
noteId = id;
|
|
note = n;
|
|
tvol = 1.0;
|
|
osc = 0;
|
|
} else if (n < -1 && id == noteId) { // note off
|
|
tvol = 0.0;
|
|
}
|
|
mi += 5 + cp->data[mi+4]*2;
|
|
}
|
|
|
|
if (tvol <= 0) return;
|
|
size_t ts = audioEngine->curTickSize();
|
|
|
|
double rate = static_cast<double>(smp->sampleRate) / static_cast<double>(audioEngine->curSampleRate());
|
|
rate *= std::pow(SEMI, note - 60);
|
|
//qDebug() << "rate" << rate << "note" << note;
|
|
|
|
for (size_t s = 0; s < ts; s++) {
|
|
/*double ip = std::floor(osc);
|
|
double fp = osc - ip;
|
|
size_t lutIndex = static_cast<size_t>(fp*NodeLib::LUT_STEPS) % NodeLib::LUT_STEPS;
|
|
auto& pt = NodeLib::resamplerLUT[lutIndex];
|
|
AudioFrame out(0.0);
|
|
auto ii = static_cast<ptrdiff_t>(ip);
|
|
for (size_t i = 0; i < 8; i++) {
|
|
auto si = ii+static_cast<ptrdiff_t>(i);
|
|
//if (si >= 0 && si < static_cast<ptrdiff_t>(smp->length())) out += (*smp)[static_cast<size_t>(si)] * pt[i];
|
|
}
|
|
(*p)[s] = out;*/
|
|
|
|
|
|
osc += rate;
|
|
}
|
|
|
|
/*for (size_t s = 0; s < ts; s++) {
|
|
if (tvol > cvol) cvol += 64.0 / audioEngine->curSampleRate();
|
|
else if (tvol < cvol) cvol -= 16.0 / audioEngine->curSampleRate();
|
|
cvol = std::clamp(cvol, 0.0, 1.0);
|
|
if (cvol == 0.0) { osc = 0.0; }
|
|
float oscV = static_cast<float>(fOsc(osc) * std::pow(cvol*.5, 4));
|
|
|
|
double enote = note + std::sin(lfo * PI*2) * 0.1;
|
|
double freq = 440.0 * std::pow(SEMI, enote - (45+12));
|
|
osc += freq / audioEngine->curSampleRate();
|
|
|
|
lfo += 3.0 / audioEngine->curSampleRate();
|
|
lfo = std::fmod(lfo, 1.0);
|
|
|
|
p->bufL[s] = oscV;
|
|
p->bufR[s] = oscV;
|
|
}//*/
|
|
}
|
|
|
|
void TestSynth::onGadgetCreated() {
|
|
/*if (!obj) return;
|
|
auto k = new KnobGadget(obj);
|
|
k->setPos(16, 16);
|
|
static double dbl = 0.5;
|
|
k->bind(dbl);*/
|
|
}
|
|
|
|
void TestSynth::onDoubleClick() {
|
|
//
|
|
}
|