Browse Source

Move all metadata from Param to ParamQuantity.

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
357952c3d3
10 changed files with 110 additions and 144 deletions
  1. +31
    -3
      include/engine/Module.hpp
  2. +1
    -70
      include/engine/Param.hpp
  3. +28
    -3
      include/engine/ParamQuantity.hpp
  4. +7
    -21
      include/helpers.hpp
  5. +10
    -9
      src/Core/MIDI_Map.cpp
  6. +1
    -1
      src/app/ParamWidget.cpp
  7. +2
    -2
      src/engine/Engine.cpp
  8. +12
    -4
      src/engine/Module.cpp
  9. +6
    -9
      src/engine/Param.cpp
  10. +12
    -22
      src/engine/ParamQuantity.cpp

+ 31
- 3
include/engine/Module.hpp View File

@@ -5,6 +5,7 @@
#include "engine/Param.hpp"
#include "engine/Port.hpp"
#include "engine/Light.hpp"
#include "engine/ParamQuantity.hpp"
#include <vector>
#include <jansson.h>

@@ -29,6 +30,7 @@ struct Module {
std::vector<Output> outputs;
std::vector<Input> inputs;
std::vector<Light> lights;
std::vector<ParamQuantity*> paramQuantities;
/** Access to adjacent modules */
int leftModuleId = -1;
Module *leftModule = NULL;
@@ -48,12 +50,35 @@ struct Module {
DEPRECATED Module(int numParams, int numInputs, int numOutputs, int numLights = 0) : Module() {
config(numParams, numInputs, numOutputs, numLights);
}
virtual ~Module() {}
virtual ~Module();

/** Configures the number of Params, Outputs, Inputs, and Lights. */
void config(int numParams, int numInputs, int numOutputs, int numLights = 0);
json_t *toJson();
void fromJson(json_t *rootJ);

template <class TParamQuantity = ParamQuantity>
void configParam(int paramId, float minValue, float maxValue, float defaultValue, std::string label = "", std::string unit = "", float displayBase = 0.f, float displayMultiplier = 1.f, float displayOffset = 0.f) {
if (paramQuantities[paramId])
delete paramQuantities[paramId];

Param *p = &params[paramId];
p->value = defaultValue;

ParamQuantity *q = new TParamQuantity;
q->module = this;
q->paramId = paramId;
q->minValue = minValue;
q->maxValue = maxValue;
q->defaultValue = defaultValue;
if (!label.empty())
q->label = label;
else
q->label = string::f("#%d", paramId + 1);
q->unit = unit;
q->displayBase = displayBase;
q->displayMultiplier = displayMultiplier;
q->displayOffset = displayOffset;
paramQuantities[paramId] = q;
}

struct ProcessArgs {
float sampleRate;
@@ -83,6 +108,9 @@ struct Module {
/** Called when the Module is removed from the Engine */
virtual void onRemove() {}

json_t *toJson();
void fromJson(json_t *rootJ);

/** Override to store extra internal data in the "data" property of the module's JSON object. */
virtual json_t *dataToJson() { return NULL; }
virtual void dataFromJson(json_t *root) {}


+ 1
- 70
include/engine/Param.hpp View File

@@ -5,88 +5,19 @@


namespace rack {


namespace app {
struct ParamQuantity;
} // namespace app


namespace engine {


struct ParamQuantityFactory {
virtual ~ParamQuantityFactory() {}
virtual app::ParamQuantity *create() = 0;
};


struct Param {
/** Unstable API. Use setValue() and getValue() instead. */
float value = 0.f;

/** The minimum allowed value. */
float minValue = 0.f;
/** The maximum allowed value. Must be greater than minValue. */
float maxValue = 1.f;
/** The initial value. */
float defaultValue = 0.f;

/** The name of the parameter, using sentence capitalization.
e.g. "Frequency", "Pulse width", "Alternative mode"
*/
std::string label;
/** The numerical unit of measurement appended to the value.
Units that are words should have a space to separate the numerical value from the number (e.g. " semitones", " octaves").
Unit abbreviations and symbols should have no space (e.g. "V", "ms", "%", "Âş").
*/
std::string unit;
/** Set to 0 for linear, positive for exponential, negative for logarithmic. */
float displayBase = 0.f;
float displayMultiplier = 1.f;
float displayOffset = 0.f;
/** An optional one-sentence description of the parameter. */
std::string description;
ParamQuantityFactory *paramQuantityFactory = NULL;

~Param() {
if (paramQuantityFactory)
delete paramQuantityFactory;
}

template<class TParamQuantity = app::ParamQuantity>
void config(float minValue, float maxValue, float defaultValue, std::string label = "", std::string unit = "", float displayBase = 0.f, float displayMultiplier = 1.f, float displayOffset = 0.f) {
this->value = defaultValue;
this->minValue = minValue;
this->maxValue = maxValue;
this->defaultValue = defaultValue;
if (!label.empty())
this->label = label;
this->unit = unit;
this->displayBase = displayBase;
this->displayMultiplier = displayMultiplier;
this->displayOffset = displayOffset;

struct TParamQuantityFactory : ParamQuantityFactory {
app::ParamQuantity *create() override {return new TParamQuantity;}
};
if (paramQuantityFactory)
delete paramQuantityFactory;
paramQuantityFactory = new TParamQuantityFactory;
}

float getValue() {
return value;
}

/* Clamps and sets the value. */
void setValue(float value) {
this->value = math::clampSafe(value, minValue, maxValue);
}

/** Returns whether the Param has finite range between minValue and maxValue. */
bool isBounded() {
return std::isfinite(minValue) && std::isfinite(maxValue);
this->value = value;
}

json_t *toJson();


+ 28
- 3
include/engine/ParamQuantity.hpp View File

@@ -1,6 +1,5 @@
#pragma once
#include "Quantity.hpp"
#include "engine/Module.hpp"
#include "engine/Param.hpp"


@@ -8,12 +7,38 @@ namespace rack {
namespace engine {


struct Module;


/** A Quantity that wraps an engine::Param. */
struct ParamQuantity : Quantity {
engine::Module *module = NULL;
Module *module = NULL;
int paramId = 0;

engine::Param *getParam();
/** The minimum allowed value. */
float minValue = 0.f;
/** The maximum allowed value. Must be greater than minValue. */
float maxValue = 1.f;
/** The initial value. */
float defaultValue = 0.f;

/** The name of the parameter, using sentence capitalization.
e.g. "Frequency", "Pulse width", "Alternative mode"
*/
std::string label;
/** The numerical unit of measurement appended to the value.
Units that are words should have a space to separate the numerical value from the number (e.g. " semitones", " octaves").
Unit abbreviations and symbols should have no space (e.g. "V", "ms", "%", "Âş").
*/
std::string unit;
/** Set to 0 for linear, positive for exponential, negative for logarithmic. */
float displayBase = 0.f;
float displayMultiplier = 1.f;
float displayOffset = 0.f;
/** An optional one-sentence description of the parameter. */
std::string description;

Param *getParam();
/** Request to the engine to smoothly set the value */
void setSmoothValue(float smoothValue);
float getSmoothValue();


+ 7
- 21
include/helpers.hpp View File

@@ -62,13 +62,7 @@ TParamWidget *createParam(math::Vec pos, engine::Module *module, int paramId) {
TParamWidget *o = new TParamWidget;
o->box.pos = pos;
if (module) {
engine::ParamQuantityFactory *f = module->params[paramId].paramQuantityFactory;
if (f)
o->paramQuantity = f->create();
else
o->paramQuantity = new engine::ParamQuantity;
o->paramQuantity->module = module;
o->paramQuantity->paramId = paramId;
o->paramQuantity = module->paramQuantities[paramId];
}
return o;
}
@@ -92,11 +86,8 @@ TPortWidget *createInput(math::Vec pos, engine::Module *module, int inputId) {

template <class TPortWidget>
TPortWidget *createInputCentered(math::Vec pos, engine::Module *module, int inputId) {
TPortWidget *o = new TPortWidget;
o->box.pos = pos.minus(o->box.size.div(2));
o->module = module;
o->type = app::PortWidget::INPUT;
o->portId = inputId;
TPortWidget *o = createInput<TPortWidget>(pos, module, inputId);
o->box.pos = o->box.pos.minus(o->box.size.div(2));
return o;
}

@@ -112,11 +103,8 @@ TPortWidget *createOutput(math::Vec pos, engine::Module *module, int outputId) {

template <class TPortWidget>
TPortWidget *createOutputCentered(math::Vec pos, engine::Module *module, int outputId) {
TPortWidget *o = new TPortWidget;
o->box.pos = pos.minus(o->box.size.div(2));
o->module = module;
o->type = app::PortWidget::OUTPUT;
o->portId = outputId;
TPortWidget *o = createOutput<TPortWidget>(pos, module, outputId);
o->box.pos = o->box.pos.minus(o->box.size.div(2));
return o;
}

@@ -131,10 +119,8 @@ TModuleLightWidget *createLight(math::Vec pos, engine::Module *module, int first

template <class TModuleLightWidget>
TModuleLightWidget *createLightCentered(math::Vec pos, engine::Module *module, int firstLightId) {
TModuleLightWidget *o = new TModuleLightWidget;
o->box.pos = pos.minus(o->box.size.div(2));
o->module = module;
o->firstLightId = firstLightId;
TModuleLightWidget *o = createLight<TModuleLightWidget>(pos, module, firstLightId);
o->box.pos = o->box.pos.minus(o->box.size.div(2));
return o;
}



+ 10
- 9
src/Core/MIDI_Map.cpp View File

@@ -79,20 +79,21 @@ struct MIDI_Map : Module {
// Check if CC value has been set
if (values[cc] < 0)
continue;
// Get module
// Get Module
Module *module = paramHandles[id].module;
if (!module)
continue;
// Get param
// Get ParamQuantity
int paramId = paramHandles[id].paramId;
Param *param = &module->params[paramId];
if (!param->isBounded())
ParamQuantity *paramQuantity = module->paramQuantities[paramId];
if (!paramQuantity)
continue;
// Set param
if (!paramQuantity->isBounded())
continue;
// Set ParamQuantity
float v = rescale(values[cc], 0, 127, 0.f, 1.f);
v = valueFilters[id].process(args.sampleTime, v);
v = rescale(v, 0.f, 1.f, param->minValue, param->maxValue);
APP->engine->setParam(module, paramId, v);
paramQuantity->setScaledValue(v);
}
}

@@ -354,11 +355,11 @@ struct MIDI_MapChoice : LedDisplayChoice {
int paramId = paramHandle->paramId;
if (paramId >= (int) m->params.size())
return "";
Param *param = &m->params[paramId];
ParamQuantity *paramQuantity = m->paramQuantities[paramId];
std::string s;
s += mw->model->name;
s += " ";
s += param->label;
s += paramQuantity->label;
return s;
}
};


+ 1
- 1
src/app/ParamWidget.cpp View File

@@ -65,7 +65,7 @@ struct ParamTooltip : ui::Tooltip {
// Quantity string
text = paramWidget->paramQuantity->getString();
// Param description
std::string description = paramWidget->paramQuantity->getParam()->description;
std::string description = paramWidget->paramQuantity->description;
if (!description.empty())
text += "\n" + description;
}


+ 2
- 2
src/engine/Engine.cpp View File

@@ -246,8 +246,8 @@ static void Engine_step(Engine *that) {
// decay rate is 1 graphics frame
const float smoothLambda = 60.f;
float newValue = value + (smoothValue - value) * smoothLambda * internal->sampleTime;
if (value == newValue || !(param->minValue <= newValue && newValue <= param->maxValue)) {
// Snap to actual smooth value if the value doesn't change enough (due to the granularity of floats), or if newValue is out of bounds
if (value == newValue) {
// Snap to actual smooth value if the value doesn't change enough (due to the granularity of floats)
param->setValue(smoothValue);
internal->smoothModule = NULL;
internal->smoothParamId = 0;


+ 12
- 4
src/engine/Module.cpp View File

@@ -8,15 +8,23 @@ namespace engine {
Module::Module() {
}

Module::~Module() {
for (ParamQuantity *paramQuantity : paramQuantities) {
if (paramQuantity)
delete paramQuantity;
}
}

void Module::config(int numParams, int numInputs, int numOutputs, int numLights) {
params.resize(numParams);
// Create default param labels
for (int i = 0; i < numParams; i++) {
params[i].label = string::f("#%d", i + 1);
}
inputs.resize(numInputs);
outputs.resize(numOutputs);
lights.resize(numLights);
paramQuantities.resize(numParams);
// Initialize paramQuantities
for (int i = 0; i < numParams; i++) {
configParam(i, 0.f, 1.f, 0.f);
}
}

json_t *Module::toJson() {


+ 6
- 9
src/engine/Param.cpp View File

@@ -10,20 +10,17 @@ namespace engine {
json_t *Param::toJson() {
json_t *rootJ = json_object();

// Infinite params should serialize to 0
if (isBounded()) {
json_object_set_new(rootJ, "value", json_real(value));
}
// TODO Handle unbounded case
json_object_set_new(rootJ, "value", json_real(value));

return rootJ;
}

void Param::fromJson(json_t *rootJ) {
if (isBounded()) {
json_t *valueJ = json_object_get(rootJ, "value");
if (valueJ)
value = json_number_value(valueJ);
}
// TODO Handle unbounded case
json_t *valueJ = json_object_get(rootJ, "value");
if (valueJ)
value = json_number_value(valueJ);
}




+ 12
- 22
src/engine/ParamQuantity.cpp View File

@@ -20,15 +20,15 @@ void ParamQuantity::setSmoothValue(float smoothValue) {
}

float ParamQuantity::getSmoothValue() {
if (!module)
return 0.f;
return APP->engine->getSmoothParam(module, paramId);
}

void ParamQuantity::setValue(float value) {
if (!module)
return;
if (!std::isfinite(value))
return;
// This setter clamps the value
value = math::clampSafe(value, getMinValue(), getMaxValue());
APP->engine->setParam(module, paramId, value);
}

@@ -39,30 +39,24 @@ float ParamQuantity::getValue() {
}

float ParamQuantity::getMinValue() {
if (!module)
return -1.f;
return getParam()->minValue;
return minValue;
}

float ParamQuantity::getMaxValue() {
if (!module)
return 1.f;
return getParam()->maxValue;
return maxValue;
}

float ParamQuantity::getDefaultValue() {
if (!module)
return 0.f;
return getParam()->defaultValue;
return defaultValue;
}

float ParamQuantity::getDisplayValue() {
if (!module)
return Quantity::getDisplayValue();
float v = getSmoothValue();
float displayBase = getParam()->displayBase;
if (displayBase == 0.f) {
// Linear
// v is unchanged
}
else if (displayBase < 0.f) {
// Logarithmic
@@ -72,16 +66,16 @@ float ParamQuantity::getDisplayValue() {
// Exponential
v = std::pow(displayBase, v);
}
return v * getParam()->displayMultiplier + getParam()->displayOffset;
return v * displayMultiplier + displayOffset;
}

void ParamQuantity::setDisplayValue(float displayValue) {
if (!module)
return;
float v = (displayValue - getParam()->displayOffset) / getParam()->displayMultiplier;
float displayBase = getParam()->displayBase;
float v = (displayValue - displayOffset) / displayMultiplier;
if (displayBase == 0.f) {
// Linear
// v is unchanged
}
else if (displayBase < 0.f) {
// Logarithmic
@@ -107,15 +101,11 @@ void ParamQuantity::setDisplayValueString(std::string s) {
}

std::string ParamQuantity::getLabel() {
if (!module)
return Quantity::getLabel();
return getParam()->label;
return label;
}

std::string ParamQuantity::getUnit() {
if (!module)
return Quantity::getUnit();
return getParam()->unit;
return unit;
}




Loading…
Cancel
Save