From 779af6bdaba1a3d0af578c742437a284b20f4adc Mon Sep 17 00:00:00 2001 From: zetaPRIME Date: Thu, 24 Mar 2022 02:27:04 -0400 Subject: [PATCH] automatable param stuff --- xybrid/nodelib/param.cpp | 22 +++++++++ xybrid/nodelib/param.h | 96 +++++++++++++++++++++++++++++++++++++++ xybrid/nodelib/svfilter.h | 4 ++ 3 files changed, 122 insertions(+) create mode 100644 xybrid/nodelib/param.cpp create mode 100644 xybrid/nodelib/param.h diff --git a/xybrid/nodelib/param.cpp b/xybrid/nodelib/param.cpp new file mode 100644 index 0000000..6c805ca --- /dev/null +++ b/xybrid/nodelib/param.cpp @@ -0,0 +1,22 @@ +#include "param.h" + +using Xybrid::NodeLib::Param; +using namespace Xybrid::Data; + +ParameterPort* Param::makePort(Data::Node* node, const QString& name) { + if (port) return port; + + node->inputs.try_emplace(Port::Parameter); + auto& inp = node->inputs.find(Port::Parameter)->second; + + uint8_t id = 0; + auto it = inp.begin(); + while (it != inp.end() && it->first == id) { ++id; ++it; } // scan for first unused id + + auto n = name; + if (n.isEmpty()) n = this->name.toLower(); + + port = static_cast(node->addPort(Port::Input, Port::Parameter, id).get()); + port->name = n; + return port; +} diff --git a/xybrid/nodelib/param.h b/xybrid/nodelib/param.h new file mode 100644 index 0000000..b0205ce --- /dev/null +++ b/xybrid/nodelib/param.h @@ -0,0 +1,96 @@ +#pragma once + +#include +#include +#include + +#include "data/node.h" +#include "data/porttypes.h" + +//namespace Xybrid::Data { class ParameterPort; } +namespace Xybrid::NodeLib { + /// Plugin parameter with associated metadata and automation faculties + class Param { + // + Param() = default; + public: + class Reader { + friend class Param; + Param* p; + size_t pos = 0; + bool r; + Reader(Param* p, bool r) : p(p), r(r) { } + public: + double next() { + if (r) { + auto v = p->port->data[pos++]; + if (!std::isnan(v)) { + if (p->min == -p->max) // "signed" logic if symmetrical around zero + v = std::clamp(v, -1.0, 1.0) * p->max; + else // extents 0.0 .. 1.0 scaled across parameter range + v = std::clamp(p->min + v * (p->max - p->min), p->min, p->max); + + p->vt = v; + } + } + if (!std::isnan(p->vt)) return p->vt; + return p->value; + } + }; + + enum Flags : uint8_t { + ResetOnTick = 0b00000001, + }; + + QString name; + double min, max, def; + + double value; + double vt = std::numeric_limits::quiet_NaN(); + + Flags flags; + + Data::ParameterPort* port = nullptr; + + Param(const QString& name, double min, double max, double def, Flags flags = {}) : Param() { + this->name = name; + this->min = min; + this->max = max; + this->def = def; + this->value = def; + this->flags = flags; + } + + Data::ParameterPort* makePort(Data::Node*, const QString& name = { }); + + Reader start() { + bool r = port && port->isConnected(); + if (r) port->pull(); + if (flags & ResetOnTick) vt = std::numeric_limits::quiet_NaN(); + return Reader(this, r); + } + + inline QString saveName() { + return name.toLower().remove(' '); + } + + inline void save(QCborMap& m, QString id = { }) { + if (id.isEmpty()) id = saveName(); + m[id] = value; + } + + inline void load(QCborMap& m, QString id = { }) { + if (id.isEmpty()) id = saveName(); + value = m.value(id).toDouble(value); + vt = std::numeric_limits::quiet_NaN(); + } + + // - give it a Reader abstraction (grab from a "startTick" thing, call its next() function for tracking and values) + // - functions to automatically save/load from QCborMap + // binding a knobgadget automatically populates range+defaults(+label) + // - figure out how to do range stuff + // - "signed" extents only if min == -max + + // meta info for parameter ports? + }; +} diff --git a/xybrid/nodelib/svfilter.h b/xybrid/nodelib/svfilter.h index b283cc2..695646e 100644 --- a/xybrid/nodelib/svfilter.h +++ b/xybrid/nodelib/svfilter.h @@ -43,6 +43,10 @@ namespace Xybrid::NodeLib { }; + // explicit instantiation declarations to eliminate warnings + //template<> void Xybrid::NodeLib::GenericSVFilter::process(Data::AudioFrame, double, double, int); + //template<> void Xybrid::NodeLib::GenericSVFilter::process(double, double, double, int); + /// 12db Chamberlin State Variable Filter typedef GenericSVFilter SVFilter; /// 12db Chamberlin State Variable Filter (mono version)