@@ -94,6 +94,21 @@ endif | |||||
BUILD_C_FLAGS += -fno-finite-math-only -fno-strict-aliasing | BUILD_C_FLAGS += -fno-finite-math-only -fno-strict-aliasing | ||||
BUILD_CXX_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 | # Rack build flags | ||||
@@ -163,8 +178,6 @@ endif | |||||
BASE_FLAGS += -I$(abspath $(ROOT)/dpf/dgl/src/nanovg) | BASE_FLAGS += -I$(abspath $(ROOT)/dpf/dgl/src/nanovg) | ||||
BASE_FLAGS += -I$(abspath $(ROOT)/dpf/distrho) | 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) | ||||
BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/include) | BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/include) | ||||
BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/include/dsp) | 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/nanosvg/src) | ||||
BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/oui-blendish) | 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/pffft) | ||||
BASE_FLAGS += -I$(abspath $(ROOT)/src/Rack/dep/tinyexpr) | |||||
BUILD_C_FLAGS += -std=gnu11 | BUILD_C_FLAGS += -std=gnu11 | ||||
@@ -1 +1 @@ | |||||
Subproject commit 9c1cad538702767d51fc59d17080c74313c280cd | |||||
Subproject commit e58f7a8c7a8797656747b11a2608fc8b6ec90b8e |
@@ -197,14 +197,10 @@ $(RACK_DEP_PATH)/libsamplerate-0.1.9/.stamp-patched: | |||||
touch $@ | touch $@ | ||||
# libspeexdsp: hide symbols | # libspeexdsp: hide symbols | ||||
$(RACK_DEP_PATH)/lib/libspeexdsp.a: $(RACK_DEP_PATH)/speexdsp-SpeexDSP-1.2rc3/.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)/lib/libspeexdsp.a: $(RACK_DEP_PATH)/speexdsp/.stamp-patched | |||||
$(RACK_DEP_PATH)/speexdsp/.stamp-patched: | |||||
sed -i -e 's/__attribute__((visibility("default")))//' $(RACK_DEP_PATH)/speexdsp/configure.ac | |||||
touch $@ | touch $@ | ||||
# custom zstd build for only building static libs | # custom zstd build for only building static libs | ||||
@@ -279,12 +275,7 @@ endif | |||||
endif | endif | ||||
# same flags as applied to main build | # 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? | # possibly use fftw? | ||||
# ifeq ($(shell $(PKG_CONFIG) --exists fftw3 fftw3f && echo true),true) | # 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_LUA=TRUE \ | ||||
-DSURGE_SKIP_ODDSOUND_MTS=TRUE \ | -DSURGE_SKIP_ODDSOUND_MTS=TRUE \ | ||||
-DSURGE_JUCE_PATH=$(abspath ../carla/source) \ | -DSURGE_JUCE_PATH=$(abspath ../carla/source) \ | ||||
-DSURGE_SIMDE_PATH=$(abspath ../include/simde) \ | |||||
-DSURGE_SIMDE_PATH=$(abspath ../src/Rack/dep/simde) \ | |||||
$(SURGE_SRC_PATH) | $(SURGE_SRC_PATH) | ||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
@@ -352,7 +343,6 @@ clean: | |||||
rm -rf $(RACK_DEP_PATH)/jansson-2.12 | rm -rf $(RACK_DEP_PATH)/jansson-2.12 | ||||
rm -rf $(RACK_DEP_PATH)/libarchive-3.4.3 | rm -rf $(RACK_DEP_PATH)/libarchive-3.4.3 | ||||
rm -rf $(RACK_DEP_PATH)/libsamplerate-0.1.9 | 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 $(RACK_DEP_PATH)/zstd-1.4.5 | ||||
rm -rf $(SURGE_DEP_PATH) | rm -rf $(SURGE_DEP_PATH) | ||||
@@ -360,7 +350,6 @@ download: \ | |||||
$(RACK_DEP_PATH)/jansson-2.12 \ | $(RACK_DEP_PATH)/jansson-2.12 \ | ||||
$(RACK_DEP_PATH)/libarchive-3.4.3/.stamp-patched \ | $(RACK_DEP_PATH)/libarchive-3.4.3/.stamp-patched \ | ||||
$(RACK_DEP_PATH)/libsamplerate-0.1.9/.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 | $(RACK_DEP_PATH)/zstd-1.4.5/.stamp-patched | ||||
quickjs: $(RACK_DEP_PATH)/lib/libquickjs.a | quickjs: $(RACK_DEP_PATH)/lib/libquickjs.a | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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) | #if (defined(__i386__) || defined(__x86_64__) || defined(__EMSCRIPTEN__)) && !defined(CARDINAL_NOSIMD) | ||||
# include_next <emmintrin.h> | # include_next <emmintrin.h> | ||||
#else | #else | ||||
# define SIMDE_ACCURACY_PREFERENCE 0 | |||||
# define SIMDE_ENABLE_NATIVE_ALIASES | # 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 | #endif |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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) | #if (defined(__i386__) || defined(__x86_64__) || defined(__EMSCRIPTEN__)) && !defined(CARDINAL_NOSIMD) | ||||
# include_next <immintrin.h> | # include_next <immintrin.h> | ||||
#else | #else | ||||
# define SIMDE_ACCURACY_PREFERENCE 0 | |||||
# define SIMDE_ENABLE_NATIVE_ALIASES | # 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/sse.h" | ||||
# include "../simde/simde/x86/sse2.h" | # include "../simde/simde/x86/sse2.h" | ||||
# undef SIMDE_ENABLE_NATIVE_ALIASES | |||||
#endif | #endif |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
@@ -22,12 +22,7 @@ | |||||
#elif defined(__EMSCRIPTEN__) && !defined(CARDINAL_NOSIMD) | #elif defined(__EMSCRIPTEN__) && !defined(CARDINAL_NOSIMD) | ||||
# include <wasm_simd128.h> | # include <wasm_simd128.h> | ||||
#else | #else | ||||
# define SIMDE_ACCURACY_PREFERENCE 0 | |||||
# define SIMDE_ENABLE_NATIVE_ALIASES | # 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" | # include "../simde/simde/x86/mmx.h" | ||||
# undef SIMDE_ENABLE_NATIVE_ALIASES | |||||
#endif | #endif |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
@@ -32,7 +32,7 @@ | |||||
// assume SSE3 only on macOS | // assume SSE3 only on macOS | ||||
# ifndef ARCH_MAC | # ifndef ARCH_MAC | ||||
# include "../simde/simde/x86/sse3.h" | |||||
# include "simde/x86/sse3.h" | |||||
# endif | # endif | ||||
# ifdef _WIN32_WAS_DEFINED | # ifdef _WIN32_WAS_DEFINED | ||||
@@ -40,6 +40,9 @@ | |||||
# undef _WIN32_WAS_DEFINED | # undef _WIN32_WAS_DEFINED | ||||
# endif | # endif | ||||
# undef SIMDE_X86_SSE2_NATIVE | |||||
# undef SIMDE_X86_SSE3_ENABLE_NATIVE_ALIASES | |||||
#elif defined(__EMSCRIPTEN__) && !defined(CARDINAL_NOSIMD) | #elif defined(__EMSCRIPTEN__) && !defined(CARDINAL_NOSIMD) | ||||
# include_next <pmmintrin.h> | # include_next <pmmintrin.h> | ||||
@@ -67,14 +70,9 @@ __m64 _mm_set1_pi16(short w) | |||||
*/ | */ | ||||
#else | #else | ||||
# define SIMDE_ACCURACY_PREFERENCE 0 | |||||
# define SIMDE_ENABLE_NATIVE_ALIASES | # 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 | #endif |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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) | #if (defined(__i386__) || defined(__x86_64__) || defined(__EMSCRIPTEN__)) && !defined(CARDINAL_NOSIMD) | ||||
# include_next <xmmintrin.h> | # include_next <xmmintrin.h> | ||||
#else | #else | ||||
# define SIMDE_ACCURACY_PREFERENCE 0 | |||||
# define SIMDE_ENABLE_NATIVE_ALIASES | # 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 | #endif |
@@ -1 +0,0 @@ | |||||
Subproject commit dd0b662fd8cf4b1617dbbb4d08aa053e512b08e4 |
@@ -643,7 +643,7 @@ CATROMODULO_CUSTOM = LowFrequencyOscillator NumDisplayWidget | |||||
PLUGIN_FILES += $(filter-out cf/src/plugin.cpp,$(wildcard cf/src/*.cpp)) | PLUGIN_FILES += $(filter-out cf/src/plugin.cpp,$(wildcard cf/src/*.cpp)) | ||||
# modules/types which are present in other plugins | # modules/types which are present in other plugins | ||||
CF_CUSTOM = $(DRWAV) | |||||
CF_CUSTOM = $(DRWAV) ledTrigger | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# dBiz | # dBiz | ||||
@@ -1 +1 @@ | |||||
Subproject commit b6c4a66ffc153d78c7efa00fa886657eb182b15d | |||||
Subproject commit 8aca80cbaa30787e0aed1edb886767fa756b9846 |
@@ -1 +1 @@ | |||||
Subproject commit 80883512cc397c173e40e3bc014640b838ab343a | |||||
Subproject commit e5c6048071b9e1fc34b4a97072f1966b88235455 |
@@ -393,6 +393,8 @@ Initializer::Initializer(const CardinalBasePlugin* const plugin, const CardinalB | |||||
settings::browserZoom = -1.f; | settings::browserZoom = -1.f; | ||||
settings::invertZoom = false; | settings::invertZoom = false; | ||||
settings::squeezeModules = true; | settings::squeezeModules = true; | ||||
settings::darkMode = true; | |||||
settings::uiTheme = "dark"; | |||||
// runtime behaviour | // runtime behaviour | ||||
settings::devMode = true; | settings::devMode = true; | ||||
@@ -635,12 +637,20 @@ void Initializer::loadSettings(const bool isRealInstance) | |||||
settings::pixelRatio = 0.0; | settings::pixelRatio = 0.0; | ||||
settings::sampleRate = 0; | settings::sampleRate = 0; | ||||
settings::threadCount = 1; | settings::threadCount = 1; | ||||
settings::frameSwapInterval = 1; | |||||
settings::autosaveInterval = 0; | settings::autosaveInterval = 0; | ||||
settings::skipLoadOnLaunch = true; | settings::skipLoadOnLaunch = true; | ||||
settings::autoCheckUpdates = false; | settings::autoCheckUpdates = false; | ||||
settings::showTipsOnLaunch = false; | settings::showTipsOnLaunch = false; | ||||
settings::tipIndex = -1; | 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"); | |||||
} | } | ||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
@@ -57,6 +57,8 @@ extern char* patchStorageSlug; | |||||
std::string homeDir(); | std::string homeDir(); | ||||
void switchDarkMode(bool darkMode); | |||||
} // namespace rack | } // namespace rack | ||||
// ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
@@ -62,6 +62,7 @@ IGNORED_FILES += Rack/src/gamepad.cpp | |||||
IGNORED_FILES += Rack/src/keyboard.cpp | IGNORED_FILES += Rack/src/keyboard.cpp | ||||
IGNORED_FILES += Rack/src/library.cpp | IGNORED_FILES += Rack/src/library.cpp | ||||
IGNORED_FILES += Rack/src/midi.cpp | IGNORED_FILES += Rack/src/midi.cpp | ||||
IGNORED_FILES += Rack/src/midiloopback.cpp | |||||
IGNORED_FILES += Rack/src/network.cpp | IGNORED_FILES += Rack/src/network.cpp | ||||
IGNORED_FILES += Rack/src/plugin.cpp | IGNORED_FILES += Rack/src/plugin.cpp | ||||
IGNORED_FILES += Rack/src/rtaudio.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 += Rack/src/window/Window.cpp | ||||
IGNORED_FILES += $(wildcard Rack/src/core/*.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 += $(wildcard Rack/src/*/*.c) | RACK_FILES += $(wildcard Rack/src/*/*.c) | ||||
RACK_FILES += $(filter-out $(IGNORED_FILES),$(wildcard Rack/src/*.cpp)) | 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)/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) | -include $(RACK_OBJS:%.o=%.d) | ||||
@@ -1 +1 @@ | |||||
Subproject commit 5551617afff182925940908eaf73a7d7361303cc | |||||
Subproject commit f1576e2bb870da297789300117accb9d5fe44c5e |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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 | * 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 | * This program is free software: you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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&) { | void Window::screenshot(const std::string&) { | ||||
@@ -64,6 +64,10 @@ void updateForcingBlackSilverScrewMode(std::string slug) { | |||||
namespace settings { | namespace settings { | ||||
bool darkMode = true; | bool darkMode = true; | ||||
int rateLimit = 0; | int rateLimit = 0; | ||||
extern std::string uiTheme; | |||||
} | |||||
namespace ui { | |||||
void refreshTheme(); | |||||
} | } | ||||
} | } | ||||
@@ -1468,13 +1472,17 @@ void nsvgDeleteCardinal(NSVGimage* const handle) | |||||
nsvgDelete(handle); | nsvgDelete(handle); | ||||
} | } | ||||
namespace rack { | |||||
void switchDarkMode(const bool darkMode) | void switchDarkMode(const bool darkMode) | ||||
{ | { | ||||
#ifndef HEADLESS | #ifndef HEADLESS | ||||
if (rack::settings::darkMode == darkMode) | |||||
if (settings::darkMode == darkMode) | |||||
return; | return; | ||||
rack::settings::darkMode = darkMode; | |||||
settings::darkMode = darkMode; | |||||
settings::uiTheme = darkMode ? "dark" : "light"; | |||||
ui::refreshTheme(); | |||||
for (ExtendedNSVGimage& ext : loadedDarkSVGs) | for (ExtendedNSVGimage& ext : loadedDarkSVGs) | ||||
{ | { | ||||
@@ -1494,7 +1502,6 @@ void switchDarkMode(const bool darkMode) | |||||
#endif | #endif | ||||
} | } | ||||
namespace rack { | |||||
namespace asset { | namespace asset { | ||||
void destroy() { | void destroy() { | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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 | * 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 | * This program is free software: you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
@@ -83,8 +83,8 @@ struct Engine::Internal { | |||||
float sampleRate = 0.f; | float sampleRate = 0.f; | ||||
float sampleTime = 0.f; | float sampleTime = 0.f; | ||||
int64_t block = 0; | |||||
int64_t frame = 0; | int64_t frame = 0; | ||||
int64_t block = 0; | |||||
int64_t blockFrame = 0; | int64_t blockFrame = 0; | ||||
double blockTime = 0.0; | double blockTime = 0.0; | ||||
int blockFrames = 0; | int blockFrames = 0; | ||||
@@ -653,18 +653,13 @@ void Engine::yieldWorkers() { | |||||
} | } | ||||
int64_t Engine::getBlock() { | |||||
return internal->block; | |||||
} | |||||
int64_t Engine::getFrame() { | int64_t Engine::getFrame() { | ||||
return internal->frame; | 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(),); | DISTRHO_SAFE_ASSERT_RETURN(it == internal->modules.end(),); | ||||
auto tit = std::find(internal->terminalModules.begin(), internal->terminalModules.end(), module); | auto tit = std::find(internal->terminalModules.begin(), internal->terminalModules.end(), module); | ||||
DISTRHO_SAFE_ASSERT_RETURN(tit == internal->terminalModules.end(),); | 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 | // Set ID if unset or collides with an existing ID | ||||
while (module->id < 0 || internal->modulesCache.find(module->id) != internal->modulesCache.end()) { | while (module->id < 0 || internal->modulesCache.find(module->id) != internal->modulesCache.end()) { | ||||
// Randomly generate ID | // Randomly generate ID | ||||
@@ -1005,8 +998,6 @@ void Engine::addCable(Cable* cable) { | |||||
if (cable2->outputModule == cable->outputModule && cable2->outputId == cable->outputId) | if (cable2->outputModule == cable->outputModule && cable2->outputId == cable->outputId) | ||||
outputWasConnected = true; | outputWasConnected = true; | ||||
} | } | ||||
// Reinitialize random module since it uses thread-local RNG state | |||||
random::init(); | |||||
// Set ID if unset or collides with an existing ID | // Set ID if unset or collides with an existing ID | ||||
while (cable->id < 0 || internal->cablesCache.find(cable->id) != internal->cablesCache.end()) { | while (cable->id < 0 || internal->cablesCache.find(cable->id) != internal->cablesCache.end()) { | ||||
// Randomly generate ID | // Randomly generate ID | ||||
@@ -1106,19 +1097,19 @@ void Engine::setParamValue(Module* module, int paramId, float value) { | |||||
if (internal->remoteDetails != nullptr) { | if (internal->remoteDetails != nullptr) { | ||||
sendParamChangeToRemote(internal->remoteDetails, module->id, paramId, value); | sendParamChangeToRemote(internal->remoteDetails, module->id, paramId, value); | ||||
} | } | ||||
module->params[paramId].value = value; | |||||
module->params[paramId].setValue(value); | |||||
} | } | ||||
float Engine::getParamValue(Module* module, int paramId) { | 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) { | void Engine::setParamSmoothValue(Module* module, int paramId, float value) { | ||||
// If another param is being smoothed, jump value | // If another param is being smoothed, jump value | ||||
if (internal->smoothModule && !(internal->smoothModule == module && internal->smoothParamId == paramId)) { | 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->smoothParamId = paramId; | ||||
internal->smoothValue = value; | internal->smoothValue = value; | ||||
@@ -1130,7 +1121,7 @@ void Engine::setParamSmoothValue(Module* module, int paramId, float value) { | |||||
float Engine::getParamSmoothValue(Module* module, int paramId) { | float Engine::getParamSmoothValue(Module* module, int paramId) { | ||||
if (internal->smoothModule == module && internal->smoothParamId == paramId) | if (internal->smoothModule == module && internal->smoothParamId == paramId) | ||||
return internal->smoothValue; | return internal->smoothValue; | ||||
return module->params[paramId].value; | |||||
return module->params[paramId].getValue(); | |||||
} | } | ||||
@@ -17,7 +17,7 @@ | |||||
/** | /** | ||||
* This file is an edited version of VCVRack's app/MenuBar.cpp | * 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 | * This program is free software: you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
@@ -60,8 +60,6 @@ | |||||
# include <lo/lo.h> | # include <lo/lo.h> | ||||
#endif | #endif | ||||
void switchDarkMode(bool darkMode); | |||||
namespace rack { | namespace rack { | ||||
namespace asset { | namespace asset { | ||||
std::string patchesPath(); | std::string patchesPath(); | ||||
@@ -739,7 +737,7 @@ struct HelpButton : MenuButton { | |||||
patchUtils::openBrowser("https://vcvrack.com/manual"); | 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/"); | patchUtils::openBrowser("https://github.com/DISTRHO/Cardinal/"); | ||||
})); | })); | ||||
@@ -751,7 +749,6 @@ struct HelpButton : MenuButton { | |||||
menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
menu->addChild(createMenuLabel("Cardinal " + APP_EDITION + " " + CARDINAL_VERSION)); | |||||
menu->addChild(createMenuLabel("Rack " + APP_VERSION + " Compatible")); | 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 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 { | void step() override { | ||||
// Compute frame rate | // Compute frame rate | ||||
double frameDuration = APP->window->getLastFrameDuration(); | double frameDuration = APP->window->getLastFrameDuration(); | ||||
frameDurationTotal += frameDuration; | |||||
frameIndex++; | |||||
if (std::isfinite(frameDuration)) { | |||||
frameDurationTotal += frameDuration; | |||||
frameCount++; | |||||
} | |||||
if (frameDurationTotal >= 1.0) { | if (frameDurationTotal >= 1.0) { | ||||
frameDurationAvg = frameDurationTotal / frameIndex; | |||||
frameDurationAvg = frameDurationTotal / frameCount; | |||||
frameDurationTotal = 0.0; | frameDurationTotal = 0.0; | ||||
frameIndex = 0; | |||||
frameCount = 0; | |||||
} | } | ||||
// Compute UI thread CPU | // Compute UI thread CPU | ||||
@@ -791,13 +790,21 @@ struct MeterLabel : ui::Label { | |||||
// uiLastTime = time; | // uiLastTime = time; | ||||
// } | // } | ||||
text = ""; | |||||
if (box.size.x >= 400) { | |||||
double fps = std::isfinite(frameDurationAvg) ? 1.0 / frameDurationAvg : 0.0; | |||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #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 | #else | ||||
text = string::f("%.1f fps", 1.0 / frameDurationAvg); | |||||
text = string::f("%.1f fps", fps); | |||||
#endif | #endif | ||||
text += " "; | |||||
} | |||||
text += "Cardinal " + APP_EDITION + " " + CARDINAL_VERSION; | |||||
Label::step(); | Label::step(); | ||||
} | } | ||||
@@ -805,7 +812,7 @@ struct MeterLabel : ui::Label { | |||||
struct MenuBar : widget::OpaqueWidget { | struct MenuBar : widget::OpaqueWidget { | ||||
MeterLabel* meterLabel; | |||||
InfoLabel* infoLabel; | |||||
MenuBar(const bool isStandalone) | MenuBar(const bool isStandalone) | ||||
: widget::OpaqueWidget() | : widget::OpaqueWidget() | ||||
@@ -840,16 +847,10 @@ struct MenuBar : widget::OpaqueWidget { | |||||
helpButton->text = "Help"; | helpButton->text = "Help"; | ||||
layout->addChild(helpButton); | 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 { | void draw(const DrawArgs& args) override { | ||||
@@ -860,8 +861,10 @@ struct MenuBar : widget::OpaqueWidget { | |||||
} | } | ||||
void step() override { | void step() override { | ||||
meterLabel->box.pos.x = box.size.x - meterLabel->box.size.x - 5; | |||||
Widget::step(); | 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); | |||||
} | } | ||||
}; | }; | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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 | * 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 | * This program is free software: you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
@@ -85,9 +85,12 @@ void Model::fromJson(json_t* rootJ) { | |||||
// hidden | // hidden | ||||
json_t* hiddenJ = json_object_get(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) | if (!hiddenJ) | ||||
hiddenJ = json_object_get(rootJ, "disabled"); | 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) { | if (hiddenJ) { | ||||
// Don't un-hide Model if already hidden by C++ | // Don't un-hide Model if already hidden by C++ | ||||
if (json_boolean_value(hiddenJ)) | 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 | // Favorite | ||||
std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : ""; | std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : ""; | ||||
if (isFavorite()) | if (isFavorite()) | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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 | * 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 | * This program is free software: you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
@@ -30,8 +30,6 @@ | |||||
#include <thread> | #include <thread> | ||||
#include <regex> | #include <regex> | ||||
#include <osdialog.h> | |||||
#include <app/ModuleWidget.hpp> | #include <app/ModuleWidget.hpp> | ||||
#include <app/Scene.hpp> | #include <app/Scene.hpp> | ||||
#include <engine/Engine.hpp> | #include <engine/Engine.hpp> | ||||
@@ -420,6 +418,7 @@ void ModuleWidget::onButton(const ButtonEvent& e) { | |||||
// If module positions are locked, don't consume left-click | // If module positions are locked, don't consume left-click | ||||
if (settings::lockModules) { | if (settings::lockModules) { | ||||
e.consume(NULL); | |||||
return; | return; | ||||
} | } | ||||
@@ -449,6 +448,7 @@ void ModuleWidget::onButton(const ButtonEvent& e) { | |||||
// If module positions are locked, don't consume left-click | // If module positions are locked, don't consume left-click | ||||
if (settings::lockModules) { | if (settings::lockModules) { | ||||
e.consume(NULL); | |||||
return; | return; | ||||
} | } | ||||
@@ -700,7 +700,7 @@ void ModuleWidget::save(std::string filename) { | |||||
FILE* file = std::fopen(filename.c_str(), "w"); | FILE* file = std::fopen(filename.c_str(), "w"); | ||||
if (!file) { | if (!file) { | ||||
std::string message = string::f("Could not save preset to file %s", filename.c_str()); | 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; | return; | ||||
} | } | ||||
DEFER({std::fclose(file);}); | DEFER({std::fclose(file);}); | ||||
@@ -718,10 +718,12 @@ void ModuleWidget::saveTemplate() { | |||||
void ModuleWidget::saveTemplateDialog() { | void ModuleWidget::saveTemplateDialog() { | ||||
if (hasTemplate()) { | if (hasTemplate()) { | ||||
std::string message = string::f("Overwrite default preset for %s?", model->getFullName().c_str()); | 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<ModuleWidget> weakThis = this; | |||||
async_dialog_message(message.c_str(), [=]{ | |||||
if (weakThis) | |||||
weakThis->saveTemplate(); | |||||
}); | |||||
} | } | ||||
saveTemplate(); | |||||
} | } | ||||
bool ModuleWidget::hasTemplate() { | bool ModuleWidget::hasTemplate() { | ||||
@@ -738,9 +740,11 @@ void ModuleWidget::clearTemplate() { | |||||
void ModuleWidget::clearTemplateDialog() { | void ModuleWidget::clearTemplateDialog() { | ||||
std::string message = string::f("Delete default preset for %s?", model->getFullName().c_str()); | 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<ModuleWidget> weakThis = this; | |||||
async_dialog_message(message.c_str(), [=]{ | |||||
if (weakThis) | |||||
weakThis->clearTemplate(); | |||||
}); | |||||
} | } | ||||
void ModuleWidget::saveDialog() { | void ModuleWidget::saveDialog() { | ||||
@@ -978,12 +982,16 @@ static void appendPresetItems(ui::Menu* menu, WeakPtr<ModuleWidget> moduleWidget | |||||
std::regex r("^\\d+_"); | std::regex r("^\\d+_"); | ||||
name = std::regex_replace(name, r, ""); | 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") { | else if (system::getExtension(path) == ".vcvm" && name != "template") { | ||||
if (!hasPresets) | |||||
menu->addChild(new ui::MenuSeparator); | |||||
hasPresets = true; | hasPresets = true; | ||||
menu->addChild(createMenuItem(name, "", [=]() { | menu->addChild(createMenuItem(name, "", [=]() { | ||||
@@ -999,6 +1007,9 @@ static void appendPresetItems(ui::Menu* menu, WeakPtr<ModuleWidget> moduleWidget | |||||
} | } | ||||
} | } | ||||
} | } | ||||
if (!hasPresets) { | |||||
menu->addChild(createMenuLabel("(None)")); | |||||
} | |||||
}; | }; | ||||
@@ -1037,7 +1048,6 @@ void ModuleWidget::createContextMenu() { | |||||
weakThis->loadDialog(); | weakThis->loadDialog(); | ||||
})); | })); | ||||
/* TODO requires setting up user dir | |||||
menu->addChild(createMenuItem("Save as", "", [=]() { | menu->addChild(createMenuItem("Save as", "", [=]() { | ||||
if (!weakThis) | if (!weakThis) | ||||
return; | return; | ||||
@@ -1060,13 +1070,10 @@ void ModuleWidget::createContextMenu() { | |||||
menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
menu->addChild(createMenuLabel("User presets")); | menu->addChild(createMenuLabel("User presets")); | ||||
appendPresetItems(menu, weakThis, weakThis->model->getUserPresetDirectory()); | appendPresetItems(menu, weakThis, weakThis->model->getUserPresetDirectory()); | ||||
*/ | |||||
// Scan `<plugin dir>/presets/<module slug>` for presets. | // Scan `<plugin dir>/presets/<module slug>` for presets. | ||||
/* TODO enable only after setting up user dir | |||||
menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
menu->addChild(createMenuLabel("Factory presets")); | menu->addChild(createMenuLabel("Factory presets")); | ||||
*/ | |||||
appendPresetItems(menu, weakThis, weakThis->model->getFactoryPresetDirectory()); | appendPresetItems(menu, weakThis, weakThis->model->getFactoryPresetDirectory()); | ||||
})); | })); | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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 | * 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 | * This program is free software: you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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 | * 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 | * This program is free software: you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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 | #ifdef DISTRHO_OS_WASM | ||||
if (e.key == GLFW_KEY_F11 && (e.mods & RACK_MOD_MASK) == 0) { | if (e.key == GLFW_KEY_F11 && (e.mods & RACK_MOD_MASK) == 0) { | ||||
APP->window->setFullScreen(!APP->window->isFullScreen()); | APP->window->setFullScreen(!APP->window->isFullScreen()); | ||||
// The MenuBar will be hidden when the mouse moves over the RackScrollWidget. | |||||
// menuBar->hide(); | |||||
e.consume(this); | e.consume(this); | ||||
} | } | ||||
#endif | #endif | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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 | * 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 | * This program is free software: you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
@@ -172,13 +172,12 @@ struct Window::Internal { | |||||
int currentRateLimit = 0; | int currentRateLimit = 0; | ||||
int frame = 0; | int frame = 0; | ||||
int frameSwapInterval = 1; | |||||
#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS | #ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS | ||||
int generateScreenshotStep = kScreenshotStepNone; | int generateScreenshotStep = kScreenshotStepNone; | ||||
#endif | #endif | ||||
double monitorRefreshRate = 60.0; | double monitorRefreshRate = 60.0; | ||||
double frameTime = 0.0; | |||||
double lastFrameDuration = 0.0; | |||||
double frameTime = NAN; | |||||
double lastFrameDuration = NAN; | |||||
std::map<std::string, std::shared_ptr<FontWithOriginalContext>> fontCache; | std::map<std::string, std::shared_ptr<FontWithOriginalContext>> fontCache; | ||||
std::map<std::string, std::shared_ptr<ImageWithOriginalContext>> imageCache; | std::map<std::string, std::shared_ptr<ImageWithOriginalContext>> imageCache; | ||||
@@ -610,11 +609,12 @@ void Window::step() { | |||||
return; | return; | ||||
double frameTime = system::getTime(); | double frameTime = system::getTime(); | ||||
double lastFrameTime = internal->frameTime; | |||||
if (std::isfinite(internal->frameTime)) { | |||||
internal->lastFrameDuration = frameTime - internal->frameTime; | |||||
} | |||||
internal->frameTime = frameTime; | internal->frameTime = frameTime; | ||||
internal->lastFrameDuration = frameTime - lastFrameTime; | |||||
internal->fbCount = 0; | 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 | // Make event handlers and step() have a clean NanoVG context | ||||
nvgReset(vg); | nvgReset(vg); | ||||
@@ -659,28 +659,31 @@ void Window::step() { | |||||
// Get framebuffer/window ratio | // Get framebuffer/window ratio | ||||
int winWidth = internal->tlw->getWidth(); | int winWidth = internal->tlw->getWidth(); | ||||
int winHeight = internal->tlw->getHeight(); | int winHeight = internal->tlw->getHeight(); | ||||
int fbWidth = winWidth;// * newPixelRatio; | |||||
int fbHeight = winHeight;// * newPixelRatio; | |||||
int fbWidth = winWidth; | |||||
int fbHeight = winHeight; | |||||
windowRatio = (float)fbWidth / winWidth; | windowRatio = (float)fbWidth / winWidth; | ||||
// t1 = system::getTime(); | |||||
if (APP->scene) { | if (APP->scene) { | ||||
// DEBUG("%f %f %d %d", pixelRatio, windowRatio, fbWidth, winWidth); | // DEBUG("%f %f %d %d", pixelRatio, windowRatio, fbWidth, winWidth); | ||||
// Resize scene | // Resize scene | ||||
APP->scene->box.size = math::Vec(fbWidth, fbHeight).div(newPixelRatio); | |||||
APP->scene->box.size = math::Vec(fbWidth, fbHeight).div(pixelRatio); | |||||
// Step scene | // Step scene | ||||
APP->scene->step(); | APP->scene->step(); | ||||
// t2 = system::getTime(); | |||||
// Render scene | // Render scene | ||||
{ | { | ||||
// Update and render | // Update and render | ||||
nvgScale(vg, newPixelRatio, newPixelRatio); | |||||
nvgScale(vg, pixelRatio, pixelRatio); | |||||
// Draw scene | // Draw scene | ||||
widget::Widget::DrawArgs args; | widget::Widget::DrawArgs args; | ||||
args.vg = vg; | args.vg = vg; | ||||
args.clipBox = APP->scene->box.zeroPos(); | args.clipBox = APP->scene->box.zeroPos(); | ||||
APP->scene->draw(args); | APP->scene->draw(args); | ||||
// t3 = system::getTime(); | |||||
glViewport(0, 0, fbWidth, fbHeight); | glViewport(0, 0, fbWidth, fbHeight); | ||||
#ifdef CARDINAL_TRANSPARENT_SCREENSHOTS | #ifdef CARDINAL_TRANSPARENT_SCREENSHOTS | ||||
@@ -690,8 +693,18 @@ void Window::step() { | |||||
#endif | #endif | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | 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; | ++internal->frame; | ||||
#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS | #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 | #ifdef DISTRHO_OS_WASM | ||||
if (fullscreen) | |||||
if (fullScreen) | |||||
emscripten_request_fullscreen(internal->tlw->getWindow().getApp().getClassName(), false); | emscripten_request_fullscreen(internal->tlw->getWindow().getApp().getClassName(), false); | ||||
else | else | ||||
emscripten_exit_fullscreen(); | emscripten_exit_fullscreen(); | ||||
@@ -816,6 +825,7 @@ bool Window::isFullScreen() { | |||||
#endif | #endif | ||||
} | } | ||||
double Window::getMonitorRefreshRate() { | double Window::getMonitorRefreshRate() { | ||||
return internal->monitorRefreshRate; | return internal->monitorRefreshRate; | ||||
} | } | ||||
@@ -832,8 +842,8 @@ double Window::getLastFrameDuration() { | |||||
double Window::getFrameDurationRemaining() { | 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); | |||||
} | } | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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 | * 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 | * This program is free software: you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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 = getPluginFormatName(); | ||||
const std::string APP_EDITION_NAME = "Audio Plugin"; | const std::string APP_EDITION_NAME = "Audio Plugin"; | ||||
const std::string APP_VERSION_MAJOR = "2"; | 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 | #if defined ARCH_WIN | ||||
const std::string APP_OS = "win"; | const std::string APP_OS = "win"; | ||||
const std::string APP_OS_NAME = "Windows"; | |||||
#elif defined ARCH_MAC | #elif defined ARCH_MAC | ||||
const std::string APP_OS = "mac"; | const std::string APP_OS = "mac"; | ||||
const std::string APP_OS_NAME = "macOS"; | |||||
#elif defined ARCH_LIN | #elif defined ARCH_LIN | ||||
const std::string APP_OS = "lin"; | const std::string APP_OS = "lin"; | ||||
const std::string APP_OS_NAME = "Linux"; | |||||
#else | #else | ||||
#error ARCH_LIN undefined | #error ARCH_LIN undefined | ||||
#endif | #endif | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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 | * 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 | * This program is free software: you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
@@ -31,7 +31,6 @@ | |||||
#include <engine/Engine.hpp> | #include <engine/Engine.hpp> | ||||
#include <app/Scene.hpp> | #include <app/Scene.hpp> | ||||
#include <history.hpp> | #include <history.hpp> | ||||
#include <settings.hpp> | |||||
#ifdef NDEBUG | #ifdef NDEBUG | ||||
# undef DEBUG | # undef DEBUG | ||||
@@ -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 @@ | @@ -1,3 +1,30 @@ | ||||
+/* | +/* | ||||
+ * DISTRHO Cardinal Plugin | + * DISTRHO Cardinal Plugin | ||||
+ * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
+ * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
+ * | + * | ||||
+ * This program is free software; you can redistribute it and/or | + * This program is free software; you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * 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 | + * 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 | + * This program is free software: you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * modify it under the terms of the GNU General Public License as | ||||
@@ -31,10 +31,14 @@ | |||||
#include <algorithm> | #include <algorithm> | ||||
#include <set> | #include <set> | ||||
#include <thread> | #include <thread> | ||||
@@ -6,183 +33,39 @@ | |||||
@@ -5,192 +32,47 @@ | |||||
#include <mutex> | |||||
#include <atomic> | #include <atomic> | ||||
#include <tuple> | #include <tuple> | ||||
#include <pmmintrin.h> | |||||
-#if defined ARCH_X64 | |||||
- #include <pmmintrin.h> | |||||
-#endif | |||||
+#include <pmmintrin.h> | |||||
+#include <unordered_map> | +#include <unordered_map> | ||||
#include <engine/Engine.hpp> | #include <engine/Engine.hpp> | ||||
@@ -48,14 +52,12 @@ | |||||
#include <mutex.hpp> | #include <mutex.hpp> | ||||
+#include <helpers.hpp> | +#include <helpers.hpp> | ||||
+#ifdef NDEBUG | |||||
+# undef DEBUG | |||||
+#endif | |||||
- | |||||
-namespace rack { | -namespace rack { | ||||
-namespace engine { | -namespace engine { | ||||
- | - | ||||
- | - | ||||
-#if defined ARCH_X64 | |||||
-static void initMXCSR() { | -static void initMXCSR() { | ||||
- // Set CPU to flush-to-zero (FTZ) and denormals-are-zero (DAZ) mode | - // Set CPU to flush-to-zero (FTZ) and denormals-are-zero (DAZ) mode | ||||
- // https://software.intel.com/en-us/node/682949 | - // https://software.intel.com/en-us/node/682949 | ||||
@@ -64,8 +66,13 @@ | |||||
- // Reset other flags | - // Reset other flags | ||||
- _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST); | - _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST); | ||||
-} | -} | ||||
- | |||||
- | |||||
+#ifdef NDEBUG | |||||
+# undef DEBUG | |||||
#endif | |||||
+#include "../CardinalRemote.hpp" | |||||
+#include "DistrhoUtils.hpp" | |||||
-/** Barrier based on mutexes. | -/** Barrier based on mutexes. | ||||
-Not finished or tested, do not use. | -Not finished or tested, do not use. | ||||
-*/ | -*/ | ||||
@@ -98,25 +105,21 @@ | |||||
- }); | - }); | ||||
- } | - } | ||||
-}; | -}; | ||||
+#include "../CardinalRemote.hpp" | |||||
+#include "DistrhoUtils.hpp" | |||||
- | |||||
- | |||||
-/** 2-phase barrier based on spin-locking. | -/** 2-phase barrier based on spin-locking. | ||||
-*/ | -*/ | ||||
-struct SpinBarrier { | -struct SpinBarrier { | ||||
- std::atomic<int> count{0}; | - std::atomic<int> count{0}; | ||||
- std::atomic<uint8_t> step{0}; | - std::atomic<uint8_t> step{0}; | ||||
- int threads = 0; | - int threads = 0; | ||||
+// known terminal modules | |||||
+extern std::vector<rack::plugin::Model*> hostTerminalModels; | |||||
- | |||||
- /** Must be called when no threads are calling wait(). | - /** Must be called when no threads are calling wait(). | ||||
- */ | - */ | ||||
- void setThreads(int threads) { | - void setThreads(int threads) { | ||||
- this->threads = threads; | - this->threads = threads; | ||||
- } | - } | ||||
- | |||||
- void wait() { | - void wait() { | ||||
- uint8_t s = step; | - uint8_t s = step; | ||||
- if (count.fetch_add(1, std::memory_order_acquire) + 1 >= threads) { | - if (count.fetch_add(1, std::memory_order_acquire) + 1 >= threads) { | ||||
@@ -131,12 +134,16 @@ | |||||
- while (true) { | - while (true) { | ||||
- if (step.load(std::memory_order_relaxed) != s) | - if (step.load(std::memory_order_relaxed) != s) | ||||
- return; | - return; | ||||
-#if defined ARCH_X64 | |||||
- __builtin_ia32_pause(); | - __builtin_ia32_pause(); | ||||
-#endif | |||||
- } | - } | ||||
- } | - } | ||||
-}; | -}; | ||||
- | |||||
- | |||||
+// known terminal modules | |||||
+extern std::vector<rack::plugin::Model*> hostTerminalModels; | |||||
-/** Barrier that spin-locks until yield() is called, and then all threads switch to a mutex. | -/** 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. | -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. | -Saves CPU power after yield is called. | ||||
@@ -173,12 +180,14 @@ | |||||
- } | - } | ||||
- return; | - return; | ||||
- } | - } | ||||
- | |||||
- // Spin until the last thread begins waiting | - // Spin until the last thread begins waiting | ||||
- while (!yielded.load(std::memory_order_relaxed)) { | - while (!yielded.load(std::memory_order_relaxed)) { | ||||
- if (step.load(std::memory_order_relaxed) != s) | - if (step.load(std::memory_order_relaxed) != s) | ||||
- return; | - return; | ||||
-#if defined ARCH_X64 | |||||
- __builtin_ia32_pause(); | - __builtin_ia32_pause(); | ||||
-#endif | |||||
- } | - } | ||||
- | - | ||||
- // Wait on mutex CV | - // Wait on mutex CV | ||||
@@ -195,7 +204,9 @@ | |||||
- int id; | - int id; | ||||
- std::thread thread; | - std::thread thread; | ||||
- bool running = false; | - bool running = false; | ||||
- | |||||
+namespace rack { | |||||
+namespace engine { | |||||
- void start() { | - void start() { | ||||
- assert(!running); | - assert(!running); | ||||
- running = true; | - running = true; | ||||
@@ -203,7 +214,7 @@ | |||||
- run(); | - run(); | ||||
- }); | - }); | ||||
- } | - } | ||||
- | |||||
- void requestStop() { | - void requestStop() { | ||||
- running = false; | - running = false; | ||||
- } | - } | ||||
@@ -215,8 +226,11 @@ | |||||
- | - | ||||
- void run(); | - 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 { | struct Engine::Internal { | ||||
@@ -228,7 +242,7 @@ | |||||
// moduleId | // moduleId | ||||
std::map<int64_t, Module*> modulesCache; | std::map<int64_t, Module*> modulesCache; | ||||
@@ -198,7 +81,9 @@ | |||||
@@ -206,7 +88,9 @@ | |||||
int64_t blockFrame = 0; | int64_t blockFrame = 0; | ||||
double blockTime = 0.0; | double blockTime = 0.0; | ||||
int blockFrames = 0; | int blockFrames = 0; | ||||
@@ -238,7 +252,7 @@ | |||||
// Meter | // Meter | ||||
int meterCount = 0; | int meterCount = 0; | ||||
double meterTotal = 0.0; | double meterTotal = 0.0; | ||||
@@ -206,33 +91,21 @@ | |||||
@@ -214,33 +98,32 @@ | |||||
double meterLastTime = -INFINITY; | double meterLastTime = -INFINITY; | ||||
double meterLastAverage = 0.0; | double meterLastAverage = 0.0; | ||||
double meterLastMax = 0.0; | double meterLastMax = 0.0; | ||||
@@ -260,7 +274,9 @@ | |||||
- /** Mutex that guards stepBlock() so it's not called simultaneously. | - /** Mutex that guards stepBlock() so it's not called simultaneously. | ||||
- */ | - */ | ||||
- std::mutex blockMutex; | - std::mutex blockMutex; | ||||
- | |||||
+}; | |||||
+ | |||||
- int threadCount = 0; | - int threadCount = 0; | ||||
- std::vector<EngineWorker> workers; | - std::vector<EngineWorker> workers; | ||||
- HybridBarrier engineBarrier; | - HybridBarrier engineBarrier; | ||||
@@ -273,10 +289,18 @@ | |||||
- std::thread fallbackThread; | - std::thread fallbackThread; | ||||
- std::mutex fallbackMutex; | - std::mutex fallbackMutex; | ||||
- std::condition_variable fallbackCv; | - 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; | - Engine::Internal* internal = that->internal; | ||||
- if (threadCount == internal->threadCount) | - if (threadCount == internal->threadCount) | ||||
- return; | - 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) { | - if (internal->threadCount > 0) { | ||||
- // Stop engine workers | - // Stop engine workers | ||||
- for (EngineWorker& worker : internal->workers) { | - for (EngineWorker& worker : internal->workers) { | ||||
- worker.requestStop(); | - worker.requestStop(); | ||||
- } | - } | ||||
- internal->engineBarrier.wait(); | - internal->engineBarrier.wait(); | ||||
- | |||||
- // Join and destroy engine workers | - // Join and destroy engine workers | ||||
- for (EngineWorker& worker : internal->workers) { | - for (EngineWorker& worker : internal->workers) { | ||||
- worker.join(); | - worker.join(); | ||||
- } | - } | ||||
- internal->workers.resize(0); | - 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 | - // Configure engine | ||||
- internal->threadCount = threadCount; | - internal->threadCount = threadCount; | ||||
- | - | ||||
- // Set barrier counts | - // Set barrier counts | ||||
- internal->engineBarrier.setThreads(threadCount); | - internal->engineBarrier.setThreads(threadCount); | ||||
- internal->workerBarrier.setThreads(threadCount); | - internal->workerBarrier.setThreads(threadCount); | ||||
- | |||||
- if (threadCount > 0) { | - if (threadCount > 0) { | ||||
- // Create and start engine workers | - // Create and start engine workers | ||||
- internal->workers.resize(threadCount - 1); | - internal->workers.resize(threadCount - 1); | ||||
@@ -314,17 +376,41 @@ | |||||
- worker.id = id; | - worker.id = id; | ||||
- worker.engine = that; | - worker.engine = that; | ||||
- worker.start(); | - 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) { | -static void Engine_stepWorker(Engine* that, int threadId) { | ||||
- Engine::Internal* internal = that->internal; | - Engine::Internal* internal = that->internal; | ||||
- | - | ||||
- // int threadCount = internal->threadCount; | - // int threadCount = internal->threadCount; | ||||
- int modulesLen = internal->modules.size(); | - int modulesLen = internal->modules.size(); | ||||
- | |||||
+static void Module__doProcess(Module* const module, const Module::ProcessArgs& args) { | |||||
+ Module::Internal* const internal = module->internal; | |||||
- // Build ProcessArgs | - // Build ProcessArgs | ||||
- Module::ProcessArgs processArgs; | - Module::ProcessArgs processArgs; | ||||
- processArgs.sampleRate = internal->sampleRate; | - processArgs.sampleRate = internal->sampleRate; | ||||
@@ -341,74 +427,83 @@ | |||||
- | - | ||||
- Module* module = internal->modules[i]; | - Module* module = internal->modules[i]; | ||||
- module->doProcess(processArgs); | - 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 | |||||
- 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 @@ | |||||
} | |||||
+#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 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; | |||||
- // 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); | |||||
+ | + | ||||
+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); | |||||
+ 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; | |||||
+ } | + } | ||||
+ } else { | |||||
+ terminalModule->processTerminalOutput(args); | |||||
+ } | |||||
} | |||||
- // 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 | + // 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) { | |||||
+ if (args.frame % PORT_DIVIDER == 0) { | |||||
+ float portTime = args.sampleTime * PORT_DIVIDER; | |||||
+ for (Input& input : module->inputs) { | |||||
+ Port_step(&input, portTime); | + Port_step(&input, portTime); | ||||
+ } | + } | ||||
+ for (Output& output : terminalModule->outputs) { | |||||
+ for (Output& output : module->outputs) { | |||||
+ Port_step(&output, portTime); | + Port_step(&output, portTime); | ||||
+ } | + } | ||||
+ } | |||||
+} | |||||
+ | |||||
+ | |||||
/** Steps a single frame | |||||
*/ | |||||
static void Engine_stepFrame(Engine* that) { | |||||
@@ -358,10 +213,16 @@ | |||||
} | |||||
- input->channels = channels; | |||||
+#endif | |||||
} | |||||
@@ -366,10 +294,16 @@ | |||||
float smoothValue = internal->smoothValue; | float smoothValue = internal->smoothValue; | ||||
Param* smoothParam = &smoothModule->params[smoothParamId]; | Param* smoothParam = &smoothModule->params[smoothParamId]; | ||||
float value = smoothParam->value; | 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) | // Snap to actual smooth value if the value doesn't change enough (due to the granularity of floats) | ||||
smoothParam->setValue(smoothValue); | smoothParam->setValue(smoothValue); | ||||
internal->smoothModule = NULL; | internal->smoothModule = NULL; | ||||
@@ -372,13 +233,8 @@ | |||||
@@ -380,13 +314,8 @@ | |||||
} | } | ||||
} | } | ||||
@@ -444,7 +539,7 @@ | |||||
if (module->leftExpander.messageFlipRequested) { | if (module->leftExpander.messageFlipRequested) { | ||||
std::swap(module->leftExpander.producerMessage, module->leftExpander.consumerMessage); | std::swap(module->leftExpander.producerMessage, module->leftExpander.consumerMessage); | ||||
module->leftExpander.messageFlipRequested = false; | module->leftExpander.messageFlipRequested = false; | ||||
@@ -389,13 +245,32 @@ | |||||
@@ -397,13 +326,32 @@ | |||||
} | } | ||||
} | } | ||||
@@ -463,10 +558,11 @@ | |||||
+ for (TerminalModule* terminalModule : internal->terminalModules) { | + for (TerminalModule* terminalModule : internal->terminalModules) { | ||||
+ TerminalModule__doProcess(terminalModule, processArgs, true); | + TerminalModule__doProcess(terminalModule, processArgs, true); | ||||
+ } | + } | ||||
+ | |||||
- internal->frame++; | |||||
+ // Step each module and cables | + // Step each module and cables | ||||
+ for (Module* module : internal->modules) { | + for (Module* module : internal->modules) { | ||||
+ module->doProcess(processArgs); | |||||
+ Module__doProcess(module, processArgs); | |||||
+ for (Output& output : module->outputs) { | + for (Output& output : module->outputs) { | ||||
+ for (Cable* cable : output.cables) | + for (Cable* cable : output.cables) | ||||
+ Cable_step(cable); | + Cable_step(cable); | ||||
@@ -477,13 +573,12 @@ | |||||
+ for (TerminalModule* terminalModule : internal->terminalModules) { | + for (TerminalModule* terminalModule : internal->terminalModules) { | ||||
+ TerminalModule__doProcess(terminalModule, processArgs, false); | + TerminalModule__doProcess(terminalModule, processArgs, false); | ||||
+ } | + } | ||||
- internal->frame++; | |||||
+ | |||||
+ ++internal->frame; | + ++internal->frame; | ||||
} | } | ||||
@@ -414,35 +289,119 @@ | |||||
@@ -422,35 +370,119 @@ | |||||
} | } | ||||
@@ -604,17 +699,17 @@ | |||||
- Port_setDisconnected(port); | - Port_setDisconnected(port); | ||||
+ for (Input* input : disconnectedInputs) { | + for (Input* input : disconnectedInputs) { | ||||
+ Port_setDisconnected(input); | + Port_setDisconnected(input); | ||||
+ } | |||||
} | |||||
+ for (Output* output : disconnectedOutputs) { | + for (Output* output : disconnectedOutputs) { | ||||
+ Port_setDisconnected(output); | + Port_setDisconnected(output); | ||||
+ DISTRHO_SAFE_ASSERT(output->cables.empty()); | + DISTRHO_SAFE_ASSERT(output->cables.empty()); | ||||
} | |||||
+ } | |||||
+ // Order the modules according to their connections | + // Order the modules according to their connections | ||||
+ Engine_orderModules(that); | + Engine_orderModules(that); | ||||
} | } | ||||
@@ -460,37 +419,23 @@ | |||||
@@ -468,37 +500,23 @@ | |||||
Engine::Engine() { | Engine::Engine() { | ||||
internal = new Internal; | internal = new Internal; | ||||
@@ -660,7 +755,7 @@ | |||||
delete internal; | delete internal; | ||||
} | } | ||||
@@ -519,18 +464,22 @@ | |||||
@@ -527,20 +545,22 @@ | |||||
removeModule_NoLock(module); | removeModule_NoLock(module); | ||||
delete module; | delete module; | ||||
} | } | ||||
@@ -681,12 +776,14 @@ | |||||
- std::lock_guard<std::mutex> stepLock(internal->blockMutex); | - std::lock_guard<std::mutex> stepLock(internal->blockMutex); | ||||
SharedLock<SharedMutex> lock(internal->mutex); | SharedLock<SharedMutex> lock(internal->mutex); | ||||
// Configure thread | // Configure thread | ||||
-#if defined ARCH_X64 | |||||
- uint32_t csr = _mm_getcsr(); | - uint32_t csr = _mm_getcsr(); | ||||
- initMXCSR(); | - initMXCSR(); | ||||
-#endif | |||||
random::init(); | random::init(); | ||||
internal->blockFrame = internal->frame; | internal->blockFrame = internal->frame; | ||||
@@ -543,18 +492,14 @@ | |||||
@@ -553,18 +573,14 @@ | |||||
Engine_updateExpander_NoLock(this, module, true); | Engine_updateExpander_NoLock(this, module, true); | ||||
} | } | ||||
@@ -706,14 +803,15 @@ | |||||
// Stop timer | // Stop timer | ||||
double endTime = system::getTime(); | double endTime = system::getTime(); | ||||
double meter = (endTime - startTime) / (frames * internal->sampleTime); | double meter = (endTime - startTime) / (frames * internal->sampleTime); | ||||
@@ -572,47 +517,20 @@ | |||||
@@ -582,49 +598,20 @@ | |||||
internal->meterTotal = 0.0; | internal->meterTotal = 0.0; | ||||
internal->meterMax = 0.0; | internal->meterMax = 0.0; | ||||
} | } | ||||
- | - | ||||
-#if defined ARCH_X64 | |||||
- // Reset MXCSR back to original value | - // Reset MXCSR back to original value | ||||
- _mm_setcsr(csr); | - _mm_setcsr(csr); | ||||
+#endif | |||||
#endif | |||||
} | } | ||||
@@ -756,7 +854,7 @@ | |||||
} | } | ||||
@@ -635,20 +553,13 @@ | |||||
@@ -647,20 +634,13 @@ | |||||
for (Module* module : internal->modules) { | for (Module* module : internal->modules) { | ||||
module->onSampleRateChange(e); | module->onSampleRateChange(e); | ||||
} | } | ||||
@@ -780,7 +878,7 @@ | |||||
} | } | ||||
@@ -658,7 +569,6 @@ | |||||
@@ -670,7 +650,6 @@ | |||||
void Engine::yieldWorkers() { | void Engine::yieldWorkers() { | ||||
@@ -788,7 +886,7 @@ | |||||
} | } | ||||
@@ -698,17 +608,25 @@ | |||||
@@ -705,17 +684,25 @@ | |||||
double Engine::getMeterAverage() { | double Engine::getMeterAverage() { | ||||
@@ -815,7 +913,7 @@ | |||||
} | } | ||||
@@ -718,8 +636,12 @@ | |||||
@@ -725,8 +712,12 @@ | |||||
for (Module* m : internal->modules) { | for (Module* m : internal->modules) { | ||||
if (i >= len) | if (i >= len) | ||||
break; | break; | ||||
@@ -830,7 +928,7 @@ | |||||
} | } | ||||
return i; | return i; | ||||
} | } | ||||
@@ -728,27 +650,43 @@ | |||||
@@ -735,27 +726,43 @@ | |||||
std::vector<int64_t> Engine::getModuleIds() { | std::vector<int64_t> Engine::getModuleIds() { | ||||
SharedLock<SharedMutex> lock(internal->mutex); | SharedLock<SharedMutex> lock(internal->mutex); | ||||
std::vector<int64_t> moduleIds; | std::vector<int64_t> moduleIds; | ||||
@@ -878,7 +976,7 @@ | |||||
internal->modulesCache[module->id] = module; | internal->modulesCache[module->id] = module; | ||||
// Dispatch AddEvent | // Dispatch AddEvent | ||||
Module::AddEvent eAdd; | Module::AddEvent eAdd; | ||||
@@ -763,6 +701,9 @@ | |||||
@@ -770,6 +777,9 @@ | |||||
if (paramHandle->moduleId == module->id) | if (paramHandle->moduleId == module->id) | ||||
paramHandle->module = module; | paramHandle->module = module; | ||||
} | } | ||||
@@ -888,7 +986,7 @@ | |||||
} | } | ||||
@@ -772,11 +713,11 @@ | |||||
@@ -779,11 +789,11 @@ | |||||
} | } | ||||
@@ -905,7 +1003,7 @@ | |||||
// Dispatch RemoveEvent | // Dispatch RemoveEvent | ||||
Module::RemoveEvent eRemove; | Module::RemoveEvent eRemove; | ||||
module->onRemove(eRemove); | module->onRemove(eRemove); | ||||
@@ -785,18 +726,14 @@ | |||||
@@ -792,18 +802,14 @@ | |||||
if (paramHandle->moduleId == module->id) | if (paramHandle->moduleId == module->id) | ||||
paramHandle->module = NULL; | paramHandle->module = NULL; | ||||
} | } | ||||
@@ -926,7 +1024,7 @@ | |||||
} | } | ||||
// Update expanders of other modules | // Update expanders of other modules | ||||
for (Module* m : internal->modules) { | for (Module* m : internal->modules) { | ||||
@@ -809,14 +746,31 @@ | |||||
@@ -816,14 +822,31 @@ | |||||
m->rightExpander.module = NULL; | m->rightExpander.module = NULL; | ||||
} | } | ||||
} | } | ||||
@@ -961,7 +1059,7 @@ | |||||
} | } | ||||
@@ -824,7 +778,8 @@ | |||||
@@ -831,7 +854,8 @@ | |||||
SharedLock<SharedMutex> lock(internal->mutex); | SharedLock<SharedMutex> lock(internal->mutex); | ||||
// TODO Performance could be improved by searching modulesCache, but more testing would be needed to make sure it's always valid. | // 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); | 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) { | void Engine::resetModule(Module* module) { | ||||
std::lock_guard<SharedMutex> lock(internal->mutex); | std::lock_guard<SharedMutex> lock(internal->mutex); | ||||
@@ -980,7 +1078,7 @@ | |||||
Module::ResetEvent eReset; | Module::ResetEvent eReset; | ||||
module->onReset(eReset); | module->onReset(eReset); | ||||
@@ -853,7 +808,7 @@ | |||||
@@ -860,7 +884,7 @@ | |||||
void Engine::randomizeModule(Module* module) { | void Engine::randomizeModule(Module* module) { | ||||
std::lock_guard<SharedMutex> lock(internal->mutex); | std::lock_guard<SharedMutex> lock(internal->mutex); | ||||
@@ -989,7 +1087,7 @@ | |||||
Module::RandomizeEvent eRandomize; | Module::RandomizeEvent eRandomize; | ||||
module->onRandomize(eRandomize); | module->onRandomize(eRandomize); | ||||
@@ -861,7 +816,7 @@ | |||||
@@ -868,7 +892,7 @@ | |||||
void Engine::bypassModule(Module* module, bool bypassed) { | void Engine::bypassModule(Module* module, bool bypassed) { | ||||
@@ -998,7 +1096,7 @@ | |||||
if (module->isBypassed() == bypassed) | if (module->isBypassed() == bypassed) | ||||
return; | return; | ||||
@@ -907,11 +862,17 @@ | |||||
@@ -914,11 +938,17 @@ | |||||
void Engine::prepareSave() { | void Engine::prepareSave() { | ||||
@@ -1016,7 +1114,7 @@ | |||||
} | } | ||||
@@ -946,16 +907,16 @@ | |||||
@@ -953,16 +983,16 @@ | |||||
void Engine::addCable(Cable* cable) { | void Engine::addCable(Cable* cable) { | ||||
std::lock_guard<SharedMutex> lock(internal->mutex); | std::lock_guard<SharedMutex> lock(internal->mutex); | ||||
@@ -1038,7 +1136,7 @@ | |||||
// Get connected status of output, to decide whether we need to call a PortChangeEvent. | // 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()` | // It's best to not trust `cable->outputModule->outputs[cable->outputId]->isConnected()` | ||||
if (cable2->outputModule == cable->outputModule && cable2->outputId == cable->outputId) | if (cable2->outputModule == cable->outputModule && cable2->outputId == cable->outputId) | ||||
@@ -969,6 +930,8 @@ | |||||
@@ -976,6 +1006,8 @@ | |||||
// Add the cable | // Add the cable | ||||
internal->cables.push_back(cable); | internal->cables.push_back(cable); | ||||
internal->cablesCache[cable->id] = cable; | internal->cablesCache[cable->id] = cable; | ||||
@@ -1047,7 +1145,7 @@ | |||||
Engine_updateConnected(this); | Engine_updateConnected(this); | ||||
// Dispatch input port event | // Dispatch input port event | ||||
{ | { | ||||
@@ -996,10 +959,12 @@ | |||||
@@ -1003,10 +1035,12 @@ | |||||
void Engine::removeCable_NoLock(Cable* cable) { | void Engine::removeCable_NoLock(Cable* cable) { | ||||
@@ -1062,17 +1160,17 @@ | |||||
// Remove the cable | // Remove the cable | ||||
internal->cablesCache.erase(cable->id); | internal->cablesCache.erase(cable->id); | ||||
internal->cables.erase(it); | internal->cables.erase(it); | ||||
@@ -1053,6 +1018,9 @@ | |||||
@@ -1060,6 +1094,9 @@ | |||||
internal->smoothModule = NULL; | internal->smoothModule = NULL; | ||||
internal->smoothParamId = 0; | internal->smoothParamId = 0; | ||||
} | } | ||||
+ if (internal->remoteDetails != nullptr) { | + if (internal->remoteDetails != nullptr) { | ||||
+ sendParamChangeToRemote(internal->remoteDetails, module->id, paramId, value); | + 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<SharedMutex> lock(internal->mutex); | std::lock_guard<SharedMutex> lock(internal->mutex); | ||||
// New ParamHandles must be blank. | // New ParamHandles must be blank. | ||||
// This means we don't have to refresh the cache. | // This means we don't have to refresh the cache. | ||||
@@ -1086,7 +1184,7 @@ | |||||
// Add it | // Add it | ||||
internal->paramHandles.insert(paramHandle); | internal->paramHandles.insert(paramHandle); | ||||
@@ -1106,7 +1074,7 @@ | |||||
@@ -1113,7 +1150,7 @@ | |||||
void Engine::removeParamHandle_NoLock(ParamHandle* paramHandle) { | void Engine::removeParamHandle_NoLock(ParamHandle* paramHandle) { | ||||
// Check that the ParamHandle is already added | // Check that the ParamHandle is already added | ||||
auto it = internal->paramHandles.find(paramHandle); | auto it = internal->paramHandles.find(paramHandle); | ||||
@@ -1095,7 +1193,7 @@ | |||||
// Remove it | // Remove it | ||||
paramHandle->module = NULL; | paramHandle->module = NULL; | ||||
@@ -1143,7 +1111,7 @@ | |||||
@@ -1150,7 +1187,7 @@ | |||||
void Engine::updateParamHandle_NoLock(ParamHandle* paramHandle, int64_t moduleId, int paramId, bool overwrite) { | void Engine::updateParamHandle_NoLock(ParamHandle* paramHandle, int64_t moduleId, int paramId, bool overwrite) { | ||||
// Check that it exists | // Check that it exists | ||||
auto it = internal->paramHandles.find(paramHandle); | auto it = internal->paramHandles.find(paramHandle); | ||||
@@ -1104,7 +1202,7 @@ | |||||
// Set IDs | // Set IDs | ||||
paramHandle->moduleId = moduleId; | paramHandle->moduleId = moduleId; | ||||
@@ -1187,6 +1155,10 @@ | |||||
@@ -1194,6 +1231,10 @@ | |||||
json_t* moduleJ = module->toJson(); | json_t* moduleJ = module->toJson(); | ||||
json_array_append_new(modulesJ, moduleJ); | json_array_append_new(modulesJ, moduleJ); | ||||
} | } | ||||
@@ -1115,7 +1213,7 @@ | |||||
json_object_set_new(rootJ, "modules", modulesJ); | json_object_set_new(rootJ, "modules", modulesJ); | ||||
// cables | // cables | ||||
@@ -1197,11 +1169,6 @@ | |||||
@@ -1204,11 +1245,6 @@ | |||||
} | } | ||||
json_object_set_new(rootJ, "cables", cablesJ); | json_object_set_new(rootJ, "cables", cablesJ); | ||||
@@ -1127,7 +1225,7 @@ | |||||
return rootJ; | return rootJ; | ||||
} | } | ||||
@@ -1225,14 +1192,20 @@ | |||||
@@ -1232,14 +1268,20 @@ | |||||
} | } | ||||
catch (Exception& e) { | catch (Exception& e) { | ||||
WARN("Cannot load model: %s", e.what()); | WARN("Cannot load model: %s", e.what()); | ||||
@@ -1152,7 +1250,7 @@ | |||||
try { | try { | ||||
// This doesn't need a lock because the Module is not added to the Engine yet. | // 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) { | catch (Exception& e) { | ||||
WARN("Cannot load module: %s", e.what()); | WARN("Cannot load module: %s", e.what()); | ||||
@@ -1162,7 +1260,7 @@ | |||||
delete module; | delete module; | ||||
continue; | continue; | ||||
} | } | ||||
@@ -1285,67 +1259,20 @@ | |||||
@@ -1292,69 +1335,20 @@ | |||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
@@ -1180,7 +1278,9 @@ | |||||
- // Configure thread | - // Configure thread | ||||
- contextSet(engine->internal->context); | - contextSet(engine->internal->context); | ||||
- system::setThreadName(string::f("Worker %d", id)); | - system::setThreadName(string::f("Worker %d", id)); | ||||
-#if defined ARCH_X64 | |||||
- initMXCSR(); | - initMXCSR(); | ||||
-#endif | |||||
- random::init(); | - random::init(); | ||||
- | - | ||||
- while (true) { | - while (true) { | ||||
@@ -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 @@ | @@ -1,8 +1,33 @@ | ||||
+/* | +/* | ||||
+ * DISTRHO Cardinal Plugin | + * DISTRHO Cardinal Plugin | ||||
+ * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
+ * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
+ * | + * | ||||
+ * This program is free software; you can redistribute it and/or | + * This program is free software; you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * 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 | + * 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 | + * This program is free software: you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * modify it under the terms of the GNU General Public License as | ||||
@@ -44,7 +44,7 @@ | |||||
#include <window/Window.hpp> | #include <window/Window.hpp> | ||||
#include <asset.hpp> | #include <asset.hpp> | ||||
#include <context.hpp> | #include <context.hpp> | ||||
@@ -25,8 +51,28 @@ | |||||
@@ -25,8 +51,26 @@ | |||||
#include <patch.hpp> | #include <patch.hpp> | ||||
#include <library.hpp> | #include <library.hpp> | ||||
@@ -56,8 +56,6 @@ | |||||
+#ifdef HAVE_LIBLO | +#ifdef HAVE_LIBLO | ||||
+# include <lo/lo.h> | +# include <lo/lo.h> | ||||
+#endif | +#endif | ||||
+ | |||||
+void switchDarkMode(bool darkMode); | |||||
namespace rack { | namespace rack { | ||||
+namespace asset { | +namespace asset { | ||||
@@ -73,7 +71,7 @@ | |||||
namespace app { | namespace app { | ||||
namespace menuBar { | namespace menuBar { | ||||
@@ -48,79 +94,160 @@ | |||||
@@ -48,79 +92,180 @@ | |||||
}; | }; | ||||
@@ -97,15 +95,16 @@ | |||||
struct FileButton : MenuButton { | struct FileButton : MenuButton { | ||||
+ const bool isStandalone; | + const bool isStandalone; | ||||
+#if ! CARDINAL_VARIANT_MINI | |||||
+ std::vector<std::string> demoPatches; | + std::vector<std::string> demoPatches; | ||||
+#endif | |||||
+ | + | ||||
+ FileButton(const bool standalone) | + FileButton(const bool standalone) | ||||
+ : MenuButton(), isStandalone(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"; | + const std::string patchesDir = asset::patchesPath() + DISTRHO_OS_SEP_STR "examples"; | ||||
+#endif | |||||
+ | + | ||||
+ if (system::isDirectory(patchesDir)) | + if (system::isDirectory(patchesDir)) | ||||
+ { | + { | ||||
@@ -114,7 +113,6 @@ | |||||
+ return string::lowercase(a) < string::lowercase(b); | + return string::lowercase(a) < string::lowercase(b); | ||||
+ }); | + }); | ||||
+ } | + } | ||||
+#endif | |||||
+ } | + } | ||||
+ | + | ||||
void onAction(const ActionEvent& e) override { | void onAction(const ActionEvent& e) override { | ||||
@@ -125,31 +123,36 @@ | |||||
- menu->addChild(createMenuItem("New", RACK_MOD_CTRL_NAME "+N", []() { | - menu->addChild(createMenuItem("New", RACK_MOD_CTRL_NAME "+N", []() { | ||||
- APP->patch->loadTemplateDialog(); | - APP->patch->loadTemplateDialog(); | ||||
+#ifndef DISTRHO_OS_WASM | +#ifndef DISTRHO_OS_WASM | ||||
+ const char* const NewShortcut = RACK_MOD_CTRL_NAME "+N"; | |||||
+ constexpr const char* const NewShortcut = RACK_MOD_CTRL_NAME "+N"; | |||||
+#else | +#else | ||||
+ const char* const NewShortcut = ""; | |||||
+ constexpr const char* const NewShortcut = ""; | |||||
+#endif | +#endif | ||||
+ menu->addChild(createMenuItem("New", NewShortcut, []() { | + 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", []() { | - menu->addChild(createMenuItem("Open", RACK_MOD_CTRL_NAME "+O", []() { | ||||
- APP->patch->loadDialog(); | - APP->patch->loadDialog(); | ||||
+#if ! CARDINAL_VARIANT_MINI | |||||
+#ifndef DISTRHO_OS_WASM | |||||
+ menu->addChild(createMenuItem("Open / Import...", RACK_MOD_CTRL_NAME "+O", []() { | + menu->addChild(createMenuItem("Open / Import...", RACK_MOD_CTRL_NAME "+O", []() { | ||||
+ patchUtils::loadDialog(); | + 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); | - APP->patch->loadPathDialog(path); | ||||
- })); | |||||
- } | |||||
- }, settings::recentPatchPaths.empty())); | |||||
- | |||||
+ patchUtils::loadPathDialog(path, false); | |||||
})); | |||||
} | |||||
}, settings::recentPatchPaths.empty())); | |||||
menu->addChild(createMenuItem("Save", RACK_MOD_CTRL_NAME "+S", []() { | menu->addChild(createMenuItem("Save", RACK_MOD_CTRL_NAME "+S", []() { | ||||
- APP->patch->saveDialog(); | - APP->patch->saveDialog(); | ||||
+ // NOTE: will do nothing if path is empty, intentionally | + // NOTE: will do nothing if path is empty, intentionally | ||||
@@ -188,20 +191,31 @@ | |||||
+ patchUtils::revertDialog(); | + patchUtils::revertDialog(); | ||||
+ }, APP->patch->path.empty())); | + }, APP->patch->path.empty())); | ||||
- menu->addChild(createMenuItem("Overwrite template", "", []() { | |||||
menu->addChild(createMenuItem("Overwrite template", "", []() { | |||||
- APP->patch->saveTemplateDialog(); | - 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(); | + remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote(); | ||||
+ | + | ||||
+ if (remoteDetails != nullptr && remoteDetails->connected) { | + 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); | + remoteUtils::sendFullPatchToRemote(remoteDetails); | ||||
+ })); | + })); | ||||
+ menu->addChild(createCheckMenuItem("Auto deploy to MOD", "", | |||||
+ menu->addChild(createCheckMenuItem("Auto deploy to " REMOTE_NAME, "", | |||||
+ [remoteDetails]() {return remoteDetails->autoDeploy;}, | + [remoteDetails]() {return remoteDetails->autoDeploy;}, | ||||
+ [remoteDetails]() { | + [remoteDetails]() { | ||||
+ remoteDetails->autoDeploy = !remoteDetails->autoDeploy; | + remoteDetails->autoDeploy = !remoteDetails->autoDeploy; | ||||
@@ -209,34 +223,29 @@ | |||||
+ } | + } | ||||
+ )); | + )); | ||||
+ } else { | + } else { | ||||
+ menu->addChild(createMenuItem("Connect to MOD", "", []() { | |||||
+ menu->addChild(createMenuItem("Connect to " REMOTE_NAME, "", []() { | |||||
+ DISTRHO_SAFE_ASSERT(remoteUtils::connectToRemote()); | + DISTRHO_SAFE_ASSERT(remoteUtils::connectToRemote()); | ||||
+ })); | + })); | ||||
+ } | + } | ||||
+#endif | +#endif | ||||
+ | + | ||||
+#if ! CARDINAL_VARIANT_MINI | |||||
+#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
+#ifndef DISTRHO_OS_WASM | +#ifndef DISTRHO_OS_WASM | ||||
menu->addChild(new ui::MenuSeparator); | 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", []() { | - menu->addChild(createMenuItem("Quit", RACK_MOD_CTRL_NAME "+Q", []() { | ||||
- APP->window->close(); | - APP->window->close(); | ||||
+ // Load selection | |||||
+ menu->addChild(createMenuItem("Import selection...", "", [=]() { | |||||
+ patchUtils::loadSelectionDialog(); | |||||
+ }, false, true)); | |||||
+ | |||||
+ menu->addChild(createMenuItem("Export uncompressed json...", "", []() { | + menu->addChild(createMenuItem("Export uncompressed json...", "", []() { | ||||
+ patchUtils::saveAsDialogUncompressed(); | + patchUtils::saveAsDialogUncompressed(); | ||||
})); | })); | ||||
+#endif | +#endif | ||||
+#endif | +#endif | ||||
+ | + | ||||
+#if ! CARDINAL_VARIANT_MINI | |||||
+ if (!demoPatches.empty()) | + if (!demoPatches.empty()) | ||||
+ { | + { | ||||
+ menu->addChild(new ui::MenuSeparator); | + menu->addChild(new ui::MenuSeparator); | ||||
@@ -262,7 +271,6 @@ | |||||
+ })); | + })); | ||||
+ })); | + })); | ||||
+ } | + } | ||||
+#endif | |||||
+ | + | ||||
+#ifndef DISTRHO_OS_WASM | +#ifndef DISTRHO_OS_WASM | ||||
+ if (isStandalone) { | + if (isStandalone) { | ||||
@@ -276,7 +284,7 @@ | |||||
} | } | ||||
}; | }; | ||||
@@ -166,7 +293,7 @@ | |||||
@@ -166,7 +311,7 @@ | |||||
menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
@@ -285,7 +293,7 @@ | |||||
} | } | ||||
}; | }; | ||||
@@ -256,7 +383,7 @@ | |||||
@@ -256,7 +401,7 @@ | |||||
return settings::cableTension; | return settings::cableTension; | ||||
} | } | ||||
float getDefaultValue() override { | float getDefaultValue() override { | ||||
@@ -294,7 +302,7 @@ | |||||
} | } | ||||
float getDisplayValue() override { | float getDisplayValue() override { | ||||
return getValue() * 100; | return getValue() * 100; | ||||
@@ -393,36 +520,37 @@ | |||||
@@ -393,49 +538,36 @@ | |||||
}; | }; | ||||
@@ -327,17 +335,34 @@ | |||||
- menu->addChild(createMenuItem("Fullscreen", fullscreenText, [=]() { | - menu->addChild(createMenuItem("Fullscreen", fullscreenText, [=]() { | ||||
- APP->window->setFullScreen(!fullscreen); | - 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++) { | - for (int i = 1; i <= 6; i++) { | ||||
- double frameRate = APP->window->getMonitorRefreshRate() / i; | - double frameRate = APP->window->getMonitorRefreshRate() / i; | ||||
- menu->addChild(createCheckMenuItem(string::f("%.0f Hz", frameRate), "", | - 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<std::string> uiThemes = {"dark", "light", "hcdark"}; | |||||
- static const std::vector<std::string> 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; | + std::string darkModeText; | ||||
+ if (settings::darkMode) | + if (settings::darkMode) | ||||
+ darkModeText = CHECKMARK_STRING; | + darkModeText = CHECKMARK_STRING; | ||||
@@ -345,15 +370,11 @@ | |||||
+ switchDarkMode(!settings::darkMode); | + switchDarkMode(!settings::darkMode); | ||||
+ plugin::updateStaticPluginsDarkMode(); | + plugin::updateStaticPluginsDarkMode(); | ||||
+ setAllFramebufferWidgetsDirty(APP->scene); | + setAllFramebufferWidgetsDirty(APP->scene); | ||||
})); | |||||
+ })); | |||||
- menu->addChild(new ui::MenuSeparator); | |||||
- menu->addChild(createMenuLabel("Appearance")); | |||||
- | |||||
menu->addChild(createBoolPtrMenuItem("Show tooltips", "", &settings::tooltips)); | menu->addChild(createBoolPtrMenuItem("Show tooltips", "", &settings::tooltips)); | ||||
ZoomSlider* zoomSlider = new ZoomSlider; | |||||
@@ -446,9 +574,18 @@ | |||||
@@ -460,9 +592,18 @@ | |||||
menu->addChild(haloBrightnessSlider); | menu->addChild(haloBrightnessSlider); | ||||
menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
@@ -372,13 +393,14 @@ | |||||
static const std::vector<std::string> knobModeLabels = { | static const std::vector<std::string> knobModeLabels = { | ||||
"Linear", | "Linear", | ||||
@@ -473,11 +610,34 @@ | |||||
@@ -487,11 +628,34 @@ | |||||
menu->addChild(knobScrollSensitivitySlider); | menu->addChild(knobScrollSensitivitySlider); | ||||
menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
- menu->addChild(createMenuLabel("Module dragging")); | |||||
- menu->addChild(createMenuLabel("Module")); | |||||
+ menu->addChild(createMenuLabel("Window")); | + menu->addChild(createMenuLabel("Window")); | ||||
+ | |||||
- menu->addChild(createBoolPtrMenuItem("Lock positions", "", &settings::lockModules)); | |||||
+#ifdef DISTRHO_OS_WASM | +#ifdef DISTRHO_OS_WASM | ||||
+ const bool fullscreen = APP->window->isFullScreen(); | + const bool fullscreen = APP->window->isFullScreen(); | ||||
+ std::string rightText = "F11"; | + std::string rightText = "F11"; | ||||
@@ -388,8 +410,7 @@ | |||||
+ APP->window->setFullScreen(!fullscreen); | + APP->window->setFullScreen(!fullscreen); | ||||
+ })); | + })); | ||||
+#endif | +#endif | ||||
- menu->addChild(createBoolPtrMenuItem("Lock positions", "", &settings::lockModules)); | |||||
+ | |||||
+ menu->addChild(createBoolPtrMenuItem("Invert zoom", "", &settings::invertZoom)); | + menu->addChild(createBoolPtrMenuItem("Invert zoom", "", &settings::invertZoom)); | ||||
- menu->addChild(createBoolPtrMenuItem("Auto-squeeze algorithm (experimental)", "", &settings::squeezeModules)); | - 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 { | struct EngineButton : MenuButton { | ||||
void onAction(const ActionEvent& e) override { | void onAction(const ActionEvent& e) override { | ||||
ui::Menu* menu = createMenu(); | ui::Menu* menu = createMenu(); | ||||
@@ -541,268 +660,46 @@ | |||||
@@ -555,268 +678,46 @@ | |||||
settings::cpuMeter ^= true; | settings::cpuMeter ^= true; | ||||
})); | })); | ||||
@@ -614,10 +635,10 @@ | |||||
+ })); | + })); | ||||
} | } | ||||
- } | - } | ||||
- | |||||
- MenuItem::step(); | - MenuItem::step(); | ||||
- } | - } | ||||
- | |||||
- void onAction(const ActionEvent& e) override { | - void onAction(const ActionEvent& e) override { | ||||
- std::thread t([=] { | - std::thread t([=] { | ||||
- library::syncUpdate(slug); | - library::syncUpdate(slug); | ||||
@@ -726,11 +747,11 @@ | |||||
- }); | - }); | ||||
- t.detach(); | - t.detach(); | ||||
- } | - } | ||||
- | |||||
- void step() override { | - void step() override { | ||||
- notification->box.pos = math::Vec(0, 0); | - notification->box.pos = math::Vec(0, 0); | ||||
- notification->visible = library::hasUpdates(); | - notification->visible = library::hasUpdates(); | ||||
- | |||||
- // Popup when updates finish downloading | - // Popup when updates finish downloading | ||||
- if (library::restartRequested) { | - if (library::restartRequested) { | ||||
- library::restartRequested = false; | - library::restartRequested = false; | ||||
@@ -760,7 +781,7 @@ | |||||
} | } | ||||
}; | }; | ||||
@@ -813,65 +710,23 @@ | |||||
@@ -827,32 +728,17 @@ | |||||
struct HelpButton : MenuButton { | struct HelpButton : MenuButton { | ||||
@@ -778,32 +799,29 @@ | |||||
- menu->addChild(createMenuItem("Tips", "", [=]() { | - menu->addChild(createMenuItem("Tips", "", [=]() { | ||||
- APP->scene->addChild(tipWindowCreate()); | - APP->scene->addChild(tipWindowCreate()); | ||||
- })); | |||||
- | |||||
+ menu->addChild(createMenuItem("Rack User manual", "F1", [=]() { | |||||
+ patchUtils::openBrowser("https://vcvrack.com/manual"); | |||||
})); | |||||
- menu->addChild(createMenuItem("User manual", "F1", [=]() { | - menu->addChild(createMenuItem("User manual", "F1", [=]() { | ||||
- system::openBrowser("https://vcvrack.com/manual"); | - system::openBrowser("https://vcvrack.com/manual"); | ||||
- })); | - })); | ||||
- | - | ||||
- menu->addChild(createMenuItem("Support", "", [=]() { | - menu->addChild(createMenuItem("Support", "", [=]() { | ||||
- system::openBrowser("https://vcvrack.com/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", "", [=]() { | - menu->addChild(createMenuItem("VCVRack.com", "", [=]() { | ||||
- system::openBrowser("https://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/"); | + patchUtils::openBrowser("https://github.com/DISTRHO/Cardinal/"); | ||||
})); | })); | ||||
menu->addChild(new ui::MenuSeparator); | 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", "", [=]() { | - menu->addChild(createMenuItem("Changelog", "", [=]() { | ||||
- system::openBrowser("https://github.com/VCVRack/Rack/blob/v2/CHANGELOG.md"); | - system::openBrowser("https://github.com/VCVRack/Rack/blob/v2/CHANGELOG.md"); | ||||
- })); | - })); | ||||
@@ -822,34 +840,42 @@ | |||||
- }, false, true)); | - }, false, true)); | ||||
- } | - } | ||||
- } | - } | ||||
- | |||||
+ menu->addChild(new ui::MenuSeparator); | |||||
- void step() override { | - void step() override { | ||||
- notification->box.pos = math::Vec(0, 0); | - notification->box.pos = math::Vec(0, 0); | ||||
- notification->visible = library::isAppUpdateAvailable(); | - notification->visible = library::isAppUpdateAvailable(); | ||||
- MenuButton::step(); | - MenuButton::step(); | ||||
+ menu->addChild(createMenuLabel("Cardinal " + APP_EDITION + " " + CARDINAL_VERSION)); | |||||
+ menu->addChild(createMenuLabel("Rack " + APP_VERSION + " Compatible")); | + 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 | +#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 | +#endif | ||||
+ | |||||
text += " "; | |||||
} | |||||
- text += APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION + " " + APP_OS_NAME + " " + APP_CPU_NAME; | |||||
+ text += "Cardinal " + APP_EDITION + " " + CARDINAL_VERSION; | |||||
Label::step(); | Label::step(); | ||||
} | } | ||||
}; | |||||
@@ -921,7 +781,9 @@ | |||||
@@ -944,7 +814,9 @@ | |||||
struct MenuBar : widget::OpaqueWidget { | struct MenuBar : widget::OpaqueWidget { | ||||
MeterLabel* meterLabel; | |||||
InfoLabel* infoLabel; | |||||
- MenuBar() { | - MenuBar() { | ||||
+ MenuBar(const bool isStandalone) | + MenuBar(const bool isStandalone) | ||||
@@ -858,7 +884,7 @@ | |||||
const float margin = 5; | const float margin = 5; | ||||
box.size.y = BND_WIDGET_HEIGHT + 2 * margin; | box.size.y = BND_WIDGET_HEIGHT + 2 * margin; | ||||
@@ -930,7 +792,7 @@ | |||||
@@ -953,7 +825,7 @@ | |||||
layout->spacing = math::Vec(0, 0); | layout->spacing = math::Vec(0, 0); | ||||
addChild(layout); | addChild(layout); | ||||
@@ -867,11 +893,11 @@ | |||||
fileButton->text = "File"; | fileButton->text = "File"; | ||||
layout->addChild(fileButton); | layout->addChild(fileButton); | ||||
@@ -942,13 +804,11 @@ | |||||
@@ -965,13 +837,11 @@ | |||||
viewButton->text = "View"; | viewButton->text = "View"; | ||||
layout->addChild(viewButton); | layout->addChild(viewButton); | ||||
+#if ! CARDINAL_VARIANT_MINI | |||||
+#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
EngineButton* engineButton = new EngineButton; | EngineButton* engineButton = new EngineButton; | ||||
engineButton->text = "Engine"; | engineButton->text = "Engine"; | ||||
layout->addChild(engineButton); | layout->addChild(engineButton); | ||||
@@ -883,7 +909,7 @@ | |||||
HelpButton* helpButton = new HelpButton; | HelpButton* helpButton = new HelpButton; | ||||
helpButton->text = "Help"; | helpButton->text = "Help"; | ||||
@@ -984,7 +844,7 @@ | |||||
@@ -1003,7 +873,7 @@ | |||||
widget::Widget* createMenuBar() { | widget::Widget* createMenuBar() { | ||||
@@ -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 @@ | @@ -1,3 +1,30 @@ | ||||
+/* | +/* | ||||
+ * DISTRHO Cardinal Plugin | + * DISTRHO Cardinal Plugin | ||||
+ * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
+ * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
+ * | + * | ||||
+ * This program is free software; you can redistribute it and/or | + * This program is free software; you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * 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 | + * 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 | + * This program is free software: you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * modify it under the terms of the GNU General Public License as | ||||
@@ -61,8 +61,8 @@ | |||||
- | - | ||||
// hidden | // hidden | ||||
json_t* hiddenJ = json_object_get(rootJ, "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() { | std::string Model::getFullName() { | ||||
@@ -71,7 +71,7 @@ | |||||
return plugin->getBrand() + " " + name; | return plugin->getBrand() + " " + name; | ||||
} | } | ||||
@@ -99,7 +122,7 @@ | |||||
@@ -102,7 +125,7 @@ | |||||
void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { | void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { | ||||
// plugin | // plugin | ||||
menu->addChild(createMenuItem("Plugin: " + plugin->name, "", [=]() { | menu->addChild(createMenuItem("Plugin: " + plugin->name, "", [=]() { | ||||
@@ -80,7 +80,7 @@ | |||||
}, plugin->pluginUrl == "")); | }, plugin->pluginUrl == "")); | ||||
// version | // version | ||||
@@ -108,7 +131,7 @@ | |||||
@@ -111,7 +134,7 @@ | |||||
// author | // author | ||||
if (plugin->author != "") { | if (plugin->author != "") { | ||||
menu->addChild(createMenuItem("Author: " + plugin->author, "", [=]() { | menu->addChild(createMenuItem("Author: " + plugin->author, "", [=]() { | ||||
@@ -89,7 +89,7 @@ | |||||
}, plugin->authorUrl.empty())); | }, plugin->authorUrl.empty())); | ||||
} | } | ||||
@@ -116,7 +139,7 @@ | |||||
@@ -119,7 +142,7 @@ | |||||
std::string license = plugin->license; | std::string license = plugin->license; | ||||
if (string::startsWith(license, "https://") || string::startsWith(license, "http://")) { | if (string::startsWith(license, "https://") || string::startsWith(license, "http://")) { | ||||
menu->addChild(createMenuItem("License: Open in browser", "", [=]() { | menu->addChild(createMenuItem("License: Open in browser", "", [=]() { | ||||
@@ -98,7 +98,7 @@ | |||||
})); | })); | ||||
} | } | ||||
else if (license != "") { | else if (license != "") { | ||||
@@ -133,58 +156,32 @@ | |||||
@@ -136,44 +159,32 @@ | |||||
menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
@@ -143,21 +143,21 @@ | |||||
if (plugin->changelogUrl != "") { | if (plugin->changelogUrl != "") { | ||||
menu->addChild(createMenuItem("Changelog", "", [=]() { | menu->addChild(createMenuItem("Changelog", "", [=]() { | ||||
- system::openBrowser(plugin->changelogUrl); | - 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); | + 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()) |
@@ -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 | + * DISTRHO Cardinal Plugin | ||||
+ * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
+ * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
+ * | + * | ||||
+ * This program is free software; you can redistribute it and/or | + * This program is free software; you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * 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 | + * 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 | + * This program is free software: you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * modify it under the terms of the GNU General Public License as | ||||
@@ -33,7 +33,12 @@ | |||||
#include <thread> | #include <thread> | ||||
#include <regex> | #include <regex> | ||||
@@ -375,7 +404,7 @@ | |||||
-#include <osdialog.h> | |||||
- | |||||
#include <app/ModuleWidget.hpp> | |||||
#include <app/Scene.hpp> | |||||
#include <engine/Engine.hpp> | |||||
@@ -375,7 +402,7 @@ | |||||
if (e.action == GLFW_PRESS) { | if (e.action == GLFW_PRESS) { | ||||
// Open selection context menu on right-click | // Open selection context menu on right-click | ||||
ui::Menu* menu = createMenu(); | ui::Menu* menu = createMenu(); | ||||
@@ -42,7 +47,7 @@ | |||||
} | } | ||||
e.consume(this); | e.consume(this); | ||||
} | } | ||||
@@ -627,6 +656,9 @@ | |||||
@@ -629,6 +656,9 @@ | |||||
std::string presetDir = model->getUserPresetDirectory(); | std::string presetDir = model->getUserPresetDirectory(); | ||||
system::createDirectories(presetDir); | system::createDirectories(presetDir); | ||||
@@ -52,7 +57,7 @@ | |||||
// Delete directories if empty | // Delete directories if empty | ||||
DEFER({ | DEFER({ | ||||
try { | try { | ||||
@@ -638,10 +670,8 @@ | |||||
@@ -640,10 +670,8 @@ | |||||
} | } | ||||
}); | }); | ||||
@@ -65,7 +70,7 @@ | |||||
if (!pathC) { | if (!pathC) { | ||||
// No path selected | // No path selected | ||||
return; | return; | ||||
@@ -649,11 +679,13 @@ | |||||
@@ -651,11 +679,13 @@ | |||||
DEFER({std::free(pathC);}); | DEFER({std::free(pathC);}); | ||||
try { | try { | ||||
@@ -81,7 +86,46 @@ | |||||
} | } | ||||
void ModuleWidget::save(std::string filename) { | 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<ModuleWidget> 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<ModuleWidget> weakThis = this; | |||||
+ async_dialog_message(message.c_str(), [=]{ | |||||
+ if (weakThis) | |||||
+ weakThis->clearTemplate(); | |||||
+ }); | |||||
} | |||||
void ModuleWidget::saveDialog() { | |||||
std::string presetDir = model->getUserPresetDirectory(); | std::string presetDir = model->getUserPresetDirectory(); | ||||
system::createDirectories(presetDir); | system::createDirectories(presetDir); | ||||
@@ -91,7 +135,7 @@ | |||||
// Delete directories if empty | // Delete directories if empty | ||||
DEFER({ | DEFER({ | ||||
try { | try { | ||||
@@ -726,10 +761,8 @@ | |||||
@@ -728,10 +765,8 @@ | |||||
} | } | ||||
}); | }); | ||||
@@ -104,7 +148,7 @@ | |||||
if (!pathC) { | if (!pathC) { | ||||
// No path selected | // No path selected | ||||
return; | return; | ||||
@@ -741,7 +774,8 @@ | |||||
@@ -743,7 +778,8 @@ | |||||
if (system::getExtension(path) != ".vcvm") | if (system::getExtension(path) != ".vcvm") | ||||
path += ".vcvm"; | path += ".vcvm"; | ||||
@@ -114,28 +158,7 @@ | |||||
} | } | ||||
void ModuleWidget::disconnect() { | 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); | moduleWidget->loadAction(path); | ||||
} | } | ||||
catch (Exception& e) { | 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 `<plugin dir>/presets/<module slug>` 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 | } // namespace app | ||||
@@ -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 @@ | @@ -1,3 +1,30 @@ | ||||
+/* | +/* | ||||
+ * DISTRHO Cardinal Plugin | + * DISTRHO Cardinal Plugin | ||||
+ * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
+ * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
+ * | + * | ||||
+ * This program is free software; you can redistribute it and/or | + * This program is free software; you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * 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 | + * 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 | + * This program is free software: you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * modify it under the terms of the GNU General Public License as | ||||
@@ -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 @@ | @@ -1,12 +1,36 @@ | ||||
-#include <thread> | -#include <thread> | ||||
- | - | ||||
-#include <osdialog.h> | -#include <osdialog.h> | ||||
+/* | +/* | ||||
+ * DISTRHO Cardinal Plugin | + * DISTRHO Cardinal Plugin | ||||
+ * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
+ * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
+ * | + * | ||||
+ * This program is free software; you can redistribute it and/or | + * This program is free software; you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * 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 | + * 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 | + * This program is free software: you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * modify it under the terms of the GNU General Public License as | ||||
@@ -40,7 +40,7 @@ | |||||
#include <system.hpp> | #include <system.hpp> | ||||
#include <network.hpp> | #include <network.hpp> | ||||
#include <history.hpp> | #include <history.hpp> | ||||
@@ -14,6 +38,13 @@ | |||||
@@ -14,6 +38,14 @@ | |||||
#include <patch.hpp> | #include <patch.hpp> | ||||
#include <asset.hpp> | #include <asset.hpp> | ||||
@@ -51,10 +51,11 @@ | |||||
+#include "../CardinalCommon.hpp" | +#include "../CardinalCommon.hpp" | ||||
+#include "../CardinalRemote.hpp" | +#include "../CardinalRemote.hpp" | ||||
+ | + | ||||
+#include <algorithm> | |||||
namespace rack { | namespace rack { | ||||
namespace app { | namespace app { | ||||
@@ -23,32 +54,72 @@ | |||||
@@ -23,32 +55,72 @@ | |||||
math::Vec size; | math::Vec size; | ||||
void draw(const DrawArgs& args) override { | void draw(const DrawArgs& args) override { | ||||
@@ -101,17 +102,17 @@ | |||||
+ | + | ||||
+ void onHover(const HoverEvent& e) override { | + void onHover(const HoverEvent& e) override { | ||||
+ e.consume(this); | + e.consume(this); | ||||
+ } | |||||
+ | |||||
} | |||||
- void onDragStart(const DragStartEvent& e) override { | |||||
+ void onEnter(const EnterEvent& e) override { | + void onEnter(const EnterEvent& e) override { | ||||
+ glfwSetCursor(APP->window->win, glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR)); | + glfwSetCursor(APP->window->win, glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR)); | ||||
+ } | + } | ||||
+ | + | ||||
+ void onLeave(const LeaveEvent& e) override { | + void onLeave(const LeaveEvent& e) override { | ||||
+ glfwSetCursor(APP->window->win, nullptr); | + glfwSetCursor(APP->window->win, nullptr); | ||||
} | |||||
- void onDragStart(const DragStartEvent& e) override { | |||||
+ } | |||||
+ | |||||
+ void onDragStart(const DragStartEvent&) override { | + void onDragStart(const DragStartEvent&) override { | ||||
size = APP->window->getSize(); | size = APP->window->getSize(); | ||||
} | } | ||||
@@ -137,14 +138,14 @@ | |||||
}; | }; | ||||
@@ -67,13 +138,11 @@ | |||||
@@ -67,13 +139,11 @@ | |||||
browser->hide(); | browser->hide(); | ||||
addChild(browser); | addChild(browser); | ||||
- if (settings::showTipsOnLaunch) { | - if (settings::showTipsOnLaunch) { | ||||
- addChild(tipWindowCreate()); | - addChild(tipWindowCreate()); | ||||
- } | - } | ||||
+ if (isStandalone()) | |||||
+ if (isStandalone() || isMini()) | |||||
+ return; | + return; | ||||
internal->resizeHandle = new ResizeHandle; | internal->resizeHandle = new ResizeHandle; | ||||
@@ -154,7 +155,7 @@ | |||||
addChild(internal->resizeHandle); | addChild(internal->resizeHandle); | ||||
} | } | ||||
@@ -99,22 +168,13 @@ | |||||
@@ -99,22 +169,13 @@ | |||||
rackScroll->box.pos.y = menuBar->box.size.y; | rackScroll->box.pos.y = menuBar->box.size.y; | ||||
} | } | ||||
@@ -179,7 +180,7 @@ | |||||
// Scroll RackScrollWidget with arrow keys | // Scroll RackScrollWidget with arrow keys | ||||
math::Vec arrowDelta; | math::Vec arrowDelta; | ||||
if (internal->heldArrowKeys[0]) { | if (internal->heldArrowKeys[0]) { | ||||
@@ -143,6 +203,29 @@ | |||||
@@ -143,6 +204,34 @@ | |||||
rackScroll->offset += arrowDelta * arrowSpeed; | rackScroll->offset += arrowDelta * arrowSpeed; | ||||
} | } | ||||
@@ -195,7 +196,12 @@ | |||||
+ internal->lastSceneChangeTime = time; | + internal->lastSceneChangeTime = time; | ||||
+ } else if (internal->historyActionIndex != actionIndex && actionIndex > 0 && time - internal->lastSceneChangeTime >= 1.0) { | + } else if (internal->historyActionIndex != actionIndex && actionIndex > 0 && time - internal->lastSceneChangeTime >= 1.0) { | ||||
+ const std::string& name(APP->history->actions[actionIndex - 1]->name); | + const std::string& name(APP->history->actions[actionIndex - 1]->name); | ||||
+ if (/*std::abs(internal->historyActionIndex = actionIndex) > 1 ||*/ name != "move knob") { | |||||
+ static const std::vector<std::string> 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()); | + printf("action '%s'\n", APP->history->actions[actionIndex - 1]->name.c_str()); | ||||
+ remoteUtils::sendFullPatchToRemote(remoteDetails); | + remoteUtils::sendFullPatchToRemote(remoteDetails); | ||||
+ window::generateScreenshot(); | + window::generateScreenshot(); | ||||
@@ -209,16 +215,16 @@ | |||||
Widget::step(); | Widget::step(); | ||||
} | } | ||||
@@ -172,7 +255,7 @@ | |||||
@@ -172,7 +261,7 @@ | |||||
if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | 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()); | // 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) { | if (e.keyName == "n" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { | ||||
- APP->patch->loadTemplateDialog(); | - APP->patch->loadTemplateDialog(); | ||||
+ patchUtils::loadTemplateDialog(); | |||||
+ patchUtils::loadTemplateDialog(false); | |||||
e.consume(this); | e.consume(this); | ||||
} | } | ||||
if (e.keyName == "q" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { | if (e.keyName == "q" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { | ||||
@@ -180,19 +263,22 @@ | |||||
@@ -180,19 +269,22 @@ | |||||
e.consume(this); | e.consume(this); | ||||
} | } | ||||
if (e.keyName == "o" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { | if (e.keyName == "o" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { | ||||
@@ -245,7 +251,7 @@ | |||||
e.consume(this); | e.consume(this); | ||||
} | } | ||||
if (e.keyName == "z" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { | 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)); | APP->scene->rackScroll->setZoom(std::pow(2.f, zoom)); | ||||
e.consume(this); | e.consume(this); | ||||
} | } | ||||
@@ -269,8 +275,10 @@ | |||||
} | } | ||||
+ if (e.key == GLFW_KEY_F7 && (e.mods & RACK_MOD_MASK) == 0) { | + if (e.key == GLFW_KEY_F7 && (e.mods & RACK_MOD_MASK) == 0) { | ||||
+ if (remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote()) | + if (remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote()) | ||||
+ { | |||||
+ remoteUtils::sendFullPatchToRemote(remoteDetails); | + remoteUtils::sendFullPatchToRemote(remoteDetails); | ||||
+ window::generateScreenshot(); | |||||
+ window::generateScreenshot(); | |||||
+ } | |||||
+ e.consume(this); | + e.consume(this); | ||||
+ } | + } | ||||
+ if (e.key == GLFW_KEY_F9 && (e.mods & RACK_MOD_MASK) == 0) { | + if (e.key == GLFW_KEY_F9 && (e.mods & RACK_MOD_MASK) == 0) { | ||||
@@ -280,15 +288,15 @@ | |||||
+#ifdef DISTRHO_OS_WASM | +#ifdef DISTRHO_OS_WASM | ||||
if (e.key == GLFW_KEY_F11 && (e.mods & RACK_MOD_MASK) == 0) { | if (e.key == GLFW_KEY_F11 && (e.mods & RACK_MOD_MASK) == 0) { | ||||
APP->window->setFullScreen(!APP->window->isFullScreen()); | 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); | e.consume(this); | ||||
} | } | ||||
+#endif | +#endif | ||||
// Module selections | // Module selections | ||||
if (e.keyName == "a" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { | 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 | // Key commands that can be overridden by children | ||||
if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | 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) { | if (e.keyName == "v" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { | ||||
rack->pasteClipboardAction(); | rack->pasteClipboardAction(); | ||||
e.consume(this); | e.consume(this); | ||||
@@ -351,7 +444,7 @@ | |||||
@@ -351,7 +454,7 @@ | |||||
std::string extension = system::getExtension(path); | std::string extension = system::getExtension(path); | ||||
if (extension == ".vcv") { | if (extension == ".vcv") { | ||||
@@ -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 | + * DISTRHO Cardinal Plugin | ||||
+ * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
+ * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
+ * | + * | ||||
+ * This program is free software; you can redistribute it and/or | + * This program is free software; you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * 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 | + * 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 | + * This program is free software: you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * modify it under the terms of the GNU General Public License as | ||||
@@ -57,16 +57,6 @@ | |||||
+# undef DEBUG | +# undef DEBUG | ||||
+#endif | +#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 "DistrhoUI.hpp" | ||||
+#include "Application.hpp" | +#include "Application.hpp" | ||||
+#include "extra/String.hpp" | +#include "extra/String.hpp" | ||||
@@ -77,6 +67,22 @@ | |||||
+#ifndef DGL_NO_SHARED_RESOURCES | +#ifndef DGL_NO_SHARED_RESOURCES | ||||
+# include "src/Resources.hpp" | +# include "src/Resources.hpp" | ||||
+#endif | +#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 | +#ifdef DISTRHO_OS_WASM | ||||
+# include <emscripten/html5.h> | +# include <emscripten/html5.h> | ||||
@@ -86,7 +92,7 @@ | |||||
namespace window { | 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); | +static const math::Vec WINDOW_SIZE_MIN = math::Vec(648, 538); | ||||
+ | + | ||||
+ | + | ||||
@@ -102,7 +108,7 @@ | |||||
Font::~Font() { | Font::~Font() { | ||||
@@ -42,9 +97,8 @@ | |||||
@@ -42,9 +103,8 @@ | |||||
// Transfer ownership of font data to font object | // Transfer ownership of font data to font object | ||||
uint8_t* data = system::readFile(filename, &size); | uint8_t* data = system::readFile(filename, &size); | ||||
// Don't use nvgCreateFont because it doesn't properly handle UTF-8 filenames on Windows. | // 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()); | throw Exception("Failed to load font %s", filename.c_str()); | ||||
} | } | ||||
INFO("Loaded 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 { | +enum ScreenshotStep { | ||||
+ kScreenshotStepNone, | + kScreenshotStepNone, | ||||
+ kScreenshotStepStarted, | + kScreenshotStepStarted, | ||||
@@ -124,6 +131,7 @@ | |||||
+ kScreenshotStepSecondPass, | + kScreenshotStepSecondPass, | ||||
+ kScreenshotStepSaving | + kScreenshotStepSaving | ||||
+}; | +}; | ||||
+#endif | |||||
+ | + | ||||
+ | + | ||||
struct Window::Internal { | struct Window::Internal { | ||||
@@ -153,15 +161,13 @@ | |||||
int frame = 0; | int frame = 0; | ||||
- bool ignoreNextMouseDelta = false; | - bool ignoreNextMouseDelta = false; | ||||
- int frameSwapInterval = -1; | |||||
- double monitorRefreshRate = 0.0; | - double monitorRefreshRate = 0.0; | ||||
+ int frameSwapInterval = 1; | |||||
+#ifndef DGL_USE_GLES | |||||
+#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS | |||||
+ int generateScreenshotStep = kScreenshotStepNone; | + int generateScreenshotStep = kScreenshotStepNone; | ||||
+#endif | +#endif | ||||
+ double monitorRefreshRate = 60.0; | + double monitorRefreshRate = 60.0; | ||||
double frameTime = 0.0; | |||||
double lastFrameDuration = 0.0; | |||||
double frameTime = NAN; | |||||
double lastFrameDuration = NAN; | |||||
- math::Vec lastMousePos; | - math::Vec lastMousePos; | ||||
- | - | ||||
@@ -173,8 +179,8 @@ | |||||
bool fbDirtyOnSubpixelChange = true; | bool fbDirtyOnSubpixelChange = true; | ||||
int fbCount = 0; | int fbCount = 0; | ||||
-}; | -}; | ||||
- | |||||
- | |||||
-static void windowPosCallback(GLFWwindow* win, int x, int y) { | -static void windowPosCallback(GLFWwindow* win, int x, int y) { | ||||
- if (glfwGetWindowAttrib(win, GLFW_MAXIMIZED)) | - if (glfwGetWindowAttrib(win, GLFW_MAXIMIZED)) | ||||
- return; | - return; | ||||
@@ -484,15 +490,11 @@ | |||||
- APP->event->handleDrop(APP->window->internal->lastMousePos, pathsVec); | - APP->event->handleDrop(APP->window->internal->lastMousePos, pathsVec); | ||||
-} | -} | ||||
- | - | ||||
- | |||||
-static void errorCallback(int error, const char* description) { | -static void errorCallback(int error, const char* description) { | ||||
- WARN("GLFW error %d: %s", error, description); | - WARN("GLFW error %d: %s", error, description); | ||||
-} | -} | ||||
- | |||||
- | |||||
-Window::Window() { | |||||
- internal = new Internal; | |||||
- int err; | |||||
+ if (ui != nullptr) | + if (ui != nullptr) | ||||
+ { | + { | ||||
+ const GLubyte* vendor = glGetString(GL_VENDOR); | + const GLubyte* vendor = glGetString(GL_VENDOR); | ||||
@@ -514,6 +516,10 @@ | |||||
+ window->internal->r_fbVg = nvgCreateSharedGL2(window->internal->r_vg, NVG_ANTIALIAS); | + window->internal->r_fbVg = nvgCreateSharedGL2(window->internal->r_vg, NVG_ANTIALIAS); | ||||
+#endif | +#endif | ||||
-Window::Window() { | |||||
- internal = new Internal; | |||||
- int err; | |||||
- | |||||
- // Set window hints | - // Set window hints | ||||
-#if defined NANOVG_GL2 | -#if defined NANOVG_GL2 | ||||
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); | - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); | ||||
@@ -558,7 +564,7 @@ | |||||
- glfwSetInputMode(win, GLFW_LOCK_KEY_MODS, 1); | - glfwSetInputMode(win, GLFW_LOCK_KEY_MODS, 1); | ||||
- | - | ||||
- glfwMakeContextCurrent(win); | - glfwMakeContextCurrent(win); | ||||
- glfwSwapInterval(1); | |||||
- glfwSwapInterval(0); | |||||
- const GLFWvidmode* monitorMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); | - const GLFWvidmode* monitorMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); | ||||
- if (monitorMode->refreshRate > 0) { | - if (monitorMode->refreshRate > 0) { | ||||
- internal->monitorRefreshRate = monitorMode->refreshRate; | - internal->monitorRefreshRate = monitorMode->refreshRate; | ||||
@@ -731,14 +737,14 @@ | |||||
+#else | +#else | ||||
+ nvgDeleteGL2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); | + nvgDeleteGL2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); | ||||
+ nvgDeleteGL2(internal->o_vg != nullptr ? internal->o_vg : vg); | + nvgDeleteGL2(internal->o_vg != nullptr ? internal->o_vg : vg); | ||||
+#endif | |||||
#endif | |||||
+#else | +#else | ||||
+#if defined NANOVG_GLES2 | +#if defined NANOVG_GLES2 | ||||
+ nvgDeleteGLES2(fbVg); | + nvgDeleteGLES2(fbVg); | ||||
+#else | +#else | ||||
+ nvgDeleteGL2(fbVg); | + nvgDeleteGL2(fbVg); | ||||
+#endif | +#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) { | +static void Window__flipBitmap(uint8_t* pixels, const int width, const int height, const int depth) { | ||||
+ for (int y = 0; y < height / 2; y++) { | + for (int y = 0; y < height / 2; y++) { | ||||
+ const int flipY = height - y - 1; | + const int flipY = height - y - 1; | ||||
@@ -785,10 +791,10 @@ | |||||
+ std::memcpy(tmp, &pixels[y * width * depth], width * depth); | + std::memcpy(tmp, &pixels[y * width * depth], width * depth); | ||||
+ std::memmove(&pixels[y * width * depth], &pixels[flipY * 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); | + std::memcpy(&pixels[flipY * width * depth], tmp, width * depth); | ||||
} | |||||
} | |||||
+ } | |||||
+} | |||||
+ | |||||
+ | |||||
+#ifdef STBI_WRITE_NO_STDIO | +#ifdef STBI_WRITE_NO_STDIO | ||||
+static void Window__downscaleBitmap(uint8_t* pixels, int& width, int& height) { | +static void Window__downscaleBitmap(uint8_t* pixels, int& width, int& height) { | ||||
+ int targetWidth = width; | + int targetWidth = width; | ||||
@@ -828,12 +834,12 @@ | |||||
+ ui->setState("screenshot", screenshot); | + ui->setState("screenshot", screenshot); | ||||
+ remoteUtils::sendScreenshotToRemote(ui->remoteDetails, screenshot); | + remoteUtils::sendScreenshotToRemote(ui->remoteDetails, screenshot); | ||||
+ std::free(screenshot); | + std::free(screenshot); | ||||
+ } | |||||
+} | |||||
} | |||||
} | |||||
+#endif | +#endif | ||||
+#endif | +#endif | ||||
+ | |||||
+ | |||||
void Window::step() { | void Window::step() { | ||||
+ DISTRHO_SAFE_ASSERT_RETURN(internal->tlw != nullptr,); | + DISTRHO_SAFE_ASSERT_RETURN(internal->tlw != nullptr,); | ||||
+ | + | ||||
@@ -841,13 +847,9 @@ | |||||
+ return; | + return; | ||||
+ | + | ||||
double frameTime = system::getTime(); | 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 | // Make event handlers and step() have a clean NanoVG context | ||||
nvgReset(vg); | nvgReset(vg); | ||||
@@ -861,10 +863,6 @@ | |||||
- | - | ||||
- // In case glfwPollEvents() sets another OpenGL context | - // In case glfwPollEvents() sets another OpenGL context | ||||
- glfwMakeContextCurrent(win); | - glfwMakeContextCurrent(win); | ||||
- if (settings::frameSwapInterval != internal->frameSwapInterval) { | |||||
- glfwSwapInterval(settings::frameSwapInterval); | |||||
- internal->frameSwapInterval = settings::frameSwapInterval; | |||||
- } | |||||
- | - | ||||
- // Call cursorPosCallback every frame, not just when the mouse moves | - // Call cursorPosCallback every frame, not just when the mouse moves | ||||
- { | - { | ||||
@@ -878,17 +876,27 @@ | |||||
// Set window title | // Set window title | ||||
- std::string windowTitle = APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION; | - 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()); | - 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 | // Get desired pixel ratio | ||||
@@ -906,7 +914,7 @@ | |||||
APP->event->handleDirty(); | APP->event->handleDirty(); | ||||
} | } | ||||
+#ifndef DGL_USE_GLES | |||||
+#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS | |||||
+ // Hide menu and background if generating screenshot | + // Hide menu and background if generating screenshot | ||||
+ if (internal->generateScreenshotStep == kScreenshotStepStarted) { | + if (internal->generateScreenshotStep == kScreenshotStepStarted) { | ||||
+#ifdef CARDINAL_TRANSPARENT_SCREENSHOTS | +#ifdef CARDINAL_TRANSPARENT_SCREENSHOTS | ||||
@@ -925,20 +933,13 @@ | |||||
- glfwGetWindowSize(win, &winWidth, &winHeight); | - glfwGetWindowSize(win, &winWidth, &winHeight); | ||||
+ int winWidth = internal->tlw->getWidth(); | + int winWidth = internal->tlw->getWidth(); | ||||
+ int winHeight = internal->tlw->getHeight(); | + int winHeight = internal->tlw->getHeight(); | ||||
+ int fbWidth = winWidth;// * newPixelRatio; | |||||
+ int fbHeight = winHeight;// * newPixelRatio; | |||||
+ int fbWidth = winWidth; | |||||
+ int fbHeight = winHeight; | |||||
windowRatio = (float)fbWidth / winWidth; | 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 | // Render scene | ||||
- bool visible = glfwGetWindowAttrib(win, GLFW_VISIBLE) && !glfwGetWindowAttrib(win, GLFW_ICONIFIED); | - bool visible = glfwGetWindowAttrib(win, GLFW_VISIBLE) && !glfwGetWindowAttrib(win, GLFW_ICONIFIED); | ||||
@@ -946,15 +947,11 @@ | |||||
+ { | + { | ||||
// Update and render | // Update and render | ||||
- nvgBeginFrame(vg, fbWidth, fbHeight, pixelRatio); | - nvgBeginFrame(vg, fbWidth, fbHeight, pixelRatio); | ||||
- nvgScale(vg, pixelRatio, pixelRatio); | |||||
+ nvgScale(vg, newPixelRatio, newPixelRatio); | |||||
nvgScale(vg, pixelRatio, pixelRatio); | |||||
// Draw scene | // 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); | glViewport(0, 0, fbWidth, fbHeight); | ||||
+#ifdef CARDINAL_TRANSPARENT_SCREENSHOTS | +#ifdef CARDINAL_TRANSPARENT_SCREENSHOTS | ||||
@@ -964,19 +961,32 @@ | |||||
+#endif | +#endif | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | ||||
- nvgEndFrame(vg); | - nvgEndFrame(vg); | ||||
- // t4 = system::getTime(); | |||||
} | } | ||||
// t4 = system::getTime(); | |||||
} | } | ||||
- glfwSwapBuffers(win); | - 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; | + ++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<double>(frameDurationRemaining)); | |||||
- } | |||||
+#ifndef DGL_USE_GLES | |||||
+#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS | |||||
+ if (internal->generateScreenshotStep != kScreenshotStepNone) { | + if (internal->generateScreenshotStep != kScreenshotStepNone) { | ||||
+ ++internal->generateScreenshotStep; | + ++internal->generateScreenshotStep; | ||||
+ | + | ||||
@@ -988,24 +998,20 @@ | |||||
+ constexpr const int depth = 3; | + constexpr const int depth = 3; | ||||
+#endif | +#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 | + // Allocate pixel color buffer | ||||
+ uint8_t* const pixels = new uint8_t[winHeight * winWidth * 4]; | + 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) | + // glReadPixels defaults to GL_BACK, but the back-buffer is unstable, so use the front buffer (what the user sees) | ||||
+ glReadBuffer(GL_FRONT); | + glReadBuffer(GL_FRONT); | ||||
+ glReadPixels(0, 0, winWidth, winHeight, depth == 3 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, pixels); | + glReadPixels(0, 0, winWidth, winHeight, depth == 3 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, pixels); | ||||
+ | |||||
+ if (internal->generateScreenshotStep == kScreenshotStepSaving) | + if (internal->generateScreenshotStep == kScreenshotStepSaving) | ||||
+ { | + { | ||||
+ // Write pixels to PNG | + // Write pixels to PNG | ||||
@@ -1020,33 +1026,19 @@ | |||||
+#else | +#else | ||||
+ stbi_write_png("screenshot.png", winWidth, winHeight, depth, pixelsWithOffset, stride); | + stbi_write_png("screenshot.png", winWidth, winHeight, depth, pixelsWithOffset, stride); | ||||
+#endif | +#endif | ||||
-void Window::activateContext() { | |||||
- glfwMakeContextCurrent(win); | |||||
+ | |||||
+ internal->generateScreenshotStep = kScreenshotStepNone; | + internal->generateScreenshotStep = kScreenshotStepNone; | ||||
+ APP->scene->menuBar->show(); | + APP->scene->menuBar->show(); | ||||
+ APP->scene->rack->children.front()->show(); | + APP->scene->rack->children.front()->show(); | ||||
+ } | + } | ||||
+ | + | ||||
+ delete[] pixels; | + delete[] pixels; | ||||
+ } | |||||
} | |||||
+#endif | +#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 | - // Get window framebuffer size | ||||
- int width, height; | - int width, height; | ||||
- glfwGetFramebufferSize(APP->window->win, &width, &height); | - glfwGetFramebufferSize(APP->window->win, &width, &height); | ||||
@@ -1063,10 +1055,10 @@ | |||||
- stbi_write_png(screenshotPath.c_str(), width, height, 4, pixels, width * 4); | - stbi_write_png(screenshotPath.c_str(), width, height, 4, pixels, width * 4); | ||||
- | - | ||||
- delete[] pixels; | - 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 | - // Iterate plugins and create directories | ||||
- system::createDirectories(screenshotsDir); | - system::createDirectories(screenshotsDir); | ||||
- for (plugin::Plugin* p : plugin::plugins) { | - for (plugin::Plugin* p : plugin::plugins) { | ||||
@@ -1111,20 +1103,17 @@ | |||||
- nvgImageSize(vg, fbw->getImageHandle(), &width, &height); | - nvgImageSize(vg, fbw->getImageHandle(), &width, &height); | ||||
- uint8_t* pixels = new uint8_t[height * width * 4]; | - uint8_t* pixels = new uint8_t[height * width * 4]; | ||||
- glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); | - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); | ||||
+void Window::screenshot(const std::string&) { | |||||
+} | |||||
- | |||||
- // Write pixels to PNG | - // Write pixels to PNG | ||||
- flipBitmap(pixels, width, height, 4); | - flipBitmap(pixels, width, height, 4); | ||||
- stbi_write_png(filename.c_str(), width, height, 4, pixels, width * 4); | - stbi_write_png(filename.c_str(), width, height, 4, pixels, width * 4); | ||||
- | |||||
- // Cleanup | - // Cleanup | ||||
- delete[] pixels; | - delete[] pixels; | ||||
- nvgluBindFramebuffer(NULL); | - nvgluBindFramebuffer(NULL); | ||||
- delete fbw; | - 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) { | - if (!fullScreen) { | ||||
- glfwSetWindowMonitor(win, NULL, internal->lastWindowX, internal->lastWindowY, internal->lastWindowWidth, internal->lastWindowHeight, GLFW_DONT_CARE); | - glfwSetWindowMonitor(win, NULL, internal->lastWindowX, internal->lastWindowY, internal->lastWindowWidth, internal->lastWindowHeight, GLFW_DONT_CARE); | ||||
- } | - } | ||||
@@ -1200,9 +1189,8 @@ | |||||
- const GLFWvidmode* mode = glfwGetVideoMode(monitor); | - const GLFWvidmode* mode = glfwGetVideoMode(monitor); | ||||
- glfwSetWindowMonitor(win, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); | - glfwSetWindowMonitor(win, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); | ||||
- } | - } | ||||
+void Window::setFullScreen(const bool fullscreen) { | |||||
+#ifdef DISTRHO_OS_WASM | +#ifdef DISTRHO_OS_WASM | ||||
+ if (fullscreen) | |||||
+ if (fullScreen) | |||||
+ emscripten_request_fullscreen(internal->tlw->getWindow().getApp().getClassName(), false); | + emscripten_request_fullscreen(internal->tlw->getWindow().getApp().getClassName(), false); | ||||
+ else | + else | ||||
+ emscripten_exit_fullscreen(); | + emscripten_exit_fullscreen(); | ||||
@@ -1218,18 +1206,24 @@ | |||||
+ if (emscripten_get_fullscreen_status(&status) == EMSCRIPTEN_RESULT_SUCCESS) | + if (emscripten_get_fullscreen_status(&status) == EMSCRIPTEN_RESULT_SUCCESS) | ||||
+ return status.isFullscreen; | + return status.isFullscreen; | ||||
+ return false; | + 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; | + return internal->generateScreenshotStep != kScreenshotStepNone; | ||||
+#else | +#else | ||||
+ return false; | + return false; | ||||
+#endif | +#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; | return pair->second; | ||||
// Load font | // Load font | ||||
@@ -1248,7 +1242,7 @@ | |||||
} | } | ||||
internal->fontCache[filename] = font; | internal->fontCache[filename] = font; | ||||
return font; | return font; | ||||
@@ -742,14 +854,15 @@ | |||||
@@ -733,14 +874,15 @@ | |||||
return pair->second; | return pair->second; | ||||
// Load image | // Load image | ||||
@@ -1267,7 +1261,7 @@ | |||||
} | } | ||||
internal->imageCache[filename] = image; | internal->imageCache[filename] = image; | ||||
return 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_CHDIR_RESOURCES, GLFW_TRUE); | ||||
- glfwInitHint(GLFW_COCOA_MENUBAR, GLFW_FALSE); | - glfwInitHint(GLFW_COCOA_MENUBAR, GLFW_FALSE); | ||||
+void generateScreenshot() { | +void generateScreenshot() { | ||||
+#ifndef DGL_USE_GLES | |||||
+#ifdef CARDINAL_WINDOW_CAN_GENERATE_SCREENSHOTS | |||||
+ APP->window->internal->generateScreenshotStep = kScreenshotStepStarted; | + APP->window->internal->generateScreenshotStep = kScreenshotStepStarted; | ||||
#endif | #endif | ||||
+} | +} | ||||
@@ -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 @@ | @@ -61,7 +61,7 @@ | ||||
} | } | ||||
@@ -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 @@ | @@ -1,12 +1,57 @@ | ||||
+/* | +/* | ||||
+ * DISTRHO Cardinal Plugin | + * DISTRHO Cardinal Plugin | ||||
+ * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
+ * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
+ * | + * | ||||
+ * This program is free software; you can redistribute it and/or | + * This program is free software; you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * 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 | + * 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 | + * This program is free software: you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * modify it under the terms of the GNU General Public License as | ||||
@@ -60,7 +60,7 @@ | |||||
} | } | ||||
#endif | #endif | ||||
@@ -14,20 +59,21 @@ | |||||
@@ -14,12 +59,11 @@ | |||||
namespace rack { | namespace rack { | ||||
@@ -73,17 +73,24 @@ | |||||
+const std::string APP_EDITION_NAME = "Audio Plugin"; | +const std::string APP_EDITION_NAME = "Audio Plugin"; | ||||
const std::string APP_VERSION_MAJOR = "2"; | const std::string APP_VERSION_MAJOR = "2"; | ||||
-const std::string APP_VERSION = TOSTRING(_APP_VERSION); | -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 | #if defined ARCH_WIN | ||||
const std::string APP_OS = "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 | #elif defined ARCH_LIN | ||||
const std::string APP_OS = "lin"; | const std::string APP_OS = "lin"; | ||||
const std::string APP_OS_NAME = "Linux"; | |||||
+#else | +#else | ||||
+ #error ARCH_LIN undefined | + #error ARCH_LIN undefined | ||||
#endif | #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 = "https://api.vcvrack.com"; | ||||
+const std::string API_URL = ""; | +const std::string API_URL = ""; | ||||
@@ -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 | + * DISTRHO Cardinal Plugin | ||||
+ * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
+ * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
+ * | + * | ||||
+ * This program is free software; you can redistribute it and/or | + * This program is free software; you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * 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 | + * 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 | + * This program is free software: you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * modify it under the terms of the GNU General Public License as | ||||
@@ -31,9 +31,10 @@ | |||||
#include <context.hpp> | #include <context.hpp> | ||||
#include <window/Window.hpp> | #include <window/Window.hpp> | ||||
#include <patch.hpp> | #include <patch.hpp> | ||||
@@ -6,9 +33,13 @@ | |||||
#include <engine/Engine.hpp> | |||||
#include <app/Scene.hpp> | |||||
#include <history.hpp> | #include <history.hpp> | ||||
#include <settings.hpp> | |||||
-#include <midiloopback.hpp> | |||||
+#ifdef NDEBUG | +#ifdef NDEBUG | ||||
+# undef DEBUG | +# undef DEBUG | ||||
@@ -46,7 +47,17 @@ | |||||
Context::~Context() { | Context::~Context() { | ||||
// Deleting NULL is safe in C++. | // 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; | static thread_local Context* threadContext = NULL; | ||||
Context* contextGet() { | Context* contextGet() { | ||||
@@ -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 @@ | @@ -1,3 +1,30 @@ | ||||
+/* | +/* | ||||
+ * DISTRHO Cardinal Plugin | + * DISTRHO Cardinal Plugin | ||||
+ * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
+ * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
+ * | + * | ||||
+ * This program is free software; you can redistribute it and/or | + * This program is free software; you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * 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 | + * 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 | + * This program is free software: you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * modify it under the terms of the GNU General Public License as | ||||
@@ -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 <thread> | -#include <thread> | ||||
-#include <map> | -#include <map> | ||||
-#include <stdexcept> | -#include <stdexcept> | ||||
@@ -20,7 +20,7 @@ | |||||
-#include <dirent.h> | -#include <dirent.h> | ||||
+/* | +/* | ||||
+ * DISTRHO Cardinal Plugin | + * DISTRHO Cardinal Plugin | ||||
+ * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
+ * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
+ * | + * | ||||
+ * This program is free software; you can redistribute it and/or | + * This program is free software; you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * 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 | + * 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 | + * This program is free software: you can redistribute it and/or | ||||
+ * modify it under the terms of the GNU General Public License as | + * modify it under the terms of the GNU General Public License as | ||||
@@ -133,7 +133,16 @@ | |||||
-#elif ARCH_MAC | -#elif ARCH_MAC | ||||
- libraryExt = "dylib"; | - libraryExt = "dylib"; | ||||
-#endif | -#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 | - // Check file existence | ||||
- if (!system::isFile(libraryPath)) | - if (!system::isFile(libraryPath)) | ||||
@@ -227,7 +236,7 @@ | |||||
- return NULL; | - 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); | - plugins.push_back(plugin); | ||||
- return plugin; | - return plugin; | ||||
-} | -} | ||||
@@ -372,15 +381,13 @@ | |||||
/** Given slug => fallback slug. | /** 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<std::string, std::string> pluginSlugFallbacks = { | |||||
{"VultModulesFree", "VultModules"}, | |||||
@@ -399,8 +89,19 @@ | |||||
*/ | */ | ||||
using PluginModuleSlug = std::tuple<std::string, std::string>; | using PluginModuleSlug = std::tuple<std::string, std::string>; | ||||
static const std::map<PluginModuleSlug, PluginModuleSlug> moduleSlugFallbacks = { | static const std::map<PluginModuleSlug, PluginModuleSlug> moduleSlugFallbacks = { | ||||
@@ -401,7 +408,7 @@ | |||||
// {{"", ""}, {"", ""}}, | // {{"", ""}, {"", ""}}, | ||||
}; | }; | ||||
@@ -478,7 +189,6 @@ | |||||
@@ -488,7 +189,6 @@ | |||||
} | } | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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 | * 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 | * This program is free software: you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Cardinal Plugin | * DISTRHO Cardinal Plugin | ||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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 | * 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 | * This program is free software: you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
@@ -39,7 +39,7 @@ void settingsMergeJson(json_t*) {} | |||||
/** Given slug => fallback slug. | /** 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. | To request fallback slugs to be added to this list, open a GitHub issue. | ||||
*/ | */ | ||||
static const std::map<std::string, std::string> pluginSlugFallbacks = { | static const std::map<std::string, std::string> pluginSlugFallbacks = { | ||||