Browse Source

Move all metadata from Param to ParamQuantity.

tags/v1.0.0
Andrew Belt 6 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/Param.hpp"
#include "engine/Port.hpp" #include "engine/Port.hpp"
#include "engine/Light.hpp" #include "engine/Light.hpp"
#include "engine/ParamQuantity.hpp"
#include <vector> #include <vector>
#include <jansson.h> #include <jansson.h>


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


/** Configures the number of Params, Outputs, Inputs, and Lights. */ /** Configures the number of Params, Outputs, Inputs, and Lights. */
void config(int numParams, int numInputs, int numOutputs, int numLights = 0); 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 { struct ProcessArgs {
float sampleRate; float sampleRate;
@@ -83,6 +108,9 @@ struct Module {
/** Called when the Module is removed from the Engine */ /** Called when the Module is removed from the Engine */
virtual void onRemove() {} 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. */ /** Override to store extra internal data in the "data" property of the module's JSON object. */
virtual json_t *dataToJson() { return NULL; } virtual json_t *dataToJson() { return NULL; }
virtual void dataFromJson(json_t *root) {} virtual void dataFromJson(json_t *root) {}


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

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




namespace rack { namespace rack {


namespace app {
struct ParamQuantity;
} // namespace app


namespace engine { namespace engine {




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


struct Param { struct Param {
/** Unstable API. Use setValue() and getValue() instead. */ /** Unstable API. Use setValue() and getValue() instead. */
float value = 0.f; 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() { float getValue() {
return value; return value;
} }


/* Clamps and sets the value. */
void setValue(float 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(); json_t *toJson();


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

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




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




struct Module;


/** A Quantity that wraps an engine::Param. */ /** A Quantity that wraps an engine::Param. */
struct ParamQuantity : Quantity { struct ParamQuantity : Quantity {
engine::Module *module = NULL;
Module *module = NULL;
int paramId = 0; 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 */ /** Request to the engine to smoothly set the value */
void setSmoothValue(float smoothValue); void setSmoothValue(float smoothValue);
float getSmoothValue(); 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; TParamWidget *o = new TParamWidget;
o->box.pos = pos; o->box.pos = pos;
if (module) { 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; return o;
} }
@@ -92,11 +86,8 @@ TPortWidget *createInput(math::Vec pos, engine::Module *module, int inputId) {


template <class TPortWidget> template <class TPortWidget>
TPortWidget *createInputCentered(math::Vec pos, engine::Module *module, int inputId) { 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; return o;
} }


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


template <class TPortWidget> template <class TPortWidget>
TPortWidget *createOutputCentered(math::Vec pos, engine::Module *module, int outputId) { 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; return o;
} }


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


template <class TModuleLightWidget> template <class TModuleLightWidget>
TModuleLightWidget *createLightCentered(math::Vec pos, engine::Module *module, int firstLightId) { 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; 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 // Check if CC value has been set
if (values[cc] < 0) if (values[cc] < 0)
continue; continue;
// Get module
// Get Module
Module *module = paramHandles[id].module; Module *module = paramHandles[id].module;
if (!module) if (!module)
continue; continue;
// Get param
// Get ParamQuantity
int paramId = paramHandles[id].paramId; int paramId = paramHandles[id].paramId;
Param *param = &module->params[paramId];
if (!param->isBounded())
ParamQuantity *paramQuantity = module->paramQuantities[paramId];
if (!paramQuantity)
continue; continue;
// Set param
if (!paramQuantity->isBounded())
continue;
// Set ParamQuantity
float v = rescale(values[cc], 0, 127, 0.f, 1.f); float v = rescale(values[cc], 0, 127, 0.f, 1.f);
v = valueFilters[id].process(args.sampleTime, v); 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; int paramId = paramHandle->paramId;
if (paramId >= (int) m->params.size()) if (paramId >= (int) m->params.size())
return ""; return "";
Param *param = &m->params[paramId];
ParamQuantity *paramQuantity = m->paramQuantities[paramId];
std::string s; std::string s;
s += mw->model->name; s += mw->model->name;
s += " "; s += " ";
s += param->label;
s += paramQuantity->label;
return s; return s;
} }
}; };


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

@@ -65,7 +65,7 @@ struct ParamTooltip : ui::Tooltip {
// Quantity string // Quantity string
text = paramWidget->paramQuantity->getString(); text = paramWidget->paramQuantity->getString();
// Param description // Param description
std::string description = paramWidget->paramQuantity->getParam()->description;
std::string description = paramWidget->paramQuantity->description;
if (!description.empty()) if (!description.empty())
text += "\n" + description; 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 // decay rate is 1 graphics frame
const float smoothLambda = 60.f; const float smoothLambda = 60.f;
float newValue = value + (smoothValue - value) * smoothLambda * internal->sampleTime; 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); param->setValue(smoothValue);
internal->smoothModule = NULL; internal->smoothModule = NULL;
internal->smoothParamId = 0; internal->smoothParamId = 0;


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

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


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

void Module::config(int numParams, int numInputs, int numOutputs, int numLights) { void Module::config(int numParams, int numInputs, int numOutputs, int numLights) {
params.resize(numParams); 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); inputs.resize(numInputs);
outputs.resize(numOutputs); outputs.resize(numOutputs);
lights.resize(numLights); 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() { json_t *Module::toJson() {


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

@@ -10,20 +10,17 @@ namespace engine {
json_t *Param::toJson() { json_t *Param::toJson() {
json_t *rootJ = json_object(); 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; return rootJ;
} }


void Param::fromJson(json_t *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() { float ParamQuantity::getSmoothValue() {
if (!module)
return 0.f;
return APP->engine->getSmoothParam(module, paramId); return APP->engine->getSmoothParam(module, paramId);
} }


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


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


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


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


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


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


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


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


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






Loading…
Cancel
Save