xybrid/xybrid/nodelib/param.h

97 lines
2.9 KiB
C++

#pragma once
#include <cmath>
#include <limits>
#include <QCborMap>
#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<double>::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<double>::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<double>::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?
};
}