initial naive sample playback; AudioFrame

portability/boost
zetaPRIME 2019-06-18 07:37:33 -04:00
parent 8824df9efc
commit bc4b421642
6 changed files with 92 additions and 24 deletions

View File

@ -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};
}

29
xybrid/data/audioframe.h Normal file
View File

@ -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); }
};
}

View File

@ -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;

View File

@ -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 {

View File

@ -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() {

View File

@ -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: