Browse Source

Alternative approach to zero-latency cables; Update patches

Signed-off-by: falkTX <falktx@falktx.com>
tags/22.02
falkTX 3 years ago
parent
commit
0000456cf5
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
12 changed files with 659 additions and 189 deletions
  1. +15
    -39
      include/engine/Port.hpp
  2. +31
    -0
      include/engine/TerminalModule.hpp
  3. +1
    -1
      plugins/Bidoo
  4. +36
    -16
      plugins/Cardinal/src/HostAudio.cpp
  5. +1
    -0
      plugins/Cardinal/src/plugin.hpp
  6. +141
    -33
      src/override/Engine.cpp
  7. +356
    -53
      src/override/diffs/Engine.cpp.diff
  8. +34
    -31
      src/override/diffs/MenuBar.cpp.diff
  9. +29
    -9
      src/override/diffs/Scene.cpp.diff
  10. +1
    -1
      src/override/diffs/common.cpp.diff
  11. +1
    -1
      src/override/diffs/context.cpp.diff
  12. +13
    -5
      src/override/diffs/plugin.cpp.diff

+ 15
- 39
include/engine/Port.hpp View File

@@ -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<Cable*> 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 <typename T>
T getVoltageSimd(int firstChannel) {
return T::load(&cvoltages[firstChannel]);
return T::load(&voltages[firstChannel]);
}

template <typename T>
@@ -204,8 +181,7 @@ struct Port {

template <typename T>
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) {


+ 31
- 0
include/engine/TerminalModule.hpp View File

@@ -0,0 +1,31 @@
/*
* DISTRHO Cardinal Plugin
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
*
* 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 <engine/Module.hpp>

namespace rack {
namespace engine {

struct TerminalModule : Module {
virtual void processTerminalInput(const ProcessArgs& args) = 0;
virtual void processTerminalOutput(const ProcessArgs& args) = 0;
};

}
}

+ 1
- 1
plugins/Bidoo

@@ -1 +1 @@
Subproject commit 988c2372a95d163b71d04b217080e612b767c539
Subproject commit e55fcd2e1d7c0fef69d4919baac6f791172c89ca

+ 36
- 16
plugins/Cardinal/src/HostAudio.cpp View File

@@ -24,7 +24,7 @@
USE_NAMESPACE_DISTRHO;

template<int numIO>
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; i<numOutputs; ++i)
outputs[i].setVoltage(0.0f);
}
else if (dataIns != nullptr)
{
for (int i=0; i<numOutputs; ++i)
outputs[i].setVoltage(dataIns[i][k] * 10.0f);
}
}

void processTerminalOutput(const ProcessArgs&) override
{
float** const dataOuts = pcontext->dataOuts;

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<numInputs; ++i)
if (! isBypassed())
{
float v = inputs[i].getVoltageSum() * 0.1f;

// Apply DC filter
if (dcFilterEnabled)
for (int i=0; i<numInputs; ++i)
{
dcFilters[i].process(v);
v = dcFilters[i].highpass();
}
float v = inputs[i].getVoltageSum() * 0.1f;

dataOuts[i][k] += clamp(v * gain, -1.0f, 1.0f);
// Apply DC filter
if (dcFilterEnabled)
{
dcFilters[i].process(v);
v = dcFilters[i].highpass();
}

dataOuts[i][k] += clamp(v * gain, -1.0f, 1.0f);
}
}

if (numInputs == 2)


+ 1
- 0
plugins/Cardinal/src/plugin.hpp View File

@@ -18,6 +18,7 @@
#pragma once

#include "rack.hpp"
#include "engine/TerminalModule.hpp"

#ifdef NDEBUG
# undef DEBUG


+ 141
- 33
src/override/Engine.cpp View File

@@ -35,6 +35,7 @@
#include <pmmintrin.h>

#include <engine/Engine.hpp>
#include <engine/TerminalModule.hpp>
#include <settings.hpp>
#include <system.hpp>
#include <random.hpp>
@@ -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<Module*> modules;
std::vector<TerminalModule*> terminalModules;
std::vector<Cable*> cables;
std::set<ParamHandle*> 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<TerminalModule*> 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<int64_t> Engine::getModuleIds() {
SharedLock<SharedMutex> lock(internal->mutex);
std::vector<int64_t> 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<TerminalModule*>(module);
return nullptr;
}


void Engine::addModule(Module* module) {
std::lock_guard<SharedMutex> 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<CardinalPluginModelHelper*>(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<SharedMutex> 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


+ 356
- 53
src/override/diffs/Engine.cpp.diff View File

@@ -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 <algorithm>
#include <set>
#include <thread>
@@ -11,178 +38,25 @@
@@ -8,181 +35,36 @@
#include <pmmintrin.h>
#include <engine/Engine.hpp>
+#include <engine/TerminalModule.hpp>
#include <settings.hpp>
#include <system.hpp>
#include <random.hpp>
@@ -40,17 +44,15 @@
#include <plugin.hpp>
#include <mutex.hpp>
+#include <helpers.hpp>
+
+#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<Module*> modules;
+ std::vector<TerminalModule*> terminalModules;
std::vector<Cable*> cables;
std::set<ParamHandle*> paramHandles;
- Module* masterModule = NULL;
// moduleId
std::map<int64_t, Module*> 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<TerminalModule*> 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<std::mutex> stepLock(internal->blockMutex);
SharedLock<SharedMutex> 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<int64_t> Engine::getModuleIds() {
SharedLock<SharedMutex> lock(internal->mutex);
std::vector<int64_t> 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<TerminalModule*>(module);
+ return nullptr;
+}
+
+
void Engine::addModule(Module* module) {
std::lock_guard<SharedMutex> 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<CardinalPluginModelHelper*>(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<SharedMutex> 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<SharedMutex> 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<SharedMutex> 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<SharedMutex> 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<SharedMutex> 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;
}
}


+ 34
- 31
src/override/diffs/MenuBar.cpp.diff View File

@@ -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<std::string> 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() {


+ 29
- 9
src/override/diffs/Scene.cpp.diff View File

@@ -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
+}
+
+


+ 1
- 1
src/override/diffs/common.cpp.diff View File

@@ -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


+ 1
- 1
src/override/diffs/context.cpp.diff View File

@@ -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 @@
+/*


+ 13
- 5
src/override/diffs/plugin.cpp.diff View File

@@ -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 <thread>
-#include <map>
@@ -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<std::string, std::string>;
static const std::map<PluginModuleSlug, PluginModuleSlug> 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 @@
}


Loading…
Cancel
Save