@@ -87,20 +87,29 @@ struct ExponentialSlewLimiter { | |||||
\f$ \frac{dy}{dt} = x \lambda \f$. | \f$ \frac{dy}{dt} = x \lambda \f$. | ||||
*/ | */ | ||||
struct ExponentialFilter { | struct ExponentialFilter { | ||||
float out = 0.f; | |||||
float out; | |||||
float lambda = 0.f; | float lambda = 0.f; | ||||
ExponentialFilter() { | |||||
reset(); | |||||
} | |||||
void reset() { | void reset() { | ||||
out = 0.f; | |||||
out = NAN; | |||||
} | } | ||||
float process(float deltaTime, float in) { | float process(float deltaTime, float in) { | ||||
float y = out + (in - out) * lambda * deltaTime; | |||||
// If no change was detected, assume float granularity is too small and snap output to input | |||||
if (out == y) | |||||
if (std::isnan(out)) { | |||||
out = in; | out = in; | ||||
else | |||||
out = y; | |||||
} | |||||
else { | |||||
float y = out + (in - out) * lambda * deltaTime; | |||||
// If no change was detected, assume float granularity is too small and snap output to input | |||||
if (out == y) | |||||
out = in; | |||||
else | |||||
out = y; | |||||
} | |||||
return out; | return out; | ||||
} | } | ||||
@@ -29,7 +29,11 @@ struct Engine { | |||||
float getSampleTime(); | float getSampleTime(); | ||||
// Modules | // Modules | ||||
/** Does not transfer pointer ownership. */ | |||||
/** Adds a module to the rack engine. | |||||
The module ID must not be taken by another module. | |||||
If the module ID is -1, an ID is automatically assigned. | |||||
Does not transfer pointer ownership. | |||||
*/ | |||||
void addModule(Module *module); | void addModule(Module *module); | ||||
void removeModule(Module *module); | void removeModule(Module *module); | ||||
Module *getModule(int moduleId); | Module *getModule(int moduleId); | ||||
@@ -38,7 +42,11 @@ struct Engine { | |||||
void bypassModule(Module *module, bool bypass); | void bypassModule(Module *module, bool bypass); | ||||
// Cables | // Cables | ||||
/** Does not transfer pointer ownership. */ | |||||
/** Adds a cable to the rack engine. | |||||
The cable ID must not be taken by another cable. | |||||
If the cable ID is -1, an ID is automatically assigned. | |||||
Does not transfer pointer ownership. | |||||
*/ | |||||
void addCable(Cable *cable); | void addCable(Cable *cable); | ||||
void removeCable(Cable *cable); | void removeCable(Cable *cable); | ||||
@@ -47,6 +55,12 @@ struct Engine { | |||||
float getParam(Module *module, int paramId); | float getParam(Module *module, int paramId); | ||||
void setSmoothParam(Module *module, int paramId, float value); | void setSmoothParam(Module *module, int paramId, float value); | ||||
float getSmoothParam(Module *module, int paramId); | float getSmoothParam(Module *module, int paramId); | ||||
void setTouchedParam(Module *module, int paramId); | |||||
void getTouchedParam(Module *&module, int ¶mId); | |||||
// ModuleHandles | |||||
void addModuleHandle(ModuleHandle *moduleHandle); | |||||
void removeModuleHandle(ModuleHandle *moduleHandle); | |||||
}; | }; | ||||
@@ -56,5 +56,12 @@ struct Module { | |||||
}; | }; | ||||
struct ModuleHandle { | |||||
int id = -1; | |||||
/** Automatically set when added to the Engine. */ | |||||
Module *module = NULL; | |||||
}; | |||||
} // namespace engine | } // namespace engine | ||||
} // namespace rack | } // namespace rack |
@@ -81,6 +81,9 @@ struct Param { | |||||
return value; | return value; | ||||
} | } | ||||
/* Clamps and set the value. | |||||
Don't call this directly from Modules. Use `APP->engine->setParam()`. | |||||
*/ | |||||
void setValue(float value) { | void setValue(float value) { | ||||
this->value = math::clamp(value, minValue, maxValue); | this->value = math::clamp(value, minValue, maxValue); | ||||
} | } | ||||
@@ -1,20 +0,0 @@ | |||||
#pragma once | |||||
#include "common.hpp" | |||||
#include <jansson.h> | |||||
namespace rack { | |||||
namespace engine { | |||||
struct ParamMap { | |||||
int moduleId = -1; | |||||
int paramId = -1; | |||||
json_t *toJson(); | |||||
void fromJson(json_t *rootJ); | |||||
}; | |||||
} // namespace engine | |||||
} // namespace rack |
@@ -72,7 +72,6 @@ | |||||
#include "engine/Module.hpp" | #include "engine/Module.hpp" | ||||
#include "engine/Param.hpp" | #include "engine/Param.hpp" | ||||
#include "engine/Cable.hpp" | #include "engine/Cable.hpp" | ||||
#include "engine/ParamMap.hpp" | |||||
#include "plugin/Plugin.hpp" | #include "plugin/Plugin.hpp" | ||||
#include "plugin/Model.hpp" | #include "plugin/Model.hpp" | ||||
@@ -91,7 +91,7 @@ struct MIDI_CC : Module { | |||||
} | } | ||||
// Allow CC to be negative if the 8th bit is set. | // Allow CC to be negative if the 8th bit is set. | ||||
// The gamepad driver abuses this, for example. | // The gamepad driver abuses this, for example. | ||||
values[cc] = msg.data2; | |||||
values[cc] = clamp(msg.data2, -127, 127); | |||||
} | } | ||||
json_t *dataToJson() override { | json_t *dataToJson() override { | ||||
@@ -16,26 +16,38 @@ struct MIDI_Map : Module { | |||||
}; | }; | ||||
midi::InputQueue midiInput; | midi::InputQueue midiInput; | ||||
int8_t values[128]; | |||||
int learningId; | int learningId; | ||||
int lastLearnedCc; | |||||
int learnedCcs[8]; | int learnedCcs[8]; | ||||
ModuleHandle learnedModuleHandles[8]; | |||||
int learnedParamIds[8]; | |||||
int8_t values[128]; | |||||
dsp::ExponentialFilter valueFilters[8]; | dsp::ExponentialFilter valueFilters[8]; | ||||
ParamMap paramMaps[8]; | |||||
MIDI_Map() { | MIDI_Map() { | ||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | ||||
for (int i = 0; i < 8; i++) { | for (int i = 0; i < 8; i++) { | ||||
valueFilters[i].lambda = 40.f; | |||||
valueFilters[i].lambda = 60.f; | |||||
} | } | ||||
onReset(); | onReset(); | ||||
} | } | ||||
~MIDI_Map() { | |||||
for (int i = 0; i < 8; i++) { | |||||
unloadModuleHandle(i); | |||||
} | |||||
} | |||||
void onReset() override { | void onReset() override { | ||||
learningId = -1; | learningId = -1; | ||||
lastLearnedCc = -1; | |||||
for (int i = 0; i < 8; i++) { | for (int i = 0; i < 8; i++) { | ||||
learnedCcs[i] = -1; | learnedCcs[i] = -1; | ||||
unloadModuleHandle(i); | |||||
learnedModuleHandles[i].id = -1; | |||||
learnedParamIds[i] = 0; | |||||
valueFilters[i].reset(); | |||||
} | |||||
for (int i = 0; i < 128; i++) { | |||||
values[i] = -1; | |||||
} | } | ||||
midiInput.reset(); | midiInput.reset(); | ||||
} | } | ||||
@@ -48,23 +60,43 @@ struct MIDI_Map : Module { | |||||
float deltaTime = APP->engine->getSampleTime(); | float deltaTime = APP->engine->getSampleTime(); | ||||
// Check touched params when learning | |||||
if (learningId >= 0) { | |||||
Module *module; | |||||
int paramId; | |||||
APP->engine->getTouchedParam(module, paramId); | |||||
APP->engine->setTouchedParam(NULL, 0); | |||||
if (module) { | |||||
unloadModuleHandle(learningId); | |||||
learnedModuleHandles[learningId].id = module->id; | |||||
loadModuleHandle(learningId); | |||||
learnedParamIds[learningId] = paramId; | |||||
commitLearn(); | |||||
} | |||||
} | |||||
// Step channels | |||||
for (int i = 0; i < 8; i++) { | for (int i = 0; i < 8; i++) { | ||||
// Get module | |||||
int moduleId = paramMaps[i].moduleId; | |||||
if (moduleId < 0) | |||||
int cc = learnedCcs[i]; | |||||
if (cc < 0) | |||||
continue; | continue; | ||||
Module *module = APP->engine->getModule(moduleId); | |||||
// Check if CC value has been set | |||||
if (values[cc] < 0) | |||||
continue; | |||||
// Get module | |||||
Module *module = learnedModuleHandles[i].module; | |||||
if (!module) | if (!module) | ||||
continue; | continue; | ||||
// Get param | // Get param | ||||
int paramId = paramMaps[i].paramId; | |||||
int paramId = learnedParamIds[i]; | |||||
Param *param = &module->params[paramId]; | Param *param = &module->params[paramId]; | ||||
if (!param->isBounded()) | if (!param->isBounded()) | ||||
continue; | continue; | ||||
// Set param | // Set param | ||||
float v = rescale(values[i], 0, 127, param->minValue, param->maxValue); | |||||
float v = rescale(values[cc], 0, 127, 0.f, 1.f); | |||||
v = valueFilters[i].process(deltaTime, v); | v = valueFilters[i].process(deltaTime, v); | ||||
module->params[paramId].setValue(v); | |||||
v = rescale(v, 0.f, 1.f, param->minValue, param->maxValue); | |||||
APP->engine->setParam(module, paramId, v); | |||||
} | } | ||||
} | } | ||||
@@ -81,17 +113,44 @@ struct MIDI_Map : Module { | |||||
void processCC(midi::Message msg) { | void processCC(midi::Message msg) { | ||||
uint8_t cc = msg.getNote(); | uint8_t cc = msg.getNote(); | ||||
// Learn | // Learn | ||||
if (learningId >= 0 && values[cc] != msg.data2) { | |||||
if (lastLearnedCc != cc) { | |||||
learnedCcs[learningId] = cc; | |||||
lastLearnedCc = cc; | |||||
if (++learningId >= 8) | |||||
learningId = -1; | |||||
} | |||||
if (learningId >= 0 && values[cc] != msg.getValue()) { | |||||
learnedCcs[learningId] = cc; | |||||
commitLearn(); | |||||
} | } | ||||
values[cc] = msg.getValue(); | values[cc] = msg.getValue(); | ||||
} | } | ||||
void loadModuleHandle(int i) { | |||||
if (learnedModuleHandles[i].id >= 0) { | |||||
APP->engine->addModuleHandle(&learnedModuleHandles[i]); | |||||
} | |||||
} | |||||
void unloadModuleHandle(int i) { | |||||
if (learnedModuleHandles[i].id >= 0) { | |||||
APP->engine->removeModuleHandle(&learnedModuleHandles[i]); | |||||
} | |||||
} | |||||
void commitLearn() { | |||||
if (learningId < 0) | |||||
return; | |||||
if (learnedModuleHandles[learningId].id < 0) | |||||
return; | |||||
if (learnedCcs[learningId] < 0) | |||||
return; | |||||
learningId++; | |||||
if (learningId >= 8) | |||||
learningId = -1; | |||||
} | |||||
void clearLearn(int id) { | |||||
learnedCcs[id] = -1; | |||||
unloadModuleHandle(id); | |||||
learnedModuleHandles[id].id = -1; | |||||
loadModuleHandle(id); | |||||
} | |||||
json_t *dataToJson() override { | json_t *dataToJson() override { | ||||
json_t *rootJ = json_object(); | json_t *rootJ = json_object(); | ||||
@@ -101,11 +160,17 @@ struct MIDI_Map : Module { | |||||
} | } | ||||
json_object_set_new(rootJ, "ccs", ccsJ); | json_object_set_new(rootJ, "ccs", ccsJ); | ||||
json_t *paramMapsJ = json_array(); | |||||
json_t *moduleIdsJ = json_array(); | |||||
for (int i = 0; i < 8; i++) { | for (int i = 0; i < 8; i++) { | ||||
json_array_append_new(paramMapsJ, paramMaps[i].toJson()); | |||||
json_array_append_new(moduleIdsJ, json_integer(learnedModuleHandles[i].id)); | |||||
} | } | ||||
json_object_set_new(rootJ, "paramMaps", paramMapsJ); | |||||
json_object_set_new(rootJ, "moduleIds", moduleIdsJ); | |||||
json_t *paramIdsJ = json_array(); | |||||
for (int i = 0; i < 8; i++) { | |||||
json_array_append_new(paramIdsJ, json_integer(learnedParamIds[i])); | |||||
} | |||||
json_object_set_new(rootJ, "paramIds", paramIdsJ); | |||||
json_object_set_new(rootJ, "midi", midiInput.toJson()); | json_object_set_new(rootJ, "midi", midiInput.toJson()); | ||||
return rootJ; | return rootJ; | ||||
@@ -121,12 +186,23 @@ struct MIDI_Map : Module { | |||||
} | } | ||||
} | } | ||||
json_t *paramMapsJ = json_object_get(rootJ, "paramMaps"); | |||||
if (paramMapsJ) { | |||||
json_t *moduleIdsJ = json_object_get(rootJ, "moduleIds"); | |||||
if (moduleIdsJ) { | |||||
for (int i = 0; i < 8; i++) { | for (int i = 0; i < 8; i++) { | ||||
json_t *paramMapJ = json_array_get(paramMapsJ, i); | |||||
if (paramMapJ) | |||||
paramMaps[i].fromJson(paramMapJ); | |||||
json_t *moduleIdJ = json_array_get(moduleIdsJ, i); | |||||
unloadModuleHandle(i); | |||||
if (moduleIdJ) | |||||
learnedModuleHandles[i].id = json_integer_value(moduleIdJ); | |||||
loadModuleHandle(i); | |||||
} | |||||
} | |||||
json_t *paramIdsJ = json_object_get(rootJ, "paramIds"); | |||||
if (paramIdsJ) { | |||||
for (int i = 0; i < 8; i++) { | |||||
json_t *paramIdJ = json_array_get(paramIdsJ, i); | |||||
if (paramIdJ) | |||||
learnedParamIds[i] = json_integer_value(paramIdJ); | |||||
} | } | ||||
} | } | ||||
@@ -145,10 +221,17 @@ struct MIDI_MapChoice : LedDisplayChoice { | |||||
this->module = module; | this->module = module; | ||||
} | } | ||||
void onAction(const event::Action &e) override { | |||||
if (!module) | |||||
return; | |||||
module->lastLearnedCc = -1; | |||||
void onButton(const event::Button &e) override { | |||||
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT) { | |||||
APP->engine->setTouchedParam(NULL, 0); | |||||
e.consume(this); | |||||
} | |||||
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) { | |||||
if (module) { | |||||
module->clearLearn(id); | |||||
} | |||||
} | |||||
} | } | ||||
void onSelect(const event::Select &e) override { | void onSelect(const event::Select &e) override { | ||||
@@ -170,8 +253,6 @@ struct MIDI_MapChoice : LedDisplayChoice { | |||||
if (!module) | if (!module) | ||||
return; | return; | ||||
if (module->learningId == id) { | if (module->learningId == id) { | ||||
text = "Mapping..."; | |||||
color.a = 1.0; | |||||
bgColor = color; | bgColor = color; | ||||
bgColor.a = 0.15; | bgColor.a = 0.15; | ||||
@@ -180,22 +261,56 @@ struct MIDI_MapChoice : LedDisplayChoice { | |||||
APP->event->setSelected(this); | APP->event->setSelected(this); | ||||
} | } | ||||
else { | else { | ||||
if (module->learnedCcs[id] >= 0) { | |||||
text = string::f("CC%d", module->learnedCcs[id]); | |||||
color.a = 1.0; | |||||
bgColor = nvgRGBA(0, 0, 0, 0); | |||||
bgColor = nvgRGBA(0, 0, 0, 0); | |||||
// HACK | |||||
if (APP->event->selectedWidget == this) | |||||
APP->event->setSelected(NULL); | |||||
} | |||||
text = ""; | |||||
color.a = 1.0; | |||||
if (module->learnedCcs[id] >= 0) { | |||||
text += string::f("CC%d ", module->learnedCcs[id]); | |||||
} | |||||
if (module->learnedModuleHandles[id].id >= 0) { | |||||
text += getParamName(); | |||||
} | |||||
if (!(module->learnedCcs[id] >= 0) && !(module->learnedModuleHandles[id].id >= 0)) { | |||||
if (module->learningId == id) { | |||||
text = "Mapping..."; | |||||
} | } | ||||
else { | else { | ||||
text = "Unmapped"; | text = "Unmapped"; | ||||
color.a = 0.5; | color.a = 0.5; | ||||
bgColor = nvgRGBA(0, 0, 0, 0); | |||||
} | } | ||||
// HACK | |||||
if (APP->event->selectedWidget == this) | |||||
APP->event->setSelected(NULL); | |||||
} | } | ||||
} | } | ||||
std::string getParamName() { | |||||
if (!module) | |||||
return ""; | |||||
ModuleHandle *moduleHandle = &module->learnedModuleHandles[id]; | |||||
if (moduleHandle->id < 0) | |||||
return ""; | |||||
ModuleWidget *mw = APP->scene->rackWidget->getModule(moduleHandle->id); | |||||
if (!mw) | |||||
return ""; | |||||
// Get the Module from the ModuleWidget instead of the ModuleHandle. | |||||
// I think this is more elegant since this method is called in the app world instead of the engine world. | |||||
Module *m = mw->module; | |||||
if (!m) | |||||
return ""; | |||||
int paramId = module->learnedParamIds[id]; | |||||
if (paramId >= (int) m->params.size()) | |||||
return ""; | |||||
Param *param = &m->params[paramId]; | |||||
std::string s; | |||||
s += mw->model->name; | |||||
s += " "; | |||||
s += param->label; | |||||
return s; | |||||
} | |||||
}; | }; | ||||
@@ -4,6 +4,7 @@ | |||||
#include "app/Scene.hpp" | #include "app/Scene.hpp" | ||||
#include "app/ParamQuantity.hpp" | #include "app/ParamQuantity.hpp" | ||||
#include "app.hpp" | #include "app.hpp" | ||||
#include "engine/Engine.hpp" | |||||
#include "settings.hpp" | #include "settings.hpp" | ||||
#include "random.hpp" | #include "random.hpp" | ||||
#include "history.hpp" | #include "history.hpp" | ||||
@@ -143,6 +144,13 @@ void ParamWidget::draw(const widget::DrawContext &ctx) { | |||||
} | } | ||||
void ParamWidget::onButton(const event::Button &e) { | void ParamWidget::onButton(const event::Button &e) { | ||||
// Touch parameter | |||||
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && (e.mods & WINDOW_MOD_MASK) == 0) { | |||||
if (paramQuantity) { | |||||
APP->engine->setTouchedParam(paramQuantity->module, paramQuantity->paramId); | |||||
} | |||||
} | |||||
// Right click to open context menu | // Right click to open context menu | ||||
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & WINDOW_MOD_MASK) == 0) { | if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & WINDOW_MOD_MASK) == 0) { | ||||
createContextMenu(); | createContextMenu(); | ||||
@@ -127,6 +127,7 @@ struct EngineWorker { | |||||
struct Engine::Internal { | struct Engine::Internal { | ||||
std::vector<Module*> modules; | std::vector<Module*> modules; | ||||
std::vector<Cable*> cables; | std::vector<Cable*> cables; | ||||
std::vector<ModuleHandle*> moduleHandles; | |||||
bool paused = false; | bool paused = false; | ||||
bool running = false; | bool running = false; | ||||
@@ -149,6 +150,9 @@ struct Engine::Internal { | |||||
std::vector<EngineWorker> workers; | std::vector<EngineWorker> workers; | ||||
SpinBarrier engineBarrier; | SpinBarrier engineBarrier; | ||||
SpinBarrier workerBarrier; | SpinBarrier workerBarrier; | ||||
Module *touchedModule = NULL; | |||||
int touchedParamId = 0; | |||||
}; | }; | ||||
@@ -173,6 +177,7 @@ Engine::~Engine() { | |||||
// If this happens, a module must have failed to remove itself before the RackWidget was destroyed. | // If this happens, a module must have failed to remove itself before the RackWidget was destroyed. | ||||
assert(internal->cables.empty()); | assert(internal->cables.empty()); | ||||
assert(internal->modules.empty()); | assert(internal->modules.empty()); | ||||
assert(internal->moduleHandles.empty()); | |||||
delete internal; | delete internal; | ||||
} | } | ||||
@@ -235,6 +240,7 @@ static void Engine_step(Engine *engine) { | |||||
// 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 | // 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 | ||||
param->setValue(smoothValue); | param->setValue(smoothValue); | ||||
internal->smoothModule = NULL; | internal->smoothModule = NULL; | ||||
internal->smoothParamId = 0; | |||||
} | } | ||||
else { | else { | ||||
param->value = newValue; | param->value = newValue; | ||||
@@ -400,6 +406,11 @@ void Engine::addModule(Module *module) { | |||||
internal->nextModuleId = module->id + 1; | internal->nextModuleId = module->id + 1; | ||||
} | } | ||||
} | } | ||||
// Update ModuleHandle | |||||
for (ModuleHandle *moduleHandle : internal->moduleHandles) { | |||||
if (moduleHandle->id == module->id) | |||||
moduleHandle->module = module; | |||||
} | |||||
// Add module | // Add module | ||||
internal->modules.push_back(module); | internal->modules.push_back(module); | ||||
} | } | ||||
@@ -417,6 +428,16 @@ void Engine::removeModule(Module *module) { | |||||
assert(cable->outputModule != module); | assert(cable->outputModule != module); | ||||
assert(cable->inputModule != module); | assert(cable->inputModule != module); | ||||
} | } | ||||
// Remove touched param | |||||
if (internal->touchedModule == module) { | |||||
internal->touchedModule = NULL; | |||||
internal->touchedParamId = 0; | |||||
} | |||||
// Update ModuleHandle | |||||
for (ModuleHandle *moduleHandle : internal->moduleHandles) { | |||||
if (moduleHandle->id == module->id) | |||||
moduleHandle->module = NULL; | |||||
} | |||||
// Check that the module actually exists | // Check that the module actually exists | ||||
auto it = std::find(internal->modules.begin(), internal->modules.end(), module); | auto it = std::find(internal->modules.begin(), internal->modules.end(), module); | ||||
assert(it != internal->modules.end()); | assert(it != internal->modules.end()); | ||||
@@ -537,6 +558,11 @@ void Engine::removeCable(Cable *cable) { | |||||
void Engine::setParam(Module *module, int paramId, float value) { | void Engine::setParam(Module *module, int paramId, float value) { | ||||
// TODO Does this need to be thread-safe? | // TODO Does this need to be thread-safe? | ||||
// If being smoothed, cancel smoothing | |||||
if (internal->smoothModule == module && internal->smoothParamId == paramId) { | |||||
internal->smoothModule = NULL; | |||||
internal->smoothParamId = 0; | |||||
} | |||||
module->params[paramId].value = value; | module->params[paramId].value = value; | ||||
} | } | ||||
@@ -551,6 +577,7 @@ void Engine::setSmoothParam(Module *module, int paramId, float value) { | |||||
} | } | ||||
internal->smoothParamId = paramId; | internal->smoothParamId = paramId; | ||||
internal->smoothValue = value; | internal->smoothValue = value; | ||||
// Set this last so the above values are valid as soon as it is set | |||||
internal->smoothModule = module; | internal->smoothModule = module; | ||||
} | } | ||||
@@ -560,6 +587,39 @@ float Engine::getSmoothParam(Module *module, int paramId) { | |||||
return getParam(module, paramId); | return getParam(module, paramId); | ||||
} | } | ||||
void Engine::setTouchedParam(Module *module, int paramId) { | |||||
internal->touchedModule = module; | |||||
internal->touchedParamId = paramId; | |||||
} | |||||
void Engine::getTouchedParam(Module *&module, int ¶mId) { | |||||
module = internal->touchedModule; | |||||
paramId = internal->touchedParamId; | |||||
} | |||||
void Engine::addModuleHandle(ModuleHandle *moduleHandle) { | |||||
VIPLock vipLock(internal->vipMutex); | |||||
std::lock_guard<std::recursive_mutex> lock(internal->mutex); | |||||
// Check that the ModuleHandle is not already added | |||||
auto it = std::find(internal->moduleHandles.begin(), internal->moduleHandles.end(), moduleHandle); | |||||
assert(it == internal->moduleHandles.end()); | |||||
moduleHandle->module = getModule(moduleHandle->id); | |||||
internal->moduleHandles.push_back(moduleHandle); | |||||
} | |||||
void Engine::removeModuleHandle(ModuleHandle *moduleHandle) { | |||||
VIPLock vipLock(internal->vipMutex); | |||||
std::lock_guard<std::recursive_mutex> lock(internal->mutex); | |||||
moduleHandle->module = NULL; | |||||
// Check that the ModuleHandle is already added | |||||
auto it = std::find(internal->moduleHandles.begin(), internal->moduleHandles.end(), moduleHandle); | |||||
assert(it != internal->moduleHandles.end()); | |||||
internal->moduleHandles.erase(it); | |||||
} | |||||
void EngineWorker::step() { | void EngineWorker::step() { | ||||
engine->internal->engineBarrier.wait(); | engine->internal->engineBarrier.wait(); | ||||
@@ -1,27 +0,0 @@ | |||||
#include "engine/ParamMap.hpp" | |||||
namespace rack { | |||||
namespace engine { | |||||
json_t *ParamMap::toJson() { | |||||
json_t *rootJ = json_object(); | |||||
json_object_set_new(rootJ, "moduleId", json_integer(moduleId)); | |||||
json_object_set_new(rootJ, "paramId", json_integer(paramId)); | |||||
return rootJ; | |||||
} | |||||
void ParamMap::fromJson(json_t *rootJ) { | |||||
json_t *moduleIdJ = json_object_get(rootJ, "moduleId"); | |||||
if (moduleIdJ) | |||||
moduleId = json_integer_value(moduleIdJ); | |||||
json_t *paramIdJ = json_object_get(rootJ, "paramId"); | |||||
if (paramIdJ) | |||||
paramId = json_integer_value(paramIdJ); | |||||
} | |||||
} // namespace engine | |||||
} // namespace rack |