Browse Source

Make power meter display in microseconds instead of millisamples. Add history::ComplexAction. Split Param into Param and ParamInfo. Rename setup() to config().

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
cb7e139b47
18 changed files with 154 additions and 98 deletions
  1. +2
    -0
      include/app/ParamQuantity.hpp
  2. +6
    -4
      include/engine/Module.hpp
  3. +1
    -13
      include/engine/Param.hpp
  4. +48
    -0
      include/engine/ParamInfo.hpp
  5. +11
    -10
      include/helpers.hpp
  6. +11
    -25
      include/history.hpp
  7. +1
    -1
      src/Core/AudioInterface.cpp
  8. +1
    -1
      src/Core/MIDICCToCVInterface.cpp
  9. +1
    -1
      src/Core/MIDIToCVInterface.cpp
  10. +1
    -1
      src/Core/MIDITriggerToCVInterface.cpp
  11. +1
    -1
      src/Core/QuadMIDIToCVInterface.cpp
  12. +14
    -14
      src/app/ModuleWidget.cpp
  13. +17
    -12
      src/app/ParamQuantity.cpp
  14. +1
    -1
      src/app/ParamWidget.cpp
  15. +5
    -3
      src/engine/Engine.cpp
  16. +6
    -5
      src/engine/Module.cpp
  17. +3
    -1
      src/engine/Param.cpp
  18. +24
    -5
      src/history.cpp

+ 2
- 0
include/app/ParamQuantity.hpp View File

@@ -2,6 +2,7 @@
#include "ui/Quantity.hpp"
#include "engine/Module.hpp"
#include "engine/Param.hpp"
#include "engine/ParamInfo.hpp"


namespace rack {
@@ -18,6 +19,7 @@ struct ParamQuantity : Quantity {
float snapValue = 0.f;

Param *getParam();
ParamInfo *getParamInfo();
void commitSnap();

void setValue(float value) override;


+ 6
- 4
include/engine/Module.hpp View File

@@ -5,6 +5,7 @@
#include "engine/Input.hpp"
#include "engine/Output.hpp"
#include "engine/Light.hpp"
#include "engine/ParamInfo.hpp"
#include <vector>
#include <jansson.h>

@@ -18,19 +19,20 @@ struct Module {
std::vector<Input> inputs;
std::vector<Output> outputs;
std::vector<Light> lights;
std::vector<ParamInfo> paramInfos;
/** For power meter */
float cpuTime = 0.f;
bool bypass = false;

/** Constructs a Module with no params, inputs, outputs, and lights */
Module();
/** Deprecated. Use setup() instead. */
Module(int numParams, int numInputs, int numOutputs, int numLights = 0) : Module() {
setup(numParams, numInputs, numOutputs, numLights);
/** Deprecated. Use config() instead. */
DEPRECATED Module(int numParams, int numInputs, int numOutputs, int numLights = 0) : Module() {
config(numParams, numInputs, numOutputs, numLights);
}
virtual ~Module() {}

void setup(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);
void reset();


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

@@ -12,23 +12,11 @@ struct Param {
float maxValue = 1.f;
float defaultValue = 0.f;

// For formatting/displaying the value
/** Set to 0 for linear, nonzero for exponential */
float displayBase = 0.f;
float displayMultiplier = 1.f;
std::string label;
std::string unit;
std::string description;

void setup(float minValue, float maxValue, float defaultValue, std::string label = "", std::string unit = "", float displayBase = 0.f, float displayMultiplier = 1.f) {
void config(float minValue, float maxValue, float defaultValue) {
this->value = defaultValue;
this->minValue = minValue;
this->maxValue = maxValue;
this->defaultValue = defaultValue;
this->label = label;
this->unit = unit;
this->displayBase = displayBase;
this->displayMultiplier = displayMultiplier;
}

json_t *toJson();


+ 48
- 0
include/engine/ParamInfo.hpp View File

@@ -0,0 +1,48 @@
#pragma once
#include "common.hpp"


namespace rack {


struct ParamQuantity;


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


struct ParamInfo {
// For formatting/displaying the value
/** Set to 0 for linear, nonzero for exponential */
std::string label;
std::string unit;
float displayBase = 0.f;
float displayMultiplier = 1.f;
std::string description;
ParamQuantityFactory *paramQuantityFactory = NULL;

~ParamInfo() {
delete paramQuantityFactory;
}

template<class TParamQuantity = ParamQuantity>
void config(std::string label = "", std::string unit = "", float displayBase = 0.f, float displayMultiplier = 1.f) {
this->label = label;
this->unit = unit;
this->displayBase = displayBase;
this->displayMultiplier = displayMultiplier;

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


} // namespace rack

+ 11
- 10
include/helpers.hpp View File

@@ -57,21 +57,22 @@ template <class TParamWidget>
TParamWidget *createParam(math::Vec pos, Module *module, int paramId) {
TParamWidget *o = new TParamWidget;
o->box.pos = pos;
ParamQuantity *q = new ParamQuantity;
q->module = module;
q->paramId = paramId;
o->paramQuantity = q;
if (module) {
ParamQuantityFactory *f = module->paramInfos[paramId].paramQuantityFactory;
if (f)
o->paramQuantity = f->create();
else
o->paramQuantity = new ParamQuantity;
o->paramQuantity->module = module;
o->paramQuantity->paramId = paramId;
}
return o;
}

template <class TParamWidget>
TParamWidget *createParamCentered(math::Vec pos, Module *module, int paramId) {
TParamWidget *o = new TParamWidget;
o->box.pos = pos.minus(o->box.size.div(2));
ParamQuantity *q = new ParamQuantity;
q->module = module;
q->paramId = paramId;
o->paramQuantity = q;
TParamWidget *o = createParam<TParamWidget>(pos, module, paramId);
o->box.pos = o->box.pos.minus(o->box.size.div(2));
return o;
}



+ 11
- 25
include/history.hpp View File

@@ -17,6 +17,17 @@ struct Action {
};


/** Batches multiple actions into one */
struct ComplexAction : Action {
/** Ordered by time occurred. Undoing will replay them backwards. */
std::vector<Action*> actions;
~ComplexAction();
void undo() override;
void redo() override;
void push(Action *action);
};


/** An action operating on a module
Subclass this to create your own custom actions for your module.
*/
@@ -37,16 +48,6 @@ struct ModuleRemove : ModuleAction {
Model *model;
math::Vec pos;
json_t *moduleJ;

struct CableInfo {
int cableId;
int outputModuleId;
int outputId;
int inputModuleId;
int inputId;
};
std::vector<CableInfo> cableInfos;

~ModuleRemove();
void undo() override;
void redo() override;
@@ -92,21 +93,6 @@ struct CableRemove : Action {
};


struct CableMove : Action {
int cableId;
int oldOutputModuleId;
int oldOutputId;
int oldInputModuleId;
int oldInputId;
int newOutputModuleId;
int newOutputId;
int newInputModuleId;
int newInputId;
void undo() override;
void redo() override;
};


struct State {
std::vector<Action*> actions;
int actionIndex = 0;


+ 1
- 1
src/Core/AudioInterface.cpp View File

@@ -118,7 +118,7 @@ struct AudioInterface : Module {
dsp::DoubleRingBuffer<dsp::Frame<AUDIO_OUTPUTS>, 16> outputBuffer;

AudioInterface() {
setup(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
onSampleRateChange();
}



+ 1
- 1
src/Core/MIDICCToCVInterface.cpp View File

@@ -25,7 +25,7 @@ struct MIDICCToCVInterface : Module {
int learnedCcs[16] = {};

MIDICCToCVInterface() {
setup(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
onReset();
}



+ 1
- 1
src/Core/MIDIToCVInterface.cpp View File

@@ -56,7 +56,7 @@ struct MIDIToCVInterface : Module {
bool gate;

MIDIToCVInterface() {
setup(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
heldNotes.resize(128, 0);
onReset();
}


+ 1
- 1
src/Core/MIDITriggerToCVInterface.cpp View File

@@ -28,7 +28,7 @@ struct MIDITriggerToCVInterface : Module {
bool velocity = false;

MIDITriggerToCVInterface() {
setup(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
onReset();
}



+ 1
- 1
src/Core/QuadMIDIToCVInterface.cpp View File

@@ -51,7 +51,7 @@ struct QuadMIDIToCVInterface : Module {
int stealIndex;

QuadMIDIToCVInterface() {
setup(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
cachedNotes.resize(128, 0);
onReset();
}


+ 14
- 14
src/app/ModuleWidget.cpp View File

@@ -282,18 +282,14 @@ void ModuleWidget::draw(NVGcontext *vg) {
nvgBeginPath(vg);
nvgRect(vg,
0, box.size.y - 20,
55, 20);
65, 20);
nvgFillColor(vg, nvgRGBAf(0, 0, 0, 0.5));
nvgFill(vg);

std::string cpuText = string::f("%.0f mS", module->cpuTime * 1000.f);
// TODO Use blendish text function
nvgFontFaceId(vg, app()->window->uiFont->handle);
nvgFontSize(vg, 12);
nvgFillColor(vg, nvgRGBf(1, 1, 1));
nvgText(vg, 10.0, box.size.y - 6.0, cpuText.c_str(), NULL);
std::string cpuText = string::f("%.2f ÎĽs", module->cpuTime * 1e6f);
bndLabel(vg, 2.0, box.size.y - 20.0, INFINITY, INFINITY, -1, cpuText.c_str());

float p = math::clamp(module->cpuTime, 0.f, 1.f);
float p = math::clamp(module->cpuTime / app()->engine->getSampleTime(), 0.f, 1.f);
nvgBeginPath(vg);
nvgRect(vg,
0, (1.f - p) * box.size.y,
@@ -318,13 +314,17 @@ void ModuleWidget::drawShadow(NVGcontext *vg) {
}

static void ModuleWidget_removeAction(ModuleWidget *moduleWidget) {
history::ComplexAction *complexAction = new history::ComplexAction;

// Push ModuleRemove history action
history::ModuleRemove *h = new history::ModuleRemove;
h->model = moduleWidget->model;
h->moduleId = moduleWidget->module->id;
h->pos = moduleWidget->box.pos;
h->moduleJ = moduleWidget->toJson();
app()->history->push(h);
history::ModuleRemove *moduleRemove = new history::ModuleRemove;
moduleRemove->model = moduleWidget->model;
moduleRemove->moduleId = moduleWidget->module->id;
moduleRemove->pos = moduleWidget->box.pos;
moduleRemove->moduleJ = moduleWidget->toJson();
complexAction->push(moduleRemove);

app()->history->push(complexAction);

app()->scene->rackWidget->removeModule(moduleWidget);
delete moduleWidget;


+ 17
- 12
src/app/ParamQuantity.cpp View File

@@ -9,6 +9,11 @@ Param *ParamQuantity::getParam() {
return &module->params[paramId];
}

ParamInfo *ParamQuantity::getParamInfo() {
assert(module);
return &module->paramInfos[paramId];
}

void ParamQuantity::commitSnap() {
// TODO
}
@@ -49,34 +54,34 @@ float ParamQuantity::getDefaultValue() {
float ParamQuantity::getDisplayValue() {
if (!module)
return Quantity::getDisplayValue();
if (getParam()->displayBase == 0.f) {
if (getParamInfo()->displayBase == 0.f) {
// Linear
return getValue() * getParam()->displayMultiplier;
return getValue() * getParamInfo()->displayMultiplier;
}
else if (getParam()->displayBase == 1.f) {
else if (getParamInfo()->displayBase == 1.f) {
// Fixed (special case of exponential)
return getParam()->displayMultiplier;
return getParamInfo()->displayMultiplier;
}
else {
// Exponential
return std::pow(getParam()->displayBase, getValue()) * getParam()->displayMultiplier;
return std::pow(getParamInfo()->displayBase, getValue()) * getParamInfo()->displayMultiplier;
}
}

void ParamQuantity::setDisplayValue(float displayValue) {
if (!module)
return;
if (getParam()->displayBase == 0.f) {
if (getParamInfo()->displayBase == 0.f) {
// Linear
setValue(displayValue / getParam()->displayMultiplier);
setValue(displayValue / getParamInfo()->displayMultiplier);
}
else if (getParam()->displayBase == 1.f) {
else if (getParamInfo()->displayBase == 1.f) {
// Fixed
setValue(getParam()->displayMultiplier);
setValue(getParamInfo()->displayMultiplier);
}
else {
// Exponential
setValue(std::log(displayValue / getParam()->displayMultiplier) / std::log(getParam()->displayBase));
setValue(std::log(displayValue / getParamInfo()->displayMultiplier) / std::log(getParamInfo()->displayBase));
}
}

@@ -95,13 +100,13 @@ int ParamQuantity::getDisplayPrecision() {
std::string ParamQuantity::getLabel() {
if (!module)
return Quantity::getLabel();
return getParam()->label;
return getParamInfo()->label;
}

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




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

@@ -82,7 +82,7 @@ void ParamWidget::step() {
// Quantity string
tooltip->text = paramQuantity->getString();
// Param description
std::string description = paramQuantity->getParam()->description;
std::string description = paramQuantity->getParamInfo()->description;
if (!description.empty())
tooltip->text += "\n" + description;
}


+ 5
- 3
src/engine/Engine.cpp View File

@@ -144,10 +144,10 @@ static void Engine_step(Engine *engine) {
module->step();

auto stopTime = std::chrono::high_resolution_clock::now();
float cpuTime = std::chrono::duration<float>(stopTime - startTime).count() * engine->internal->sampleRate;
float cpuTime = std::chrono::duration<float>(stopTime - startTime).count();
// Smooth cpu time
float powerLambda = 2.f / 10.f;
module->cpuTime += (cpuTime - module->cpuTime) * engine->internal->sampleTime * powerLambda;
float powerLambda = engine->internal->sampleTime / 2.f;
module->cpuTime += (cpuTime - module->cpuTime) * powerLambda;
}
else {
module->step();
@@ -240,6 +240,7 @@ void Engine::addModule(Module *module) {
}
else {
// Manual ID
assert(module->id < internal->nextModuleId);
// Check that the ID is not already taken
for (Module *m : modules) {
assert(module->id != m->id);
@@ -315,6 +316,7 @@ void Engine::addCable(Cable *cable) {
}
else {
// Manual ID
assert(cable->id < internal->nextCableId);
// Check that the ID is not already taken
for (Cable *w : cables) {
assert(cable->id != w->id);


+ 6
- 5
src/engine/Module.cpp View File

@@ -7,15 +7,16 @@ namespace rack {
Module::Module() {
}

void Module::setup(int numParams, int numInputs, int numOutputs, int numLights) {
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);
paramInfos.resize(numParams);
// Create default param labels
for (int i = 0; i < numParams; i++) {
paramInfos[i].label = string::f("#%d", i + 1);
}
}

json_t *Module::toJson() {


+ 3
- 1
src/engine/Param.cpp View File

@@ -9,8 +9,10 @@ namespace rack {
json_t *Param::toJson() {
json_t *rootJ = json_object();

float v = 0.f;
// Infinite params should serialize to 0
float v = (std::isfinite(minValue) && std::isfinite(maxValue)) ? value : 0.f;
if (std::isfinite(minValue) && std::isfinite(maxValue))
v = value;
json_object_set_new(rootJ, "value", json_real(v));

return rootJ;


+ 24
- 5
src/history.cpp View File

@@ -7,6 +7,30 @@ namespace rack {
namespace history {


ComplexAction::~ComplexAction() {
for (Action *action : actions) {
delete action;
}
}

void ComplexAction::undo() {
for (auto it = actions.rbegin(); it != actions.rend(); it++) {
Action *action = *it;
action->undo();
}
}

void ComplexAction::redo() {
for (Action *action : actions) {
action->redo();
}
}

void ComplexAction::push(Action *action) {
actions.push_back(action);
}


void ModuleAdd::undo() {
ModuleWidget *moduleWidget = app()->scene->rackWidget->getModule(moduleId);
assert(moduleWidget);
@@ -36,11 +60,6 @@ void ModuleRemove::undo() {
moduleWidget->box.pos = pos;
moduleWidget->fromJson(moduleJ);
app()->scene->rackWidget->addModule(moduleWidget);

// Add cables
for (CableInfo &cableInfo : cableInfos) {
// TODO Add cable
}
}

void ModuleRemove::redo() {


Loading…
Cancel
Save