diff --git a/include/engine/Module.hpp b/include/engine/Module.hpp index 2c0c566d..21405c5d 100644 --- a/include/engine/Module.hpp +++ b/include/engine/Module.hpp @@ -24,10 +24,20 @@ struct Module { plugin::Model *model = NULL; /** Automatically generated by the engine. */ int id = -1; + /** Arrays of components */ std::vector params; std::vector outputs; std::vector inputs; std::vector lights; + /** Access to adjacent modules */ + int leftModuleId = -1; + Module *leftModule = NULL; + void *leftProducerMessage = NULL; + void *leftConsumerMessage = NULL; + int rightModuleId = -1; + Module *rightModule = NULL; + void *rightProducerMessage = NULL; + void *rightConsumerMessage = NULL; /** For CPU meter. */ float cpuTime = 0.f; bool bypass = false; diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index ee298485..17230970 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -317,6 +317,35 @@ void RackWidget::pastePresetClipboardAction() { } } +static void RackWidget_updateAdjacent(RackWidget *that) { + // TODO This can be better than O(n^2) + for (widget::Widget *w : that->moduleContainer->children) { + ModuleWidget *m = dynamic_cast(w); + math::Vec pRight = m->box.getTopRight().div(RACK_GRID_SIZE).round(); + bool found = false; + + for (widget::Widget *w2 : that->moduleContainer->children) { + ModuleWidget *m2 = dynamic_cast(w2); + + if (m == m2) + continue; + math::Vec p2 = m->box.pos.div(RACK_GRID_SIZE).round(); + + // Check if m is to the right of m2 + if (pRight.isEqual(p2)) { + m->module->leftModuleId = m2->module->id; + m2->module->rightModuleId = m->module->id; + found = true; + break; + } + } + + if (!found) { + m->module->leftModuleId = -1; + } + } +} + void RackWidget::addModule(ModuleWidget *m) { // Add module to ModuleContainer assert(m); @@ -326,6 +355,7 @@ void RackWidget::addModule(ModuleWidget *m) { // Add module to Engine APP->engine->addModule(m->module); } + RackWidget_updateAdjacent(this); } void RackWidget::addModuleAtMouse(ModuleWidget *m) { @@ -373,6 +403,7 @@ bool RackWidget::requestModuleBox(ModuleWidget *m, math::Rect requestedBox) { // Accept requested position m->box = requestedBox; + RackWidget_updateAdjacent(this); return true; } diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index f1f08a63..fb6952f3 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -185,8 +185,8 @@ Engine::~Engine() { delete internal; } -static void Engine_stepModules(Engine *engine, int threadId) { - Engine::Internal *internal = engine->internal; +static void Engine_stepModules(Engine *that, int threadId) { + Engine::Internal *internal = that->internal; // int threadCount = internal->threadCount; int modulesLen = internal->modules.size(); @@ -233,8 +233,8 @@ static void Engine_stepModules(Engine *engine, int threadId) { } } -static void Engine_step(Engine *engine) { - Engine::Internal *internal = engine->internal; +static void Engine_step(Engine *that) { + Engine::Internal *internal = that->internal; // Param smoothing Module *smoothModule = internal->smoothModule; @@ -260,44 +260,70 @@ static void Engine_step(Engine *engine) { // Step modules along with workers internal->workerModuleIndex = 0; internal->engineBarrier.wait(); - Engine_stepModules(engine, 0); + Engine_stepModules(that, 0); internal->workerBarrier.wait(); // Step cables - for (Cable *cable : engine->internal->cables) { + for (Cable *cable : that->internal->cables) { cable->step(); } } -static void Engine_run(Engine *engine) { +static void Engine_updateAdjacent(Engine *that, Module *m) { + // Sync leftModule + if (m->leftModuleId >= 0) { + if (!m->leftModule || m->leftModule->id != m->leftModuleId) { + m->leftModule = that->getModule(m->leftModuleId); + } + } + else { + if (m->leftModule) { + m->leftModule = NULL; + } + } + + // Sync rightModule + if (m->rightModuleId >= 0) { + if (!m->rightModule || m->rightModule->id != m->rightModuleId) { + m->rightModule = that->getModule(m->rightModuleId); + } + } + else { + if (m->rightModule) { + m->rightModule = NULL; + } + } +} + +static void Engine_run(Engine *that) { // Set up thread system::setThreadName("Engine"); system::setThreadRealTime(); disableDenormals(); - // Every time the engine waits and locks a mutex, it steps this many frames - const int mutexSteps = 64; - // Time in seconds that the engine is rushing ahead of the estimated clock time + // Every time the that waits and locks a mutex, it steps this many frames + const int mutexSteps = 128; + // Time in seconds that the that is rushing ahead of the estimated clock time double ahead = 0.0; auto lastTime = std::chrono::high_resolution_clock::now(); - while (engine->internal->running) { - engine->internal->vipMutex.wait(); + while (that->internal->running) { + that->internal->vipMutex.wait(); - if (!engine->internal->paused) { - std::lock_guard lock(engine->internal->mutex); - // auto startTime = std::chrono::high_resolution_clock::now(); + if (!that->internal->paused) { + std::lock_guard lock(that->internal->mutex); - for (int i = 0; i < mutexSteps; i++) { - Engine_step(engine); + for (Module *module : that->internal->modules) { + Engine_updateAdjacent(that, module); } - // auto stopTime = std::chrono::high_resolution_clock::now(); - // float cpuTime = std::chrono::duration(stopTime - startTime).count(); - // DEBUG("%g", cpuTime / mutexSteps * 44100); + // Step modules + for (int i = 0; i < mutexSteps; i++) { + Engine_step(that); + } } - double stepTime = mutexSteps * engine->internal->sampleTime; + double stepTime = mutexSteps * that->internal->sampleTime; ahead += stepTime; auto currTime = std::chrono::high_resolution_clock::now(); const double aheadFactor = 2.0; @@ -441,6 +467,17 @@ void Engine::removeModule(Module *module) { if (paramHandle->moduleId == module->id) paramHandle->module = NULL; } + // Update adjacent modules + for (Module *module : internal->modules) { + if (module->leftModule == module) { + module->leftModuleId = -1; + module->leftModule = NULL; + } + if (module->rightModule == module) { + module->rightModuleId = -1; + module->rightModule = NULL; + } + } // Check that the module actually exists auto it = std::find(internal->modules.begin(), internal->modules.end(), module); assert(it != internal->modules.end()); @@ -496,9 +533,9 @@ void Engine::bypassModule(Module *module, bool bypass) { module->bypass = bypass; } -static void Engine_updateConnected(Engine *engine) { +static void Engine_updateConnected(Engine *that) { // Set everything to unconnected - for (Module *module : engine->internal->modules) { + for (Module *module : that->internal->modules) { for (Input &input : module->inputs) { input.active = false; } @@ -507,7 +544,7 @@ static void Engine_updateConnected(Engine *engine) { } } // Set inputs/outputs to active - for (Cable *cable : engine->internal->cables) { + for (Cable *cable : that->internal->cables) { cable->outputModule->outputs[cable->outputId].active = true; cable->inputModule->inputs[cable->inputId].active = true; }