From cc711b6d2df1b97323e46025846af39ac6411a6b Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 14 Nov 2019 07:53:28 -0500 Subject: [PATCH] Replace module disabling with bypassing using BypassRoute and Module::configBypass(). --- include/engine/Module.hpp | 25 +++++++++++++++++++++++++ src/app/ModuleWidget.cpp | 2 +- src/engine/Engine.cpp | 37 ++++++++++++++++++++++--------------- src/engine/Module.cpp | 14 ++++++++++++++ 4 files changed, 62 insertions(+), 16 deletions(-) diff --git a/include/engine/Module.hpp b/include/engine/Module.hpp index f17111ac..2275754d 100644 --- a/include/engine/Module.hpp +++ b/include/engine/Module.hpp @@ -75,6 +75,12 @@ struct Module { Expander leftExpander; Expander rightExpander; + struct BypassRoute { + int inputId = -1; + int outputId = -1; + }; + std::vector bypassRoutes; + /** Seconds spent in the process() method, with exponential smoothing. Only written when CPU timing is enabled, since time measurement is expensive. */ @@ -146,6 +152,21 @@ struct Module { outputInfos[portId] = p; } + /** Adds a direct route from an input to an output when the module is bypassed. */ + void configBypass(int inputId, int outputId) { + assert(inputId < (int) inputs.size()); + assert(outputId < (int) outputs.size()); + // Check that output is not yet routed + for (BypassRoute& br : bypassRoutes) { + assert(br.outputId != outputId); + } + + BypassRoute br; + br.inputId = inputId; + br.outputId = outputId; + bypassRoutes.push_back(br); + } + struct ProcessArgs { float sampleRate; float sampleTime; @@ -158,6 +179,10 @@ struct Module { } /** DEPRECATED. Override `process(const ProcessArgs& args)` instead. */ virtual void step() {} + /** Called instead of process() when Module is bypassed. + Typically you do not need to override this. Use configBypass() instead. + */ + virtual void processBypass(const ProcessArgs& args); json_t* toJson(); /** This is virtual only for the purpose of unserializing legacy data when you could set properties of the `.modules[]` object itself. diff --git a/src/app/ModuleWidget.cpp b/src/app/ModuleWidget.cpp index 11b4c1d0..c64a1d25 100644 --- a/src/app/ModuleWidget.cpp +++ b/src/app/ModuleWidget.cpp @@ -306,7 +306,7 @@ void ModuleWidget::draw(const DrawArgs& args) { Widget::draw(args); // Power meter - if (module && settings::cpuMeter && !module->disabled) { + if (module && settings::cpuMeter) { nvgBeginPath(args.vg); nvgRect(args.vg, 0, box.size.y - 35, diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 5ef6a313..05dd14c0 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -220,21 +220,28 @@ static void Engine_stepModulesWorker(Engine* that, int threadId) { break; Module* module = internal->modules[i]; - if (!module->disabled) { - // Step module - if (cpuMeter) { - auto beginTime = std::chrono::high_resolution_clock::now(); - module->process(processArgs); - auto endTime = std::chrono::high_resolution_clock::now(); - float duration = std::chrono::duration(endTime - beginTime).count(); - - // Smooth CPU time - const float cpuTau = 2.f /* seconds */; - module->cpuTime += (duration - module->cpuTime) * processArgs.sampleTime / cpuTau; - } - else { - module->process(processArgs); - } + + // Start CPU timer + using time_point = std::chrono::time_point; + time_point beginTime; + if (cpuMeter) { + beginTime = std::chrono::high_resolution_clock::now(); + } + + // Step module + if (!module->disabled) + module->process(processArgs); + else + module->processBypass(processArgs); + + // Stop CPU timer + if (cpuMeter) { + time_point endTime = std::chrono::high_resolution_clock::now(); + float duration = std::chrono::duration(endTime - beginTime).count(); + + // Smooth CPU time + const float cpuTau = 2.f /* seconds */; + module->cpuTime += (duration - module->cpuTime) * processArgs.sampleTime / cpuTau; } // Iterate ports to step plug lights diff --git a/src/engine/Module.cpp b/src/engine/Module.cpp index 63b2be91..d6cffe90 100644 --- a/src/engine/Module.cpp +++ b/src/engine/Module.cpp @@ -47,6 +47,20 @@ void Module::config(int numParams, int numInputs, int numOutputs, int numLights) } } +void Module::processBypass(const ProcessArgs& args) { + for (BypassRoute& bypassRoute : bypassRoutes) { + // Route input voltages to output + Input& input = inputs[bypassRoute.inputId]; + Output& output = outputs[bypassRoute.outputId]; + int channels = input.getChannels(); + for (int c = 0; c < channels; c++) { + float v = input.getVoltage(c); + output.setVoltage(v, c); + } + output.setChannels(channels); + } +} + json_t* Module::toJson() { json_t* rootJ = json_object();