diff --git a/Makefile.base.mk b/Makefile.base.mk index b248d89..24852bd 100644 --- a/Makefile.base.mk +++ b/Makefile.base.mk @@ -94,6 +94,21 @@ endif BUILD_C_FLAGS += -fno-finite-math-only -fno-strict-aliasing BUILD_CXX_FLAGS += -fno-finite-math-only -fno-strict-aliasing +# ----------------------------------------------------------------------------- +# simde flags + +BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/simde) +BASE_FLAGS += -DSIMDE_ACCURACY_PREFERENCE=0 +BASE_FLAGS += -DSIMDE_FAST_CONVERSION_RANGE +BASE_FLAGS += -DSIMDE_FAST_MATH +BASE_FLAGS += -DSIMDE_FAST_NANS +BASE_FLAGS += -DSIMDE_FAST_ROUND_MODE +BASE_FLAGS += -DSIMDE_FAST_ROUND_TIES + +# unwanted +BASE_FLAGS += -DSIMDE_X86_SSE4_1_H +BASE_FLAGS += -DSIMDE_X86_SSE4_2_H + # ----------------------------------------------------------------------------- # Rack build flags @@ -163,8 +178,6 @@ endif BASE_FLAGS += -I$(abspath $(ROOT)/dpf/dgl/src/nanovg) BASE_FLAGS += -I$(abspath $(ROOT)/dpf/distrho) -BASE_FLAGS += -I$(abspath $(ROOT)/include/simde) - BASE_FLAGS += -I$(abspath $(ROOT)/src) BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/include) BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/include/dsp) @@ -174,6 +187,7 @@ BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/glfw/include) BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/nanosvg/src) BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/oui-blendish) BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/pffft) +BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/tinyexpr) BUILD_C_FLAGS += -std=gnu11 diff --git a/carla b/carla index 9c1cad5..e58f7a8 160000 --- a/carla +++ b/carla @@ -1 +1 @@ -Subproject commit 9c1cad538702767d51fc59d17080c74313c280cd +Subproject commit e58f7a8c7a8797656747b11a2608fc8b6ec90b8e diff --git a/deps/Makefile b/deps/Makefile index 97c986a..c845a97 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -197,14 +197,10 @@ $(RACK_DEP_PATH)/libsamplerate-0.1.9/.stamp-patched: touch $@ # libspeexdsp: hide symbols -$(RACK_DEP_PATH)/lib/libspeexdsp.a: $(RACK_DEP_PATH)/speexdsp-SpeexDSP-1.2rc3/.stamp-patched +$(RACK_DEP_PATH)/lib/libspeexdsp.a: $(RACK_DEP_PATH)/speexdsp/.stamp-patched -$(RACK_DEP_PATH)/speexdsp-SpeexDSP-1.2rc3/.stamp-patched: - $(DEP_MAKE2) -C $(RACK_DEP_PATH) speexdsp-SpeexDSP-1.2rc3 \ - WGET="wget -c http://downloads.xiph.org/releases/speex/speexdsp-1.2rc3.tar.gz && mv speexdsp-1.2rc3.tar.gz speexdsp-SpeexDSP-1.2rc3.tgz #" \ - SHA256SUM="true" \ - UNTAR="mkdir -p speexdsp-SpeexDSP-1.2rc3 && tar -x --strip-components=1 --directory=$(RACK_DEP_PATH)/speexdsp-SpeexDSP-1.2rc3 -f" - sed -i -e "s/#pragma GCC visibility push/#error we dont want this/" $(RACK_DEP_PATH)/speexdsp-SpeexDSP-1.2rc3/configure +$(RACK_DEP_PATH)/speexdsp/.stamp-patched: + sed -i -e 's/__attribute__((visibility("default")))//' $(RACK_DEP_PATH)/speexdsp/configure.ac touch $@ # custom zstd build for only building static libs @@ -279,12 +275,7 @@ endif endif # same flags as applied to main build -SURGE_CXX_FLAGS += -DSIMDE_ACCURACY_PREFERENCE=0 -SURGE_CXX_FLAGS += -DSIMDE_FAST_CONVERSION_RANGE -SURGE_CXX_FLAGS += -DSIMDE_FAST_MATH -SURGE_CXX_FLAGS += -DSIMDE_FAST_NANS -SURGE_CXX_FLAGS += -DSIMDE_FAST_ROUND_MODE -SURGE_CXX_FLAGS += -DSIMDE_FAST_ROUND_TIES +SURGE_CXX_FLAGS += -I$(abspath ../src/Rack/dep/simde) # possibly use fftw? # ifeq ($(shell $(PKG_CONFIG) --exists fftw3 fftw3f && echo true),true) @@ -315,7 +306,7 @@ $(SURGE_DEP_PATH)/Makefile: $(SURGE_SRC_PATH)/CMakeLists.txt -DSURGE_SKIP_LUA=TRUE \ -DSURGE_SKIP_ODDSOUND_MTS=TRUE \ -DSURGE_JUCE_PATH=$(abspath ../carla/source) \ - -DSURGE_SIMDE_PATH=$(abspath ../include/simde) \ + -DSURGE_SIMDE_PATH=$(abspath ../src/Rack/dep/simde) \ $(SURGE_SRC_PATH) # -------------------------------------------------------------- @@ -352,7 +343,6 @@ clean: rm -rf $(RACK_DEP_PATH)/jansson-2.12 rm -rf $(RACK_DEP_PATH)/libarchive-3.4.3 rm -rf $(RACK_DEP_PATH)/libsamplerate-0.1.9 - rm -rf $(RACK_DEP_PATH)/speexdsp-SpeexDSP-1.2rc3 rm -rf $(RACK_DEP_PATH)/zstd-1.4.5 rm -rf $(SURGE_DEP_PATH) @@ -360,7 +350,6 @@ download: \ $(RACK_DEP_PATH)/jansson-2.12 \ $(RACK_DEP_PATH)/libarchive-3.4.3/.stamp-patched \ $(RACK_DEP_PATH)/libsamplerate-0.1.9/.stamp-patched \ - $(RACK_DEP_PATH)/speexdsp-SpeexDSP-1.2rc3/.stamp-patched \ $(RACK_DEP_PATH)/zstd-1.4.5/.stamp-patched quickjs: $(RACK_DEP_PATH)/lib/libquickjs.a diff --git a/include/simd-compat/emmintrin.h b/include/simd-compat/emmintrin.h index f3f798b..1fc6dc0 100644 --- a/include/simd-compat/emmintrin.h +++ b/include/simd-compat/emmintrin.h @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -20,12 +20,7 @@ #if (defined(__i386__) || defined(__x86_64__) || defined(__EMSCRIPTEN__)) && !defined(CARDINAL_NOSIMD) # include_next #else -# define SIMDE_ACCURACY_PREFERENCE 0 # define SIMDE_ENABLE_NATIVE_ALIASES -# define SIMDE_FAST_CONVERSION_RANGE -# define SIMDE_FAST_MATH -# define SIMDE_FAST_NANS -# define SIMDE_FAST_ROUND_MODE -# define SIMDE_FAST_ROUND_TIES -# include "../simde/simde/x86/sse.h" +# include "simde/x86/sse.h" +# undef SIMDE_ENABLE_NATIVE_ALIASES #endif diff --git a/include/simd-compat/immintrin.h b/include/simd-compat/immintrin.h index 20fe5e4..3490cb8 100644 --- a/include/simd-compat/immintrin.h +++ b/include/simd-compat/immintrin.h @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -20,13 +20,8 @@ #if (defined(__i386__) || defined(__x86_64__) || defined(__EMSCRIPTEN__)) && !defined(CARDINAL_NOSIMD) # include_next #else -# define SIMDE_ACCURACY_PREFERENCE 0 # define SIMDE_ENABLE_NATIVE_ALIASES -# define SIMDE_FAST_CONVERSION_RANGE -# define SIMDE_FAST_MATH -# define SIMDE_FAST_NANS -# define SIMDE_FAST_ROUND_MODE -# define SIMDE_FAST_ROUND_TIES # include "../simde/simde/x86/sse.h" # include "../simde/simde/x86/sse2.h" +# undef SIMDE_ENABLE_NATIVE_ALIASES #endif diff --git a/include/simd-compat/mmintrin.h b/include/simd-compat/mmintrin.h index 92d9b45..3ca24af 100644 --- a/include/simd-compat/mmintrin.h +++ b/include/simd-compat/mmintrin.h @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -22,12 +22,7 @@ #elif defined(__EMSCRIPTEN__) && !defined(CARDINAL_NOSIMD) # include #else -# define SIMDE_ACCURACY_PREFERENCE 0 # define SIMDE_ENABLE_NATIVE_ALIASES -# define SIMDE_FAST_CONVERSION_RANGE -# define SIMDE_FAST_MATH -# define SIMDE_FAST_NANS -# define SIMDE_FAST_ROUND_MODE -# define SIMDE_FAST_ROUND_TIES # include "../simde/simde/x86/mmx.h" +# undef SIMDE_ENABLE_NATIVE_ALIASES #endif diff --git a/include/simd-compat/pmmintrin.h b/include/simd-compat/pmmintrin.h index d16f1bf..8ba6b36 100644 --- a/include/simd-compat/pmmintrin.h +++ b/include/simd-compat/pmmintrin.h @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -32,7 +32,7 @@ // assume SSE3 only on macOS # ifndef ARCH_MAC -# include "../simde/simde/x86/sse3.h" +# include "simde/x86/sse3.h" # endif # ifdef _WIN32_WAS_DEFINED @@ -40,6 +40,9 @@ # undef _WIN32_WAS_DEFINED # endif +# undef SIMDE_X86_SSE2_NATIVE +# undef SIMDE_X86_SSE3_ENABLE_NATIVE_ALIASES + #elif defined(__EMSCRIPTEN__) && !defined(CARDINAL_NOSIMD) # include_next @@ -67,14 +70,9 @@ __m64 _mm_set1_pi16(short w) */ #else -# define SIMDE_ACCURACY_PREFERENCE 0 # define SIMDE_ENABLE_NATIVE_ALIASES -# define SIMDE_FAST_CONVERSION_RANGE -# define SIMDE_FAST_MATH -# define SIMDE_FAST_NANS -# define SIMDE_FAST_ROUND_MODE -# define SIMDE_FAST_ROUND_TIES -# include "../simde/simde/x86/sse.h" -# include "../simde/simde/x86/sse2.h" -# include "../simde/simde/x86/sse3.h" +# include "simde/x86/sse.h" +# include "simde/x86/sse2.h" +# include "simde/x86/sse3.h" +# undef SIMDE_ENABLE_NATIVE_ALIASES #endif diff --git a/include/simd-compat/xmmintrin.h b/include/simd-compat/xmmintrin.h index 9a860e5..3500893 100644 --- a/include/simd-compat/xmmintrin.h +++ b/include/simd-compat/xmmintrin.h @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -20,12 +20,7 @@ #if (defined(__i386__) || defined(__x86_64__) || defined(__EMSCRIPTEN__)) && !defined(CARDINAL_NOSIMD) # include_next #else -# define SIMDE_ACCURACY_PREFERENCE 0 # define SIMDE_ENABLE_NATIVE_ALIASES -# define SIMDE_FAST_CONVERSION_RANGE -# define SIMDE_FAST_MATH -# define SIMDE_FAST_NANS -# define SIMDE_FAST_ROUND_MODE -# define SIMDE_FAST_ROUND_TIES -# include "../simde/simde/x86/avx.h" +# include "simde/x86/avx.h" +# undef SIMDE_ENABLE_NATIVE_ALIASES #endif diff --git a/include/simde b/include/simde deleted file mode 160000 index dd0b662..0000000 --- a/include/simde +++ /dev/null @@ -1 +0,0 @@ -Subproject commit dd0b662fd8cf4b1617dbbb4d08aa053e512b08e4 diff --git a/plugins/Makefile b/plugins/Makefile index 6d7cf81..76df0ad 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -643,7 +643,7 @@ CATROMODULO_CUSTOM = LowFrequencyOscillator NumDisplayWidget PLUGIN_FILES += $(filter-out cf/src/plugin.cpp,$(wildcard cf/src/*.cpp)) # modules/types which are present in other plugins -CF_CUSTOM = $(DRWAV) +CF_CUSTOM = $(DRWAV) ledTrigger # -------------------------------------------------------------- # dBiz diff --git a/plugins/cf b/plugins/cf index b6c4a66..8aca80c 160000 --- a/plugins/cf +++ b/plugins/cf @@ -1 +1 @@ -Subproject commit b6c4a66ffc153d78c7efa00fa886657eb182b15d +Subproject commit 8aca80cbaa30787e0aed1edb886767fa756b9846 diff --git a/plugins/mscHack b/plugins/mscHack index 8088351..e5c6048 160000 --- a/plugins/mscHack +++ b/plugins/mscHack @@ -1 +1 @@ -Subproject commit 80883512cc397c173e40e3bc014640b838ab343a +Subproject commit e5c6048071b9e1fc34b4a97072f1966b88235455 diff --git a/src/CardinalCommon.cpp b/src/CardinalCommon.cpp index 80874ac..16c04d1 100644 --- a/src/CardinalCommon.cpp +++ b/src/CardinalCommon.cpp @@ -393,6 +393,8 @@ Initializer::Initializer(const CardinalBasePlugin* const plugin, const CardinalB settings::browserZoom = -1.f; settings::invertZoom = false; settings::squeezeModules = true; + settings::darkMode = true; + settings::uiTheme = "dark"; // runtime behaviour settings::devMode = true; @@ -635,12 +637,20 @@ void Initializer::loadSettings(const bool isRealInstance) settings::pixelRatio = 0.0; settings::sampleRate = 0; settings::threadCount = 1; - settings::frameSwapInterval = 1; settings::autosaveInterval = 0; settings::skipLoadOnLaunch = true; settings::autoCheckUpdates = false; settings::showTipsOnLaunch = false; settings::tipIndex = -1; + + if (settings::uiTheme != "dark" && settings::uiTheme != "light") + { + settings::uiTheme = "dark"; + rack::ui::refreshTheme(); + } + + // reload dark/light mode as necessary + switchDarkMode(settings::uiTheme == "dark"); } // -------------------------------------------------------------------------------------------------------------------- diff --git a/src/CardinalCommon.hpp b/src/CardinalCommon.hpp index 0d1d28e..6fa736f 100644 --- a/src/CardinalCommon.hpp +++ b/src/CardinalCommon.hpp @@ -57,6 +57,8 @@ extern char* patchStorageSlug; std::string homeDir(); +void switchDarkMode(bool darkMode); + } // namespace rack // ----------------------------------------------------------------------------------------------------------- diff --git a/src/Makefile b/src/Makefile index 9e7cf1b..3c45e8f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -62,6 +62,7 @@ IGNORED_FILES += Rack/src/gamepad.cpp IGNORED_FILES += Rack/src/keyboard.cpp IGNORED_FILES += Rack/src/library.cpp IGNORED_FILES += Rack/src/midi.cpp +IGNORED_FILES += Rack/src/midiloopback.cpp IGNORED_FILES += Rack/src/network.cpp IGNORED_FILES += Rack/src/plugin.cpp IGNORED_FILES += Rack/src/rtaudio.cpp @@ -79,6 +80,7 @@ IGNORED_FILES += Rack/src/widget/OpenGlWidget.cpp IGNORED_FILES += Rack/src/window/Window.cpp IGNORED_FILES += $(wildcard Rack/src/core/*.cpp) +RACK_FILES += Rack/dep/tinyexpr/tinyexpr.c RACK_FILES += $(wildcard Rack/src/*.c) RACK_FILES += $(wildcard Rack/src/*/*.c) RACK_FILES += $(filter-out $(IGNORED_FILES),$(wildcard Rack/src/*.cpp)) @@ -190,6 +192,8 @@ $(BUILD_DIR)/%.cpp.o: %.cpp $(BUILD_DIR)/emscripten/WasmUtils.cpp.o: BUILD_CXX_FLAGS += -fno-exceptions +$(BUILD_DIR)/Rack/dep/tinyexpr/tinyexpr.c.o: BUILD_C_FLAGS += -DTE_POW_FROM_RIGHT -DTE_NAT_LOG + # -------------------------------------------------------------- -include $(RACK_OBJS:%.o=%.d) diff --git a/src/Rack b/src/Rack index 5551617..f1576e2 160000 --- a/src/Rack +++ b/src/Rack @@ -1 +1 @@ -Subproject commit 5551617afff182925940908eaf73a7d7361303cc +Subproject commit f1576e2bb870da297789300117accb9d5fe44c5e diff --git a/src/custom/RemoteWindow.cpp b/src/custom/RemoteWindow.cpp index 29a3cff..e0e9fab 100644 --- a/src/custom/RemoteWindow.cpp +++ b/src/custom/RemoteWindow.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's Window.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -108,8 +108,8 @@ void Window::step() { } -void Window::activateContext() { -} +// void Window::activateContext() { +// } void Window::screenshot(const std::string&) { diff --git a/src/custom/dep.cpp b/src/custom/dep.cpp index 5efde7c..6c5ba80 100644 --- a/src/custom/dep.cpp +++ b/src/custom/dep.cpp @@ -64,6 +64,10 @@ void updateForcingBlackSilverScrewMode(std::string slug) { namespace settings { bool darkMode = true; int rateLimit = 0; +extern std::string uiTheme; +} +namespace ui { +void refreshTheme(); } } @@ -1468,13 +1472,17 @@ void nsvgDeleteCardinal(NSVGimage* const handle) nsvgDelete(handle); } +namespace rack { + void switchDarkMode(const bool darkMode) { #ifndef HEADLESS - if (rack::settings::darkMode == darkMode) + if (settings::darkMode == darkMode) return; - rack::settings::darkMode = darkMode; + settings::darkMode = darkMode; + settings::uiTheme = darkMode ? "dark" : "light"; + ui::refreshTheme(); for (ExtendedNSVGimage& ext : loadedDarkSVGs) { @@ -1494,7 +1502,6 @@ void switchDarkMode(const bool darkMode) #endif } -namespace rack { namespace asset { void destroy() { diff --git a/src/override/Engine.cpp b/src/override/Engine.cpp index 2a9deeb..de59842 100644 --- a/src/override/Engine.cpp +++ b/src/override/Engine.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's engine/Engine.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -83,8 +83,8 @@ struct Engine::Internal { float sampleRate = 0.f; float sampleTime = 0.f; - int64_t block = 0; int64_t frame = 0; + int64_t block = 0; int64_t blockFrame = 0; double blockTime = 0.0; int blockFrames = 0; @@ -653,18 +653,13 @@ void Engine::yieldWorkers() { } -int64_t Engine::getBlock() { - return internal->block; -} - - int64_t Engine::getFrame() { return internal->frame; } -void Engine::setFrame(int64_t frame) { - internal->frame = frame; +int64_t Engine::getBlock() { + return internal->block; } @@ -758,8 +753,6 @@ void Engine::addModule(Module* 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(),); - // Reinitialize random module since it uses thread-local RNG state - random::init(); // 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 @@ -1005,8 +998,6 @@ void Engine::addCable(Cable* cable) { if (cable2->outputModule == cable->outputModule && cable2->outputId == cable->outputId) outputWasConnected = true; } - // Reinitialize random module since it uses thread-local RNG state - random::init(); // Set ID if unset or collides with an existing ID while (cable->id < 0 || internal->cablesCache.find(cable->id) != internal->cablesCache.end()) { // Randomly generate ID @@ -1106,19 +1097,19 @@ void Engine::setParamValue(Module* module, int paramId, float value) { if (internal->remoteDetails != nullptr) { sendParamChangeToRemote(internal->remoteDetails, module->id, paramId, value); } - module->params[paramId].value = value; + module->params[paramId].setValue(value); } float Engine::getParamValue(Module* module, int paramId) { - return module->params[paramId].value; + return module->params[paramId].getValue(); } void Engine::setParamSmoothValue(Module* module, int paramId, float value) { // If another param is being smoothed, jump value if (internal->smoothModule && !(internal->smoothModule == module && internal->smoothParamId == paramId)) { - internal->smoothModule->params[internal->smoothParamId].value = internal->smoothValue; + internal->smoothModule->params[internal->smoothParamId].setValue(internal->smoothValue); } internal->smoothParamId = paramId; internal->smoothValue = value; @@ -1130,7 +1121,7 @@ void Engine::setParamSmoothValue(Module* module, int paramId, float value) { float Engine::getParamSmoothValue(Module* module, int paramId) { if (internal->smoothModule == module && internal->smoothParamId == paramId) return internal->smoothValue; - return module->params[paramId].value; + return module->params[paramId].getValue(); } diff --git a/src/override/MenuBar.cpp b/src/override/MenuBar.cpp index 659c7a4..62bfbac 100644 --- a/src/override/MenuBar.cpp +++ b/src/override/MenuBar.cpp @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's app/MenuBar.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -60,8 +60,6 @@ # include #endif -void switchDarkMode(bool darkMode); - namespace rack { namespace asset { std::string patchesPath(); @@ -739,7 +737,7 @@ struct HelpButton : MenuButton { patchUtils::openBrowser("https://vcvrack.com/manual"); })); - menu->addChild(createMenuItem("Cardinal Project page", "", [=]() { + menu->addChild(createMenuItem("Cardinal project page", "", [=]() { patchUtils::openBrowser("https://github.com/DISTRHO/Cardinal/"); })); @@ -751,7 +749,6 @@ struct HelpButton : MenuButton { menu->addChild(new ui::MenuSeparator); - menu->addChild(createMenuLabel("Cardinal " + APP_EDITION + " " + CARDINAL_VERSION)); menu->addChild(createMenuLabel("Rack " + APP_VERSION + " Compatible")); } }; @@ -762,23 +759,25 @@ struct HelpButton : MenuButton { //////////////////// -struct MeterLabel : ui::Label { - int frameIndex = 0; +struct InfoLabel : ui::Label { + int frameCount = 0; double frameDurationTotal = 0.0; - double frameDurationAvg = 0.0; - double uiLastTime = 0.0; - double uiLastThreadTime = 0.0; - double uiFrac = 0.0; + double frameDurationAvg = NAN; + // double uiLastTime = 0.0; + // double uiLastThreadTime = 0.0; + // double uiFrac = 0.0; void step() override { // Compute frame rate double frameDuration = APP->window->getLastFrameDuration(); - frameDurationTotal += frameDuration; - frameIndex++; + if (std::isfinite(frameDuration)) { + frameDurationTotal += frameDuration; + frameCount++; + } if (frameDurationTotal >= 1.0) { - frameDurationAvg = frameDurationTotal / frameIndex; + frameDurationAvg = frameDurationTotal / frameCount; frameDurationTotal = 0.0; - frameIndex = 0; + frameCount = 0; } // Compute UI thread CPU @@ -791,13 +790,21 @@ struct MeterLabel : ui::Label { // uiLastTime = time; // } + text = ""; + + if (box.size.x >= 400) { + double fps = std::isfinite(frameDurationAvg) ? 1.0 / frameDurationAvg : 0.0; #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS - double meterAverage = APP->engine->getMeterAverage(); - double meterMax = APP->engine->getMeterMax(); - text = string::f("%.1f fps %.1f%% avg %.1f%% max", 1.0 / frameDurationAvg, meterAverage * 100, meterMax * 100); + double meterAverage = APP->engine->getMeterAverage(); + double meterMax = APP->engine->getMeterMax(); + text = string::f("%.1f fps %.1f%% avg %.1f%% max", fps, meterAverage * 100, meterMax * 100); #else - text = string::f("%.1f fps", 1.0 / frameDurationAvg); + text = string::f("%.1f fps", fps); #endif + text += " "; + } + + text += "Cardinal " + APP_EDITION + " " + CARDINAL_VERSION; Label::step(); } @@ -805,7 +812,7 @@ struct MeterLabel : ui::Label { struct MenuBar : widget::OpaqueWidget { - MeterLabel* meterLabel; + InfoLabel* infoLabel; MenuBar(const bool isStandalone) : widget::OpaqueWidget() @@ -840,16 +847,10 @@ struct MenuBar : widget::OpaqueWidget { helpButton->text = "Help"; layout->addChild(helpButton); - // ui::Label* titleLabel = new ui::Label; - // titleLabel->color.a = 0.5; - // layout->addChild(titleLabel); - - meterLabel = new MeterLabel; - meterLabel->box.pos.y = margin; - meterLabel->box.size.x = 300; - meterLabel->alignment = ui::Label::RIGHT_ALIGNMENT; - meterLabel->color.a = 0.5; - addChild(meterLabel); + infoLabel = new InfoLabel; + infoLabel->box.size.x = 600; + infoLabel->alignment = ui::Label::RIGHT_ALIGNMENT; + layout->addChild(infoLabel); } void draw(const DrawArgs& args) override { @@ -860,8 +861,10 @@ struct MenuBar : widget::OpaqueWidget { } void step() override { - meterLabel->box.pos.x = box.size.x - meterLabel->box.size.x - 5; Widget::step(); + infoLabel->box.size.x = box.size.x - infoLabel->box.pos.x - 5; + // Setting 50% alpha prevents Label from using the default UI theme color, so set the color manually here. + infoLabel->color = color::alpha(bndGetTheme()->regularTheme.textColor, 0.5); } }; diff --git a/src/override/Model.cpp b/src/override/Model.cpp index a2541be..454292b 100644 --- a/src/override/Model.cpp +++ b/src/override/Model.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's plugin/Model.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -85,9 +85,12 @@ void Model::fromJson(json_t* rootJ) { // hidden json_t* hiddenJ = json_object_get(rootJ, "hidden"); - // Use `disabled` as an alias which was deprecated in Rack 2.0 + // "disabled" was a deprecated alias in Rack <2 if (!hiddenJ) hiddenJ = json_object_get(rootJ, "disabled"); + // "deprecated" was a deprecated alias in Rack <2.2.4 + if (!hiddenJ) + hiddenJ = json_object_get(rootJ, "deprecated"); if (hiddenJ) { // Don't un-hide Model if already hidden by C++ if (json_boolean_value(hiddenJ)) @@ -185,6 +188,13 @@ void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { })); } + // author email + if (plugin->authorEmail != "") { + menu->addChild(createMenuItem("Author email", "Copy to clipboard", [=]() { + glfwSetClipboardString(APP->window->win, plugin->authorEmail.c_str()); + })); + } + // Favorite std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : ""; if (isFavorite()) diff --git a/src/override/ModuleWidget.cpp b/src/override/ModuleWidget.cpp index 002c510..36423e3 100644 --- a/src/override/ModuleWidget.cpp +++ b/src/override/ModuleWidget.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's ModuleWidget.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -30,8 +30,6 @@ #include #include -#include - #include #include #include @@ -420,6 +418,7 @@ void ModuleWidget::onButton(const ButtonEvent& e) { // If module positions are locked, don't consume left-click if (settings::lockModules) { + e.consume(NULL); return; } @@ -449,6 +448,7 @@ void ModuleWidget::onButton(const ButtonEvent& e) { // If module positions are locked, don't consume left-click if (settings::lockModules) { + e.consume(NULL); return; } @@ -700,7 +700,7 @@ void ModuleWidget::save(std::string filename) { FILE* file = std::fopen(filename.c_str(), "w"); if (!file) { std::string message = string::f("Could not save preset to file %s", filename.c_str()); - osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str()); + async_dialog_message(message.c_str()); return; } DEFER({std::fclose(file);}); @@ -718,10 +718,12 @@ void ModuleWidget::saveTemplate() { void ModuleWidget::saveTemplateDialog() { if (hasTemplate()) { std::string message = string::f("Overwrite default preset for %s?", model->getFullName().c_str()); - if (!osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, message.c_str())) - return; + WeakPtr weakThis = this; + async_dialog_message(message.c_str(), [=]{ + if (weakThis) + weakThis->saveTemplate(); + }); } - saveTemplate(); } bool ModuleWidget::hasTemplate() { @@ -738,9 +740,11 @@ void ModuleWidget::clearTemplate() { void ModuleWidget::clearTemplateDialog() { std::string message = string::f("Delete default preset for %s?", model->getFullName().c_str()); - if (!osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, message.c_str())) - return; - clearTemplate(); + WeakPtr weakThis = this; + async_dialog_message(message.c_str(), [=]{ + if (weakThis) + weakThis->clearTemplate(); + }); } void ModuleWidget::saveDialog() { @@ -978,12 +982,16 @@ static void appendPresetItems(ui::Menu* menu, WeakPtr moduleWidget std::regex r("^\\d+_"); name = std::regex_replace(name, r, ""); - if (false) { + if (system::isDirectory(path)) { + hasPresets = true; + + menu->addChild(createSubmenuItem(name, "", [=](ui::Menu* menu) { + if (!moduleWidget) + return; + appendPresetItems(menu, moduleWidget, path); + })); } else if (system::getExtension(path) == ".vcvm" && name != "template") { - if (!hasPresets) - menu->addChild(new ui::MenuSeparator); - hasPresets = true; menu->addChild(createMenuItem(name, "", [=]() { @@ -999,6 +1007,9 @@ static void appendPresetItems(ui::Menu* menu, WeakPtr moduleWidget } } } + if (!hasPresets) { + menu->addChild(createMenuLabel("(None)")); + } }; @@ -1037,7 +1048,6 @@ void ModuleWidget::createContextMenu() { weakThis->loadDialog(); })); - /* TODO requires setting up user dir menu->addChild(createMenuItem("Save as", "", [=]() { if (!weakThis) return; @@ -1060,13 +1070,10 @@ void ModuleWidget::createContextMenu() { menu->addChild(new ui::MenuSeparator); menu->addChild(createMenuLabel("User presets")); appendPresetItems(menu, weakThis, weakThis->model->getUserPresetDirectory()); - */ // Scan `/presets/` for presets. - /* TODO enable only after setting up user dir menu->addChild(new ui::MenuSeparator); menu->addChild(createMenuLabel("Factory presets")); - */ appendPresetItems(menu, weakThis, weakThis->model->getFactoryPresetDirectory()); })); diff --git a/src/override/OpenGlWidget.cpp b/src/override/OpenGlWidget.cpp index a8aad19..da448d0 100644 --- a/src/override/OpenGlWidget.cpp +++ b/src/override/OpenGlWidget.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's OpenGlWidget.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/override/Scene.cpp b/src/override/Scene.cpp index 184507f..fcb2317 100644 --- a/src/override/Scene.cpp +++ b/src/override/Scene.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's app/Scene.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -343,6 +343,8 @@ void Scene::onHoverKey(const HoverKeyEvent& e) { #ifdef DISTRHO_OS_WASM 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(); e.consume(this); } #endif diff --git a/src/override/Window.cpp b/src/override/Window.cpp index af99839..66b62d3 100644 --- a/src/override/Window.cpp +++ b/src/override/Window.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's window/Window.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -172,13 +172,12 @@ struct Window::Internal { int currentRateLimit = 0; int frame = 0; - int frameSwapInterval = 1; #ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS int generateScreenshotStep = kScreenshotStepNone; #endif double monitorRefreshRate = 60.0; - double frameTime = 0.0; - double lastFrameDuration = 0.0; + double frameTime = NAN; + double lastFrameDuration = NAN; std::map> fontCache; std::map> imageCache; @@ -610,11 +609,12 @@ void Window::step() { return; double frameTime = system::getTime(); - double lastFrameTime = internal->frameTime; + if (std::isfinite(internal->frameTime)) { + internal->lastFrameDuration = frameTime - internal->frameTime; + } internal->frameTime = frameTime; - internal->lastFrameDuration = frameTime - lastFrameTime; internal->fbCount = 0; - // DEBUG("%.2lf Hz", 1.0 / internal->lastFrameDuration); + // double t1 = 0.0, t2 = 0.0, t3 = 0.0, t4 = 0.0, t5 = 0.0; // Make event handlers and step() have a clean NanoVG context nvgReset(vg); @@ -659,28 +659,31 @@ void Window::step() { // Get framebuffer/window ratio int winWidth = internal->tlw->getWidth(); int winHeight = internal->tlw->getHeight(); - int fbWidth = winWidth;// * newPixelRatio; - int fbHeight = winHeight;// * newPixelRatio; + int fbWidth = winWidth; + int fbHeight = winHeight; windowRatio = (float)fbWidth / winWidth; + // t1 = system::getTime(); if (APP->scene) { // DEBUG("%f %f %d %d", pixelRatio, windowRatio, fbWidth, winWidth); // Resize scene - APP->scene->box.size = math::Vec(fbWidth, fbHeight).div(newPixelRatio); + APP->scene->box.size = math::Vec(fbWidth, fbHeight).div(pixelRatio); // Step scene APP->scene->step(); + // t2 = system::getTime(); // Render scene { // Update and render - nvgScale(vg, newPixelRatio, newPixelRatio); + nvgScale(vg, pixelRatio, pixelRatio); // Draw scene widget::Widget::DrawArgs args; args.vg = vg; args.clipBox = APP->scene->box.zeroPos(); APP->scene->draw(args); + // t3 = system::getTime(); glViewport(0, 0, fbWidth, fbHeight); #ifdef CARDINAL_TRANSPARENT_SCREENSHOTS @@ -690,8 +693,18 @@ void Window::step() { #endif glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } + // t4 = system::getTime(); } + // t5 = system::getTime(); + // DEBUG("pre-step %6.1f step %6.1f draw %6.1f nvgEndFrame %6.1f glfwSwapBuffers %6.1f total %6.1f", + // (t1 - frameTime) * 1e3f, + // (t2 - t1) * 1e3f, + // (t3 - t2) * 1e3f, + // (t4 - t3) * 1e3f, + // (t5 - t4) * 1e3f, + // (t5 - frameTime) * 1e3f + // ); ++internal->frame; #ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS @@ -739,15 +752,11 @@ void Window::step() { } -void Window::activateContext() { +void Window::screenshot(const std::string& screenshotPath) { } -void Window::screenshot(const std::string&) { -} - - -void Window::screenshotModules(const std::string&, float) { +void Window::screenshotModules(const std::string& screenshotsDir, float zoom) { } @@ -793,9 +802,9 @@ int Window::getMods() { } -void Window::setFullScreen(const bool fullscreen) { +void Window::setFullScreen(bool fullScreen) { #ifdef DISTRHO_OS_WASM - if (fullscreen) + if (fullScreen) emscripten_request_fullscreen(internal->tlw->getWindow().getApp().getClassName(), false); else emscripten_exit_fullscreen(); @@ -816,6 +825,7 @@ bool Window::isFullScreen() { #endif } + double Window::getMonitorRefreshRate() { return internal->monitorRefreshRate; } @@ -832,8 +842,8 @@ double Window::getLastFrameDuration() { double Window::getFrameDurationRemaining() { - double frameDurationDesired = internal->frameSwapInterval / internal->monitorRefreshRate; - return frameDurationDesired - (system::getTime() - internal->frameTime); + double frameDuration = 1.f / internal->monitorRefreshRate; + return frameDuration - (system::getTime() - internal->frameTime); } diff --git a/src/override/common.cpp b/src/override/common.cpp index b61839f..32b9962 100644 --- a/src/override/common.cpp +++ b/src/override/common.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's common.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -63,13 +63,16 @@ 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 = "2.1.2"; +const std::string APP_VERSION = "2.3.0"; #if defined ARCH_WIN const std::string APP_OS = "win"; + const std::string APP_OS_NAME = "Windows"; #elif defined ARCH_MAC const std::string APP_OS = "mac"; + const std::string APP_OS_NAME = "macOS"; #elif defined ARCH_LIN const std::string APP_OS = "lin"; + const std::string APP_OS_NAME = "Linux"; #else #error ARCH_LIN undefined #endif diff --git a/src/override/context.cpp b/src/override/context.cpp index 3f08e74..f1ce13b 100644 --- a/src/override/context.cpp +++ b/src/override/context.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's context.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -31,7 +31,6 @@ #include #include #include -#include #ifdef NDEBUG # undef DEBUG diff --git a/src/override/diffs/Engine.cpp.diff b/src/override/diffs/Engine.cpp.diff index b3609d4..7470727 100644 --- a/src/override/diffs/Engine.cpp.diff +++ b/src/override/diffs/Engine.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/engine/Engine.cpp 2022-09-21 19:49:12.200540736 +0100 -+++ Engine.cpp 2022-12-29 16:15:36.061769776 +0000 +--- ../Rack/src/engine/Engine.cpp 2023-05-20 17:03:33.006081772 +0200 ++++ Engine.cpp 2023-05-20 19:35:00.711346791 +0200 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's engine/Engine.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -31,10 +31,14 @@ #include #include #include -@@ -6,183 +33,39 @@ +@@ -5,192 +32,47 @@ + #include #include #include - #include +-#if defined ARCH_X64 +- #include +-#endif ++#include +#include #include @@ -48,14 +52,12 @@ #include +#include -+#ifdef NDEBUG -+# undef DEBUG -+#endif - +- -namespace rack { -namespace engine { - - +-#if defined ARCH_X64 -static void initMXCSR() { - // Set CPU to flush-to-zero (FTZ) and denormals-are-zero (DAZ) mode - // https://software.intel.com/en-us/node/682949 @@ -64,8 +66,13 @@ - // Reset other flags - _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST); -} -- -- ++#ifdef NDEBUG ++# undef DEBUG + #endif + ++#include "../CardinalRemote.hpp" ++#include "DistrhoUtils.hpp" + -/** Barrier based on mutexes. -Not finished or tested, do not use. -*/ @@ -98,25 +105,21 @@ - }); - } -}; -+#include "../CardinalRemote.hpp" -+#include "DistrhoUtils.hpp" - - +- +- -/** 2-phase barrier based on spin-locking. -*/ -struct SpinBarrier { - std::atomic count{0}; - std::atomic step{0}; - int threads = 0; -+// known terminal modules -+extern std::vector hostTerminalModels; - +- - /** 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) { @@ -131,12 +134,16 @@ - while (true) { - if (step.load(std::memory_order_relaxed) != s) - return; +-#if defined ARCH_X64 - __builtin_ia32_pause(); +-#endif - } - } -}; -- -- + ++// known terminal modules ++extern std::vector hostTerminalModels; + -/** 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. @@ -173,12 +180,14 @@ - } - return; - } -- + - // Spin until the last thread begins waiting - while (!yielded.load(std::memory_order_relaxed)) { - if (step.load(std::memory_order_relaxed) != s) - return; +-#if defined ARCH_X64 - __builtin_ia32_pause(); +-#endif - } - - // Wait on mutex CV @@ -195,7 +204,9 @@ - int id; - std::thread thread; - bool running = false; -- ++namespace rack { ++namespace engine { + - void start() { - assert(!running); - running = true; @@ -203,7 +214,7 @@ - run(); - }); - } -- + - void requestStop() { - running = false; - } @@ -215,8 +226,11 @@ - - void run(); -}; -+namespace rack { -+namespace engine { ++static constexpr const int PORT_DIVIDER = 7; ++// Arbitrary prime number so it doesn't over- or under-estimate time of buffered processors. ++static constexpr const int METER_DIVIDER = 37; ++static constexpr const int METER_BUFFER_LEN = 32; ++static constexpr const float METER_TIME = 1.f; struct Engine::Internal { @@ -228,7 +242,7 @@ // moduleId std::map modulesCache; -@@ -198,7 +81,9 @@ +@@ -206,7 +88,9 @@ int64_t blockFrame = 0; double blockTime = 0.0; int blockFrames = 0; @@ -238,7 +252,7 @@ // Meter int meterCount = 0; double meterTotal = 0.0; -@@ -206,33 +91,21 @@ +@@ -214,33 +98,32 @@ double meterLastTime = -INFINITY; double meterLastAverage = 0.0; double meterLastMax = 0.0; @@ -260,7 +274,9 @@ - /** Mutex that guards stepBlock() so it's not called simultaneously. - */ - std::mutex blockMutex; -- ++}; ++ + - int threadCount = 0; - std::vector workers; - HybridBarrier engineBarrier; @@ -273,10 +289,18 @@ - std::thread fallbackThread; - std::mutex fallbackMutex; - std::condition_variable fallbackCv; ++struct Module::Internal { ++ bool bypassed = false; ++ ++ int meterSamples = 0; ++ float meterDurationTotal = 0.f; ++ ++ float meterBuffer[METER_BUFFER_LEN] = {}; ++ int meterIndex = 0; }; -@@ -260,76 +133,11 @@ +@@ -268,89 +151,134 @@ } @@ -284,28 +308,66 @@ - Engine::Internal* internal = that->internal; - if (threadCount == internal->threadCount) - return; -- ++static void Cable_step(Cable* that) { ++ Output* output = &that->outputModule->outputs[that->outputId]; ++ Input* input = &that->inputModule->inputs[that->inputId]; ++ // Match number of polyphonic channels to output port ++ const int channels = output->channels; ++ // Copy all voltages from output to input ++ for (int c = 0; c < channels; c++) { ++ if (!std::isfinite(output->voltages[c])) ++ __builtin_unreachable(); ++ input->voltages[c] = output->voltages[c]; ++ } ++ // Set higher channel voltages to 0 ++ for (int c = channels; c < input->channels; c++) { ++ input->voltages[c] = 0.f; ++ } ++ input->channels = channels; ++} + - 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); -- } -- ++#ifndef HEADLESS ++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); ++ } ++} ++#endif + - // 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); @@ -314,17 +376,41 @@ - worker.id = id; - worker.engine = that; - worker.start(); -- } -- } --} -- -- ++static void TerminalModule__doProcess(TerminalModule* const 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); ++ } ++ ++#ifndef HEADLESS ++ // Iterate ports to step plug lights ++ if (args.frame % PORT_DIVIDER == 0) { ++ float portTime = args.sampleTime * PORT_DIVIDER; ++ for (Input& input : terminalModule->inputs) { ++ Port_step(&input, portTime); ++ } ++ for (Output& output : terminalModule->outputs) { ++ Port_step(&output, portTime); + } + } ++#endif + } + + -static void Engine_stepWorker(Engine* that, int threadId) { - Engine::Internal* internal = that->internal; - - // int threadCount = internal->threadCount; - int modulesLen = internal->modules.size(); -- ++static void Module__doProcess(Module* const module, const Module::ProcessArgs& args) { ++ Module::Internal* const internal = module->internal; + - // Build ProcessArgs - Module::ProcessArgs processArgs; - processArgs.sampleRate = internal->sampleRate; @@ -341,74 +427,83 @@ - - Module* module = internal->modules[i]; - module->doProcess(processArgs); -- } ++#ifndef HEADLESS ++ // This global setting can change while the function is running, so use a local variable. ++ bool meterEnabled = settings::cpuMeter && (args.frame % METER_DIVIDER == 0); ++ ++ // Start CPU timer ++ double startTime; ++ if (meterEnabled) { ++ startTime = system::getTime(); + } -} - -- - static void Cable_step(Cable* that) { - Output* output = &that->outputModule->outputs[that->outputId]; - Input* input = &that->inputModule->inputs[that->inputId]; - // Match number of polyphonic channels to output port ++#endif + +-static void Cable_step(Cable* that) { +- Output* output = &that->outputModule->outputs[that->outputId]; +- Input* input = &that->inputModule->inputs[that->inputId]; +- // 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 +154,53 @@ +- // Copy all voltages from output to input +- for (int c = 0; c < channels; c++) { +- float v = output->voltages[c]; +- // Set 0V if infinite or NaN +- if (!std::isfinite(v)) +- v = 0.f; +- input->voltages[c] = v; ++ // Step module ++ if (!internal->bypassed) ++ module->process(args); ++ else ++ module->processBypass(args); ++ ++#ifndef HEADLESS ++ // Stop CPU timer ++ if (meterEnabled) { ++ double endTime = system::getTime(); ++ // Subtract call time of getTime() itself, since we only want to measure process() time. ++ double endTime2 = system::getTime(); ++ float duration = (endTime - startTime) - (endTime2 - endTime); ++ ++ internal->meterSamples++; ++ internal->meterDurationTotal += duration; ++ ++ // Seconds we've been measuring ++ float meterTime = internal->meterSamples * METER_DIVIDER * args.sampleTime; ++ ++ if (meterTime >= METER_TIME) { ++ // Push time to buffer ++ if (internal->meterSamples > 0) { ++ internal->meterIndex++; ++ internal->meterIndex %= METER_BUFFER_LEN; ++ internal->meterBuffer[internal->meterIndex] = internal->meterDurationTotal / internal->meterSamples; ++ } ++ // Reset total ++ internal->meterSamples = 0; ++ internal->meterDurationTotal = 0.f; ++ } + } +- // Set higher channel voltages to 0 +- for (int c = channels; c < input->channels; c++) { +- input->voltages[c] = 0.f; ++ ++ // Iterate ports to step plug lights ++ if (args.frame % PORT_DIVIDER == 0) { ++ float portTime = args.sampleTime * PORT_DIVIDER; ++ for (Input& input : module->inputs) { ++ Port_step(&input, portTime); ++ } ++ for (Output& output : module->outputs) { ++ Port_step(&output, portTime); ++ } + } +- input->channels = channels; ++#endif } -+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) { -@@ -358,10 +213,16 @@ +@@ -366,10 +294,16 @@ float smoothValue = internal->smoothValue; Param* smoothParam = &smoothModule->params[smoothParamId]; float value = smoothParam->value; @@ -429,7 +524,7 @@ // Snap to actual smooth value if the value doesn't change enough (due to the granularity of floats) smoothParam->setValue(smoothValue); internal->smoothModule = NULL; -@@ -372,13 +233,8 @@ +@@ -380,13 +314,8 @@ } } @@ -444,7 +539,7 @@ if (module->leftExpander.messageFlipRequested) { std::swap(module->leftExpander.producerMessage, module->leftExpander.consumerMessage); module->leftExpander.messageFlipRequested = false; -@@ -389,13 +245,32 @@ +@@ -397,13 +326,32 @@ } } @@ -463,10 +558,11 @@ + for (TerminalModule* terminalModule : internal->terminalModules) { + TerminalModule__doProcess(terminalModule, processArgs, true); + } -+ + +- internal->frame++; + // Step each module and cables + for (Module* module : internal->modules) { -+ module->doProcess(processArgs); ++ Module__doProcess(module, processArgs); + for (Output& output : module->outputs) { + for (Cable* cable : output.cables) + Cable_step(cable); @@ -477,13 +573,12 @@ + for (TerminalModule* terminalModule : internal->terminalModules) { + TerminalModule__doProcess(terminalModule, processArgs, false); + } - -- internal->frame++; ++ + ++internal->frame; } -@@ -414,35 +289,119 @@ +@@ -422,35 +370,119 @@ } @@ -604,17 +699,17 @@ - Port_setDisconnected(port); + for (Input* input : disconnectedInputs) { + Port_setDisconnected(input); -+ } + } + for (Output* output : disconnectedOutputs) { + Port_setDisconnected(output); + DISTRHO_SAFE_ASSERT(output->cables.empty()); - } ++ } + // Order the modules according to their connections + Engine_orderModules(that); } -@@ -460,37 +419,23 @@ +@@ -468,37 +500,23 @@ Engine::Engine() { internal = new Internal; @@ -660,7 +755,7 @@ delete internal; } -@@ -519,18 +464,22 @@ +@@ -527,20 +545,22 @@ removeModule_NoLock(module); delete module; } @@ -681,12 +776,14 @@ - std::lock_guard stepLock(internal->blockMutex); SharedLock lock(internal->mutex); // Configure thread +-#if defined ARCH_X64 - uint32_t csr = _mm_getcsr(); - initMXCSR(); +-#endif random::init(); internal->blockFrame = internal->frame; -@@ -543,18 +492,14 @@ +@@ -553,18 +573,14 @@ Engine_updateExpander_NoLock(this, module, true); } @@ -706,14 +803,15 @@ // Stop timer double endTime = system::getTime(); double meter = (endTime - startTime) / (frames * internal->sampleTime); -@@ -572,47 +517,20 @@ +@@ -582,49 +598,20 @@ internal->meterTotal = 0.0; internal->meterMax = 0.0; } - +-#if defined ARCH_X64 - // Reset MXCSR back to original value - _mm_setcsr(csr); -+#endif + #endif } @@ -756,7 +854,7 @@ } -@@ -635,20 +553,13 @@ +@@ -647,20 +634,13 @@ for (Module* module : internal->modules) { module->onSampleRateChange(e); } @@ -780,7 +878,7 @@ } -@@ -658,7 +569,6 @@ +@@ -670,7 +650,6 @@ void Engine::yieldWorkers() { @@ -788,7 +886,7 @@ } -@@ -698,17 +608,25 @@ +@@ -705,17 +684,25 @@ double Engine::getMeterAverage() { @@ -815,7 +913,7 @@ } -@@ -718,8 +636,12 @@ +@@ -725,8 +712,12 @@ for (Module* m : internal->modules) { if (i >= len) break; @@ -830,7 +928,7 @@ } return i; } -@@ -728,27 +650,43 @@ +@@ -735,27 +726,43 @@ std::vector Engine::getModuleIds() { SharedLock lock(internal->mutex); std::vector moduleIds; @@ -878,7 +976,7 @@ internal->modulesCache[module->id] = module; // Dispatch AddEvent Module::AddEvent eAdd; -@@ -763,6 +701,9 @@ +@@ -770,6 +777,9 @@ if (paramHandle->moduleId == module->id) paramHandle->module = module; } @@ -888,7 +986,7 @@ } -@@ -772,11 +713,11 @@ +@@ -779,11 +789,11 @@ } @@ -905,7 +1003,7 @@ // Dispatch RemoveEvent Module::RemoveEvent eRemove; module->onRemove(eRemove); -@@ -785,18 +726,14 @@ +@@ -792,18 +802,14 @@ if (paramHandle->moduleId == module->id) paramHandle->module = NULL; } @@ -926,7 +1024,7 @@ } // Update expanders of other modules for (Module* m : internal->modules) { -@@ -809,14 +746,31 @@ +@@ -816,14 +822,31 @@ m->rightExpander.module = NULL; } } @@ -961,7 +1059,7 @@ } -@@ -824,7 +778,8 @@ +@@ -831,7 +854,8 @@ SharedLock lock(internal->mutex); // TODO Performance could be improved by searching modulesCache, but more testing would be needed to make sure it's always valid. auto it = std::find(internal->modules.begin(), internal->modules.end(), module); @@ -971,7 +1069,7 @@ } -@@ -844,7 +799,7 @@ +@@ -851,7 +875,7 @@ void Engine::resetModule(Module* module) { std::lock_guard lock(internal->mutex); @@ -980,7 +1078,7 @@ Module::ResetEvent eReset; module->onReset(eReset); -@@ -853,7 +808,7 @@ +@@ -860,7 +884,7 @@ void Engine::randomizeModule(Module* module) { std::lock_guard lock(internal->mutex); @@ -989,7 +1087,7 @@ Module::RandomizeEvent eRandomize; module->onRandomize(eRandomize); -@@ -861,7 +816,7 @@ +@@ -868,7 +892,7 @@ void Engine::bypassModule(Module* module, bool bypassed) { @@ -998,7 +1096,7 @@ if (module->isBypassed() == bypassed) return; -@@ -907,11 +862,17 @@ +@@ -914,11 +938,17 @@ void Engine::prepareSave() { @@ -1016,7 +1114,7 @@ } -@@ -946,16 +907,16 @@ +@@ -953,16 +983,16 @@ void Engine::addCable(Cable* cable) { std::lock_guard lock(internal->mutex); @@ -1038,7 +1136,7 @@ // 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) -@@ -969,6 +930,8 @@ +@@ -976,6 +1006,8 @@ // Add the cable internal->cables.push_back(cable); internal->cablesCache[cable->id] = cable; @@ -1047,7 +1145,7 @@ Engine_updateConnected(this); // Dispatch input port event { -@@ -996,10 +959,12 @@ +@@ -1003,10 +1035,12 @@ void Engine::removeCable_NoLock(Cable* cable) { @@ -1062,17 +1160,17 @@ // Remove the cable internal->cablesCache.erase(cable->id); internal->cables.erase(it); -@@ -1053,6 +1018,9 @@ +@@ -1060,6 +1094,9 @@ internal->smoothModule = NULL; internal->smoothParamId = 0; } + if (internal->remoteDetails != nullptr) { + sendParamChangeToRemote(internal->remoteDetails, module->id, paramId, value); + } - module->params[paramId].value = value; + module->params[paramId].setValue(value); } -@@ -1085,11 +1053,11 @@ +@@ -1092,11 +1129,11 @@ std::lock_guard lock(internal->mutex); // New ParamHandles must be blank. // This means we don't have to refresh the cache. @@ -1086,7 +1184,7 @@ // Add it internal->paramHandles.insert(paramHandle); -@@ -1106,7 +1074,7 @@ +@@ -1113,7 +1150,7 @@ void Engine::removeParamHandle_NoLock(ParamHandle* paramHandle) { // Check that the ParamHandle is already added auto it = internal->paramHandles.find(paramHandle); @@ -1095,7 +1193,7 @@ // Remove it paramHandle->module = NULL; -@@ -1143,7 +1111,7 @@ +@@ -1150,7 +1187,7 @@ void Engine::updateParamHandle_NoLock(ParamHandle* paramHandle, int64_t moduleId, int paramId, bool overwrite) { // Check that it exists auto it = internal->paramHandles.find(paramHandle); @@ -1104,7 +1202,7 @@ // Set IDs paramHandle->moduleId = moduleId; -@@ -1187,6 +1155,10 @@ +@@ -1194,6 +1231,10 @@ json_t* moduleJ = module->toJson(); json_array_append_new(modulesJ, moduleJ); } @@ -1115,7 +1213,7 @@ json_object_set_new(rootJ, "modules", modulesJ); // cables -@@ -1197,11 +1169,6 @@ +@@ -1204,11 +1245,6 @@ } json_object_set_new(rootJ, "cables", cablesJ); @@ -1127,7 +1225,7 @@ return rootJ; } -@@ -1225,14 +1192,20 @@ +@@ -1232,14 +1268,20 @@ } catch (Exception& e) { WARN("Cannot load model: %s", e.what()); @@ -1152,7 +1250,7 @@ try { // This doesn't need a lock because the Module is not added to the Engine yet. -@@ -1248,7 +1221,8 @@ +@@ -1255,7 +1297,8 @@ } catch (Exception& e) { WARN("Cannot load module: %s", e.what()); @@ -1162,7 +1260,7 @@ delete module; continue; } -@@ -1285,67 +1259,20 @@ +@@ -1292,69 +1335,20 @@ continue; } } @@ -1180,7 +1278,9 @@ - // Configure thread - contextSet(engine->internal->context); - system::setThreadName(string::f("Worker %d", id)); +-#if defined ARCH_X64 - initMXCSR(); +-#endif - random::init(); - - while (true) { diff --git a/src/override/diffs/MenuBar.cpp.diff b/src/override/diffs/MenuBar.cpp.diff index e34016e..167fcbe 100644 --- a/src/override/diffs/MenuBar.cpp.diff +++ b/src/override/diffs/MenuBar.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/app/MenuBar.cpp 2022-09-21 19:49:12.198540676 +0100 -+++ MenuBar.cpp 2022-12-30 14:50:06.801891005 +0000 +--- ../Rack/src/app/MenuBar.cpp 2023-05-20 17:03:33.005081737 +0200 ++++ MenuBar.cpp 2023-05-20 19:32:57.019576570 +0200 @@ -1,8 +1,33 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's app/MenuBar.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -44,7 +44,7 @@ #include #include #include -@@ -25,8 +51,28 @@ +@@ -25,8 +51,26 @@ #include #include @@ -56,8 +56,6 @@ +#ifdef HAVE_LIBLO +# include +#endif -+ -+void switchDarkMode(bool darkMode); namespace rack { +namespace asset { @@ -73,7 +71,7 @@ namespace app { namespace menuBar { -@@ -48,79 +94,160 @@ +@@ -48,79 +92,180 @@ }; @@ -97,15 +95,16 @@ struct FileButton : MenuButton { + const bool isStandalone; -+#if ! CARDINAL_VARIANT_MINI + std::vector demoPatches; -+#endif + + FileButton(const bool standalone) + : MenuButton(), isStandalone(standalone) + { -+#if ! CARDINAL_VARIANT_MINI ++#if CARDINAL_VARIANT_MINI ++ const std::string patchesDir = asset::patchesPath() + DISTRHO_OS_SEP_STR "mini"; ++#else + const std::string patchesDir = asset::patchesPath() + DISTRHO_OS_SEP_STR "examples"; ++#endif + + if (system::isDirectory(patchesDir)) + { @@ -114,7 +113,6 @@ + return string::lowercase(a) < string::lowercase(b); + }); + } -+#endif + } + void onAction(const ActionEvent& e) override { @@ -125,31 +123,36 @@ - menu->addChild(createMenuItem("New", RACK_MOD_CTRL_NAME "+N", []() { - APP->patch->loadTemplateDialog(); +#ifndef DISTRHO_OS_WASM -+ const char* const NewShortcut = RACK_MOD_CTRL_NAME "+N"; ++ constexpr const char* const NewShortcut = RACK_MOD_CTRL_NAME "+N"; +#else -+ const char* const NewShortcut = ""; ++ constexpr const char* const NewShortcut = ""; +#endif + menu->addChild(createMenuItem("New", NewShortcut, []() { -+ patchUtils::loadTemplateDialog(); ++ patchUtils::loadTemplateDialog(false); ++ })); ++ ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS ++#ifndef DISTRHO_OS_WASM ++ menu->addChild(createMenuItem("New (factory template)", "", []() { ++ patchUtils::loadTemplateDialog(true); })); - menu->addChild(createMenuItem("Open", RACK_MOD_CTRL_NAME "+O", []() { - APP->patch->loadDialog(); -+#if ! CARDINAL_VARIANT_MINI -+#ifndef DISTRHO_OS_WASM + 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, "", [=]() { + 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())); -- ++ patchUtils::loadPathDialog(path, false); + })); + } + }, settings::recentPatchPaths.empty())); + menu->addChild(createMenuItem("Save", RACK_MOD_CTRL_NAME "+S", []() { - APP->patch->saveDialog(); + // NOTE: will do nothing if path is empty, intentionally @@ -188,20 +191,31 @@ + patchUtils::revertDialog(); + }, APP->patch->path.empty())); -- menu->addChild(createMenuItem("Overwrite template", "", []() { + menu->addChild(createMenuItem("Overwrite template", "", []() { - APP->patch->saveTemplateDialog(); -- })); -+#if defined(HAVE_LIBLO) && ! CARDINAL_VARIANT_MINI -+ menu->addChild(new ui::MenuSeparator); -+ ++ patchUtils::saveTemplateDialog(); + })); + ++#if defined(HAVE_LIBLO) || ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS ++#ifdef __MOD_DEVICES__ ++#define REMOTE_NAME "MOD" ++#else ++#define REMOTE_NAME "Remote" ++#endif + menu->addChild(new ui::MenuSeparator); + +- // Load selection +- menu->addChild(createMenuItem("Import selection", "", [=]() { +- APP->scene->rack->loadSelectionDialog(); +- }, false, true)); + remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote(); + + if (remoteDetails != nullptr && remoteDetails->connected) { -+ menu->addChild(createMenuItem("Deploy to MOD", "F7", [remoteDetails]() { ++ menu->addChild(createMenuItem("Deploy to " REMOTE_NAME, "F7", [remoteDetails]() { + remoteUtils::sendFullPatchToRemote(remoteDetails); + })); -+ menu->addChild(createCheckMenuItem("Auto deploy to MOD", "", ++ menu->addChild(createCheckMenuItem("Auto deploy to " REMOTE_NAME, "", + [remoteDetails]() {return remoteDetails->autoDeploy;}, + [remoteDetails]() { + remoteDetails->autoDeploy = !remoteDetails->autoDeploy; @@ -209,34 +223,29 @@ + } + )); + } else { -+ menu->addChild(createMenuItem("Connect to MOD", "", []() { ++ menu->addChild(createMenuItem("Connect to " REMOTE_NAME, "", []() { + DISTRHO_SAFE_ASSERT(remoteUtils::connectToRemote()); + })); + } +#endif + -+#if ! CARDINAL_VARIANT_MINI ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS +#ifndef DISTRHO_OS_WASM menu->addChild(new ui::MenuSeparator); - // Load selection -- menu->addChild(createMenuItem("Import selection", "", [=]() { -- APP->scene->rack->loadSelectionDialog(); -+ menu->addChild(createMenuItem("Import selection...", "", [=]() { -+ patchUtils::loadSelectionDialog(); - }, false, true)); - -- menu->addChild(new ui::MenuSeparator); -- - menu->addChild(createMenuItem("Quit", RACK_MOD_CTRL_NAME "+Q", []() { - APP->window->close(); ++ // Load selection ++ menu->addChild(createMenuItem("Import selection...", "", [=]() { ++ patchUtils::loadSelectionDialog(); ++ }, false, true)); ++ + menu->addChild(createMenuItem("Export uncompressed json...", "", []() { + patchUtils::saveAsDialogUncompressed(); })); +#endif +#endif + -+#if ! CARDINAL_VARIANT_MINI + if (!demoPatches.empty()) + { + menu->addChild(new ui::MenuSeparator); @@ -262,7 +271,6 @@ + })); + })); + } -+#endif + +#ifndef DISTRHO_OS_WASM + if (isStandalone) { @@ -276,7 +284,7 @@ } }; -@@ -166,7 +293,7 @@ +@@ -166,7 +311,7 @@ menu->addChild(new ui::MenuSeparator); @@ -285,7 +293,7 @@ } }; -@@ -256,7 +383,7 @@ +@@ -256,7 +401,7 @@ return settings::cableTension; } float getDefaultValue() override { @@ -294,7 +302,7 @@ } float getDisplayValue() override { return getValue() * 100; -@@ -393,36 +520,37 @@ +@@ -393,49 +538,36 @@ }; @@ -327,17 +335,34 @@ - menu->addChild(createMenuItem("Fullscreen", fullscreenText, [=]() { - APP->window->setFullScreen(!fullscreen); - })); -+ menu->addChild(createMenuLabel("Appearance")); - -- double frameRate = APP->window->getMonitorRefreshRate() / settings::frameSwapInterval; -- menu->addChild(createSubmenuItem("Frame rate", string::f("%.0f Hz", frameRate), [=](ui::Menu* menu) { +- +- menu->addChild(createSubmenuItem("Frame rate", string::f("%.0f Hz", settings::frameRateLimit), [=](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;} +- [=]() {return settings::frameRateLimit == frameRate;}, +- [=]() {settings::frameRateLimit = frameRate;} - )); - } +- })); +- +- menu->addChild(new ui::MenuSeparator); + menu->addChild(createMenuLabel("Appearance")); + +- static const std::vector uiThemes = {"dark", "light", "hcdark"}; +- static const std::vector uiThemeLabels = {"Dark", "Light", "High contrast dark"}; +- menu->addChild(createIndexSubmenuItem("Theme", uiThemeLabels, +- [=]() -> size_t { +- auto it = std::find(uiThemes.begin(), uiThemes.end(), settings::uiTheme); +- if (it == uiThemes.end()) +- return -1; +- return it - uiThemes.begin(); +- }, +- [=](size_t i) { +- settings::uiTheme = uiThemes[i]; +- ui::refreshTheme(); +- } +- )); + std::string darkModeText; + if (settings::darkMode) + darkModeText = CHECKMARK_STRING; @@ -345,15 +370,11 @@ + switchDarkMode(!settings::darkMode); + plugin::updateStaticPluginsDarkMode(); + setAllFramebufferWidgetsDirty(APP->scene); - })); ++ })); -- menu->addChild(new ui::MenuSeparator); -- menu->addChild(createMenuLabel("Appearance")); -- menu->addChild(createBoolPtrMenuItem("Show tooltips", "", &settings::tooltips)); - ZoomSlider* zoomSlider = new ZoomSlider; -@@ -446,9 +574,18 @@ +@@ -460,9 +592,18 @@ menu->addChild(haloBrightnessSlider); menu->addChild(new ui::MenuSeparator); @@ -372,13 +393,14 @@ static const std::vector knobModeLabels = { "Linear", -@@ -473,11 +610,34 @@ +@@ -487,11 +628,34 @@ menu->addChild(knobScrollSensitivitySlider); menu->addChild(new ui::MenuSeparator); -- menu->addChild(createMenuLabel("Module dragging")); +- menu->addChild(createMenuLabel("Module")); + menu->addChild(createMenuLabel("Window")); -+ + +- menu->addChild(createBoolPtrMenuItem("Lock positions", "", &settings::lockModules)); +#ifdef DISTRHO_OS_WASM + const bool fullscreen = APP->window->isFullScreen(); + std::string rightText = "F11"; @@ -388,8 +410,7 @@ + APP->window->setFullScreen(!fullscreen); + })); +#endif - -- menu->addChild(createBoolPtrMenuItem("Lock positions", "", &settings::lockModules)); ++ + menu->addChild(createBoolPtrMenuItem("Invert zoom", "", &settings::invertZoom)); - menu->addChild(createBoolPtrMenuItem("Auto-squeeze algorithm (experimental)", "", &settings::squeezeModules)); @@ -410,7 +431,7 @@ } }; -@@ -487,47 +647,6 @@ +@@ -501,47 +665,6 @@ //////////////////// @@ -458,7 +479,7 @@ struct EngineButton : MenuButton { void onAction(const ActionEvent& e) override { ui::Menu* menu = createMenu(); -@@ -541,268 +660,46 @@ +@@ -555,268 +678,46 @@ settings::cpuMeter ^= true; })); @@ -614,10 +635,10 @@ + })); } - } - +- - MenuItem::step(); - } -- + - void onAction(const ActionEvent& e) override { - std::thread t([=] { - library::syncUpdate(slug); @@ -726,11 +747,11 @@ - }); - 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; @@ -760,7 +781,7 @@ } }; -@@ -813,65 +710,23 @@ +@@ -827,32 +728,17 @@ struct HelpButton : MenuButton { @@ -778,32 +799,29 @@ - menu->addChild(createMenuItem("Tips", "", [=]() { - APP->scene->addChild(tipWindowCreate()); -- })); -- ++ menu->addChild(createMenuItem("Rack User manual", "F1", [=]() { ++ patchUtils::openBrowser("https://vcvrack.com/manual"); + })); + - menu->addChild(createMenuItem("User manual", "F1", [=]() { - system::openBrowser("https://vcvrack.com/manual"); - })); - - menu->addChild(createMenuItem("Support", "", [=]() { - system::openBrowser("https://vcvrack.com/support"); -+ menu->addChild(createMenuItem("Rack User manual", "F1", [=]() { -+ patchUtils::openBrowser("https://vcvrack.com/manual"); - })); - +- })); +- - menu->addChild(createMenuItem("VCVRack.com", "", [=]() { - system::openBrowser("https://vcvrack.com/"); -+ menu->addChild(createMenuItem("Cardinal Project page", "", [=]() { ++ menu->addChild(createMenuItem("Cardinal project page", "", [=]() { + patchUtils::openBrowser("https://github.com/DISTRHO/Cardinal/"); })); menu->addChild(new ui::MenuSeparator); +@@ -861,29 +747,9 @@ + system::openDirectory(asset::user("")); + })); -- menu->addChild(createMenuLabel(APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION)); -- -- menu->addChild(createMenuItem("Open user folder", "", [=]() { -- system::openDirectory(asset::user("")); -- })); -- - menu->addChild(createMenuItem("Changelog", "", [=]() { - system::openBrowser("https://github.com/VCVRack/Rack/blob/v2/CHANGELOG.md"); - })); @@ -822,34 +840,42 @@ - }, false, true)); - } - } -- ++ menu->addChild(new ui::MenuSeparator); + - 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")); } }; -@@ -910,9 +765,14 @@ - // uiLastTime = time; - // } +@@ -926,15 +792,19 @@ -+#if CARDINAL_VARIANT_MINI -+ text = string::f("%.1f fps", 1.0 / frameDurationAvg); + text = ""; + +- if (box.size.x >= 460) { ++ if (box.size.x >= 400) { + double fps = std::isfinite(frameDurationAvg) ? 1.0 / frameDurationAvg : 0.0; ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + double meterAverage = APP->engine->getMeterAverage(); + double meterMax = APP->engine->getMeterMax(); +- text += string::f("%.1f fps %.1f%% avg %.1f%% max", fps, meterAverage * 100, meterMax * 100); ++ text = string::f("%.1f fps %.1f%% avg %.1f%% max", fps, meterAverage * 100, meterMax * 100); +#else - double meterAverage = APP->engine->getMeterAverage(); - double meterMax = APP->engine->getMeterMax(); - text = string::f("%.1f fps %.1f%% avg %.1f%% max", 1.0 / frameDurationAvg, meterAverage * 100, meterMax * 100); ++ text = string::f("%.1f fps", fps); +#endif -+ + text += " "; + } + +- text += APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION + " " + APP_OS_NAME + " " + APP_CPU_NAME; ++ text += "Cardinal " + APP_EDITION + " " + CARDINAL_VERSION; + Label::step(); } - }; -@@ -921,7 +781,9 @@ +@@ -944,7 +814,9 @@ struct MenuBar : widget::OpaqueWidget { - MeterLabel* meterLabel; + InfoLabel* infoLabel; - MenuBar() { + MenuBar(const bool isStandalone) @@ -858,7 +884,7 @@ const float margin = 5; box.size.y = BND_WIDGET_HEIGHT + 2 * margin; -@@ -930,7 +792,7 @@ +@@ -953,7 +825,7 @@ layout->spacing = math::Vec(0, 0); addChild(layout); @@ -867,11 +893,11 @@ fileButton->text = "File"; layout->addChild(fileButton); -@@ -942,13 +804,11 @@ +@@ -965,13 +837,11 @@ viewButton->text = "View"; layout->addChild(viewButton); -+#if ! CARDINAL_VARIANT_MINI ++#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS EngineButton* engineButton = new EngineButton; engineButton->text = "Engine"; layout->addChild(engineButton); @@ -883,7 +909,7 @@ HelpButton* helpButton = new HelpButton; helpButton->text = "Help"; -@@ -984,7 +844,7 @@ +@@ -1003,7 +873,7 @@ widget::Widget* createMenuBar() { diff --git a/src/override/diffs/Model.cpp.diff b/src/override/diffs/Model.cpp.diff index 1c251b2..1807058 100644 --- a/src/override/diffs/Model.cpp.diff +++ b/src/override/diffs/Model.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/plugin/Model.cpp 2022-09-21 19:49:12.200540736 +0100 -+++ Model.cpp 2022-09-21 19:41:45.883648777 +0100 +--- ../Rack/src/plugin/Model.cpp 2023-05-20 17:03:33.007081806 +0200 ++++ Model.cpp 2023-05-20 18:29:51.484669742 +0200 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's plugin/Model.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -61,8 +61,8 @@ - // hidden json_t* hiddenJ = json_object_get(rootJ, "hidden"); - // Use `disabled` as an alias which was deprecated in Rack 2.0 -@@ -74,7 +97,7 @@ + // "disabled" was a deprecated alias in Rack <2 +@@ -77,7 +100,7 @@ std::string Model::getFullName() { @@ -71,7 +71,7 @@ return plugin->getBrand() + " " + name; } -@@ -99,7 +122,7 @@ +@@ -102,7 +125,7 @@ void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { // plugin menu->addChild(createMenuItem("Plugin: " + plugin->name, "", [=]() { @@ -80,7 +80,7 @@ }, plugin->pluginUrl == "")); // version -@@ -108,7 +131,7 @@ +@@ -111,7 +134,7 @@ // author if (plugin->author != "") { menu->addChild(createMenuItem("Author: " + plugin->author, "", [=]() { @@ -89,7 +89,7 @@ }, plugin->authorUrl.empty())); } -@@ -116,7 +139,7 @@ +@@ -119,7 +142,7 @@ std::string license = plugin->license; if (string::startsWith(license, "https://") || string::startsWith(license, "http://")) { menu->addChild(createMenuItem("License: Open in browser", "", [=]() { @@ -98,7 +98,7 @@ })); } else if (license != "") { -@@ -133,58 +156,32 @@ +@@ -136,44 +159,32 @@ menu->addChild(new ui::MenuSeparator); @@ -143,21 +143,21 @@ if (plugin->changelogUrl != "") { menu->addChild(createMenuItem("Changelog", "", [=]() { - system::openBrowser(plugin->changelogUrl); -- })); -- } -- -- // author email -- if (plugin->authorEmail != "") { -- menu->addChild(createMenuItem("Author email", "Copy to clipboard", [=]() { -- glfwSetClipboardString(APP->window->win, plugin->authorEmail.c_str()); -- })); -- } -- -- // plugin folder -- if (plugin->path != "") { -- menu->addChild(createMenuItem("Open plugin folder", "", [=]() { -- system::openDirectory(plugin->path); + patchUtils::openBrowser(plugin->changelogUrl); })); } +@@ -184,13 +195,6 @@ + })); + } + +- // 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()) diff --git a/src/override/diffs/ModuleWidget.cpp.diff b/src/override/diffs/ModuleWidget.cpp.diff index b1e635d..beefa43 100644 --- a/src/override/diffs/ModuleWidget.cpp.diff +++ b/src/override/diffs/ModuleWidget.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/app/ModuleWidget.cpp 2022-09-21 19:49:12.198540676 +0100 -+++ ModuleWidget.cpp 2022-12-02 19:11:45.780215974 +0000 -@@ -1,3 +1,32 @@ +--- ../Rack/src/app/ModuleWidget.cpp 2023-05-20 17:03:33.005081737 +0200 ++++ ModuleWidget.cpp 2023-05-20 18:40:08.948302802 +0200 +@@ -1,8 +1,35 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's ModuleWidget.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -33,7 +33,12 @@ #include #include -@@ -375,7 +404,7 @@ +-#include +- + #include + #include + #include +@@ -375,7 +402,7 @@ if (e.action == GLFW_PRESS) { // Open selection context menu on right-click ui::Menu* menu = createMenu(); @@ -42,7 +47,7 @@ } e.consume(this); } -@@ -627,6 +656,9 @@ +@@ -629,6 +656,9 @@ std::string presetDir = model->getUserPresetDirectory(); system::createDirectories(presetDir); @@ -52,7 +57,7 @@ // Delete directories if empty DEFER({ try { -@@ -638,10 +670,8 @@ +@@ -640,10 +670,8 @@ } }); @@ -65,7 +70,7 @@ if (!pathC) { // No path selected return; -@@ -649,11 +679,13 @@ +@@ -651,11 +679,13 @@ DEFER({std::free(pathC);}); try { @@ -81,7 +86,46 @@ } void ModuleWidget::save(std::string filename) { -@@ -715,6 +747,9 @@ +@@ -670,7 +700,7 @@ + FILE* file = std::fopen(filename.c_str(), "w"); + if (!file) { + std::string message = string::f("Could not save preset to file %s", filename.c_str()); +- osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str()); ++ async_dialog_message(message.c_str()); + return; + } + DEFER({std::fclose(file);}); +@@ -688,10 +718,12 @@ + void ModuleWidget::saveTemplateDialog() { + if (hasTemplate()) { + std::string message = string::f("Overwrite default preset for %s?", model->getFullName().c_str()); +- if (!osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, message.c_str())) +- return; ++ WeakPtr weakThis = this; ++ async_dialog_message(message.c_str(), [=]{ ++ if (weakThis) ++ weakThis->saveTemplate(); ++ }); + } +- saveTemplate(); + } + + bool ModuleWidget::hasTemplate() { +@@ -708,15 +740,20 @@ + + void ModuleWidget::clearTemplateDialog() { + std::string message = string::f("Delete default preset for %s?", model->getFullName().c_str()); +- if (!osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, message.c_str())) +- return; +- clearTemplate(); ++ WeakPtr weakThis = this; ++ async_dialog_message(message.c_str(), [=]{ ++ if (weakThis) ++ weakThis->clearTemplate(); ++ }); + } + + void ModuleWidget::saveDialog() { std::string presetDir = model->getUserPresetDirectory(); system::createDirectories(presetDir); @@ -91,7 +135,7 @@ // Delete directories if empty DEFER({ try { -@@ -726,10 +761,8 @@ +@@ -728,10 +765,8 @@ } }); @@ -104,7 +148,7 @@ if (!pathC) { // No path selected return; -@@ -741,7 +774,8 @@ +@@ -743,7 +778,8 @@ if (system::getExtension(path) != ".vcvm") path += ".vcvm"; @@ -114,28 +158,7 @@ } void ModuleWidget::disconnect() { -@@ -944,16 +978,12 @@ - std::regex r("^\\d+_"); - name = std::regex_replace(name, r, ""); - -- if (system::isDirectory(path)) { -- hasPresets = true; -- -- menu->addChild(createSubmenuItem(name, "", [=](ui::Menu* menu) { -- if (!moduleWidget) -- return; -- appendPresetItems(menu, moduleWidget, path); -- })); -+ if (false) { - } - else if (system::getExtension(path) == ".vcvm" && name != "template") { -+ if (!hasPresets) -+ menu->addChild(new ui::MenuSeparator); -+ - hasPresets = true; - - menu->addChild(createMenuItem(name, "", [=]() { -@@ -963,15 +993,12 @@ +@@ -965,7 +1001,7 @@ moduleWidget->loadAction(path); } catch (Exception& e) { @@ -144,37 +167,7 @@ } })); } - } - } -- if (!hasPresets) { -- menu->addChild(createMenuLabel("(None)")); -- } - }; - - -@@ -1010,6 +1037,7 @@ - weakThis->loadDialog(); - })); - -+ /* TODO requires setting up user dir - menu->addChild(createMenuItem("Save as", "", [=]() { - if (!weakThis) - return; -@@ -1032,10 +1060,13 @@ - menu->addChild(new ui::MenuSeparator); - menu->addChild(createMenuLabel("User presets")); - appendPresetItems(menu, weakThis, weakThis->model->getUserPresetDirectory()); -+ */ - - // Scan `/presets/` for presets. -+ /* TODO enable only after setting up user dir - menu->addChild(new ui::MenuSeparator); - menu->addChild(createMenuLabel("Factory presets")); -+ */ - appendPresetItems(menu, weakThis, weakThis->model->getFactoryPresetDirectory()); - })); - -@@ -1127,4 +1158,4 @@ +@@ -1129,4 +1165,4 @@ } // namespace app diff --git a/src/override/diffs/OpenGlWidget.cpp.diff b/src/override/diffs/OpenGlWidget.cpp.diff index 1fb7156..202f864 100644 --- a/src/override/diffs/OpenGlWidget.cpp.diff +++ b/src/override/diffs/OpenGlWidget.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/widget/OpenGlWidget.cpp 2022-09-21 19:49:12.201540766 +0100 -+++ OpenGlWidget.cpp 2022-09-21 19:41:45.883648777 +0100 +--- ../Rack/src/widget/OpenGlWidget.cpp 2022-09-21 20:49:12.201540766 +0200 ++++ OpenGlWidget.cpp 2023-05-20 18:41:22.249200486 +0200 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's OpenGlWidget.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as diff --git a/src/override/diffs/Scene.cpp.diff b/src/override/diffs/Scene.cpp.diff index 5520940..f2210d0 100644 --- a/src/override/diffs/Scene.cpp.diff +++ b/src/override/diffs/Scene.cpp.diff @@ -1,12 +1,12 @@ ---- ../Rack/src/app/Scene.cpp 2022-09-21 19:49:12.199540706 +0100 -+++ Scene.cpp 2022-12-30 14:50:06.801891005 +0000 +--- ../Rack/src/app/Scene.cpp 2022-09-21 20:49:12.199540706 +0200 ++++ Scene.cpp 2023-05-20 18:44:57.551491858 +0200 @@ -1,12 +1,36 @@ -#include - -#include +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -23,7 +23,7 @@ + +/** + * This file is an edited version of VCVRack's app/Scene.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -40,7 +40,7 @@ #include #include #include -@@ -14,6 +38,13 @@ +@@ -14,6 +38,14 @@ #include #include @@ -51,10 +51,11 @@ +#include "../CardinalCommon.hpp" +#include "../CardinalRemote.hpp" + ++#include namespace rack { namespace app { -@@ -23,32 +54,72 @@ +@@ -23,32 +55,72 @@ math::Vec size; void draw(const DrawArgs& args) override { @@ -101,17 +102,17 @@ + + void onHover(const HoverEvent& e) override { + e.consume(this); -+ } -+ + } + +- void onDragStart(const DragStartEvent& e) override { + void onEnter(const EnterEvent& e) override { + glfwSetCursor(APP->window->win, glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR)); + } + + void onLeave(const LeaveEvent& e) override { + glfwSetCursor(APP->window->win, nullptr); - } - -- void onDragStart(const DragStartEvent& e) override { ++ } ++ + void onDragStart(const DragStartEvent&) override { size = APP->window->getSize(); } @@ -137,14 +138,14 @@ }; -@@ -67,13 +138,11 @@ +@@ -67,13 +139,11 @@ browser->hide(); addChild(browser); - if (settings::showTipsOnLaunch) { - addChild(tipWindowCreate()); - } -+ if (isStandalone()) ++ if (isStandalone() || isMini()) + return; internal->resizeHandle = new ResizeHandle; @@ -154,7 +155,7 @@ addChild(internal->resizeHandle); } -@@ -99,22 +168,13 @@ +@@ -99,22 +169,13 @@ rackScroll->box.pos.y = menuBar->box.size.y; } @@ -179,7 +180,7 @@ // Scroll RackScrollWidget with arrow keys math::Vec arrowDelta; if (internal->heldArrowKeys[0]) { -@@ -143,6 +203,29 @@ +@@ -143,6 +204,34 @@ rackScroll->offset += arrowDelta * arrowSpeed; } @@ -195,7 +196,12 @@ + internal->lastSceneChangeTime = time; + } else if (internal->historyActionIndex != actionIndex && actionIndex > 0 && time - internal->lastSceneChangeTime >= 1.0) { + const std::string& name(APP->history->actions[actionIndex - 1]->name); -+ if (/*std::abs(internal->historyActionIndex = actionIndex) > 1 ||*/ name != "move knob") { ++ static const std::vector ignoredNames = { ++ "move knob", ++ "move modules", ++ "move switch", ++ }; ++ if (std::find(ignoredNames.cbegin(), ignoredNames.cend(), name) == ignoredNames.cend()) { + printf("action '%s'\n", APP->history->actions[actionIndex - 1]->name.c_str()); + remoteUtils::sendFullPatchToRemote(remoteDetails); + window::generateScreenshot(); @@ -209,16 +215,16 @@ Widget::step(); } -@@ -172,7 +255,7 @@ +@@ -172,7 +261,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(); ++ patchUtils::loadTemplateDialog(false); e.consume(this); } if (e.keyName == "q" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { -@@ -180,19 +263,22 @@ +@@ -180,19 +269,22 @@ e.consume(this); } if (e.keyName == "o" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { @@ -245,7 +251,7 @@ e.consume(this); } if (e.keyName == "z" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { -@@ -220,24 +306,38 @@ +@@ -220,24 +312,42 @@ APP->scene->rackScroll->setZoom(std::pow(2.f, zoom)); e.consume(this); } @@ -269,8 +275,10 @@ } + if (e.key == GLFW_KEY_F7 && (e.mods & RACK_MOD_MASK) == 0) { + if (remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote()) ++ { + remoteUtils::sendFullPatchToRemote(remoteDetails); -+ window::generateScreenshot(); ++ window::generateScreenshot(); ++ } + e.consume(this); + } + if (e.key == GLFW_KEY_F9 && (e.mods & RACK_MOD_MASK) == 0) { @@ -280,15 +288,15 @@ +#ifdef DISTRHO_OS_WASM 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(); + // The MenuBar will be hidden when the mouse moves over the RackScrollWidget. + // menuBar->hide(); e.consume(this); } +#endif // Module selections if (e.keyName == "a" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { -@@ -326,13 +426,6 @@ +@@ -326,13 +436,6 @@ // Key commands that can be overridden by children if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { @@ -302,7 +310,7 @@ if (e.keyName == "v" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { rack->pasteClipboardAction(); e.consume(this); -@@ -351,7 +444,7 @@ +@@ -351,7 +454,7 @@ std::string extension = system::getExtension(path); if (extension == ".vcv") { diff --git a/src/override/diffs/Window.cpp.diff b/src/override/diffs/Window.cpp.diff index e71c075..dd2c760 100644 --- a/src/override/diffs/Window.cpp.diff +++ b/src/override/diffs/Window.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/window/Window.cpp 2022-09-21 19:49:12.202540796 +0100 -+++ Window.cpp 2022-12-29 17:16:45.012337253 +0000 -@@ -1,33 +1,88 @@ +--- ../Rack/src/window/Window.cpp 2023-05-20 17:03:33.007081806 +0200 ++++ Window.cpp 2023-05-20 19:01:25.266135825 +0200 +@@ -1,33 +1,94 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's window/Window.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -57,16 +57,6 @@ +# undef DEBUG +#endif + -+// comment out if wanting to generate a local screenshot.png -+#define STBI_WRITE_NO_STDIO -+ -+// uncomment to generate screenshots without the rack rail background (ie, transparent) -+// #define CARDINAL_TRANSPARENT_SCREENSHOTS - -+// used in Window::screenshot -+#define STB_IMAGE_WRITE_IMPLEMENTATION -+#include "stb_image_write.h" -+ +#include "DistrhoUI.hpp" +#include "Application.hpp" +#include "extra/String.hpp" @@ -77,6 +67,22 @@ +#ifndef DGL_NO_SHARED_RESOURCES +# include "src/Resources.hpp" +#endif + ++#if !(defined(DGL_USE_GLES) || CARDINAL_VARIANT_MINI) ++ ++#define CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS ++ ++// comment out if wanting to generate a local screenshot.png ++#define STBI_WRITE_NO_STDIO ++ ++// uncomment to generate screenshots without the rack rail background (ie, transparent) ++// #define CARDINAL_TRANSPARENT_SCREENSHOTS ++ ++// used in Window::screenshot ++#define STB_IMAGE_WRITE_IMPLEMENTATION ++#include "stb_image_write.h" ++ ++#endif + +#ifdef DISTRHO_OS_WASM +# include @@ -86,7 +92,7 @@ namespace window { --static const math::Vec WINDOW_SIZE_MIN = math::Vec(480, 320); +-static const math::Vec WINDOW_SIZE_MIN = math::Vec(640, 480); +static const math::Vec WINDOW_SIZE_MIN = math::Vec(648, 538); + + @@ -102,7 +108,7 @@ Font::~Font() { -@@ -42,9 +97,8 @@ +@@ -42,9 +103,8 @@ // Transfer ownership of font data to font object uint8_t* data = system::readFile(filename, &size); // Don't use nvgCreateFont because it doesn't properly handle UTF-8 filenames on Windows. @@ -113,10 +119,11 @@ throw Exception("Failed to load font %s", filename.c_str()); } INFO("Loaded font %s", filename.c_str()); -@@ -79,375 +133,489 @@ +@@ -79,338 +139,475 @@ } ++#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS +enum ScreenshotStep { + kScreenshotStepNone, + kScreenshotStepStarted, @@ -124,6 +131,7 @@ + kScreenshotStepSecondPass, + kScreenshotStepSaving +}; ++#endif + + struct Window::Internal { @@ -153,15 +161,13 @@ int frame = 0; - bool ignoreNextMouseDelta = false; -- int frameSwapInterval = -1; - double monitorRefreshRate = 0.0; -+ int frameSwapInterval = 1; -+#ifndef DGL_USE_GLES ++#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS + int generateScreenshotStep = kScreenshotStepNone; +#endif + double monitorRefreshRate = 60.0; - double frameTime = 0.0; - double lastFrameDuration = 0.0; + double frameTime = NAN; + double lastFrameDuration = NAN; - math::Vec lastMousePos; - @@ -173,8 +179,8 @@ bool fbDirtyOnSubpixelChange = true; int fbCount = 0; -}; -- +- -static void windowPosCallback(GLFWwindow* win, int x, int y) { - if (glfwGetWindowAttrib(win, GLFW_MAXIMIZED)) - return; @@ -484,15 +490,11 @@ - APP->event->handleDrop(APP->window->internal->lastMousePos, pathsVec); -} - - +- -static void errorCallback(int error, const char* description) { - WARN("GLFW error %d: %s", error, description); -} -- -- --Window::Window() { -- internal = new Internal; -- int err; + + if (ui != nullptr) + { + const GLubyte* vendor = glGetString(GL_VENDOR); @@ -514,6 +516,10 @@ + window->internal->r_fbVg = nvgCreateSharedGL2(window->internal->r_vg, NVG_ANTIALIAS); +#endif +-Window::Window() { +- internal = new Internal; +- int err; +- - // Set window hints -#if defined NANOVG_GL2 - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); @@ -558,7 +564,7 @@ - glfwSetInputMode(win, GLFW_LOCK_KEY_MODS, 1); - - glfwMakeContextCurrent(win); -- glfwSwapInterval(1); +- glfwSwapInterval(0); - const GLFWvidmode* monitorMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); - if (monitorMode->refreshRate > 0) { - internal->monitorRefreshRate = monitorMode->refreshRate; @@ -731,14 +737,14 @@ +#else + nvgDeleteGL2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); + nvgDeleteGL2(internal->o_vg != nullptr ? internal->o_vg : vg); -+#endif + #endif +#else +#if defined NANOVG_GLES2 + nvgDeleteGLES2(fbVg); +#else + nvgDeleteGL2(fbVg); +#endif - #endif ++#endif + } + } @@ -777,7 +783,7 @@ +} + + -+#ifndef DGL_USE_GLES ++#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS +static void Window__flipBitmap(uint8_t* pixels, const int width, const int height, const int depth) { + for (int y = 0; y < height / 2; y++) { + const int flipY = height - y - 1; @@ -785,10 +791,10 @@ + std::memcpy(tmp, &pixels[y * width * depth], width * depth); + std::memmove(&pixels[y * width * depth], &pixels[flipY * width * depth], width * depth); + std::memcpy(&pixels[flipY * width * depth], tmp, width * depth); - } - } - - ++ } ++} ++ ++ +#ifdef STBI_WRITE_NO_STDIO +static void Window__downscaleBitmap(uint8_t* pixels, int& width, int& height) { + int targetWidth = width; @@ -828,12 +834,12 @@ + ui->setState("screenshot", screenshot); + remoteUtils::sendScreenshotToRemote(ui->remoteDetails, screenshot); + std::free(screenshot); -+ } -+} + } + } +#endif +#endif -+ -+ + + void Window::step() { + DISTRHO_SAFE_ASSERT_RETURN(internal->tlw != nullptr,); + @@ -841,13 +847,9 @@ + return; + double frameTime = system::getTime(); - double lastFrameTime = internal->frameTime; - internal->frameTime = frameTime; - internal->lastFrameDuration = frameTime - lastFrameTime; - internal->fbCount = 0; - // DEBUG("%.2lf Hz", 1.0 / internal->lastFrameDuration); -- // double t1 = 0.0, t2 = 0.0, t3 = 0.0, t4 = 0.0, t5 = 0.0; - + if (std::isfinite(internal->frameTime)) { + internal->lastFrameDuration = frameTime - internal->frameTime; +@@ -422,57 +619,48 @@ // Make event handlers and step() have a clean NanoVG context nvgReset(vg); @@ -861,10 +863,6 @@ - - // In case glfwPollEvents() sets another OpenGL context - glfwMakeContextCurrent(win); -- if (settings::frameSwapInterval != internal->frameSwapInterval) { -- glfwSwapInterval(settings::frameSwapInterval); -- internal->frameSwapInterval = settings::frameSwapInterval; -- } - - // Call cursorPosCallback every frame, not just when the mouse moves - { @@ -878,17 +876,27 @@ // Set window title - std::string windowTitle = APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION; -+ std::string windowTitle = "Cardinal"; - if (APP->patch->path != "") { - windowTitle += " - "; - if (!APP->history->isSaved()) -@@ -455,246 +623,189 @@ - windowTitle += system::getFilename(APP->patch->path); - } - if (windowTitle != internal->lastWindowTitle) { +- if (APP->patch->path != "") { +- windowTitle += " - "; +- if (!APP->history->isSaved()) +- windowTitle += "*"; +- windowTitle += system::getFilename(APP->patch->path); +- } +- if (windowTitle != internal->lastWindowTitle) { - glfwSetWindowTitle(win, windowTitle.c_str()); -+ internal->tlw->getWindow().setTitle(windowTitle.c_str()); - internal->lastWindowTitle = windowTitle; +- internal->lastWindowTitle = windowTitle; ++ if (isStandalone()) { ++ std::string windowTitle = "Cardinal"; ++ if (APP->patch->path != "") { ++ windowTitle += " - "; ++ if (!APP->history->isSaved()) ++ windowTitle += "*"; ++ windowTitle += system::getFilename(APP->patch->path); ++ } ++ if (windowTitle != internal->lastWindowTitle) { ++ internal->tlw->getWindow().setTitle(windowTitle.c_str()); ++ internal->lastWindowTitle = windowTitle; ++ } } // Get desired pixel ratio @@ -906,7 +914,7 @@ APP->event->handleDirty(); } -+#ifndef DGL_USE_GLES ++#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS + // Hide menu and background if generating screenshot + if (internal->generateScreenshotStep == kScreenshotStepStarted) { +#ifdef CARDINAL_TRANSPARENT_SCREENSHOTS @@ -925,20 +933,13 @@ - glfwGetWindowSize(win, &winWidth, &winHeight); + int winWidth = internal->tlw->getWidth(); + int winHeight = internal->tlw->getHeight(); -+ int fbWidth = winWidth;// * newPixelRatio; -+ int fbHeight = winHeight;// * newPixelRatio; ++ int fbWidth = winWidth; ++ int fbHeight = winHeight; windowRatio = (float)fbWidth / winWidth; -- // t1 = system::getTime(); + // t1 = system::getTime(); - if (APP->scene) { - // DEBUG("%f %f %d %d", pixelRatio, windowRatio, fbWidth, winWidth); - // Resize scene -- APP->scene->box.size = math::Vec(fbWidth, fbHeight).div(pixelRatio); -+ APP->scene->box.size = math::Vec(fbWidth, fbHeight).div(newPixelRatio); - - // Step scene - APP->scene->step(); -- // t2 = system::getTime(); +@@ -486,10 +674,8 @@ + // t2 = system::getTime(); // Render scene - bool visible = glfwGetWindowAttrib(win, GLFW_VISIBLE) && !glfwGetWindowAttrib(win, GLFW_ICONIFIED); @@ -946,15 +947,11 @@ + { // Update and render - nvgBeginFrame(vg, fbWidth, fbHeight, pixelRatio); -- nvgScale(vg, pixelRatio, pixelRatio); -+ nvgScale(vg, newPixelRatio, newPixelRatio); + nvgScale(vg, pixelRatio, pixelRatio); // Draw scene - widget::Widget::DrawArgs args; - args.vg = vg; - args.clipBox = APP->scene->box.zeroPos(); - APP->scene->draw(args); -- // t3 = system::getTime(); +@@ -500,23 +686,16 @@ + // t3 = system::getTime(); glViewport(0, 0, fbWidth, fbHeight); +#ifdef CARDINAL_TRANSPARENT_SCREENSHOTS @@ -964,19 +961,32 @@ +#endif glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - nvgEndFrame(vg); -- // t4 = system::getTime(); } + // t4 = system::getTime(); } - glfwSwapBuffers(win); +- +- // Limit frame rate +- if (settings::frameRateLimit > 0) { +- double remaining = getFrameDurationRemaining(); +- if (remaining > 0.0) { +- system::sleep(remaining); +- } +- } +- + // t5 = system::getTime(); + // DEBUG("pre-step %6.1f step %6.1f draw %6.1f nvgEndFrame %6.1f glfwSwapBuffers %6.1f total %6.1f", + // (t1 - frameTime) * 1e3f, +@@ -526,163 +705,124 @@ + // (t5 - t4) * 1e3f, + // (t5 - frameTime) * 1e3f + // ); +- internal->frame++; +-} + ++internal->frame; -- // On some platforms, glfwSwapBuffers() doesn't wait on monitor refresh, so we have to sleep as a fallback. -- double frameDurationRemaining = getFrameDurationRemaining(); -- if (frameDurationRemaining > 0.0) { -- std::this_thread::sleep_for(std::chrono::duration(frameDurationRemaining)); -- } -+#ifndef DGL_USE_GLES ++#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS + if (internal->generateScreenshotStep != kScreenshotStepNone) { + ++internal->generateScreenshotStep; + @@ -988,24 +998,20 @@ + constexpr const int depth = 3; +#endif -- // t5 = system::getTime(); +-static void flipBitmap(uint8_t* pixels, int width, int height, int depth) { +- for (int y = 0; y < height / 2; y++) { +- int flipY = height - y - 1; +- uint8_t tmp[width * depth]; +- std::memcpy(tmp, &pixels[y * width * depth], width * depth); +- std::memcpy(&pixels[y * width * depth], &pixels[flipY * width * depth], width * depth); +- std::memcpy(&pixels[flipY * width * depth], tmp, width * depth); + // Allocate pixel color buffer + uint8_t* const pixels = new uint8_t[winHeight * winWidth * 4]; - -- // DEBUG("pre-step %6.1f step %6.1f draw %6.1f nvgEndFrame %6.1f glfwSwapBuffers %6.1f total %6.1f", -- // (t1 - frameTime) * 1e3f, -- // (t2 - t1) * 1e3f, -- // (t3 - t2) * 1e3f, -- // (t4 - t2) * 1e3f, -- // (t5 - t4) * 1e3f, -- // (t5 - frameTime) * 1e3f -- // ); -- internal->frame++; --} ++ + // glReadPixels defaults to GL_BACK, but the back-buffer is unstable, so use the front buffer (what the user sees) + glReadBuffer(GL_FRONT); + glReadPixels(0, 0, winWidth, winHeight, depth == 3 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, pixels); - ++ + if (internal->generateScreenshotStep == kScreenshotStepSaving) + { + // Write pixels to PNG @@ -1020,33 +1026,19 @@ +#else + stbi_write_png("screenshot.png", winWidth, winHeight, depth, pixelsWithOffset, stride); +#endif - --void Window::activateContext() { -- glfwMakeContextCurrent(win); ++ + internal->generateScreenshotStep = kScreenshotStepNone; + APP->scene->menuBar->show(); + APP->scene->rack->children.front()->show(); + } + + delete[] pixels; -+ } + } +#endif } --static void flipBitmap(uint8_t* pixels, int width, int height, int depth) { -- for (int y = 0; y < height / 2; y++) { -- int flipY = height - y - 1; -- uint8_t tmp[width * depth]; -- std::memcpy(tmp, &pixels[y * width * depth], width * depth); -- std::memcpy(&pixels[y * width * depth], &pixels[flipY * width * depth], width * depth); -- std::memcpy(&pixels[flipY * width * depth], tmp, width * depth); -- } -+void Window::activateContext() { - } - - --void Window::screenshot(const std::string& screenshotPath) { + void Window::screenshot(const std::string& screenshotPath) { - // Get window framebuffer size - int width, height; - glfwGetFramebufferSize(APP->window->win, &width, &height); @@ -1063,10 +1055,10 @@ - stbi_write_png(screenshotPath.c_str(), width, height, 4, pixels, width * 4); - - delete[] pixels; --} -- -- --void Window::screenshotModules(const std::string& screenshotsDir, float zoom) { + } + + + void Window::screenshotModules(const std::string& screenshotsDir, float zoom) { - // Iterate plugins and create directories - system::createDirectories(screenshotsDir); - for (plugin::Plugin* p : plugin::plugins) { @@ -1111,20 +1103,17 @@ - nvgImageSize(vg, fbw->getImageHandle(), &width, &height); - uint8_t* pixels = new uint8_t[height * width * 4]; - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); -+void Window::screenshot(const std::string&) { -+} - +- - // Write pixels to PNG - flipBitmap(pixels, width, height, 4); - stbi_write_png(filename.c_str(), width, height, 4, pixels, width * 4); - +- - // Cleanup - delete[] pixels; - nvgluBindFramebuffer(NULL); - delete fbw; - } - } -+void Window::screenshotModules(const std::string&, float) { } @@ -1189,7 +1178,7 @@ } --void Window::setFullScreen(bool fullScreen) { + void Window::setFullScreen(bool fullScreen) { - if (!fullScreen) { - glfwSetWindowMonitor(win, NULL, internal->lastWindowX, internal->lastWindowY, internal->lastWindowWidth, internal->lastWindowHeight, GLFW_DONT_CARE); - } @@ -1200,9 +1189,8 @@ - const GLFWvidmode* mode = glfwGetVideoMode(monitor); - glfwSetWindowMonitor(win, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); - } -+void Window::setFullScreen(const bool fullscreen) { +#ifdef DISTRHO_OS_WASM -+ if (fullscreen) ++ if (fullScreen) + emscripten_request_fullscreen(internal->tlw->getWindow().getApp().getClassName(), false); + else + emscripten_exit_fullscreen(); @@ -1218,18 +1206,24 @@ + if (emscripten_get_fullscreen_status(&status) == EMSCRIPTEN_RESULT_SUCCESS) + return status.isFullscreen; + return false; -+#elif defined(CARDINAL_TRANSPARENT_SCREENSHOTS) && !defined(DGL_USE_GLES) ++#elif defined(CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS) && defined(CARDINAL_TRANSPARENT_SCREENSHOTS) + return internal->generateScreenshotStep != kScreenshotStepNone; +#else + return false; +#endif } -- - double Window::getMonitorRefreshRate() { - return internal->monitorRefreshRate; + +@@ -702,7 +842,7 @@ + + + double Window::getFrameDurationRemaining() { +- double frameDuration = 1.f / settings::frameRateLimit; ++ double frameDuration = 1.f / internal->monitorRefreshRate; + return frameDuration - (system::getTime() - internal->frameTime); } -@@ -722,14 +833,15 @@ + +@@ -713,14 +853,15 @@ return pair->second; // Load font @@ -1248,7 +1242,7 @@ } internal->fontCache[filename] = font; return font; -@@ -742,14 +854,15 @@ +@@ -733,14 +874,15 @@ return pair->second; // Load image @@ -1267,7 +1261,7 @@ } internal->imageCache[filename] = image; return image; -@@ -766,28 +879,156 @@ +@@ -757,28 +899,156 @@ } @@ -1279,7 +1273,7 @@ - glfwInitHint(GLFW_COCOA_CHDIR_RESOURCES, GLFW_TRUE); - glfwInitHint(GLFW_COCOA_MENUBAR, GLFW_FALSE); +void generateScreenshot() { -+#ifndef DGL_USE_GLES ++#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS + APP->window->internal->generateScreenshotStep = kScreenshotStepStarted; #endif +} diff --git a/src/override/diffs/blendish.c.diff b/src/override/diffs/blendish.c.diff index 90a2481..ee4b10e 100644 --- a/src/override/diffs/blendish.c.diff +++ b/src/override/diffs/blendish.c.diff @@ -1,5 +1,5 @@ ---- ../Rack/dep/oui-blendish/blendish.c 2022-09-21 19:49:29.973066921 +0100 -+++ blendish.c 2022-09-21 19:41:45.883648777 +0100 +--- ../Rack/dep/oui-blendish/blendish.c 2022-09-21 20:49:29.973066921 +0200 ++++ blendish.c 2022-09-21 20:41:45.883648777 +0200 @@ -61,7 +61,7 @@ } diff --git a/src/override/diffs/common.cpp.diff b/src/override/diffs/common.cpp.diff index 5675f5a..1531d72 100644 --- a/src/override/diffs/common.cpp.diff +++ b/src/override/diffs/common.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/common.cpp 2022-09-21 19:49:12.199540706 +0100 -+++ common.cpp 2022-12-02 19:11:45.780215974 +0000 +--- ../Rack/src/common.cpp 2023-05-20 17:03:33.006081772 +0200 ++++ common.cpp 2023-05-20 17:51:04.675045244 +0200 @@ -1,12 +1,57 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's common.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -60,7 +60,7 @@ } #endif -@@ -14,20 +59,21 @@ +@@ -14,12 +59,11 @@ namespace rack { @@ -73,17 +73,24 @@ +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.1.2"; ++const std::string APP_VERSION = "2.3.0"; #if defined ARCH_WIN const std::string APP_OS = "win"; --#elif ARCH_MAC -+#elif defined ARCH_MAC - const std::string APP_OS = "mac"; + const std::string APP_OS_NAME = "Windows"; +@@ -29,15 +73,10 @@ #elif defined ARCH_LIN const std::string APP_OS = "lin"; + const std::string APP_OS_NAME = "Linux"; +#else + #error ARCH_LIN undefined #endif +-#if defined ARCH_X64 +- const std::string APP_CPU = "x64"; +- const std::string APP_CPU_NAME = "x64"; +-#elif defined ARCH_ARM64 +- const std::string APP_CPU = "arm64"; +- const std::string APP_CPU_NAME = "ARM64"; +-#endif -const std::string API_URL = "https://api.vcvrack.com"; +const std::string API_URL = ""; diff --git a/src/override/diffs/context.cpp.diff b/src/override/diffs/context.cpp.diff index 8b6fa4d..6b2be58 100644 --- a/src/override/diffs/context.cpp.diff +++ b/src/override/diffs/context.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/context.cpp 2022-09-21 19:49:12.199540706 +0100 -+++ context.cpp 2022-09-21 19:41:45.883648777 +0100 -@@ -1,3 +1,30 @@ +--- ../Rack/src/context.cpp 2023-05-20 17:03:33.006081772 +0200 ++++ context.cpp 2023-05-20 18:08:56.497736615 +0200 +@@ -1,14 +1,44 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's context.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -31,9 +31,10 @@ #include #include #include -@@ -6,9 +33,13 @@ + #include + #include #include - #include +-#include +#ifdef NDEBUG +# undef DEBUG @@ -46,7 +47,17 @@ Context::~Context() { // Deleting NULL is safe in C++. -@@ -44,7 +75,7 @@ +@@ -38,17 +68,13 @@ + INFO("Deleting engine"); + delete engine; + engine = NULL; +- +- INFO("Deleting MIDI loopback"); +- delete midiLoopbackContext; +- midiLoopbackContext = NULL; + } + + static thread_local Context* threadContext = NULL; Context* contextGet() { diff --git a/src/override/diffs/minblep.cpp.diff b/src/override/diffs/minblep.cpp.diff index 5d549e8..def4996 100644 --- a/src/override/diffs/minblep.cpp.diff +++ b/src/override/diffs/minblep.cpp.diff @@ -1,9 +1,9 @@ ---- ../Rack/src/dsp/minblep.cpp 2022-09-21 19:49:12.200540736 +0100 -+++ minblep.cpp 2022-09-21 19:41:45.884648820 +0100 +--- ../Rack/src/dsp/minblep.cpp 2022-09-21 20:49:12.200540736 +0200 ++++ minblep.cpp 2023-05-20 18:21:44.019059009 +0200 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ + +/** + * This file is an edited version of VCVRack's dsp/minblep.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as diff --git a/src/override/diffs/plugin.cpp.diff b/src/override/diffs/plugin.cpp.diff index 2a68bf6..dee7583 100644 --- a/src/override/diffs/plugin.cpp.diff +++ b/src/override/diffs/plugin.cpp.diff @@ -1,6 +1,6 @@ ---- ../Rack/src/plugin.cpp 2022-09-21 19:49:12.200540736 +0100 -+++ plugin.cpp 2022-11-25 18:24:09.485450570 +0000 -@@ -1,342 +1,41 @@ +--- ../Rack/src/plugin.cpp 2023-05-20 17:03:33.006081772 +0200 ++++ plugin.cpp 2023-05-20 18:43:27.496323540 +0200 +@@ -1,356 +1,46 @@ -#include -#include -#include @@ -20,7 +20,7 @@ -#include +/* + * DISTRHO Cardinal Plugin -+ * Copyright (C) 2021-2022 Filipe Coelho ++ * Copyright (C) 2021-2023 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -37,7 +37,7 @@ + +/** + * This file is an edited version of VCVRack's plugin.cpp -+ * Copyright (C) 2016-2021 VCV. ++ * Copyright (C) 2016-2023 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as @@ -133,7 +133,16 @@ -#elif ARCH_MAC - libraryExt = "dylib"; -#endif -- std::string libraryPath = system::join(plugin->path, "plugin." + libraryExt); +- +-#if defined ARCH_X64 +- // Use `plugin.EXT` on x64 for backward compatibility. +- // Change to `plugin-OS-CPU.EXT` in Rack 3. +- std::string libraryFilename = "plugin." + libraryExt; +-#else +- // Use `plugin-CPU.EXT` on other CPUs like ARM64 +- std::string libraryFilename = "plugin-" + APP_CPU + "." + libraryExt; +-#endif +- std::string libraryPath = system::join(plugin->path, libraryFilename); - - // Check file existence - if (!system::isFile(libraryPath)) @@ -227,7 +236,7 @@ - return NULL; - } - -- INFO("Loaded %s v%s", plugin->slug.c_str(), plugin->version.c_str()); +- INFO("Loaded %s %s", plugin->slug.c_str(), plugin->version.c_str()); - plugins.push_back(plugin); - return plugin; -} @@ -372,15 +381,13 @@ /** Given slug => fallback slug. -@@ -348,6 +47,7 @@ - {"VultModules", "VultModulesFree"}, - {"AudibleInstrumentsPreview", "AudibleInstruments"}, - {"SequelSequencers", "DanielDavies"}, -+ {"DelexanderVol1", "DelexandraVol1"}, - // {"", ""}, - }; - -@@ -389,8 +89,19 @@ + Supports bidirectional fallbacks. +-To request fallback slugs to be added to this list, contact VCV support. ++To request fallback slugs to be added to this list, open a GitHub issue. + */ + static const std::map pluginSlugFallbacks = { + {"VultModulesFree", "VultModules"}, +@@ -399,8 +89,19 @@ */ using PluginModuleSlug = std::tuple; static const std::map moduleSlugFallbacks = { @@ -401,7 +408,7 @@ // {{"", ""}, {"", ""}}, }; -@@ -478,7 +189,6 @@ +@@ -488,7 +189,6 @@ } diff --git a/src/override/minblep.cpp b/src/override/minblep.cpp index 6242b0d..fa5bbfe 100644 --- a/src/override/minblep.cpp +++ b/src/override/minblep.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's dsp/minblep.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/override/plugin.cpp b/src/override/plugin.cpp index 058c4b4..957fe9d 100644 --- a/src/override/plugin.cpp +++ b/src/override/plugin.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021-2022 Filipe Coelho + * Copyright (C) 2021-2023 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ /** * This file is an edited version of VCVRack's plugin.cpp - * Copyright (C) 2016-2021 VCV. + * Copyright (C) 2016-2023 VCV. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -39,7 +39,7 @@ void settingsMergeJson(json_t*) {} /** Given slug => fallback slug. -Correctly handles bidirectional fallbacks. +Supports bidirectional fallbacks. To request fallback slugs to be added to this list, open a GitHub issue. */ static const std::map pluginSlugFallbacks = {