initial naive sample playback; AudioFrame
parent
8824df9efc
commit
bc4b421642
|
@ -0,0 +1,16 @@
|
|||
#include "audioframe.h"
|
||||
using Xybrid::Data::AudioFrame;
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace {
|
||||
const constexpr double PI = 3.141592653589793238462643383279502884197169399375105820974;
|
||||
const constexpr double PAN_MULT = 1.414213562373095048801688724209698078569671875376948073176;
|
||||
}
|
||||
|
||||
AudioFrame AudioFrame::gainBalanceMult(double gain, double balance) {
|
||||
// calculate multipliers
|
||||
double gm = std::pow(10.0, gain / 20.0); // dBFS
|
||||
double s = (balance+1.0) * PI * 0.25;
|
||||
return {std::cos(s) * PAN_MULT * gm, std::sin(s) * PAN_MULT * gm};
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
namespace Xybrid::Data {
|
||||
class AudioFrame {
|
||||
public:
|
||||
// stored as double here for operational precision
|
||||
double l = 0;
|
||||
double r = 0;
|
||||
|
||||
AudioFrame(double v) : l(v), r(v) { }
|
||||
AudioFrame(float v) : AudioFrame(static_cast<double>(v)) { }
|
||||
AudioFrame(double l, double r) : l(l), r(r) { }
|
||||
AudioFrame(float l, float r) : l(static_cast<double>(l)), r(static_cast<double>(r)) { }
|
||||
|
||||
AudioFrame operator*(AudioFrame o) const { return {l*o.l, r*o.r}; }
|
||||
void operator*=(AudioFrame o) {
|
||||
l *= o.l;
|
||||
r *= o.r;
|
||||
}
|
||||
AudioFrame operator*(double m) const { return {l*m, r*m}; }
|
||||
void operator*=(double m) {
|
||||
l *= m;
|
||||
r *= m;
|
||||
}
|
||||
|
||||
static AudioFrame gainBalanceMult(double gain, double balance);
|
||||
AudioFrame gainBalance(double gain, double balance) const { return *this*gainBalanceMult(gain, balance); }
|
||||
};
|
||||
}
|
|
@ -1,11 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include "data/node.h"
|
||||
#include "data/audioframe.h"
|
||||
|
||||
namespace Xybrid::Data {
|
||||
class AudioPort : public Port {
|
||||
|
||||
public:
|
||||
class FrameRef {
|
||||
friend class AudioPort;
|
||||
AudioPort* port;
|
||||
size_t at;
|
||||
FrameRef(AudioPort* port, size_t at) : port(port), at(at) { }
|
||||
public:
|
||||
FrameRef& operator=(AudioFrame f) {
|
||||
port->bufL[at] = static_cast<float>(f.l);
|
||||
port->bufR[at] = static_cast<float>(f.r);
|
||||
return *this;
|
||||
}
|
||||
operator AudioFrame() const { return {port->bufL[at], port->bufR[at]}; }
|
||||
AudioFrame operator*(AudioFrame o) const { return static_cast<AudioFrame>(*this) * o; }
|
||||
};
|
||||
|
||||
float* bufL;
|
||||
float* bufR;
|
||||
size_t size;
|
||||
|
@ -13,13 +28,14 @@ namespace Xybrid::Data {
|
|||
AudioPort() = default;
|
||||
~AudioPort() override = default;
|
||||
|
||||
FrameRef operator[](size_t at) { return {this, at}; }
|
||||
|
||||
Port::DataType dataType() const override { return Port::Audio; }
|
||||
|
||||
void pull() override;
|
||||
};
|
||||
|
||||
class CommandPort : public Port {
|
||||
|
||||
public:
|
||||
uint8_t* data;
|
||||
size_t dataSize;
|
||||
|
|
|
@ -5,6 +5,7 @@ using namespace Xybrid::Data;
|
|||
#include "nodelib/basics.h"
|
||||
using namespace Xybrid::NodeLib;
|
||||
|
||||
#include "data/audioframe.h"
|
||||
#include "data/porttypes.h"
|
||||
|
||||
#include "config/pluginregistry.h"
|
||||
|
@ -46,14 +47,7 @@ void GainBalance::init() {
|
|||
}
|
||||
|
||||
void GainBalance::process() { // TODO: lerp from tick to tick?
|
||||
double g = gain.load();
|
||||
double b = balance.load();
|
||||
|
||||
// calculate multipliers
|
||||
double gm = std::pow(10.0, g / 20.0); // dBFS
|
||||
double s = (b+1.0) * PI * 0.25;
|
||||
double lm = std::cos(s) * PAN_MULT;
|
||||
double rm = std::sin(s) * PAN_MULT;
|
||||
auto m = AudioFrame::gainBalanceMult(gain.load(), balance.load());
|
||||
|
||||
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));
|
||||
|
@ -61,11 +55,7 @@ void GainBalance::process() { // TODO: lerp from tick to tick?
|
|||
out->pull();
|
||||
|
||||
size_t ts = audioEngine->curTickSize();
|
||||
|
||||
for (size_t s = 0; s < ts; s++) {
|
||||
out->bufL[s] = static_cast<float>(static_cast<double>(in->bufL[s]) * gm * lm);
|
||||
out->bufR[s] = static_cast<float>(static_cast<double>(in->bufR[s]) * gm * rm);
|
||||
}
|
||||
for (size_t s = 0; s < ts; s++) (*out)[s] = (*in)[s] * m;
|
||||
}
|
||||
|
||||
void GainBalance::saveData(QCborMap& m) const {
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
using Xybrid::Instruments::TestSynth;
|
||||
using namespace Xybrid::Data;
|
||||
|
||||
#include "data/project.h"
|
||||
#include "data/sample.h"
|
||||
|
||||
#include "data/porttypes.h"
|
||||
|
||||
#include "config/pluginregistry.h"
|
||||
|
@ -63,18 +66,19 @@ void TestSynth::reset() {
|
|||
}
|
||||
|
||||
void TestSynth::process() {
|
||||
if (!name.empty()) {
|
||||
size_t cur = audioEngine->curTickId();
|
||||
static size_t last = 0;
|
||||
if (cur == last) qDebug() << "tick processed twice" << cur;
|
||||
last = cur;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
qDebug() << "testron start";
|
||||
|
||||
if (!project) return;
|
||||
if (project->samples.empty()) return;
|
||||
auto smp = *(project->samples.begin());
|
||||
|
||||
qDebug() << "testron past check";
|
||||
|
||||
size_t mi = 0;
|
||||
while (cp->dataSize >= mi+5) {
|
||||
uint16_t id = reinterpret_cast<uint16_t&>(cp->data[mi]);
|
||||
|
@ -83,15 +87,28 @@ void TestSynth::process() {
|
|||
noteId = id;
|
||||
note = n;
|
||||
tvol = 1.0;
|
||||
spos = 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();
|
||||
|
||||
for (size_t s = 0; s < ts; s++) {
|
||||
//if (spos >= static_cast<size_t>(smp->length())) return;
|
||||
auto lc = &(smp->data[0]);
|
||||
auto rc = &(smp->data[1]);
|
||||
if (rc->empty()) rc = lc;
|
||||
|
||||
if (spos < lc->size()) p->bufL[s] = (*lc)[spos];
|
||||
if (spos < rc->size()) p->bufR[s] = (*rc)[spos];
|
||||
spos++;
|
||||
}
|
||||
|
||||
/*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);
|
||||
|
@ -107,8 +124,7 @@ void TestSynth::process() {
|
|||
|
||||
p->bufL[s] = oscV;
|
||||
p->bufR[s] = oscV;
|
||||
}
|
||||
//audioEngine->curSampleRate()
|
||||
}//*/
|
||||
}
|
||||
|
||||
void TestSynth::onGadgetCreated() {
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Xybrid::Instruments {
|
|||
double lfo = 0;
|
||||
|
||||
uint16_t noteId = 0;
|
||||
size_t spos = 0;
|
||||
double cvol = 0;
|
||||
double tvol = 0;
|
||||
public:
|
||||
|
|
Loading…
Reference in New Issue