From f33945d08821b45038e423ec53743c61d1897b1f Mon Sep 17 00:00:00 2001 From: Francesco Cameli Date: Fri, 25 Nov 2022 18:56:39 +0100 Subject: [PATCH] Order modules according to cable connections (#410) * Engine: re-order modules at each cable connection * Cleanup Engine.cpp * Ignore .vscode * Engine: re-work feedback detection with debug printing * Engine: simplify ordering and add debug printing * Engine: use DEBUG_ORDERED_MODULES to print debugging info * Ignore .vscode --- src/override/Engine.cpp | 75 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/override/Engine.cpp b/src/override/Engine.cpp index 2a31fe8..b443cb7 100644 --- a/src/override/Engine.cpp +++ b/src/override/Engine.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -278,6 +279,75 @@ static void Port_setConnected(Port* that) { } +template +using IdentityDictionary = std::unordered_map; + +template +inline bool dictContains(IdentityDictionary &dict, T key) { + return dict.find(key) != dict.end(); +} + +template +inline void dictAdd(IdentityDictionary &dict, T key) { + dict[key] = key; +} + +static void Engine_storeTerminalModulesIDs(std::vector terminalModules, IdentityDictionary &terminalModulesIDs) { + for (TerminalModule* terminalModule : terminalModules) + dictAdd(terminalModulesIDs, terminalModule->id); +} + +static void Engine_orderModule(Module* module, IdentityDictionary &touchedModules, std::vector &orderedModules, IdentityDictionary &terminalModulesIDs) { + if (!dictContains(touchedModules, module) && !dictContains(terminalModulesIDs, module->id)) { // Ignore feedback loops and terminal modules + dictAdd(touchedModules, module); + for (Output& output : module->outputs) { + for (Cable* cable : output.cables) { + Module* receiver = cable->inputModule; // The input to the cable is the receiving module + Engine_orderModule(receiver, touchedModules, orderedModules, terminalModulesIDs); + } + } + orderedModules.push_back(module); + } +} + +static void Engine_assignOrderedModules(std::vector &modules, std::vector &orderedModules) { + std::reverse(orderedModules.begin(), orderedModules.end()); // These are stored bottom up + if (orderedModules.size() == modules.size()) { + for (unsigned int i = 0; i < orderedModules.size(); i++) + modules[i] = orderedModules[i]; + } +} + +#if DEBUG_ORDERED_MODULES +static void Engine_debugOrderedModules(std::vector &modules) { + printf("\n--- Ordered modules ---\n"); + for (unsigned int i = 0; i < modules.size(); i++) + printf("%d) %s - %ld\n", i, modules[i]->model->getFullName().c_str(), modules[i]->id); +} +#endif + +/** Order the modules so that they always read the most recent sample from their inputs +*/ +static void Engine_orderModules(Engine* that) { + Engine::Internal* internal = that->internal; + + IdentityDictionary terminalModulesIDs; + Engine_storeTerminalModulesIDs(internal->terminalModules, terminalModulesIDs); + + IdentityDictionary touchedModules; + std::vector orderedModules; + orderedModules.reserve(internal->modules.size()); + for (Module* module : internal->modules) + Engine_orderModule(module, touchedModules, orderedModules, terminalModulesIDs); + + Engine_assignOrderedModules(internal->modules, orderedModules); + +#if DEBUG_ORDERED_MODULES + Engine_debugOrderedModules(internal->modules); +#endif +} + + static void Engine_updateConnected(Engine* that) { // Find disconnected ports std::set disconnectedInputs; @@ -320,6 +390,8 @@ static void Engine_updateConnected(Engine* that) { Port_setDisconnected(output); DISTRHO_SAFE_ASSERT(output->cables.empty()); } + // Order the modules according to their connections + Engine_orderModules(that); } @@ -619,6 +691,9 @@ void Engine::addModule(Module* module) { if (paramHandle->moduleId == module->id) paramHandle->module = module; } +#if DEBUG_ORDERED_MODULES + printf("New module: %s - %ld\n", module->model->getFullName().c_str(), module->id); +#endif }