Add diffs for the overriden files

Signed-off-by: falkTX <falktx@falktx.com>
This commit is contained in:
falkTX 2022-01-23 17:19:14 +00:00
parent 2c3867ca6a
commit 810928190c
No known key found for this signature in database
GPG key ID: CDBAA37ABC74FBA0
9 changed files with 3047 additions and 0 deletions

12
src/override/.generate-diffs.sh Executable file
View file

@ -0,0 +1,12 @@
#!/bin/bash
set -e
diff -U3 ../Rack/dep/oui-blendish/blendish.c blendish.c > diffs/blendish.c.diff
diff -U3 ../Rack/src/common.cpp common.cpp > diffs/common.cpp.diff
diff -U3 ../Rack/src/context.cpp context.cpp > diffs/context.cpp.diff
diff -U3 ../Rack/src/app/MenuBar.cpp MenuBar.cpp > diffs/MenuBar.cpp.diff
diff -U3 ../Rack/src/app/Scene.cpp Scene.cpp > diffs/Scene.cpp.diff
diff -U3 ../Rack/src/engine/Engine.cpp Engine.cpp > diffs/Engine.cpp.diff
diff -U3 ../Rack/src/plugin/Model.cpp Model.cpp > diffs/Model.cpp.diff
diff -U3 ../Rack/src/window/Window.cpp Window.cpp > diffs/Window.cpp.diff

View file

@ -0,0 +1,761 @@
--- ../Rack/src/engine/Engine.cpp 2022-01-15 14:44:46.395281005 +0000
+++ Engine.cpp 2022-01-23 17:13:03.200930905 +0000
@@ -1,3 +1,30 @@
+/*
+ * 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.
+ */
+
+/**
+ * This file is an edited version of VCVRack's engine/Engine.cpp
+ * Copyright (C) 2016-2021 VCV.
+ *
+ * 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 (at your option) any later version.
+ */
+
#include <algorithm>
#include <set>
#include <thread>
@@ -11,178 +38,25 @@
#include <settings.hpp>
#include <system.hpp>
#include <random.hpp>
-#include <context.hpp>
#include <patch.hpp>
#include <plugin.hpp>
#include <mutex.hpp>
+#include <helpers.hpp>
+
+#ifdef NDEBUG
+# undef DEBUG
+#endif
+#include "DistrhoUtils.hpp"
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
- _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
- _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
- // Reset other flags
- _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST);
-}
-
-
-/** Barrier based on mutexes.
-Not finished or tested, do not use.
-*/
-struct Barrier {
- int count = 0;
- uint8_t step = 0;
- int threads = 0;
-
- std::mutex mutex;
- std::condition_variable cv;
-
- void setThreads(int threads) {
- this->threads = threads;
- }
-
- void wait() {
- std::unique_lock<std::mutex> lock(mutex);
- uint8_t s = step;
- if (++count >= threads) {
- // We're the last thread. Reset next phase.
- count = 0;
- // Allow other threads to exit wait()
- step++;
- cv.notify_all();
- return;
- }
-
- cv.wait(lock, [&] {
- return step != s;
- });
- }
-};
-
-
-/** 2-phase barrier based on spin-locking.
-*/
-struct SpinBarrier {
- std::atomic<int> count{0};
- std::atomic<uint8_t> step{0};
- int threads = 0;
-
- /** Must be called when no threads are calling wait().
- */
- void setThreads(int threads) {
- this->threads = threads;
- }
-
- void wait() {
- uint8_t s = step;
- if (count.fetch_add(1, std::memory_order_acquire) + 1 >= threads) {
- // We're the last thread. Reset next phase.
- count = 0;
- // Allow other threads to exit wait()
- step++;
- return;
- }
-
- // Spin until the last thread begins waiting
- while (true) {
- if (step.load(std::memory_order_relaxed) != s)
- return;
- __builtin_ia32_pause();
- }
- }
-};
-
-
-/** 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.
-*/
-struct HybridBarrier {
- std::atomic<int> count{0};
- std::atomic<uint8_t> step{0};
- int threads = 0;
-
- std::atomic<bool> yielded{false};
- std::mutex mutex;
- std::condition_variable cv;
-
- void setThreads(int threads) {
- this->threads = threads;
- }
-
- void yield() {
- yielded = true;
- }
-
- void wait() {
- uint8_t s = step;
- if (count.fetch_add(1, std::memory_order_acquire) + 1 >= threads) {
- // We're the last thread. Reset next phase.
- count = 0;
- bool wasYielded = yielded;
- yielded = false;
- // Allow other threads to exit wait()
- step++;
- if (wasYielded) {
- std::unique_lock<std::mutex> lock(mutex);
- cv.notify_all();
- }
- return;
- }
-
- // Spin until the last thread begins waiting
- while (!yielded.load(std::memory_order_relaxed)) {
- if (step.load(std::memory_order_relaxed) != s)
- return;
- __builtin_ia32_pause();
- }
-
- // Wait on mutex CV
- std::unique_lock<std::mutex> lock(mutex);
- cv.wait(lock, [&] {
- return step != s;
- });
- }
-};
-
-
-struct EngineWorker {
- Engine* engine;
- int id;
- std::thread thread;
- bool running = false;
-
- void start() {
- assert(!running);
- running = true;
- thread = std::thread([&] {
- run();
- });
- }
-
- void requestStop() {
- running = false;
- }
-
- void join() {
- assert(thread.joinable());
- thread.join();
- }
-
- void run();
-};
-
-
struct Engine::Internal {
std::vector<Module*> modules;
std::vector<Cable*> cables;
std::set<ParamHandle*> paramHandles;
- Module* masterModule = NULL;
// moduleId
std::map<int64_t, Module*> modulesCache;
@@ -217,22 +91,6 @@
Readers lock when using the engine's state.
*/
SharedMutex mutex;
- /** Mutex that guards stepBlock() so it's not called simultaneously.
- */
- std::mutex blockMutex;
-
- int threadCount = 0;
- std::vector<EngineWorker> workers;
- HybridBarrier engineBarrier;
- HybridBarrier workerBarrier;
- std::atomic<int> workerModuleIndex;
- // For worker threads
- Context* context;
-
- bool fallbackRunning = false;
- std::thread fallbackThread;
- std::mutex fallbackMutex;
- std::condition_variable fallbackCv;
};
@@ -260,71 +118,6 @@
}
-static void Engine_relaunchWorkers(Engine* that, int threadCount) {
- Engine::Internal* internal = that->internal;
- if (threadCount == internal->threadCount)
- return;
-
- if (internal->threadCount > 0) {
- // Stop engine workers
- for (EngineWorker& worker : internal->workers) {
- worker.requestStop();
- }
- internal->engineBarrier.wait();
-
- // Join and destroy engine workers
- for (EngineWorker& worker : internal->workers) {
- worker.join();
- }
- internal->workers.resize(0);
- }
-
- // Configure engine
- internal->threadCount = threadCount;
-
- // Set barrier counts
- internal->engineBarrier.setThreads(threadCount);
- internal->workerBarrier.setThreads(threadCount);
-
- if (threadCount > 0) {
- // Create and start engine workers
- internal->workers.resize(threadCount - 1);
- for (int id = 1; id < threadCount; id++) {
- EngineWorker& worker = internal->workers[id - 1];
- worker.id = id;
- worker.engine = that;
- worker.start();
- }
- }
-}
-
-
-static void Engine_stepWorker(Engine* that, int threadId) {
- Engine::Internal* internal = that->internal;
-
- // int threadCount = internal->threadCount;
- int modulesLen = internal->modules.size();
-
- // Build ProcessArgs
- Module::ProcessArgs processArgs;
- processArgs.sampleRate = internal->sampleRate;
- processArgs.sampleTime = internal->sampleTime;
- processArgs.frame = internal->frame;
-
- // Step each module
- while (true) {
- // Choose next module
- // First-come-first serve module-to-thread allocation algorithm
- int i = internal->workerModuleIndex++;
- if (i >= modulesLen)
- break;
-
- Module* module = internal->modules[i];
- module->doProcess(processArgs);
- }
-}
-
-
static void Cable_step(Cable* that) {
Output* output = &that->outputModule->outputs[that->outputId];
Input* input = &that->inputModule->inputs[that->inputId];
@@ -373,12 +166,12 @@
}
// Step cables
- for (Cable* cable : that->internal->cables) {
+ for (Cable* cable : 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 @@
}
}
- // Step modules along with workers
- internal->workerModuleIndex = 0;
- internal->engineBarrier.wait();
- Engine_stepWorker(that, 0);
- internal->workerBarrier.wait();
+ // Build ProcessArgs
+ Module::ProcessArgs processArgs;
+ processArgs.sampleRate = internal->sampleRate;
+ processArgs.sampleTime = internal->sampleTime;
+ processArgs.frame = internal->frame;
+
+ // Step each module
+ for (Module* module : internal->modules) {
+ module->doProcess(processArgs);
+ }
- internal->frame++;
+ ++internal->frame;
}
@@ -460,37 +258,22 @@
Engine::Engine() {
internal = new Internal;
-
- internal->context = contextGet();
- setSuggestedSampleRate(0.f);
}
Engine::~Engine() {
- // Stop fallback thread if running
- {
- std::lock_guard<std::mutex> lock(internal->fallbackMutex);
- internal->fallbackRunning = false;
- internal->fallbackCv.notify_all();
- }
- if (internal->fallbackThread.joinable())
- internal->fallbackThread.join();
-
- // Shut down workers
- Engine_relaunchWorkers(this, 0);
-
// Clear modules, cables, etc
clear();
// Make sure there are no cables or modules in the rack on destruction.
// If this happens, a module must have failed to remove itself before the RackWidget was destroyed.
- assert(internal->cables.empty());
- assert(internal->modules.empty());
- assert(internal->paramHandles.empty());
-
- assert(internal->modulesCache.empty());
- assert(internal->cablesCache.empty());
- assert(internal->paramHandlesCache.empty());
+ DISTRHO_SAFE_ASSERT(internal->cables.empty());
+ DISTRHO_SAFE_ASSERT(internal->modules.empty());
+ DISTRHO_SAFE_ASSERT(internal->paramHandles.empty());
+
+ DISTRHO_SAFE_ASSERT(internal->modulesCache.empty());
+ DISTRHO_SAFE_ASSERT(internal->cablesCache.empty());
+ DISTRHO_SAFE_ASSERT(internal->paramHandlesCache.empty());
delete internal;
}
@@ -526,11 +309,8 @@
// Start timer before locking
double startTime = system::getTime();
- std::lock_guard<std::mutex> stepLock(internal->blockMutex);
SharedLock<SharedMutex> lock(internal->mutex);
// Configure thread
- uint32_t csr = _mm_getcsr();
- initMXCSR();
random::init();
internal->blockFrame = internal->frame;
@@ -543,16 +323,11 @@
Engine_updateExpander_NoLock(this, module, true);
}
- // Launch workers
- Engine_relaunchWorkers(this, settings::threadCount);
-
// Step individual frames
for (int i = 0; i < frames; i++) {
Engine_stepFrame(this);
}
- yieldWorkers();
-
internal->block++;
// Stop timer
@@ -572,47 +347,19 @@
internal->meterTotal = 0.0;
internal->meterMax = 0.0;
}
-
- // Reset MXCSR back to original value
- _mm_setcsr(csr);
}
void Engine::setMasterModule(Module* module) {
- if (module == internal->masterModule)
- return;
- std::lock_guard<SharedMutex> lock(internal->mutex);
- setMasterModule_NoLock(module);
}
void Engine::setMasterModule_NoLock(Module* module) {
- if (module == internal->masterModule)
- return;
-
- if (internal->masterModule) {
- // Dispatch UnsetMasterEvent
- Module::UnsetMasterEvent e;
- internal->masterModule->onUnsetMaster(e);
- }
-
- internal->masterModule = module;
-
- if (internal->masterModule) {
- // Dispatch SetMasterEvent
- Module::SetMasterEvent e;
- internal->masterModule->onSetMaster(e);
- }
-
- // Wake up fallback thread if master module was unset
- if (!internal->masterModule) {
- internal->fallbackCv.notify_all();
- }
}
Module* Engine::getMasterModule() {
- return internal->masterModule;
+ return nullptr;
}
@@ -639,16 +386,6 @@
void Engine::setSuggestedSampleRate(float suggestedSampleRate) {
- if (settings::sampleRate > 0) {
- setSampleRate(settings::sampleRate);
- }
- else if (suggestedSampleRate > 0) {
- setSampleRate(suggestedSampleRate);
- }
- else {
- // Fallback sample rate
- setSampleRate(44100.f);
- }
}
@@ -658,7 +395,6 @@
void Engine::yieldWorkers() {
- internal->workerBarrier.yield();
}
@@ -738,10 +474,10 @@
void Engine::addModule(Module* module) {
std::lock_guard<SharedMutex> lock(internal->mutex);
- assert(module);
+ DISTRHO_SAFE_ASSERT_RETURN(module,);
// 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(),);
// 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 @@
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);
- assert(it != internal->modules.end());
+ DISTRHO_SAFE_ASSERT_RETURN(it != internal->modules.end(),);
+ // Remove from widgets cache
+ CardinalPluginModelHelper* const helper = dynamic_cast<CardinalPluginModelHelper*>(module->model);
+ DISTRHO_SAFE_ASSERT_RETURN(helper != nullptr,);
+ helper->removeCachedModuleWidget(module);
// Dispatch RemoveEvent
Module::RemoveEvent eRemove;
module->onRemove(eRemove);
@@ -785,18 +525,14 @@
if (paramHandle->moduleId == module->id)
paramHandle->module = NULL;
}
- // Unset master module
- if (getMasterModule() == module) {
- setMasterModule_NoLock(NULL);
- }
// If a param is being smoothed on this module, stop smoothing it immediately
if (module == internal->smoothModule) {
internal->smoothModule = NULL;
}
// Check that all cables are disconnected
for (Cable* cable : internal->cables) {
- assert(cable->inputModule != module);
- assert(cable->outputModule != module);
+ DISTRHO_SAFE_ASSERT(cable->inputModule != module);
+ DISTRHO_SAFE_ASSERT(cable->outputModule != module);
}
// Update expanders of other modules
for (Module* m : internal->modules) {
@@ -844,7 +580,7 @@
void Engine::resetModule(Module* module) {
std::lock_guard<SharedMutex> lock(internal->mutex);
- assert(module);
+ DISTRHO_SAFE_ASSERT_RETURN(module,);
Module::ResetEvent eReset;
module->onReset(eReset);
@@ -853,7 +589,7 @@
void Engine::randomizeModule(Module* module) {
std::lock_guard<SharedMutex> lock(internal->mutex);
- assert(module);
+ DISTRHO_SAFE_ASSERT_RETURN(module,);
Module::RandomizeEvent eRandomize;
module->onRandomize(eRandomize);
@@ -861,7 +597,7 @@
void Engine::bypassModule(Module* module, bool bypassed) {
- assert(module);
+ DISTRHO_SAFE_ASSERT_RETURN(module,);
if (module->isBypassed() == bypassed)
return;
@@ -946,16 +682,16 @@
void Engine::addCable(Cable* cable) {
std::lock_guard<SharedMutex> lock(internal->mutex);
- assert(cable);
+ DISTRHO_SAFE_ASSERT_RETURN(cable,);
// Check cable properties
- assert(cable->inputModule);
- assert(cable->outputModule);
+ DISTRHO_SAFE_ASSERT_RETURN(cable->inputModule,);
+ DISTRHO_SAFE_ASSERT_RETURN(cable->outputModule,);
bool outputWasConnected = false;
for (Cable* cable2 : internal->cables) {
// Check that the cable is not already added
- assert(cable2 != cable);
+ DISTRHO_SAFE_ASSERT_RETURN(cable2 != cable,);
// Check that the input is not already used by another cable
- assert(!(cable2->inputModule == cable->inputModule && cable2->inputId == cable->inputId));
+ DISTRHO_SAFE_ASSERT_RETURN(!(cable2->inputModule == cable->inputModule && cable2->inputId == cable->inputId),);
// 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 @@
void Engine::removeCable_NoLock(Cable* cable) {
- assert(cable);
+ DISTRHO_SAFE_ASSERT_RETURN(cable,);
// Check that the cable is already added
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
internal->cablesCache.erase(cable->id);
internal->cables.erase(it);
@@ -1085,11 +821,11 @@
std::lock_guard<SharedMutex> lock(internal->mutex);
// New ParamHandles must be blank.
// This means we don't have to refresh the cache.
- assert(paramHandle->moduleId < 0);
+ DISTRHO_SAFE_ASSERT_RETURN(paramHandle->moduleId < 0,);
// Check that the ParamHandle is not already added
auto it = internal->paramHandles.find(paramHandle);
- assert(it == internal->paramHandles.end());
+ DISTRHO_SAFE_ASSERT_RETURN(it == internal->paramHandles.end(),);
// Add it
internal->paramHandles.insert(paramHandle);
@@ -1106,7 +842,7 @@
void Engine::removeParamHandle_NoLock(ParamHandle* paramHandle) {
// Check that the ParamHandle is already added
auto it = internal->paramHandles.find(paramHandle);
- assert(it != internal->paramHandles.end());
+ DISTRHO_SAFE_ASSERT_RETURN(it != internal->paramHandles.end(),);
// Remove it
paramHandle->module = NULL;
@@ -1143,7 +879,7 @@
void Engine::updateParamHandle_NoLock(ParamHandle* paramHandle, int64_t moduleId, int paramId, bool overwrite) {
// Check that it exists
auto it = internal->paramHandles.find(paramHandle);
- assert(it != internal->paramHandles.end());
+ DISTRHO_SAFE_ASSERT_RETURN(it != internal->paramHandles.end(),);
// Set IDs
paramHandle->moduleId = moduleId;
@@ -1197,11 +933,6 @@
}
json_object_set_new(rootJ, "cables", cablesJ);
- // masterModule
- if (internal->masterModule) {
- json_object_set_new(rootJ, "masterModuleId", json_integer(internal->masterModule->id));
- }
-
return rootJ;
}
@@ -1225,14 +956,20 @@
}
catch (Exception& e) {
WARN("Cannot load model: %s", e.what());
- APP->patch->log(e.what());
+ // APP->patch->log(e.what());
continue;
}
// Create module
- INFO("Creating module %s", model->getFullName().c_str());
- Module* module = model->createModule();
- assert(module);
+ Module* const module = model->createModule();
+ DISTRHO_SAFE_ASSERT_CONTINUE(module != nullptr);
+
+ // Create the widget too, needed by a few modules
+ CardinalPluginModelHelper* const helper = dynamic_cast<CardinalPluginModelHelper*>(model);
+ DISTRHO_SAFE_ASSERT_CONTINUE(helper != nullptr);
+
+ app::ModuleWidget* const moduleWidget = helper->createModuleWidgetFromEngineLoad(module);
+ DISTRHO_SAFE_ASSERT_CONTINUE(moduleWidget != nullptr);
try {
// This doesn't need a lock because the Module is not added to the Engine yet.
@@ -1248,7 +985,8 @@
}
catch (Exception& e) {
WARN("Cannot load module: %s", e.what());
- APP->patch->log(e.what());
+ // APP->patch->log(e.what());
+ helper->removeCachedModuleWidget(module);
delete module;
continue;
}
@@ -1285,67 +1023,10 @@
continue;
}
}
-
- // masterModule
- json_t* masterModuleIdJ = json_object_get(rootJ, "masterModuleId");
- if (masterModuleIdJ) {
- Module* masterModule = getModule(json_integer_value(masterModuleIdJ));
- setMasterModule(masterModule);
- }
-}
-
-
-void EngineWorker::run() {
- // Configure thread
- contextSet(engine->internal->context);
- system::setThreadName(string::f("Worker %d", id));
- initMXCSR();
- random::init();
-
- while (true) {
- engine->internal->engineBarrier.wait();
- if (!running)
- return;
- Engine_stepWorker(engine, id);
- engine->internal->workerBarrier.wait();
- }
-}
-
-
-static void Engine_fallbackRun(Engine* that) {
- system::setThreadName("Engine fallback");
- contextSet(that->internal->context);
-
- while (that->internal->fallbackRunning) {
- if (!that->getMasterModule()) {
- // Step blocks and wait
- double start = system::getTime();
- int frames = std::floor(that->getSampleRate() / 60);
- that->stepBlock(frames);
- double end = system::getTime();
-
- double duration = frames * that->getSampleTime() - (end - start);
- if (duration > 0.0) {
- std::this_thread::sleep_for(std::chrono::duration<double>(duration));
- }
- }
- else {
- // Wait for master module to be unset, or for the request to stop running
- std::unique_lock<std::mutex> lock(that->internal->fallbackMutex);
- that->internal->fallbackCv.wait(lock, [&]() {
- return !that->internal->fallbackRunning || !that->getMasterModule();
- });
- }
- }
}
void Engine::startFallbackThread() {
- if (internal->fallbackThread.joinable())
- return;
-
- internal->fallbackRunning = true;
- internal->fallbackThread = std::thread(Engine_fallbackRun, this);
}

View file

@ -0,0 +1,704 @@
--- ../Rack/src/app/MenuBar.cpp 2022-01-15 14:44:46.391280963 +0000
+++ MenuBar.cpp 2022-01-23 17:13:16.500279828 +0000
@@ -1,8 +1,33 @@
+/*
+ * 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.
+ */
+
+/**
+ * This file is an edited version of VCVRack's app/MenuBar.cpp
+ * Copyright (C) 2016-2021 VCV.
+ *
+ * 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 (at your option) any later version.
+ */
+
#include <thread>
#include <utility>
-#include <osdialog.h>
-
#include <app/MenuBar.hpp>
#include <app/TipWindow.hpp>
#include <widget/OpaqueWidget.hpp>
@@ -25,6 +50,11 @@
#include <patch.hpp>
#include <library.hpp>
+#ifdef HAVE_LIBLO
+# include <lo/lo.h>
+#endif
+
+#include "../CardinalCommon.hpp"
namespace rack {
namespace app {
@@ -48,80 +78,108 @@
};
-struct NotificationIcon : widget::Widget {
- void draw(const DrawArgs& args) override {
- nvgBeginPath(args.vg);
- float radius = 4;
- nvgCircle(args.vg, radius, radius, radius);
- nvgFillColor(args.vg, nvgRGBf(1.0, 0.0, 0.0));
- nvgFill(args.vg);
- nvgStrokeColor(args.vg, nvgRGBf(0.5, 0.0, 0.0));
- nvgStroke(args.vg);
- }
-};
-
-
////////////////////
// File
////////////////////
struct FileButton : MenuButton {
+ const bool isStandalone;
+
+#ifdef HAVE_LIBLO
+ bool oscConnected = false;
+ lo_server oscServer = nullptr;
+
+ static int osc_handler(const char* const path, const char* const types, lo_arg** argv, const int argc, lo_message, void* const self)
+ {
+ d_stdout("osc_handler(\"%s\", \"%s\", %p, %i)", path, types, argv, argc);
+
+ if (std::strcmp(path, "/resp") == 0 && argc == 2 && types[0] == 's' && types[1] == 's') {
+ d_stdout("osc_handler(\"%s\", ...) - got resp | '%s' '%s'", path, &argv[0]->s, &argv[1]->s);
+ if (std::strcmp(&argv[0]->s, "hello") == 0 && std::strcmp(&argv[1]->s, "ok") == 0)
+ static_cast<FileButton*>(self)->oscConnected = true;
+ }
+ return 0;
+ }
+
+ ~FileButton() {
+ lo_server_free(oscServer);
+ }
+#endif
+
+ FileButton(const bool standalone)
+ : MenuButton(), isStandalone(standalone) {}
+
void onAction(const ActionEvent& e) override {
ui::Menu* menu = createMenu();
menu->cornerFlags = BND_CORNER_TOP;
menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y));
menu->addChild(createMenuItem("New", RACK_MOD_CTRL_NAME "+N", []() {
- APP->patch->loadTemplateDialog();
+ patchUtils::loadTemplateDialog();
}));
- menu->addChild(createMenuItem("Open", RACK_MOD_CTRL_NAME "+O", []() {
- APP->patch->loadDialog();
+ menu->addChild(createMenuItem("Open / Import...", RACK_MOD_CTRL_NAME "+O", []() {
+ patchUtils::loadDialog();
}));
- menu->addChild(createSubmenuItem("Open recent", "", [](ui::Menu* menu) {
- for (const std::string& path : settings::recentPatchPaths) {
- std::string name = system::getStem(path);
- menu->addChild(createMenuItem(name, "", [=]() {
- APP->patch->loadPathDialog(path);
- }));
- }
- }, settings::recentPatchPaths.empty()));
-
menu->addChild(createMenuItem("Save", RACK_MOD_CTRL_NAME "+S", []() {
- APP->patch->saveDialog();
- }));
-
- menu->addChild(createMenuItem("Save as", RACK_MOD_CTRL_NAME "+Shift+S", []() {
- APP->patch->saveAsDialog();
+ // NOTE: will do nothing if path is empty, intentionally
+ patchUtils::saveDialog(APP->patch->path);
+ }, APP->patch->path.empty()));
+
+ menu->addChild(createMenuItem("Save as / Export...", RACK_MOD_CTRL_NAME "+Shift+S", []() {
+ patchUtils::saveAsDialog();
}));
- menu->addChild(createMenuItem("Save a copy", "", []() {
- APP->patch->saveAsDialog(false);
- }));
+#ifdef HAVE_LIBLO
+ if (oscServer == nullptr || !oscConnected) {
+ menu->addChild(createMenuItem("Connect to MOD", "", [this]() {
+ if (oscServer == nullptr) {
+ oscServer = lo_server_new_with_proto(nullptr, LO_UDP, nullptr);
+ DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr,);
+ lo_server_add_method(oscServer, "/resp", nullptr, osc_handler, this);
+ }
+ const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT);
+ DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,);
+ lo_send(addr, "/hello", "");
+ lo_address_free(addr);
+ }));
+ } else {
+ menu->addChild(createMenuItem("Deploy to MOD", "F7", []() {
+ patchUtils::deployToMOD();
+ }));
+ }
+#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();
- }));
+ patchUtils::revertDialog();
+ }, APP->patch->path.empty()));
menu->addChild(new ui::MenuSeparator);
// Load selection
menu->addChild(createMenuItem("Import selection", "", [=]() {
- APP->scene->rack->loadSelectionDialog();
+ patchUtils::loadSelectionDialog();
}, false, true));
- menu->addChild(new ui::MenuSeparator);
+ if (isStandalone) {
+ menu->addChild(new ui::MenuSeparator);
- menu->addChild(createMenuItem("Quit", RACK_MOD_CTRL_NAME "+Q", []() {
- APP->window->close();
- }));
+ menu->addChild(createMenuItem("Quit", RACK_MOD_CTRL_NAME "+Q", []() {
+ APP->window->close();
+ }));
+ };
}
+
+#ifdef HAVE_LIBLO
+ void step() override {
+ MenuButton::step();
+ if (oscServer != nullptr) {
+ while (lo_server_recv_noblock(oscServer, 0) != 0) {}
+ }
+ }
+#endif
};
@@ -166,7 +224,7 @@
menu->addChild(new ui::MenuSeparator);
- APP->scene->rack->appendSelectionContextMenu(menu);
+ patchUtils::appendSelectionContextMenu(menu);
}
};
@@ -256,7 +314,7 @@
return settings::cableTension;
}
float getDefaultValue() override {
- return 0.5;
+ return 0.75;
}
float getDisplayValue() override {
return getValue() * 100;
@@ -421,28 +479,9 @@
haloBrightnessSlider->box.size.x = 250.0;
menu->addChild(haloBrightnessSlider);
- double frameRate = APP->window->getMonitorRefreshRate() / settings::frameSwapInterval;
- menu->addChild(createSubmenuItem("Frame rate", string::f("%.0f Hz", frameRate), [=](ui::Menu* menu) {
- for (int i = 1; i <= 6; i++) {
- double frameRate = APP->window->getMonitorRefreshRate() / i;
- menu->addChild(createCheckMenuItem(string::f("%.0f Hz", frameRate), "",
- [=]() {return settings::frameSwapInterval == i;},
- [=]() {settings::frameSwapInterval = i;}
- ));
- }
- }));
-
- bool fullscreen = APP->window->isFullScreen();
- std::string fullscreenText = "F11";
- if (fullscreen)
- fullscreenText += " " CHECKMARK_STRING;
- menu->addChild(createMenuItem("Fullscreen", fullscreenText, [=]() {
- APP->window->setFullScreen(!fullscreen);
- }));
-
menu->addChild(new ui::MenuSeparator);
- menu->addChild(createBoolPtrMenuItem("Lock cursor while dragging params", "", &settings::allowCursorLock));
+ // menu->addChild(createBoolPtrMenuItem("Hide cursor while dragging", "", &settings::allowCursorLock));
static const std::vector<std::string> knobModeLabels = {
"Linear",
@@ -467,6 +506,21 @@
menu->addChild(knobScrollSensitivitySlider);
menu->addChild(createBoolPtrMenuItem("Lock module positions", "", &settings::lockModules));
+
+ static const std::vector<std::string> rateLimitLabels = {
+ "None",
+ "2x",
+ "4x",
+ };
+ static const std::vector<int> rateLimits = {0, 1, 2};
+ menu->addChild(createSubmenuItem("Update rate limit", rateLimitLabels[settings::rateLimit], [=](ui::Menu* menu) {
+ for (int rateLimit : rateLimits) {
+ menu->addChild(createCheckMenuItem(rateLimitLabels[rateLimit], "",
+ [=]() {return settings::rateLimit == rateLimit;},
+ [=]() {settings::rateLimit = rateLimit;}
+ ));
+ }
+ }));
}
};
@@ -476,47 +530,6 @@
////////////////////
-struct SampleRateItem : ui::MenuItem {
- ui::Menu* createChildMenu() override {
- ui::Menu* menu = new ui::Menu;
-
- // Auto sample rate
- std::string rightText;
- if (settings::sampleRate == 0) {
- float sampleRate = APP->engine->getSampleRate();
- rightText += string::f("(%g kHz) ", sampleRate / 1000.f);
- }
- menu->addChild(createCheckMenuItem("Auto", rightText,
- [=]() {return settings::sampleRate == 0;},
- [=]() {settings::sampleRate = 0;}
- ));
-
- // Power-of-2 oversample times 44.1kHz or 48kHz
- for (int i = -2; i <= 4; i++) {
- for (int j = 0; j < 2; j++) {
- float oversample = std::pow(2.f, i);
- float sampleRate = (j == 0) ? 44100.f : 48000.f;
- sampleRate *= oversample;
-
- std::string text = string::f("%g kHz", sampleRate / 1000.f);
- std::string rightText;
- if (oversample > 1.f) {
- rightText += string::f("(%.0fx)", oversample);
- }
- else if (oversample < 1.f) {
- rightText += string::f("(1/%.0fx)", 1.f / oversample);
- }
- menu->addChild(createCheckMenuItem(text, rightText,
- [=]() {return settings::sampleRate == sampleRate;},
- [=]() {settings::sampleRate = sampleRate;}
- ));
- }
- }
- return menu;
- }
-};
-
-
struct EngineButton : MenuButton {
void onAction(const ActionEvent& e) override {
ui::Menu* menu = createMenu();
@@ -529,269 +542,6 @@
menu->addChild(createMenuItem("Performance meters", cpuMeterText, [=]() {
settings::cpuMeter ^= true;
}));
-
- menu->addChild(createMenuItem<SampleRateItem>("Sample rate", RIGHT_ARROW));
-
- menu->addChild(createSubmenuItem("Threads", string::f("%d", settings::threadCount), [=](ui::Menu* menu) {
- // BUG This assumes SMT is enabled.
- int cores = system::getLogicalCoreCount() / 2;
-
- for (int i = 1; i <= 2 * cores; i++) {
- std::string rightText;
- if (i == cores)
- rightText += "(most modules)";
- else if (i == 1)
- rightText += "(lowest CPU usage)";
- menu->addChild(createCheckMenuItem(string::f("%d", i), rightText,
- [=]() {return settings::threadCount == i;},
- [=]() {settings::threadCount = i;}
- ));
- }
- }));
- }
-};
-
-
-////////////////////
-// Plugins
-////////////////////
-
-
-struct AccountPasswordField : ui::PasswordField {
- ui::MenuItem* logInItem;
- void onAction(const ActionEvent& e) override {
- logInItem->doAction();
- }
-};
-
-
-struct LogInItem : ui::MenuItem {
- ui::TextField* emailField;
- ui::TextField* passwordField;
-
- void onAction(const ActionEvent& e) override {
- std::string email = emailField->text;
- std::string password = passwordField->text;
- std::thread t([=] {
- library::logIn(email, password);
- library::checkUpdates();
- });
- t.detach();
- e.unconsume();
- }
-
- void step() override {
- text = "Log in";
- rightText = library::loginStatus;
- MenuItem::step();
- }
-};
-
-
-struct SyncUpdatesItem : ui::MenuItem {
- void step() override {
- if (library::updateStatus != "") {
- text = library::updateStatus;
- }
- else if (library::isSyncing) {
- text = "Updating...";
- }
- else if (!library::hasUpdates()) {
- text = "Up-to-date";
- }
- else {
- text = "Update all";
- }
-
- disabled = library::isSyncing || !library::hasUpdates();
- MenuItem::step();
- }
-
- void onAction(const ActionEvent& e) override {
- std::thread t([=] {
- library::syncUpdates();
- });
- t.detach();
- e.unconsume();
- }
-};
-
-
-struct SyncUpdateItem : ui::MenuItem {
- std::string slug;
-
- void setUpdate(const std::string& slug) {
- this->slug = slug;
-
- auto it = library::updateInfos.find(slug);
- if (it == library::updateInfos.end())
- return;
- library::UpdateInfo update = it->second;
-
- text = update.name;
- }
-
- ui::Menu* createChildMenu() override {
- auto it = library::updateInfos.find(slug);
- if (it == library::updateInfos.end())
- return NULL;
- library::UpdateInfo update = it->second;
-
- if (update.changelogUrl == "")
- return NULL;
-
- ui::Menu* menu = new ui::Menu;
-
- std::string changelogUrl = update.changelogUrl;
- menu->addChild(createMenuItem("Changelog", "", [=]() {
- system::openBrowser(changelogUrl);
- }));
-
- return menu;
- }
-
- void step() override {
- disabled = library::isSyncing;
-
- auto it = library::updateInfos.find(slug);
- if (it != library::updateInfos.end()) {
- library::UpdateInfo update = it->second;
-
- if (update.downloaded) {
- rightText = CHECKMARK_STRING;
- disabled = true;
- }
- else if (slug == library::updateSlug) {
- rightText = string::f("%.0f%%", library::updateProgress * 100.f);
- }
- else {
- rightText = "";
- plugin::Plugin* p = plugin::getPlugin(slug);
- if (p) {
- rightText += p->version + " → ";
- }
- rightText += update.version;
- }
- }
-
- MenuItem::step();
- }
-
- void onAction(const ActionEvent& e) override {
- std::thread t([=] {
- library::syncUpdate(slug);
- });
- t.detach();
- e.unconsume();
- }
-};
-
-
-struct LibraryMenu : ui::Menu {
- LibraryMenu() {
- refresh();
- }
-
- void step() override {
- // Refresh menu when appropriate
- if (library::refreshRequested) {
- library::refreshRequested = false;
- refresh();
- }
- Menu::step();
- }
-
- void refresh() {
- setChildMenu(NULL);
- clearChildren();
-
- if (settings::devMode) {
- addChild(createMenuLabel("Disabled in development mode"));
- }
- else if (!library::isLoggedIn()) {
- addChild(createMenuItem("Register VCV account", "", [=]() {
- system::openBrowser("https://vcvrack.com/login");
- }));
-
- ui::TextField* emailField = new ui::TextField;
- emailField->placeholder = "Email";
- emailField->box.size.x = 240.0;
- addChild(emailField);
-
- AccountPasswordField* passwordField = new AccountPasswordField;
- passwordField->placeholder = "Password";
- passwordField->box.size.x = 240.0;
- passwordField->nextField = emailField;
- emailField->nextField = passwordField;
- addChild(passwordField);
-
- LogInItem* logInItem = new LogInItem;
- logInItem->emailField = emailField;
- logInItem->passwordField = passwordField;
- passwordField->logInItem = logInItem;
- addChild(logInItem);
- }
- else {
- addChild(createMenuItem("Log out", "", [=]() {
- library::logOut();
- }));
-
- addChild(createMenuItem("Browse VCV Library", "", [=]() {
- system::openBrowser("https://library.vcvrack.com/");
- }));
-
- SyncUpdatesItem* syncItem = new SyncUpdatesItem;
- syncItem->text = "Update all";
- addChild(syncItem);
-
- if (!library::updateInfos.empty()) {
- addChild(new ui::MenuSeparator);
- addChild(createMenuLabel("Updates"));
-
- for (auto& pair : library::updateInfos) {
- SyncUpdateItem* updateItem = new SyncUpdateItem;
- updateItem->setUpdate(pair.first);
- addChild(updateItem);
- }
- }
- }
- }
-};
-
-
-struct LibraryButton : MenuButton {
- NotificationIcon* notification;
-
- LibraryButton() {
- notification = new NotificationIcon;
- addChild(notification);
- }
-
- void onAction(const ActionEvent& e) override {
- ui::Menu* menu = createMenu<LibraryMenu>();
- menu->cornerFlags = BND_CORNER_TOP;
- menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y));
- // Check for updates when menu is opened
- std::thread t([&]() {
- system::setThreadName("Library");
- library::checkUpdates();
- });
- t.detach();
- }
-
- void step() override {
- notification->box.pos = math::Vec(0, 0);
- notification->visible = library::hasUpdates();
-
- // Popup when updates finish downloading
- if (library::restartRequested) {
- library::restartRequested = false;
- if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "All plugins have been downloaded. Close and re-launch Rack to load new updates.")) {
- APP->window->close();
- }
- }
-
- MenuButton::step();
}
};
@@ -802,63 +552,24 @@
struct HelpButton : MenuButton {
- NotificationIcon* notification;
-
- HelpButton() {
- notification = new NotificationIcon;
- addChild(notification);
- }
-
void onAction(const ActionEvent& e) override {
ui::Menu* menu = createMenu();
menu->cornerFlags = BND_CORNER_TOP;
menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y));
- menu->addChild(createMenuItem("Tips", "", [=]() {
- APP->scene->addChild(tipWindowCreate());
- }));
-
- menu->addChild(createMenuItem("User manual", "F1", [=]() {
+ menu->addChild(createMenuItem("Rack User manual", "F1", [=]() {
system::openBrowser("https://vcvrack.com/manual/");
}));
- menu->addChild(createMenuItem("VCVRack.com", "", [=]() {
- system::openBrowser("https://vcvrack.com/");
- }));
-
- menu->addChild(createMenuItem("Open user folder", "", [=]() {
- system::openDirectory(asset::user(""));
+ menu->addChild(createMenuItem("Cardinal Project page", "", [=]() {
+ system::openBrowser("https://github.com/DISTRHO/Cardinal/");
}));
- if (library::isAppUpdateAvailable()) {
- menu->addChild(new ui::MenuSeparator);
-
- menu->addChild(createMenuItem("Update " + APP_NAME, APP_VERSION + " → " + library::appVersion, [=]() {
- system::openBrowser(library::appDownloadUrl);
- }));
-
- menu->addChild(createMenuItem("Review changelog", "", [=]() {
- system::openBrowser(library::appChangelogUrl);
- }));
- }
- else if (!settings::autoCheckUpdates && !settings::devMode) {
- menu->addChild(createMenuItem("Check for " + APP_NAME + " update", "", [=]() {
- std::thread t([&]() {
- library::checkAppUpdate();
- });
- t.detach();
- }, false, true));
- }
-
menu->addChild(new ui::MenuSeparator);
- 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("Rack " + APP_VERSION + " Compatible"));
}
};
@@ -908,7 +619,9 @@
struct MenuBar : widget::OpaqueWidget {
MeterLabel* meterLabel;
- MenuBar() {
+ MenuBar(const bool isStandalone)
+ : widget::OpaqueWidget()
+ {
const float margin = 5;
box.size.y = BND_WIDGET_HEIGHT + 2 * margin;
@@ -917,7 +630,7 @@
layout->spacing = math::Vec(0, 0);
addChild(layout);
- FileButton* fileButton = new FileButton;
+ FileButton* fileButton = new FileButton(isStandalone);
fileButton->text = "File";
layout->addChild(fileButton);
@@ -933,10 +646,6 @@
engineButton->text = "Engine";
layout->addChild(engineButton);
- LibraryButton* libraryButton = new LibraryButton;
- libraryButton->text = "Library";
- layout->addChild(libraryButton);
-
HelpButton* helpButton = new HelpButton;
helpButton->text = "Help";
layout->addChild(helpButton);
@@ -971,7 +680,11 @@
widget::Widget* createMenuBar() {
- menuBar::MenuBar* menuBar = new menuBar::MenuBar;
+ return new widget::Widget;
+}
+
+widget::Widget* createMenuBar(const bool isStandalone) {
+ menuBar::MenuBar* menuBar = new menuBar::MenuBar(isStandalone);
return menuBar;
}

View file

@ -0,0 +1,129 @@
--- ../Rack/src/plugin/Model.cpp 2021-10-17 13:57:23.257633662 +0100
+++ Model.cpp 2022-01-23 17:13:22.080013846 +0000
@@ -1,3 +1,30 @@
+/*
+ * 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.
+ */
+
+/**
+ * This file is an edited version of VCVRack's plugin/Model.cpp
+ * Copyright (C) 2016-2021 VCV.
+ *
+ * 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 (at your option) any later version.
+ */
+
#include <algorithm>
#include <plugin/Model.hpp>
@@ -17,7 +44,7 @@
void Model::fromJson(json_t* rootJ) {
- assert(plugin);
+ DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr,);
json_t* nameJ = json_object_get(rootJ, "name");
if (nameJ)
@@ -54,11 +81,6 @@
if (manualUrlJ)
manualUrl = json_string_value(manualUrlJ);
- // modularGridUrl
- json_t* modularGridUrlJ = json_object_get(rootJ, "modularGridUrl");
- if (modularGridUrlJ)
- modularGridUrl = json_string_value(modularGridUrlJ);
-
// hidden
json_t* hiddenJ = json_object_get(rootJ, "hidden");
// Use `disabled` as an alias which was deprecated in Rack 2.0
@@ -73,7 +95,7 @@
std::string Model::getFullName() {
- assert(plugin);
+ DISTRHO_SAFE_ASSERT_RETURN(plugin, {});
return plugin->getBrand() + " " + name;
}
@@ -95,7 +117,7 @@
}
-void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) {
+void Model::appendContextMenu(ui::Menu* menu, bool) {
// plugin
menu->addChild(createMenuItem("Plugin: " + plugin->name, "", [=]() {
system::openBrowser(plugin->pluginUrl);
@@ -132,18 +154,6 @@
menu->addChild(new ui::MenuSeparator);
- // VCV Library page
- menu->addChild(createMenuItem("VCV Library page", "", [=]() {
- system::openBrowser("https://library.vcvrack.com/" + plugin->slug + "/" + slug);
- }));
-
- // modularGridUrl
- if (modularGridUrl != "") {
- menu->addChild(createMenuItem("ModularGrid page", "", [=]() {
- system::openBrowser(modularGridUrl);
- }));
- }
-
// manual
std::string manualUrl = getManualUrl();
if (manualUrl != "") {
@@ -172,35 +182,15 @@
system::openBrowser(plugin->changelogUrl);
}));
}
-
- // plugin folder
- if (plugin->path != "") {
- menu->addChild(createMenuItem("Open plugin folder", "", [=]() {
- system::openDirectory(plugin->path);
- }));
- }
-
- // Favorite
- std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : "";
- if (isFavorite())
- favoriteRightText += " " CHECKMARK_STRING;
- menu->addChild(createMenuItem("Favorite", favoriteRightText,
- [=]() {
- setFavorite(!isFavorite());
- }
- ));
}
bool Model::isFavorite() {
- const settings::ModuleInfo* mi = settings::getModuleInfo(plugin->slug, slug);
- return mi && mi->favorite;
+ return false;
}
-void Model::setFavorite(bool favorite) {
- settings::ModuleInfo& mi = settings::moduleInfos[plugin->slug][slug];
- mi.favorite = favorite;
+void Model::setFavorite(bool) {
}

View file

@ -0,0 +1,234 @@
--- ../Rack/src/app/Scene.cpp 2021-12-14 21:35:44.414568198 +0000
+++ Scene.cpp 2022-01-23 17:13:24.715889665 +0000
@@ -1,3 +1,30 @@
+/*
+ * 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.
+ */
+
+/**
+ * This file is an edited version of VCVRack's app/Scene.cpp
+ * Copyright (C) 2016-2021 VCV.
+ *
+ * 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 (at your option) any later version.
+ */
+
#include <thread>
#include <osdialog.h>
@@ -14,31 +41,49 @@
#include <patch.hpp>
#include <asset.hpp>
+#include "../CardinalCommon.hpp"
+
namespace rack {
namespace app {
struct ResizeHandle : widget::OpaqueWidget {
- math::Vec size;
-
void draw(const DrawArgs& args) override {
+ nvgStrokeColor(args.vg, nvgRGBf(1, 1, 1));
+ nvgStrokeWidth(args.vg, 1);
+
nvgBeginPath(args.vg);
- nvgMoveTo(args.vg, box.size.x, box.size.y);
+ nvgMoveTo(args.vg, box.size.x, 0);
nvgLineTo(args.vg, 0, box.size.y);
- nvgLineTo(args.vg, box.size.x, 0);
- nvgClosePath(args.vg);
- nvgFillColor(args.vg, nvgRGBAf(1, 1, 1, 0.15));
- nvgFill(args.vg);
- }
+ nvgStroke(args.vg);
- void onDragStart(const DragStartEvent& e) override {
- size = APP->window->getSize();
- }
+ nvgBeginPath(args.vg);
+ nvgMoveTo(args.vg, box.size.x + 5, 0);
+ nvgLineTo(args.vg, 0, box.size.y + 5);
+ nvgStroke(args.vg);
+
+ nvgBeginPath(args.vg);
+ nvgMoveTo(args.vg, box.size.x + 10, 0);
+ nvgLineTo(args.vg, 0, box.size.y + 10);
+ nvgStroke(args.vg);
+
+ nvgStrokeColor(args.vg, nvgRGBf(0, 0, 0));
+
+ nvgBeginPath(args.vg);
+ nvgMoveTo(args.vg, box.size.x+1, 0);
+ nvgLineTo(args.vg, 0, box.size.y+1);
+ nvgStroke(args.vg);
- void onDragMove(const DragMoveEvent& e) override {
- size = size.plus(e.mouseDelta);
- APP->window->setSize(size.round());
+ nvgBeginPath(args.vg);
+ nvgMoveTo(args.vg, box.size.x + 6, 0);
+ nvgLineTo(args.vg, 0, box.size.y + 6);
+ nvgStroke(args.vg);
+
+ nvgBeginPath(args.vg);
+ nvgMoveTo(args.vg, box.size.x + 11, 0);
+ nvgLineTo(args.vg, 0, box.size.y + 11);
+ nvgStroke(args.vg);
}
};
@@ -46,12 +91,15 @@
struct Scene::Internal {
ResizeHandle* resizeHandle;
- double lastAutosaveTime = 0.0;
-
bool heldArrowKeys[4] = {};
};
+void hideResizeHandle(Scene* scene) {
+ scene->internal->resizeHandle->hide();
+}
+
+
Scene::Scene() {
internal = new Internal;
@@ -67,13 +115,8 @@
browser->hide();
addChild(browser);
- if (settings::showTipsOnLaunch) {
- addChild(tipWindowCreate());
- }
-
internal->resizeHandle = new ResizeHandle;
- internal->resizeHandle->box.size = math::Vec(15, 15);
- internal->resizeHandle->hide();
+ internal->resizeHandle->box.size = math::Vec(16, 16);
addChild(internal->resizeHandle);
}
@@ -89,32 +132,13 @@
void Scene::step() {
- if (APP->window->isFullScreen()) {
- // Expand RackScrollWidget to cover entire screen if fullscreen
- rackScroll->box.pos.y = 0;
- }
- else {
- // Always show MenuBar if not fullscreen
- menuBar->show();
- rackScroll->box.pos.y = menuBar->box.size.y;
- }
-
internal->resizeHandle->box.pos = box.size.minus(internal->resizeHandle->box.size);
// Resize owned descendants
menuBar->box.size.x = box.size.x;
+ rackScroll->box.pos.y = menuBar->box.size.y;
rackScroll->box.size = box.size.minus(rackScroll->box.pos);
- // Autosave periodically
- if (settings::autosaveInterval > 0.0) {
- double time = system::getTime();
- if (time - internal->lastAutosaveTime >= settings::autosaveInterval) {
- internal->lastAutosaveTime = time;
- APP->patch->saveAutosave();
- settings::save();
- }
- }
-
// Scroll RackScrollWidget with arrow keys
math::Vec arrowDelta;
if (internal->heldArrowKeys[0]) {
@@ -172,7 +196,7 @@
if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
// DEBUG("key '%d '%c' scancode %d '%c' keyName '%s'", e.key, e.key, e.scancode, e.scancode, e.keyName.c_str());
if (e.keyName == "n" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
- APP->patch->loadTemplateDialog();
+ patchUtils::loadTemplateDialog();
e.consume(this);
}
if (e.keyName == "q" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
@@ -180,19 +204,20 @@
e.consume(this);
}
if (e.keyName == "o" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
- APP->patch->loadDialog();
+ patchUtils::loadDialog();
e.consume(this);
}
if (e.keyName == "o" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) {
- APP->patch->revertDialog();
+ patchUtils::revertDialog();
e.consume(this);
}
if (e.keyName == "s" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
- APP->patch->saveDialog();
+ // NOTE: will do nothing if path is empty, intentionally
+ patchUtils::saveDialog(APP->patch->path);
e.consume(this);
}
if (e.keyName == "s" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) {
- APP->patch->saveAsDialog();
+ patchUtils::saveAsDialog();
e.consume(this);
}
if (e.keyName == "z" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
@@ -232,10 +257,8 @@
settings::cpuMeter ^= true;
e.consume(this);
}
- if (e.key == GLFW_KEY_F11 && (e.mods & RACK_MOD_MASK) == 0) {
- APP->window->setFullScreen(!APP->window->isFullScreen());
- // The MenuBar will be hidden when the mouse moves over the RackScrollWidget.
- // menuBar->hide();
+ if (e.key == GLFW_KEY_F7 && (e.mods & RACK_MOD_MASK) == 0) {
+ patchUtils::deployToMOD();
e.consume(this);
}
@@ -326,13 +349,6 @@
// Key commands that can be overridden by children
if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
- // Alternate key command for exiting fullscreen, since F11 doesn't work reliably on Mac due to "Show desktop" OS binding.
- if (e.key == GLFW_KEY_ESCAPE && (e.mods & RACK_MOD_MASK) == 0) {
- if (APP->window->isFullScreen()) {
- APP->window->setFullScreen(false);
- e.consume(this);
- }
- }
if (e.keyName == "v" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
rack->pasteClipboardAction();
e.consume(this);
@@ -351,7 +367,7 @@
std::string extension = system::getExtension(path);
if (extension == ".vcv") {
- APP->patch->loadPathDialog(path);
+ patchUtils::loadPathDialog(path);
e.consume(this);
return;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,29 @@
--- ../Rack/dep/oui-blendish/blendish.c 2021-10-17 13:57:24.613620711 +0100
+++ blendish.c 2021-12-13 09:36:22.182673256 +0000
@@ -61,7 +61,7 @@
}
#else
- #define BND_INLINE inline
+ #define BND_INLINE static inline
#define bnd_fminf(a, b) fminf(a, b)
#define bnd_fmaxf(a, b) fmaxf(a, b)
#define bnd_fmin(a, b) fmin(a, b)
@@ -1061,7 +1061,7 @@
// search horizontal position
static NVGglyphPosition glyphs[BND_MAX_GLYPHS];
int nglyphs = nvgTextGlyphPositions(
- ctx, x, y, rows[row].start, rows[row].end + 1, glyphs, BND_MAX_GLYPHS);
+ ctx, x, y, rows[row].start, rows[row].end, glyphs, BND_MAX_GLYPHS);
int col, p = 0;
for (col = 0; col < nglyphs && glyphs[col].x < px; ++col)
p = glyphs[col].str - label;
@@ -1083,7 +1083,7 @@
if (nrows == 0) return;
*cx = rows[r].minx;
nglyphs = nvgTextGlyphPositions(
- ctx, x, y, rows[r].start, rows[r].end+1, glyphs, BND_MAX_GLYPHS);
+ ctx, x, y, rows[r].start, rows[r].end, glyphs, BND_MAX_GLYPHS);
for (int i=0; i < nglyphs; ++i) {
*cx=glyphs[i].x;
if (glyphs[i].str == caret) break;

View file

@ -0,0 +1,69 @@
--- ../Rack/src/common.cpp 2021-11-23 19:57:23.719015894 +0000
+++ common.cpp 2022-01-23 17:13:08.824652617 +0000
@@ -1,6 +1,38 @@
+/*
+ * 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.
+ */
+
+/**
+ * This file is an edited version of VCVRack's common.cpp
+ * Copyright (C) 2016-2021 VCV.
+ *
+ * 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 (at your option) any later version.
+ */
+
#include <common.hpp>
#include <string.hpp>
+#ifdef NDEBUG
+# undef DEBUG
+#endif
+
+#include "DistrhoPluginUtils.hpp"
#if defined ARCH_WIN
#include <windows.h>
@@ -14,20 +46,21 @@
namespace rack {
-
-const std::string APP_NAME = "VCV Rack";
-const std::string APP_EDITION = "Free";
-const std::string APP_EDITION_NAME = "Free";
+const std::string APP_NAME = "Cardinal";
+const std::string APP_EDITION = getPluginFormatName();
+const std::string APP_EDITION_NAME = "Audio Plugin";
const std::string APP_VERSION_MAJOR = "2";
-const std::string APP_VERSION = TOSTRING(_APP_VERSION);
+const std::string APP_VERSION = "2.0";
#if defined ARCH_WIN
const std::string APP_OS = "win";
#elif ARCH_MAC
const std::string APP_OS = "mac";
#elif defined ARCH_LIN
const std::string APP_OS = "lin";
+#else
+ #error ARCH_LIN undefined
#endif
-const std::string API_URL = "https://api.vcvrack.com";
+const std::string API_URL = "";
Exception::Exception(const char* format, ...) {

View file

@ -0,0 +1,57 @@
--- ../Rack/src/context.cpp 2022-01-15 14:44:46.391280963 +0000
+++ context.cpp 2022-01-23 17:13:11.652514338 +0000
@@ -1,3 +1,30 @@
+/*
+ * 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.
+ */
+
+/**
+ * This file is an edited version of VCVRack's context.cpp
+ * Copyright (C) 2016-2021 VCV.
+ *
+ * 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 (at your option) any later version.
+ */
+
#include <context.hpp>
#include <window/Window.hpp>
#include <patch.hpp>
@@ -6,9 +33,13 @@
#include <history.hpp>
#include <settings.hpp>
+#ifdef NDEBUG
+# undef DEBUG
+#endif
-namespace rack {
+#include "DistrhoUtils.hpp"
+namespace rack {
Context::~Context() {
// Deleting NULL is safe in C++.
@@ -44,7 +75,7 @@
static thread_local Context* threadContext = NULL;
Context* contextGet() {
- assert(threadContext);
+ DISTRHO_SAFE_ASSERT(threadContext != nullptr);
return threadContext;
}