diff --git a/include/engine/Port.hpp b/include/engine/Port.hpp index 044a39e..7e9284e 100644 --- a/include/engine/Port.hpp +++ b/include/engine/Port.hpp @@ -46,27 +46,12 @@ struct Cable; struct Port { /** Voltage of the port. */ - /** NOTE Purposefully renamed in Cardinal as a way to catch plugins using it directly. */ union { /** Unstable API. Use getVoltage() and setVoltage() instead. */ - float cvoltages[PORT_MAX_CHANNELS] = {}; + float voltages[PORT_MAX_CHANNELS] = {}; /** DEPRECATED. Unstable API. Use getVoltage() and setVoltage() instead. */ - float cvalue; + float value; }; - - /** Special trickery for backwards compatibility with plugins using DEPRECATED APIs */ - struct BackwardsCompatPortValue { - Port* const port; - BackwardsCompatPortValue(Port* p) : port(p) {} - void operator=(float value) { port->setVoltage(value); } - void operator-=(float value) { port->setVoltage(port->cvalue - value); } - void operator+=(float value) { port->setVoltage(port->cvalue + value); } - void operator*=(float value) { port->setVoltage(port->cvalue * value); } - void operator/=(float value) { port->setVoltage(port->cvalue / value); } - operator float() const { return port->cvalue; } - } value; - Port() : value(this) {} - union { /** Number of polyphonic channels. DEPRECATED. Unstable API. Use set/getChannels() instead. @@ -87,24 +72,19 @@ struct Port { OUTPUT, }; - /** Cables connected to this output port. */ + /** List of cables connected to this port (if output type). */ std::list cables; - /** Step-through the cables. - Called whenever voltage changes, required for zero latency operation. */ - void stepCables(); - /** Sets the voltage of the given channel. */ void setVoltage(float voltage, int channel = 0) { - cvoltages[channel] = voltage; - stepCables(); + voltages[channel] = voltage; } /** Returns the voltage of the given channel. Because of proper bookkeeping, all channels higher than the input port's number of channels should be 0V. */ float getVoltage(int channel = 0) { - return cvoltages[channel]; + return voltages[channel]; } /** Returns the given channel's voltage if the port is polyphonic, otherwise returns the first voltage (channel 0). */ @@ -124,15 +104,14 @@ struct Port { /** Returns a pointer to the array of voltages beginning with firstChannel. The pointer can be used for reading and writing. */ - // TODO convert to const float* for zero-latency cable stuff and fix all plugins after float* getVoltages(int firstChannel = 0) { - return &cvoltages[firstChannel]; + return &voltages[firstChannel]; } /** Copies the port's voltages to an array of size at least `channels`. */ void readVoltages(float* v) { for (int c = 0; c < channels; c++) { - v[c] = cvoltages[c]; + v[c] = voltages[c]; } } @@ -141,24 +120,22 @@ struct Port { */ void writeVoltages(const float* v) { for (int c = 0; c < channels; c++) { - cvoltages[c] = v[c]; + voltages[c] = v[c]; } - stepCables(); } /** Sets all voltages to 0. */ void clearVoltages() { for (int c = 0; c < channels; c++) { - cvoltages[c] = 0.f; + voltages[c] = 0.f; } - stepCables(); } /** Returns the sum of all voltages. */ float getVoltageSum() { float sum = 0.f; for (int c = 0; c < channels; c++) { - sum += cvoltages[c]; + sum += voltages[c]; } return sum; } @@ -171,12 +148,12 @@ struct Port { return 0.f; } else if (channels == 1) { - return std::fabs(cvoltages[0]); + return std::fabs(voltages[0]); } else { float sum = 0.f; for (int c = 0; c < channels; c++) { - sum += std::pow(cvoltages[c], 2); + sum += std::pow(voltages[c], 2); } return std::sqrt(sum); } @@ -184,7 +161,7 @@ struct Port { template T getVoltageSimd(int firstChannel) { - return T::load(&cvoltages[firstChannel]); + return T::load(&voltages[firstChannel]); } template @@ -204,8 +181,7 @@ struct Port { template void setVoltageSimd(T voltage, int firstChannel) { - voltage.store(&cvoltages[firstChannel]); - stepCables(); + voltage.store(&voltages[firstChannel]); } /** Sets the number of polyphony channels. @@ -220,7 +196,7 @@ struct Port { } // Set higher channel voltages to 0 for (int c = channels; c < this->channels; c++) { - cvoltages[c] = 0.f; + voltages[c] = 0.f; } // Don't allow caller to set port as disconnected if (channels == 0) { diff --git a/include/engine/TerminalModule.hpp b/include/engine/TerminalModule.hpp new file mode 100644 index 0000000..0f8fd28 --- /dev/null +++ b/include/engine/TerminalModule.hpp @@ -0,0 +1,31 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2022 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +#pragma once + +#include + +namespace rack { +namespace engine { + +struct TerminalModule : Module { + virtual void processTerminalInput(const ProcessArgs& args) = 0; + virtual void processTerminalOutput(const ProcessArgs& args) = 0; +}; + +} +} diff --git a/plugins/Bidoo b/plugins/Bidoo index 988c237..e55fcd2 160000 --- a/plugins/Bidoo +++ b/plugins/Bidoo @@ -1 +1 @@ -Subproject commit 988c2372a95d163b71d04b217080e612b767c539 +Subproject commit e55fcd2e1d7c0fef69d4919baac6f791172c89ca diff --git a/plugins/Cardinal/src/HostAudio.cpp b/plugins/Cardinal/src/HostAudio.cpp index 6fd21ce..1098336 100644 --- a/plugins/Cardinal/src/HostAudio.cpp +++ b/plugins/Cardinal/src/HostAudio.cpp @@ -24,7 +24,7 @@ USE_NAMESPACE_DISTRHO; template -struct HostAudio : Module { +struct HostAudio : TerminalModule { CardinalPluginContext* const pcontext; const int numParams; const int numInputs; @@ -74,45 +74,65 @@ struct HostAudio : Module { dcFilters[i].setCutoffFreq(10.f * e.sampleTime); } - void process(const ProcessArgs&) override + void processTerminalInput(const ProcessArgs&) override { const float* const* const dataIns = pcontext->dataIns; - float** const dataOuts = pcontext->dataOuts; const int blockFrames = pcontext->engine->getBlockFrames(); const int64_t blockFrame = pcontext->engine->getBlockFrame(); + // only checked on input if (lastBlockFrame != blockFrame) { dataFrame = 0; lastBlockFrame = blockFrame; } - const int k = dataFrame++; + // only incremented on output + const int k = dataFrame; DISTRHO_SAFE_ASSERT_INT2_RETURN(k < blockFrames, k, blockFrames,); - const float gain = numParams != 0 ? std::pow(params[0].getValue(), 2.f) : 1.0f; - // from host into cardinal, shows as output plug - if (dataIns != nullptr) + if (isBypassed()) + { + for (int i=0; idataOuts; + + const int blockFrames = pcontext->engine->getBlockFrames(); + + // only incremented on output + const int k = dataFrame++; + DISTRHO_SAFE_ASSERT_INT2_RETURN(k < blockFrames, k, blockFrames,); + + const float gain = numParams != 0 ? std::pow(params[0].getValue(), 2.f) : 1.0f; // from cardinal into host, shows as input plug - for (int i=0; i #include +#include #include #include #include @@ -49,12 +50,19 @@ #include "DistrhoUtils.hpp" + +// known terminal modules +extern rack::plugin::Model* modelHostAudio2; +extern rack::plugin::Model* modelHostAudio8; + + namespace rack { namespace engine { struct Engine::Internal { std::vector modules; + std::vector terminalModules; std::vector cables; std::set paramHandles; @@ -127,24 +135,64 @@ static void Cable_step(Cable* that) { const int channels = output->channels; // Copy all voltages from output to input for (int c = 0; c < channels; c++) { - float v = output->cvoltages[c]; + float v = output->voltages[c]; // Set 0V if infinite or NaN if (!std::isfinite(v)) v = 0.f; - input->cvoltages[c] = v; + input->voltages[c] = v; } // Set higher channel voltages to 0 for (int c = channels; c < input->channels; c++) { - input->cvoltages[c] = 0.f; + input->voltages[c] = 0.f; } input->channels = channels; } -void Port::stepCables() -{ - for (Cable* cable : cables) - Cable_step(cable); +static void Port_step(Port* that, float deltaTime) { + // Set plug lights + if (that->channels == 0) { + that->plugLights[0].setBrightness(0.f); + that->plugLights[1].setBrightness(0.f); + that->plugLights[2].setBrightness(0.f); + } + else if (that->channels == 1) { + float v = that->getVoltage() / 10.f; + that->plugLights[0].setSmoothBrightness(-v, deltaTime); + that->plugLights[1].setSmoothBrightness(v, deltaTime); + that->plugLights[2].setBrightness(0.f); + } + else { + float v = that->getVoltageRMS() / 10.f; + that->plugLights[0].setBrightness(0.f); + that->plugLights[1].setBrightness(0.f); + that->plugLights[2].setSmoothBrightness(v, deltaTime); + } +} + + +static void TerminalModule__doProcess(TerminalModule* terminalModule, const Module::ProcessArgs& args, bool input) { + // Step module + if (input) { + terminalModule->processTerminalInput(args); + for (Output& output : terminalModule->outputs) { + for (Cable* cable : output.cables) + Cable_step(cable); + } + } else { + terminalModule->processTerminalOutput(args); + } + + // Iterate ports to step plug lights + if (args.frame % 7 /* PORT_DIVIDER */ == 0) { + float portTime = args.sampleTime * 7 /* PORT_DIVIDER */; + for (Input& input : terminalModule->inputs) { + Port_step(&input, portTime); + } + for (Output& output : terminalModule->outputs) { + Port_step(&output, portTime); + } + } } @@ -174,14 +222,6 @@ static void Engine_stepFrame(Engine* that) { } } - /* NOTE this is likely not needed in Cardinal, but needs testing. - * Leaving it as comment in case we need it bring it back - // Step cables - for (Cable* cable : internal->cables) { - Cable_step(cable); - } - */ - // Flip messages for each module for (Module* module : internal->modules) { if (module->leftExpander.messageFlipRequested) { @@ -200,16 +240,25 @@ static void Engine_stepFrame(Engine* that) { processArgs.sampleTime = internal->sampleTime; processArgs.frame = internal->frame; - // Step each module + // Process terminal inputs first + for (TerminalModule* terminalModule : internal->terminalModules) { + TerminalModule__doProcess(terminalModule, processArgs, true); + } + + // Step each module and cables for (Module* module : internal->modules) { module->doProcess(processArgs); - // FIXME remove this section below after all modules can use zero-latency cable stuff for (Output& output : module->outputs) { for (Cable* cable : output.cables) Cable_step(cable); } } + // Process terminal outputs last + for (TerminalModule* terminalModule : internal->terminalModules) { + TerminalModule__doProcess(terminalModule, processArgs, false); + } + ++internal->frame; } @@ -217,7 +266,7 @@ static void Engine_stepFrame(Engine* that) { static void Port_setDisconnected(Port* that) { that->channels = 0; for (int c = 0; c < PORT_MAX_CHANNELS; c++) { - that->cvoltages[c] = 0.f; + that->voltages[c] = 0.f; } } @@ -240,6 +289,14 @@ static void Engine_updateConnected(Engine* that) { disconnectedPorts.insert(&output); } } + for (TerminalModule* terminalModule : that->internal->terminalModules) { + for (Input& input : terminalModule->inputs) { + disconnectedPorts.insert(&input); + } + for (Output& output : terminalModule->outputs) { + disconnectedPorts.insert(&output); + } + } for (Cable* cable : that->internal->cables) { // Connect input Input& input = cable->inputModule->inputs[cable->inputId]; @@ -287,6 +344,7 @@ Engine::~Engine() { // If this happens, a module must have failed to remove itself before the RackWidget was destroyed. DISTRHO_SAFE_ASSERT(internal->cables.empty()); DISTRHO_SAFE_ASSERT(internal->modules.empty()); + DISTRHO_SAFE_ASSERT(internal->terminalModules.empty()); DISTRHO_SAFE_ASSERT(internal->paramHandles.empty()); DISTRHO_SAFE_ASSERT(internal->modulesCache.empty()); @@ -320,6 +378,11 @@ void Engine::clear_NoLock() { removeModule_NoLock(module); delete module; } + std::vector terminalModules = internal->terminalModules; + for (TerminalModule* terminalModule : terminalModules) { + removeModule_NoLock(terminalModule); + delete terminalModule; + } } @@ -404,6 +467,9 @@ void Engine::setSampleRate(float sampleRate) { for (Module* module : internal->modules) { module->onSampleRateChange(e); } + for (TerminalModule* terminalModule : internal->terminalModules) { + terminalModule->onSampleRateChange(e); + } } @@ -474,7 +540,7 @@ double Engine::getMeterMax() { size_t Engine::getNumModules() { - return internal->modules.size(); + return internal->modules.size() + internal->terminalModules.size(); } @@ -484,8 +550,12 @@ size_t Engine::getModuleIds(int64_t* moduleIds, size_t len) { for (Module* m : internal->modules) { if (i >= len) break; - moduleIds[i] = m->id; - i++; + moduleIds[i++] = m->id; + } + for (TerminalModule* m : internal->terminalModules) { + if (i >= len) + break; + moduleIds[i++] = m->id; } return i; } @@ -494,27 +564,43 @@ size_t Engine::getModuleIds(int64_t* moduleIds, size_t len) { std::vector Engine::getModuleIds() { SharedLock lock(internal->mutex); std::vector moduleIds; - moduleIds.reserve(internal->modules.size()); + moduleIds.reserve(getNumModules()); for (Module* m : internal->modules) { moduleIds.push_back(m->id); } + for (TerminalModule* tm : internal->terminalModules) { + moduleIds.push_back(tm->id); + } return moduleIds; } +static TerminalModule* asTerminalModule(Module* const module) { + const plugin::Model* const model = module->model; + if (model == modelHostAudio2 || model == modelHostAudio8) + return static_cast(module); + return nullptr; +} + + void Engine::addModule(Module* module) { std::lock_guard lock(internal->mutex); - DISTRHO_SAFE_ASSERT_RETURN(module,); + DISTRHO_SAFE_ASSERT_RETURN(module != nullptr,); // Check that the module is not already added auto it = std::find(internal->modules.begin(), internal->modules.end(), module); DISTRHO_SAFE_ASSERT_RETURN(it == internal->modules.end(),); + auto tit = std::find(internal->terminalModules.begin(), internal->terminalModules.end(), module); + DISTRHO_SAFE_ASSERT_RETURN(tit == internal->terminalModules.end(),); // Set ID if unset or collides with an existing ID while (module->id < 0 || internal->modulesCache.find(module->id) != internal->modulesCache.end()) { // Randomly generate ID module->id = random::u64() % (1ull << 53); } // Add module - internal->modules.push_back(module); + if (TerminalModule* const terminalModule = asTerminalModule(module)) + internal->terminalModules.push_back(terminalModule); + else + internal->modules.push_back(module); internal->modulesCache[module->id] = module; // Dispatch AddEvent Module::AddEvent eAdd; @@ -538,11 +624,7 @@ void Engine::removeModule(Module* module) { } -void Engine::removeModule_NoLock(Module* module) { - DISTRHO_SAFE_ASSERT_RETURN(module,); - // Check that the module actually exists - auto it = std::find(internal->modules.begin(), internal->modules.end(), module); - DISTRHO_SAFE_ASSERT_RETURN(it != internal->modules.end(),); +static void removeModule_NoLock_common(Engine::Internal* internal, Module* module) { // Remove from widgets cache CardinalPluginModelHelper* const helper = dynamic_cast(module->model); DISTRHO_SAFE_ASSERT_RETURN(helper != nullptr,); @@ -575,14 +657,31 @@ void Engine::removeModule_NoLock(Module* module) { m->rightExpander.module = NULL; } } - // Remove module - internal->modulesCache.erase(module->id); - internal->modules.erase(it); // Reset expanders module->leftExpander.moduleId = -1; module->leftExpander.module = NULL; module->rightExpander.moduleId = -1; module->rightExpander.module = NULL; + // Remove module + internal->modulesCache.erase(module->id); +} + + +void Engine::removeModule_NoLock(Module* module) { + DISTRHO_SAFE_ASSERT_RETURN(module,); + // Check that the module actually exists + if (TerminalModule* const terminalModule = asTerminalModule(module)) { + auto tit = std::find(internal->terminalModules.begin(), internal->terminalModules.end(), terminalModule); + DISTRHO_SAFE_ASSERT_RETURN(tit != internal->terminalModules.end(),); + removeModule_NoLock_common(internal, module); + internal->terminalModules.erase(tit); + } + else { + auto it = std::find(internal->modules.begin(), internal->modules.end(), module); + DISTRHO_SAFE_ASSERT_RETURN(it != internal->modules.end(),); + removeModule_NoLock_common(internal, module); + internal->modules.erase(it); + } } @@ -590,7 +689,8 @@ bool Engine::hasModule(Module* module) { SharedLock lock(internal->mutex); // TODO Performance could be improved by searching modulesCache, but more testing would be needed to make sure it's always valid. auto it = std::find(internal->modules.begin(), internal->modules.end(), module); - return it != internal->modules.end(); + auto tit = std::find(internal->terminalModules.begin(), internal->terminalModules.end(), module); + return it != internal->modules.end() && tit != internal->terminalModules.end(); } @@ -678,6 +778,10 @@ void Engine::prepareSave() { Module::SaveEvent e; module->onSave(e); } + for (TerminalModule* terminalModule : internal->terminalModules) { + Module::SaveEvent e; + terminalModule->onSave(e); + } } @@ -957,6 +1061,10 @@ json_t* Engine::toJson() { json_t* moduleJ = module->toJson(); json_array_append_new(modulesJ, moduleJ); } + for (TerminalModule* terminalModule : internal->terminalModules) { + json_t* terminalModuleJ = terminalModule->toJson(); + json_array_append_new(modulesJ, terminalModuleJ); + } json_object_set_new(rootJ, "modules", modulesJ); // cables diff --git a/src/override/diffs/Engine.cpp.diff b/src/override/diffs/Engine.cpp.diff index c560172..ea0ba3b 100644 --- a/src/override/diffs/Engine.cpp.diff +++ b/src/override/diffs/Engine.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/engine/Engine.cpp 2022-01-15 14:44:46.395281005 +0000 -+++ Engine.cpp 2022-01-23 17:13:03.200930905 +0000 +--- ../Rack/src/engine/Engine.cpp 2022-02-05 22:30:09.253393116 +0000 ++++ Engine.cpp 2022-02-08 02:48:26.045085405 +0000 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin @@ -31,7 +31,11 @@ #include #include #include -@@ -11,178 +38,25 @@ +@@ -8,181 +35,36 @@ + #include + + #include ++#include #include #include #include @@ -40,17 +44,15 @@ #include #include +#include -+ + +#ifdef NDEBUG +# undef DEBUG +#endif -+#include "DistrhoUtils.hpp" - - namespace rack { - namespace engine { - - +-namespace rack { +-namespace engine { +- +- -static void initMXCSR() { - // Set CPU to flush-to-zero (FTZ) and denormals-are-zero (DAZ) mode - // https://software.intel.com/en-us/node/682949 @@ -107,7 +109,8 @@ - void setThreads(int threads) { - this->threads = threads; - } -- ++#include "DistrhoUtils.hpp" + - void wait() { - uint8_t s = step; - if (count.fetch_add(1, std::memory_order_acquire) + 1 >= threads) { @@ -126,8 +129,11 @@ - } - } -}; -- -- + ++// known terminal modules ++extern rack::plugin::Model* modelHostAudio2; ++extern rack::plugin::Model* modelHostAudio8; + -/** Barrier that spin-locks until yield() is called, and then all threads switch to a mutex. -yield() should be called if it is likely that all threads will block for a while and continuing to spin-lock is unnecessary. -Saves CPU power after yield is called. @@ -164,7 +170,7 @@ - } - return; - } -- + - // Spin until the last thread begins waiting - while (!yielded.load(std::memory_order_relaxed)) { - if (step.load(std::memory_order_relaxed) != s) @@ -206,17 +212,36 @@ - - void run(); -}; -- -- ++namespace rack { ++namespace engine { + + struct Engine::Internal { std::vector modules; ++ std::vector terminalModules; std::vector cables; std::set paramHandles; - Module* masterModule = NULL; // moduleId std::map modulesCache; -@@ -217,22 +91,6 @@ +@@ -199,6 +81,7 @@ + double blockTime = 0.0; + int blockFrames = 0; + ++#ifndef HEADLESS + // Meter + int meterCount = 0; + double meterTotal = 0.0; +@@ -206,6 +89,7 @@ + double meterLastTime = -INFINITY; + double meterLastAverage = 0.0; + double meterLastMax = 0.0; ++#endif + + // Parameter smoothing + Module* smoothModule = NULL; +@@ -217,22 +101,6 @@ Readers lock when using the engine's state. */ SharedMutex mutex; @@ -239,7 +264,7 @@ }; -@@ -260,71 +118,6 @@ +@@ -260,76 +128,11 @@ } @@ -311,22 +336,82 @@ static void Cable_step(Cable* that) { Output* output = &that->outputModule->outputs[that->outputId]; Input* input = &that->inputModule->inputs[that->inputId]; -@@ -373,12 +166,12 @@ - } + // Match number of polyphonic channels to output port +- int channels = output->channels; ++ const int channels = output->channels; + // Copy all voltages from output to input + for (int c = 0; c < channels; c++) { + float v = output->voltages[c]; +@@ -346,6 +149,53 @@ + } - // Step cables -- for (Cable* cable : that->internal->cables) { -+ for (Cable* cable : internal->cables) { - Cable_step(cable); + ++static void Port_step(Port* that, float deltaTime) { ++ // Set plug lights ++ if (that->channels == 0) { ++ that->plugLights[0].setBrightness(0.f); ++ that->plugLights[1].setBrightness(0.f); ++ that->plugLights[2].setBrightness(0.f); ++ } ++ else if (that->channels == 1) { ++ float v = that->getVoltage() / 10.f; ++ that->plugLights[0].setSmoothBrightness(-v, deltaTime); ++ that->plugLights[1].setSmoothBrightness(v, deltaTime); ++ that->plugLights[2].setBrightness(0.f); ++ } ++ else { ++ float v = that->getVoltageRMS() / 10.f; ++ that->plugLights[0].setBrightness(0.f); ++ that->plugLights[1].setBrightness(0.f); ++ that->plugLights[2].setSmoothBrightness(v, deltaTime); ++ } ++} ++ ++ ++static void TerminalModule__doProcess(TerminalModule* terminalModule, const Module::ProcessArgs& args, bool input) { ++ // Step module ++ if (input) { ++ terminalModule->processTerminalInput(args); ++ for (Output& output : terminalModule->outputs) { ++ for (Cable* cable : output.cables) ++ Cable_step(cable); ++ } ++ } else { ++ terminalModule->processTerminalOutput(args); ++ } ++ ++ // Iterate ports to step plug lights ++ if (args.frame % 7 /* PORT_DIVIDER */ == 0) { ++ float portTime = args.sampleTime * 7 /* PORT_DIVIDER */; ++ for (Input& input : terminalModule->inputs) { ++ Port_step(&input, portTime); ++ } ++ for (Output& output : terminalModule->outputs) { ++ Port_step(&output, portTime); ++ } ++ } ++} ++ ++ + /** Steps a single frame + */ + static void Engine_stepFrame(Engine* that) { +@@ -372,13 +222,8 @@ + } } +- // Step cables +- for (Cable* cable : that->internal->cables) { +- Cable_step(cable); +- } +- // Flip messages for each module - for (Module* module : that->internal->modules) { + for (Module* module : internal->modules) { if (module->leftExpander.messageFlipRequested) { std::swap(module->leftExpander.producerMessage, module->leftExpander.consumerMessage); module->leftExpander.messageFlipRequested = false; -@@ -389,13 +182,18 @@ +@@ -389,13 +234,32 @@ } } @@ -341,9 +426,23 @@ + processArgs.sampleTime = internal->sampleTime; + processArgs.frame = internal->frame; + -+ // Step each module ++ // Process terminal inputs first ++ for (TerminalModule* terminalModule : internal->terminalModules) { ++ TerminalModule__doProcess(terminalModule, processArgs, true); ++ } ++ ++ // Step each module and cables + for (Module* module : internal->modules) { + module->doProcess(processArgs); ++ for (Output& output : module->outputs) { ++ for (Cable* cable : output.cables) ++ Cable_step(cable); ++ } ++ } ++ ++ // Process terminal outputs last ++ for (TerminalModule* terminalModule : internal->terminalModules) { ++ TerminalModule__doProcess(terminalModule, processArgs, false); + } - internal->frame++; @@ -351,7 +450,30 @@ } -@@ -460,37 +258,22 @@ +@@ -425,6 +289,14 @@ + disconnectedPorts.insert(&output); + } + } ++ for (TerminalModule* terminalModule : that->internal->terminalModules) { ++ for (Input& input : terminalModule->inputs) { ++ disconnectedPorts.insert(&input); ++ } ++ for (Output& output : terminalModule->outputs) { ++ disconnectedPorts.insert(&output); ++ } ++ } + for (Cable* cable : that->internal->cables) { + // Connect input + Input& input = cable->inputModule->inputs[cable->inputId]; +@@ -442,6 +314,7 @@ + // Disconnect ports that have no cable + for (Port* port : disconnectedPorts) { + Port_setDisconnected(port); ++ DISTRHO_SAFE_ASSERT(port->cables.empty()); + } + } + +@@ -460,37 +333,23 @@ Engine::Engine() { internal = new Internal; @@ -388,6 +510,7 @@ - assert(internal->paramHandlesCache.empty()); + DISTRHO_SAFE_ASSERT(internal->cables.empty()); + DISTRHO_SAFE_ASSERT(internal->modules.empty()); ++ DISTRHO_SAFE_ASSERT(internal->terminalModules.empty()); + DISTRHO_SAFE_ASSERT(internal->paramHandles.empty()); + + DISTRHO_SAFE_ASSERT(internal->modulesCache.empty()); @@ -396,9 +519,23 @@ delete internal; } -@@ -526,11 +309,8 @@ +@@ -519,18 +378,22 @@ + removeModule_NoLock(module); + delete module; + } ++ std::vector terminalModules = internal->terminalModules; ++ for (TerminalModule* terminalModule : terminalModules) { ++ removeModule_NoLock(terminalModule); ++ delete terminalModule; ++ } + } + + + void Engine::stepBlock(int frames) { ++#ifndef HEADLESS // Start timer before locking double startTime = system::getTime(); ++#endif - std::lock_guard stepLock(internal->blockMutex); SharedLock lock(internal->mutex); @@ -408,7 +545,7 @@ random::init(); internal->blockFrame = internal->frame; -@@ -543,16 +323,11 @@ +@@ -543,18 +406,14 @@ Engine_updateExpander_NoLock(this, module, true); } @@ -424,14 +561,18 @@ - internal->block++; ++#ifndef HEADLESS // Stop timer -@@ -572,47 +347,19 @@ + double endTime = system::getTime(); + double meter = (endTime - startTime) / (frames * internal->sampleTime); +@@ -572,47 +431,20 @@ internal->meterTotal = 0.0; internal->meterMax = 0.0; } - - // Reset MXCSR back to original value - _mm_setcsr(csr); ++#endif } @@ -474,7 +615,14 @@ } -@@ -639,16 +386,6 @@ +@@ -635,20 +467,13 @@ + for (Module* module : internal->modules) { + module->onSampleRateChange(e); + } ++ for (TerminalModule* terminalModule : internal->terminalModules) { ++ terminalModule->onSampleRateChange(e); ++ } + } void Engine::setSuggestedSampleRate(float suggestedSampleRate) { @@ -491,7 +639,7 @@ } -@@ -658,7 +395,6 @@ +@@ -658,7 +483,6 @@ void Engine::yieldWorkers() { @@ -499,29 +647,106 @@ } -@@ -738,10 +474,10 @@ +@@ -698,17 +522,25 @@ + + + double Engine::getMeterAverage() { ++#ifndef HEADLESS + return internal->meterLastAverage; ++#else ++ return 0.0; ++#endif + } + + + double Engine::getMeterMax() { ++#ifndef HEADLESS + return internal->meterLastMax; ++#else ++ return 0.0; ++#endif + } + + + size_t Engine::getNumModules() { +- return internal->modules.size(); ++ return internal->modules.size() + internal->terminalModules.size(); + } + +@@ -718,8 +550,12 @@ + for (Module* m : internal->modules) { + if (i >= len) + break; +- moduleIds[i] = m->id; +- i++; ++ moduleIds[i++] = m->id; ++ } ++ for (TerminalModule* m : internal->terminalModules) { ++ if (i >= len) ++ break; ++ moduleIds[i++] = m->id; + } + return i; + } +@@ -728,27 +564,43 @@ + std::vector Engine::getModuleIds() { + SharedLock lock(internal->mutex); + std::vector moduleIds; +- moduleIds.reserve(internal->modules.size()); ++ moduleIds.reserve(getNumModules()); + for (Module* m : internal->modules) { + moduleIds.push_back(m->id); + } ++ for (TerminalModule* tm : internal->terminalModules) { ++ moduleIds.push_back(tm->id); ++ } + return moduleIds; + } + + ++static TerminalModule* asTerminalModule(Module* const module) { ++ const plugin::Model* const model = module->model; ++ if (model == modelHostAudio2 || model == modelHostAudio8) ++ return static_cast(module); ++ return nullptr; ++} ++ ++ void Engine::addModule(Module* module) { std::lock_guard lock(internal->mutex); - assert(module); -+ DISTRHO_SAFE_ASSERT_RETURN(module,); ++ DISTRHO_SAFE_ASSERT_RETURN(module != nullptr,); // Check that the module is not already added auto it = std::find(internal->modules.begin(), internal->modules.end(), module); - assert(it == internal->modules.end()); + DISTRHO_SAFE_ASSERT_RETURN(it == internal->modules.end(),); ++ auto tit = std::find(internal->terminalModules.begin(), internal->terminalModules.end(), module); ++ DISTRHO_SAFE_ASSERT_RETURN(tit == internal->terminalModules.end(),); // Set ID if unset or collides with an existing ID while (module->id < 0 || internal->modulesCache.find(module->id) != internal->modulesCache.end()) { // Randomly generate ID -@@ -773,10 +509,14 @@ + module->id = random::u64() % (1ull << 53); + } + // Add module +- internal->modules.push_back(module); ++ if (TerminalModule* const terminalModule = asTerminalModule(module)) ++ internal->terminalModules.push_back(terminalModule); ++ else ++ internal->modules.push_back(module); + internal->modulesCache[module->id] = module; + // Dispatch AddEvent + Module::AddEvent eAdd; +@@ -772,11 +624,11 @@ + } - void Engine::removeModule_NoLock(Module* module) { +-void Engine::removeModule_NoLock(Module* module) { - assert(module); -+ DISTRHO_SAFE_ASSERT_RETURN(module,); - // Check that the module actually exists - auto it = std::find(internal->modules.begin(), internal->modules.end(), module); +- // Check that the module actually exists +- auto it = std::find(internal->modules.begin(), internal->modules.end(), module); - assert(it != internal->modules.end()); -+ DISTRHO_SAFE_ASSERT_RETURN(it != internal->modules.end(),); ++static void removeModule_NoLock_common(Engine::Internal* internal, Module* module) { + // Remove from widgets cache + CardinalPluginModelHelper* const helper = dynamic_cast(module->model); + DISTRHO_SAFE_ASSERT_RETURN(helper != nullptr,); @@ -529,7 +754,7 @@ // Dispatch RemoveEvent Module::RemoveEvent eRemove; module->onRemove(eRemove); -@@ -785,18 +525,14 @@ +@@ -785,18 +637,14 @@ if (paramHandle->moduleId == module->id) paramHandle->module = NULL; } @@ -550,7 +775,52 @@ } // Update expanders of other modules for (Module* m : internal->modules) { -@@ -844,7 +580,7 @@ +@@ -809,14 +657,31 @@ + m->rightExpander.module = NULL; + } + } +- // Remove module +- internal->modulesCache.erase(module->id); +- internal->modules.erase(it); + // Reset expanders + module->leftExpander.moduleId = -1; + module->leftExpander.module = NULL; + module->rightExpander.moduleId = -1; + module->rightExpander.module = NULL; ++ // Remove module ++ internal->modulesCache.erase(module->id); ++} ++ ++ ++void Engine::removeModule_NoLock(Module* module) { ++ DISTRHO_SAFE_ASSERT_RETURN(module,); ++ // Check that the module actually exists ++ if (TerminalModule* const terminalModule = asTerminalModule(module)) { ++ auto tit = std::find(internal->terminalModules.begin(), internal->terminalModules.end(), terminalModule); ++ DISTRHO_SAFE_ASSERT_RETURN(tit != internal->terminalModules.end(),); ++ removeModule_NoLock_common(internal, module); ++ internal->terminalModules.erase(tit); ++ } ++ else { ++ auto it = std::find(internal->modules.begin(), internal->modules.end(), module); ++ DISTRHO_SAFE_ASSERT_RETURN(it != internal->modules.end(),); ++ removeModule_NoLock_common(internal, module); ++ internal->modules.erase(it); ++ } + } + + +@@ -824,7 +689,8 @@ + SharedLock lock(internal->mutex); + // TODO Performance could be improved by searching modulesCache, but more testing would be needed to make sure it's always valid. + auto it = std::find(internal->modules.begin(), internal->modules.end(), module); +- return it != internal->modules.end(); ++ auto tit = std::find(internal->terminalModules.begin(), internal->terminalModules.end(), module); ++ return it != internal->modules.end() && tit != internal->terminalModules.end(); + } + + +@@ -844,7 +710,7 @@ void Engine::resetModule(Module* module) { std::lock_guard lock(internal->mutex); @@ -559,7 +829,7 @@ Module::ResetEvent eReset; module->onReset(eReset); -@@ -853,7 +589,7 @@ +@@ -853,7 +719,7 @@ void Engine::randomizeModule(Module* module) { std::lock_guard lock(internal->mutex); @@ -568,7 +838,7 @@ Module::RandomizeEvent eRandomize; module->onRandomize(eRandomize); -@@ -861,7 +597,7 @@ +@@ -861,7 +727,7 @@ void Engine::bypassModule(Module* module, bool bypassed) { @@ -577,7 +847,18 @@ if (module->isBypassed() == bypassed) return; -@@ -946,16 +682,16 @@ +@@ -912,6 +778,10 @@ + Module::SaveEvent e; + module->onSave(e); + } ++ for (TerminalModule* terminalModule : internal->terminalModules) { ++ Module::SaveEvent e; ++ terminalModule->onSave(e); ++ } + } + + +@@ -946,16 +816,16 @@ void Engine::addCable(Cable* cable) { std::lock_guard lock(internal->mutex); @@ -599,7 +880,16 @@ // Get connected status of output, to decide whether we need to call a PortChangeEvent. // It's best to not trust `cable->outputModule->outputs[cable->outputId]->isConnected()` if (cable2->outputModule == cable->outputModule && cable2->outputId == cable->outputId) -@@ -996,10 +732,10 @@ +@@ -969,6 +839,8 @@ + // Add the cable + internal->cables.push_back(cable); + internal->cablesCache[cable->id] = cable; ++ // Add the cable's zero-latency shortcut ++ cable->outputModule->outputs[cable->outputId].cables.push_back(cable); + Engine_updateConnected(this); + // Dispatch input port event + { +@@ -996,10 +868,12 @@ void Engine::removeCable_NoLock(Cable* cable) { @@ -609,10 +899,12 @@ auto it = std::find(internal->cables.begin(), internal->cables.end(), cable); - assert(it != internal->cables.end()); + DISTRHO_SAFE_ASSERT_RETURN(it != internal->cables.end(),); ++ // Remove the cable's zero-latency shortcut ++ cable->outputModule->outputs[cable->outputId].cables.remove(cable); // Remove the cable internal->cablesCache.erase(cable->id); internal->cables.erase(it); -@@ -1085,11 +821,11 @@ +@@ -1085,11 +959,11 @@ std::lock_guard lock(internal->mutex); // New ParamHandles must be blank. // This means we don't have to refresh the cache. @@ -626,7 +918,7 @@ // Add it internal->paramHandles.insert(paramHandle); -@@ -1106,7 +842,7 @@ +@@ -1106,7 +980,7 @@ void Engine::removeParamHandle_NoLock(ParamHandle* paramHandle) { // Check that the ParamHandle is already added auto it = internal->paramHandles.find(paramHandle); @@ -635,7 +927,7 @@ // Remove it paramHandle->module = NULL; -@@ -1143,7 +879,7 @@ +@@ -1143,7 +1017,7 @@ void Engine::updateParamHandle_NoLock(ParamHandle* paramHandle, int64_t moduleId, int paramId, bool overwrite) { // Check that it exists auto it = internal->paramHandles.find(paramHandle); @@ -644,7 +936,18 @@ // Set IDs paramHandle->moduleId = moduleId; -@@ -1197,11 +933,6 @@ +@@ -1187,6 +1061,10 @@ + json_t* moduleJ = module->toJson(); + json_array_append_new(modulesJ, moduleJ); + } ++ for (TerminalModule* terminalModule : internal->terminalModules) { ++ json_t* terminalModuleJ = terminalModule->toJson(); ++ json_array_append_new(modulesJ, terminalModuleJ); ++ } + json_object_set_new(rootJ, "modules", modulesJ); + + // cables +@@ -1197,11 +1075,6 @@ } json_object_set_new(rootJ, "cables", cablesJ); @@ -656,7 +959,7 @@ return rootJ; } -@@ -1225,14 +956,20 @@ +@@ -1225,14 +1098,20 @@ } catch (Exception& e) { WARN("Cannot load model: %s", e.what()); @@ -681,7 +984,7 @@ try { // This doesn't need a lock because the Module is not added to the Engine yet. -@@ -1248,7 +985,8 @@ +@@ -1248,7 +1127,8 @@ } catch (Exception& e) { WARN("Cannot load module: %s", e.what()); @@ -691,7 +994,7 @@ delete module; continue; } -@@ -1285,67 +1023,10 @@ +@@ -1285,67 +1165,10 @@ continue; } } diff --git a/src/override/diffs/MenuBar.cpp.diff b/src/override/diffs/MenuBar.cpp.diff index 0a95461..ed37be2 100644 --- a/src/override/diffs/MenuBar.cpp.diff +++ b/src/override/diffs/MenuBar.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/app/MenuBar.cpp 2022-01-15 14:44:46.391280963 +0000 -+++ MenuBar.cpp 2022-01-24 11:25:15.507061204 +0000 +--- ../Rack/src/app/MenuBar.cpp 2022-02-05 22:30:09.233392896 +0000 ++++ MenuBar.cpp 2022-02-05 18:08:00.272028714 +0000 @@ -1,8 +1,33 @@ +/* + * DISTRHO Cardinal Plugin @@ -48,7 +48,7 @@ namespace rack { namespace app { -@@ -48,79 +78,75 @@ +@@ -48,79 +78,79 @@ }; @@ -103,25 +103,34 @@ - menu->addChild(createMenuItem("Save", RACK_MOD_CTRL_NAME "+S", []() { - APP->patch->saveDialog(); +- })); + // NOTE: will do nothing if path is empty, intentionally + patchUtils::saveDialog(APP->patch->path); + }, APP->patch->path.empty())); -+ + +- menu->addChild(createMenuItem("Save as", RACK_MOD_CTRL_NAME "+Shift+S", []() { +- APP->patch->saveAsDialog(); + menu->addChild(createMenuItem("Save as / Export...", RACK_MOD_CTRL_NAME "+Shift+S", []() { + patchUtils::saveAsDialog(); })); -- menu->addChild(createMenuItem("Save as", RACK_MOD_CTRL_NAME "+Shift+S", []() { -- APP->patch->saveAsDialog(); -- })); +- menu->addChild(createMenuItem("Save a copy", "", []() { +- APP->patch->saveAsDialog(false); ++ menu->addChild(createMenuItem("Export uncompressed json...", "", []() { ++ patchUtils::saveAsDialogUncompressed(); + })); + +- menu->addChild(createMenuItem("Revert", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+O", []() { +- APP->patch->revertDialog(); +- }, APP->patch->path == "")); +#ifdef HAVE_LIBLO + if (patchUtils::isRemoteConnected()) { + menu->addChild(createMenuItem("Deploy to MOD", "F7", []() { + patchUtils::deployToRemote(); + })); -- menu->addChild(createMenuItem("Save a copy", "", []() { -- APP->patch->saveAsDialog(false); +- menu->addChild(createMenuItem("Overwrite template", "", []() { +- APP->patch->saveTemplateDialog(); - })); + const bool autoDeploy = patchUtils::isRemoteAutoDeployed(); + menu->addChild(createCheckMenuItem("Auto deploy to MOD", "", @@ -129,19 +138,13 @@ + [=]() {patchUtils::setRemoteAutoDeploy(!autoDeploy);} + )); + } else { -+ menu->addChild(createMenuItem("Connect to MOD", "", [this]() { ++ menu->addChild(createMenuItem("Connect to MOD", "", []() { + patchUtils::connectToRemote(); + })); + } +#endif - - menu->addChild(createMenuItem("Revert", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+O", []() { -- APP->patch->revertDialog(); -- }, APP->patch->path == "")); -- -- menu->addChild(createMenuItem("Overwrite template", "", []() { -- APP->patch->saveTemplateDialog(); -- })); ++ ++ menu->addChild(createMenuItem("Revert", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+O", []() { + patchUtils::revertDialog(); + }, APP->patch->path.empty())); @@ -167,7 +170,7 @@ } }; -@@ -166,7 +192,7 @@ +@@ -166,7 +196,7 @@ menu->addChild(new ui::MenuSeparator); @@ -176,7 +179,7 @@ } }; -@@ -256,7 +282,7 @@ +@@ -256,7 +286,7 @@ return settings::cableTension; } float getDefaultValue() override { @@ -185,7 +188,7 @@ } float getDisplayValue() override { return getValue() * 100; -@@ -421,28 +447,9 @@ +@@ -421,28 +451,9 @@ haloBrightnessSlider->box.size.x = 250.0; menu->addChild(haloBrightnessSlider); @@ -215,7 +218,7 @@ static const std::vector knobModeLabels = { "Linear", -@@ -467,6 +474,21 @@ +@@ -467,6 +478,21 @@ menu->addChild(knobScrollSensitivitySlider); menu->addChild(createBoolPtrMenuItem("Lock module positions", "", &settings::lockModules)); @@ -237,7 +240,7 @@ } }; -@@ -476,47 +498,6 @@ +@@ -476,47 +502,6 @@ //////////////////// @@ -285,7 +288,7 @@ struct EngineButton : MenuButton { void onAction(const ActionEvent& e) override { ui::Menu* menu = createMenu(); -@@ -529,269 +510,6 @@ +@@ -529,269 +514,6 @@ menu->addChild(createMenuItem("Performance meters", cpuMeterText, [=]() { settings::cpuMeter ^= true; })); @@ -555,7 +558,7 @@ } }; -@@ -802,63 +520,24 @@ +@@ -802,63 +524,23 @@ struct HelpButton : MenuButton { @@ -614,17 +617,17 @@ - menu->addChild(createMenuLabel(APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION)); - } -+ menu->addChild(createMenuLabel(APP_EDITION + " " + APP_EDITION_NAME)); - +- - void step() override { - notification->box.pos = math::Vec(0, 0); - notification->visible = library::isAppUpdateAvailable(); - MenuButton::step(); ++ menu->addChild(createMenuLabel("Cardinal " + APP_EDITION + " " + CARDINAL_VERSION)); + menu->addChild(createMenuLabel("Rack " + APP_VERSION + " Compatible")); } }; -@@ -908,7 +587,9 @@ +@@ -908,7 +590,9 @@ struct MenuBar : widget::OpaqueWidget { MeterLabel* meterLabel; @@ -635,7 +638,7 @@ const float margin = 5; box.size.y = BND_WIDGET_HEIGHT + 2 * margin; -@@ -917,7 +598,7 @@ +@@ -917,7 +601,7 @@ layout->spacing = math::Vec(0, 0); addChild(layout); @@ -644,7 +647,7 @@ fileButton->text = "File"; layout->addChild(fileButton); -@@ -933,10 +614,6 @@ +@@ -933,10 +617,6 @@ engineButton->text = "Engine"; layout->addChild(engineButton); @@ -655,7 +658,7 @@ HelpButton* helpButton = new HelpButton; helpButton->text = "Help"; layout->addChild(helpButton); -@@ -971,7 +648,11 @@ +@@ -971,7 +651,11 @@ widget::Widget* createMenuBar() { diff --git a/src/override/diffs/Scene.cpp.diff b/src/override/diffs/Scene.cpp.diff index 6e3cad6..44a920c 100644 --- a/src/override/diffs/Scene.cpp.diff +++ b/src/override/diffs/Scene.cpp.diff @@ -1,5 +1,5 @@ --- ../Rack/src/app/Scene.cpp 2021-12-14 21:35:44.414568198 +0000 -+++ Scene.cpp 2022-01-26 18:47:48.006168325 +0000 ++++ Scene.cpp 2022-02-06 14:11:59.259830276 +0000 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin @@ -108,13 +108,13 @@ + + void onEnter(const EnterEvent& e) override { + glfwSetCursor(nullptr, (GLFWcursor*)0x1); -+ } -+ -+ void onLeave(const LeaveEvent& e) override { -+ glfwSetCursor(nullptr, nullptr); } - void onDragStart(const DragStartEvent& e) override { ++ void onLeave(const LeaveEvent& e) override { ++ glfwSetCursor(nullptr, nullptr); ++ } ++ + void onDragStart(const DragStartEvent&) override { size = APP->window->getSize(); } @@ -260,7 +260,23 @@ e.consume(this); } if (e.keyName == "z" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { -@@ -232,10 +326,8 @@ +@@ -220,10 +314,14 @@ + APP->scene->rackScroll->setZoom(std::pow(2.f, zoom)); + e.consume(this); + } +- if ((e.keyName == "0") && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { ++ if ((e.keyName == "0" || e.keyName == "1") && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { + APP->scene->rackScroll->setZoom(1.f); + e.consume(this); + } ++ if (e.keyName == "2" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { ++ APP->scene->rackScroll->setZoom(2.f); ++ e.consume(this); ++ } + if (e.key == GLFW_KEY_F1 && (e.mods & RACK_MOD_MASK) == 0) { + system::openBrowser("https://vcvrack.com/manual/"); + e.consume(this); +@@ -232,10 +330,8 @@ settings::cpuMeter ^= true; e.consume(this); } @@ -273,7 +289,7 @@ e.consume(this); } -@@ -326,13 +418,6 @@ +@@ -326,13 +422,6 @@ // Key commands that can be overridden by children if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { @@ -287,7 +303,7 @@ if (e.keyName == "v" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { rack->pasteClipboardAction(); e.consume(this); -@@ -351,7 +436,7 @@ +@@ -351,7 +440,7 @@ std::string extension = system::getExtension(path); if (extension == ".vcv") { @@ -296,7 +312,7 @@ e.consume(this); return; } -@@ -368,3 +453,73 @@ +@@ -368,3 +457,77 @@ } // namespace app } // namespace rack @@ -306,6 +322,7 @@ + + +bool connectToRemote() { ++#ifdef HAVE_LIBLO + rack::app::Scene::Internal* const internal = APP->scene->internal; + + if (internal->oscServer == nullptr) { @@ -321,6 +338,9 @@ + lo_address_free(addr); + + return true; ++#else ++ return false; ++#endif +} + + diff --git a/src/override/diffs/common.cpp.diff b/src/override/diffs/common.cpp.diff index 1437e5c..b7df75c 100644 --- a/src/override/diffs/common.cpp.diff +++ b/src/override/diffs/common.cpp.diff @@ -1,5 +1,5 @@ --- ../Rack/src/common.cpp 2021-11-23 19:57:23.719015894 +0000 -+++ common.cpp 2022-01-23 17:13:08.824652617 +0000 ++++ common.cpp 2022-01-31 13:24:14.558807713 +0000 @@ -1,6 +1,38 @@ +/* + * DISTRHO Cardinal Plugin diff --git a/src/override/diffs/context.cpp.diff b/src/override/diffs/context.cpp.diff index a499c66..72729b9 100644 --- a/src/override/diffs/context.cpp.diff +++ b/src/override/diffs/context.cpp.diff @@ -1,4 +1,4 @@ ---- ../Rack/src/context.cpp 2022-01-15 14:44:46.391280963 +0000 +--- ../Rack/src/context.cpp 2022-02-05 22:30:09.253393116 +0000 +++ context.cpp 2022-01-23 17:13:11.652514338 +0000 @@ -1,3 +1,30 @@ +/* diff --git a/src/override/diffs/plugin.cpp.diff b/src/override/diffs/plugin.cpp.diff index c394bce..73c7cb7 100644 --- a/src/override/diffs/plugin.cpp.diff +++ b/src/override/diffs/plugin.cpp.diff @@ -1,5 +1,5 @@ ---- ../Rack/src/plugin.cpp 2022-01-15 14:44:46.395281005 +0000 -+++ plugin.cpp 2022-01-24 20:38:11.436099651 +0000 +--- ../Rack/src/plugin.cpp 2022-02-05 22:30:09.265393248 +0000 ++++ plugin.cpp 2022-01-30 00:24:49.375329910 +0000 @@ -1,308 +1,40 @@ -#include -#include @@ -337,7 +337,7 @@ /** Given slug => fallback slug. Correctly handles bidirectional fallbacks. To request fallback slugs to be added to this list, open a GitHub issue. -@@ -352,6 +84,12 @@ +@@ -352,8 +84,19 @@ */ using PluginModuleSlug = std::tuple; static const std::map moduleSlugFallbacks = { @@ -345,12 +345,20 @@ + {{"Core", "AudioInterface"}, {"Cardinal", "HostAudio8"}}, + {{"Core", "AudioInterface16"}, {"Cardinal", "HostAudio8"}}, + {{"Core", "MIDIToCVInterface"}, {"Cardinal", "HostMIDI"}}, ++ {{"Core", "MIDICCToCVInterface"}, {"Cardinal", "HostMIDICC"}}, ++ {{"Core", "MIDITriggerToCVInterface"}, {"Cardinal", "HostMIDIGate"}}, + {{"Core", "CV-MIDI"}, {"Cardinal", "HostMIDI"}}, ++ {{"Core", "CV-CC"}, {"Cardinal", "HostMIDICC"}}, ++ {{"Core", "CV-Gate"}, {"Cardinal", "HostMIDIGate"}}, ++ {{"Core", "MIDI-Map"}, {"Cardinal", "HostMIDIMap"}}, + {{"Core", "Notes"}, {"Cardinal", "TextEditor"}}, ++ {{"Core", "Blank"}, {"Cardinal", "Blank"}}, {{"MindMeld-ShapeMasterPro", "ShapeMasterPro"}, {"MindMeldModular", "ShapeMaster"}}, - {{"MindMeldModular", "ShapeMaster"}, {"MindMeld-ShapeMasterPro", "ShapeMasterPro"}}, +- {{"MindMeldModular", "ShapeMaster"}, {"MindMeld-ShapeMasterPro", "ShapeMasterPro"}}, // {{"", ""}, {"", ""}}, -@@ -441,7 +179,6 @@ + }; + +@@ -441,7 +184,6 @@ }