Signed-off-by: falkTX <falktx@falktx.com>tags/23.02
@@ -29,6 +29,12 @@ | |||||
// ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
// from PluginContext.hpp | // from PluginContext.hpp | ||||
#ifndef HEADLESS | |||||
START_NAMESPACE_DGL | |||||
class NanoTopLevelWidget; | |||||
END_NAMESPACE_DGL | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
static constexpr const uint32_t kModuleParameters = 24; | static constexpr const uint32_t kModuleParameters = 24; | ||||
@@ -68,6 +74,7 @@ struct CardinalPluginContext : rack::Context { | |||||
uint32_t midiEventCount; | uint32_t midiEventCount; | ||||
Plugin* const plugin; | Plugin* const plugin; | ||||
#ifndef HEADLESS | #ifndef HEADLESS | ||||
DGL_NAMESPACE::NanoTopLevelWidget* tlw; | |||||
UI* ui; | UI* ui; | ||||
#endif | #endif | ||||
CardinalPluginContext(Plugin* const p); | CardinalPluginContext(Plugin* const p); | ||||
@@ -59,6 +59,115 @@ | |||||
const std::string CARDINAL_VERSION = "22.12"; | const std::string CARDINAL_VERSION = "22.12"; | ||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------------------------------------------- | |||||
void handleHostParameterDrag(const CardinalPluginContext* pcontext, uint index, bool started) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(pcontext->ui != nullptr,); | |||||
if (started) | |||||
{ | |||||
pcontext->ui->editParameter(index, true); | |||||
pcontext->ui->setParameterValue(index, pcontext->parameters[index]); | |||||
} | |||||
else | |||||
{ | |||||
pcontext->ui->editParameter(index, false); | |||||
} | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
bool CardinalPluginContext::addIdleCallback(IdleCallback* const cb) const | |||||
{ | |||||
if (ui == nullptr) | |||||
return false; | |||||
ui->addIdleCallback(cb); | |||||
return true; | |||||
} | |||||
void CardinalPluginContext::removeIdleCallback(IdleCallback* const cb) const | |||||
{ | |||||
if (ui == nullptr) | |||||
return; | |||||
ui->removeIdleCallback(cb); | |||||
} | |||||
void CardinalPluginContext::writeMidiMessage(const rack::midi::Message& message, const uint8_t channel) | |||||
{ | |||||
if (bypassed) | |||||
return; | |||||
const size_t size = message.bytes.size(); | |||||
DISTRHO_SAFE_ASSERT_RETURN(size > 0,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(message.frame >= 0,); | |||||
MidiEvent event; | |||||
event.frame = message.frame; | |||||
switch (message.bytes[0] & 0xF0) | |||||
{ | |||||
case 0x80: | |||||
case 0x90: | |||||
case 0xA0: | |||||
case 0xB0: | |||||
case 0xE0: | |||||
event.size = 3; | |||||
break; | |||||
case 0xC0: | |||||
case 0xD0: | |||||
event.size = 2; | |||||
break; | |||||
case 0xF0: | |||||
switch (message.bytes[0] & 0x0F) | |||||
{ | |||||
case 0x0: | |||||
case 0x4: | |||||
case 0x5: | |||||
case 0x7: | |||||
case 0x9: | |||||
case 0xD: | |||||
// unsupported | |||||
return; | |||||
case 0x1: | |||||
case 0x2: | |||||
case 0x3: | |||||
case 0xE: | |||||
event.size = 3; | |||||
break; | |||||
case 0x6: | |||||
case 0x8: | |||||
case 0xA: | |||||
case 0xB: | |||||
case 0xC: | |||||
case 0xF: | |||||
event.size = 1; | |||||
break; | |||||
} | |||||
break; | |||||
default: | |||||
// invalid | |||||
return; | |||||
} | |||||
DISTRHO_SAFE_ASSERT_RETURN(size >= event.size,); | |||||
std::memcpy(event.data, message.bytes.data(), event.size); | |||||
if (channel != 0 && event.data[0] < 0xF0) | |||||
event.data[0] |= channel & 0x0F; | |||||
plugin->writeMidiEvent(event); | |||||
} | |||||
END_NAMESPACE_DISTRHO | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
namespace rack { | namespace rack { | ||||
bool isStandalone() | bool isStandalone() | ||||
@@ -118,6 +227,8 @@ std::string homeDir() | |||||
} // namespace rack | } // namespace rack | ||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
namespace patchUtils | namespace patchUtils | ||||
{ | { | ||||
@@ -289,6 +400,8 @@ void openBrowser(const std::string& url) | |||||
} | } | ||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
void async_dialog_filebrowser(const bool saving, | void async_dialog_filebrowser(const bool saving, | ||||
const char* const defaultName, | const char* const defaultName, | ||||
const char* const startDir, | const char* const startDir, | ||||
@@ -430,75 +430,6 @@ struct Initializer | |||||
// ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
void CardinalPluginContext::writeMidiMessage(const rack::midi::Message& message, const uint8_t channel) | |||||
{ | |||||
if (bypassed) | |||||
return; | |||||
const size_t size = message.bytes.size(); | |||||
DISTRHO_SAFE_ASSERT_RETURN(size > 0,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(message.frame >= 0,); | |||||
MidiEvent event; | |||||
event.frame = message.frame; | |||||
switch (message.bytes[0] & 0xF0) | |||||
{ | |||||
case 0x80: | |||||
case 0x90: | |||||
case 0xA0: | |||||
case 0xB0: | |||||
case 0xE0: | |||||
event.size = 3; | |||||
break; | |||||
case 0xC0: | |||||
case 0xD0: | |||||
event.size = 2; | |||||
break; | |||||
case 0xF0: | |||||
switch (message.bytes[0] & 0x0F) | |||||
{ | |||||
case 0x0: | |||||
case 0x4: | |||||
case 0x5: | |||||
case 0x7: | |||||
case 0x9: | |||||
case 0xD: | |||||
// unsupported | |||||
return; | |||||
case 0x1: | |||||
case 0x2: | |||||
case 0x3: | |||||
case 0xE: | |||||
event.size = 3; | |||||
break; | |||||
case 0x6: | |||||
case 0x8: | |||||
case 0xA: | |||||
case 0xB: | |||||
case 0xC: | |||||
case 0xF: | |||||
event.size = 1; | |||||
break; | |||||
} | |||||
break; | |||||
default: | |||||
// invalid | |||||
return; | |||||
} | |||||
DISTRHO_SAFE_ASSERT_RETURN(size >= event.size,); | |||||
std::memcpy(event.data, message.bytes.data(), event.size); | |||||
if (channel != 0 && event.data[0] < 0xF0) | |||||
event.data[0] |= channel & 0x0F; | |||||
plugin->writeMidiEvent(event); | |||||
} | |||||
// ----------------------------------------------------------------------------------------------------------- | |||||
struct ScopedContext { | struct ScopedContext { | ||||
ScopedContext(const CardinalBasePlugin* const plugin) | ScopedContext(const CardinalBasePlugin* const plugin) | ||||
{ | { | ||||
@@ -1393,6 +1324,6 @@ Plugin* createPlugin() | |||||
return new CardinalPlugin(); | return new CardinalPlugin(); | ||||
} | } | ||||
// ----------------------------------------------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO |
@@ -7,8 +7,11 @@ | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# Carla stuff | # Carla stuff | ||||
CWD = ../../carla/source | |||||
ifneq ($(STATIC_BUILD),true) | |||||
STATIC_PLUGIN_TARGET = true | STATIC_PLUGIN_TARGET = true | ||||
CWD = ../../carla/source | |||||
include $(CWD)/Makefile.deps.mk | include $(CWD)/Makefile.deps.mk | ||||
CARLA_BUILD_DIR = ../../carla/build | CARLA_BUILD_DIR = ../../carla/build | ||||
@@ -23,7 +26,9 @@ CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/carla_engine_ | |||||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/carla_plugin.a | CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/carla_plugin.a | ||||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/native-plugins.a | CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/native-plugins.a | ||||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/audio_decoder.a | CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/audio_decoder.a | ||||
ifneq ($(WASM),true) | |||||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/jackbridge.min.a | CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/jackbridge.min.a | ||||
endif | |||||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/lilv.a | CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/lilv.a | ||||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/rtmempool.a | CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/rtmempool.a | ||||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/sfzero.a | CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/sfzero.a | ||||
@@ -31,10 +36,17 @@ CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/water.a | |||||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/ysfx.a | CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/ysfx.a | ||||
CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/zita-resampler.a | CARLA_EXTRA_LIBS += $(CARLA_BUILD_DIR)/modules/$(CARLA_BUILD_TYPE)/zita-resampler.a | ||||
endif # STATIC_BUILD | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# Import base definitions | # Import base definitions | ||||
DISTRHO_NAMESPACE = CardinalDISTRHO | |||||
DGL_NAMESPACE = CardinalDGL | |||||
NVG_DISABLE_SKIPPING_WHITESPACE = true | |||||
NVG_FONT_TEXTURE_FLAGS = NVG_IMAGE_NEAREST | |||||
USE_NANOVG_FBO = true | USE_NANOVG_FBO = true | ||||
WASM_EXCEPTIONS = true | |||||
include ../../dpf/Makefile.base.mk | include ../../dpf/Makefile.base.mk | ||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
@@ -57,7 +69,11 @@ endif | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# Extra libraries to link against | # Extra libraries to link against | ||||
ifeq ($(NOPLUGINS),true) | |||||
RACK_EXTRA_LIBS = ../../plugins/noplugins.a | |||||
else | |||||
RACK_EXTRA_LIBS = ../../plugins/plugins.a | RACK_EXTRA_LIBS = ../../plugins/plugins.a | ||||
endif | |||||
RACK_EXTRA_LIBS += ../rack.a | RACK_EXTRA_LIBS += ../rack.a | ||||
RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libquickjs.a | RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libquickjs.a | ||||
@@ -74,22 +90,51 @@ RACK_EXTRA_LIBS += $(DEP_LIB_PATH)/libzstd.a | |||||
endif | endif | ||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# surgext libraries | |||||
ifneq ($(NOPLUGINS),true) | |||||
SURGE_DEP_PATH = $(abspath ../../deps/surge-build) | |||||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/src/common/libsurge-common.a | |||||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/src/common/libjuce_dsp_rack_sub.a | |||||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/airwindows/libairwindows.a | |||||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/eurorack/libeurorack.a | |||||
ifeq ($(DEBUG),true) | |||||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/fmt/libfmtd.a | |||||
else | |||||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/fmt/libfmt.a | |||||
endif | |||||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sqlite-3.23.3/libsqlite.a | |||||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libsst-plugininfra.a | |||||
ifneq ($(WINDOWS),true) | |||||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libs/filesystem/libfilesystem.a | |||||
endif | |||||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libs/strnatcmp/libstrnatcmp.a | |||||
RACK_EXTRA_LIBS += $(SURGE_DEP_PATH)/libs/sst/sst-plugininfra/libs/tinyxml/libtinyxml.a | |||||
endif | |||||
# -------------------------------------------------------------- | |||||
# FIXME | |||||
ifeq ($(CIBUILD)$(WASM),truetrue) | |||||
ifneq ($(STATIC_BUILD),true) | |||||
STATIC_CARLA_PLUGIN_LIBS = -lsndfile -lopus -lFLAC -lvorbisenc -lvorbis -logg -lm | |||||
endif | |||||
endif | |||||
EXTRA_DEPENDENCIES = $(RACK_EXTRA_LIBS) $(CARLA_EXTRA_LIBS) | EXTRA_DEPENDENCIES = $(RACK_EXTRA_LIBS) $(CARLA_EXTRA_LIBS) | ||||
EXTRA_LIBS = $(RACK_EXTRA_LIBS) $(CARLA_EXTRA_LIBS) $(STATIC_CARLA_PLUGIN_LIBS) | EXTRA_LIBS = $(RACK_EXTRA_LIBS) $(CARLA_EXTRA_LIBS) $(STATIC_CARLA_PLUGIN_LIBS) | ||||
ifeq ($(shell pkg-config --exists fftw3f && echo true),true) | |||||
ifeq ($(shell $(PKG_CONFIG) --exists fftw3f && echo true),true) | |||||
EXTRA_DEPENDENCIES += ../../deps/aubio/libaubio.a | EXTRA_DEPENDENCIES += ../../deps/aubio/libaubio.a | ||||
EXTRA_LIBS += ../../deps/aubio/libaubio.a | EXTRA_LIBS += ../../deps/aubio/libaubio.a | ||||
EXTRA_LIBS += $(shell $(PKG_CONFIG) --libs fftw3f) | EXTRA_LIBS += $(shell $(PKG_CONFIG) --libs fftw3f) | ||||
endif | endif | ||||
# -------------------------------------------------------------- | |||||
# Extra flags for liblo | |||||
BASE_FLAGS += -DHAVE_LIBLO | |||||
BASE_FLAGS += $(LIBLO_FLAGS) | |||||
LINK_FLAGS += $(LIBLO_LIBS) | |||||
ifneq ($(NOPLUGINS),true) | |||||
ifeq ($(MACOS),true) | |||||
EXTRA_LIBS += -framework Accelerate | |||||
endif | |||||
endif | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# Extra flags for VCV stuff | # Extra flags for VCV stuff | ||||
@@ -106,11 +151,11 @@ BASE_FLAGS += -DPRIVATE= | |||||
BASE_FLAGS += -I.. | BASE_FLAGS += -I.. | ||||
BASE_FLAGS += -I../../dpf/dgl/src/nanovg | BASE_FLAGS += -I../../dpf/dgl/src/nanovg | ||||
BASE_FLAGS += -I../../include | BASE_FLAGS += -I../../include | ||||
BASE_FLAGS += -I../../include/neon-compat | |||||
BASE_FLAGS += -I../../include/simd-compat | |||||
BASE_FLAGS += -I../Rack/include | BASE_FLAGS += -I../Rack/include | ||||
ifeq ($(SYSDEPS),true) | ifeq ($(SYSDEPS),true) | ||||
BASE_FLAGS += -DCARDINAL_SYSDEPS | BASE_FLAGS += -DCARDINAL_SYSDEPS | ||||
BASE_FLAGS += $(shell pkg-config --cflags jansson libarchive samplerate speexdsp) | |||||
BASE_FLAGS += $(shell $(PKG_CONFIG) --cflags jansson libarchive samplerate speexdsp) | |||||
else | else | ||||
BASE_FLAGS += -DZSTDLIB_VISIBILITY= | BASE_FLAGS += -DZSTDLIB_VISIBILITY= | ||||
BASE_FLAGS += -I../Rack/dep/include | BASE_FLAGS += -I../Rack/dep/include | ||||
@@ -119,41 +164,98 @@ BASE_FLAGS += -I../Rack/dep/glfw/include | |||||
BASE_FLAGS += -I../Rack/dep/nanosvg/src | BASE_FLAGS += -I../Rack/dep/nanosvg/src | ||||
BASE_FLAGS += -I../Rack/dep/oui-blendish | BASE_FLAGS += -I../Rack/dep/oui-blendish | ||||
ifeq ($(WASM),true) | |||||
BASE_FLAGS += -DNANOVG_GLES2=1 | |||||
BASE_FLAGS += -msse -msse2 -msse3 -msimd128 | |||||
else ifneq ($(HAIKU),true) | |||||
ifeq ($(HEADLESS),true) | |||||
BASE_FLAGS += -DHEADLESS | |||||
endif | |||||
ifeq ($(MOD_BUILD),true) | |||||
BASE_FLAGS += -DDISTRHO_PLUGIN_USES_MODGUI=1 -DDISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE=0xffff | |||||
endif | |||||
ifneq ($(WASM),true) | |||||
ifneq ($(HAIKU),true) | |||||
BASE_FLAGS += -pthread | BASE_FLAGS += -pthread | ||||
endif | endif | ||||
endif | |||||
ifeq ($(WINDOWS),true) | ifeq ($(WINDOWS),true) | ||||
BASE_FLAGS += -D_USE_MATH_DEFINES | BASE_FLAGS += -D_USE_MATH_DEFINES | ||||
BASE_FLAGS += -DWIN32_LEAN_AND_MEAN | BASE_FLAGS += -DWIN32_LEAN_AND_MEAN | ||||
BASE_FLAGS += -D_WIN32_WINNT=0x0600 | |||||
BASE_FLAGS += -I../../include/mingw-compat | BASE_FLAGS += -I../../include/mingw-compat | ||||
BASE_FLAGS += -I../../include/mingw-std-threads | BASE_FLAGS += -I../../include/mingw-std-threads | ||||
endif | endif | ||||
ifeq ($(USE_GLES2),true) | |||||
BASE_FLAGS += -DNANOVG_GLES2_FORCED | |||||
else ifeq ($(USE_GLES3),true) | |||||
BASE_FLAGS += -DNANOVG_GLES3_FORCED | |||||
endif | |||||
BUILD_C_FLAGS += -std=gnu11 | BUILD_C_FLAGS += -std=gnu11 | ||||
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 | ||||
ifneq ($(MACOS),true) | ifneq ($(MACOS),true) | ||||
BUILD_CXX_FLAGS += -faligned-new -Wno-abi | BUILD_CXX_FLAGS += -faligned-new -Wno-abi | ||||
ifeq ($(MOD_BUILD),true) | |||||
BUILD_CXX_FLAGS += -std=gnu++17 | |||||
endif | |||||
endif | endif | ||||
# Rack code is not tested for this flag, unset it | # Rack code is not tested for this flag, unset it | ||||
BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS | BUILD_CXX_FLAGS += -U_GLIBCXX_ASSERTIONS -Wp,-U_GLIBCXX_ASSERTIONS | ||||
# Ignore bad behaviour from Rack API | |||||
BUILD_CXX_FLAGS += -Wno-format-security | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# FIXME lots of warnings from VCV side | # FIXME lots of warnings from VCV side | ||||
BASE_FLAGS += -Wno-unused-parameter | BASE_FLAGS += -Wno-unused-parameter | ||||
BASE_FLAGS += -Wno-unused-variable | BASE_FLAGS += -Wno-unused-variable | ||||
# -------------------------------------------------------------- | |||||
# extra linker flags | |||||
ifeq ($(HAIKU),true) | |||||
ifeq ($(WASM),true) | |||||
ifneq ($(STATIC_BUILD),true) | |||||
LINK_FLAGS += --use-preload-plugins | |||||
LINK_FLAGS += --preload-file=./jsfx | |||||
LINK_FLAGS += --preload-file=./lv2 | |||||
endif | |||||
LINK_FLAGS += --preload-file=../../bin/CardinalNative.lv2/resources@/resources | |||||
LINK_FLAGS += --use-preload-cache | |||||
ifneq ($(NOPLUGINS),true) | |||||
SYMLINKED_DIRS_RESOURCES = | |||||
# find . -type l | grep -v svg | grep -v ttf | grep -v art | grep -v json | grep -v png | grep -v otf | sort | |||||
SYMLINKED_DIRS_RESOURCES += BaconPlugs/res/midi/chopin | |||||
SYMLINKED_DIRS_RESOURCES += BaconPlugs/res/midi/debussy | |||||
SYMLINKED_DIRS_RESOURCES += BaconPlugs/res/midi/goldberg | |||||
SYMLINKED_DIRS_RESOURCES += cf/playeroscs | |||||
SYMLINKED_DIRS_RESOURCES += DrumKit/res/samples | |||||
SYMLINKED_DIRS_RESOURCES += Fundamental/presets | |||||
SYMLINKED_DIRS_RESOURCES += GrandeModular/presets | |||||
SYMLINKED_DIRS_RESOURCES += LyraeModules/presets | |||||
SYMLINKED_DIRS_RESOURCES += Meander/res | |||||
SYMLINKED_DIRS_RESOURCES += MindMeldModular/presets | |||||
SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/CommunityPresets | |||||
SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/CommunityShapes | |||||
SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/MindMeldPresets | |||||
SYMLINKED_DIRS_RESOURCES += MindMeldModular/res/ShapeMaster/MindMeldShapes | |||||
SYMLINKED_DIRS_RESOURCES += Mog/res | |||||
SYMLINKED_DIRS_RESOURCES += nonlinearcircuits/res | |||||
SYMLINKED_DIRS_RESOURCES += Orbits/presets | |||||
SYMLINKED_DIRS_RESOURCES += stoermelder-packone/presets | |||||
SYMLINKED_DIRS_RESOURCES += surgext/build/surge-data/fx_presets | |||||
SYMLINKED_DIRS_RESOURCES += surgext/build/surge-data/wavetables | |||||
SYMLINKED_DIRS_RESOURCES += surgext/patches | |||||
SYMLINKED_DIRS_RESOURCES += surgext/presets | |||||
LINK_FLAGS += $(foreach d,$(SYMLINKED_DIRS_RESOURCES),--preload-file=../../bin/CardinalNative.lv2/resources/$(d)@/resources/$(d)) | |||||
endif | |||||
LINK_FLAGS += -sALLOW_MEMORY_GROWTH | |||||
LINK_FLAGS += -sINITIAL_MEMORY=64Mb | |||||
LINK_FLAGS += -sLZ4=1 | |||||
LINK_FLAGS += --shell-file=../emscripten/shell.html | |||||
LINK_FLAGS += -O3 | |||||
else ifeq ($(HAIKU),true) | |||||
LINK_FLAGS += -lpthread | LINK_FLAGS += -lpthread | ||||
else | else | ||||
LINK_FLAGS += -pthread | LINK_FLAGS += -pthread | ||||
@@ -181,7 +283,7 @@ EXTRA_LIBS += -lws2_32 -lwinmm | |||||
endif | endif | ||||
ifeq ($(SYSDEPS),true) | ifeq ($(SYSDEPS),true) | ||||
EXTRA_LIBS += $(shell pkg-config --libs jansson libarchive samplerate speexdsp) | |||||
EXTRA_LIBS += $(shell $(PKG_CONFIG) --libs jansson libarchive samplerate speexdsp) | |||||
endif | endif | ||||
ifeq ($(WITH_LTO),true) | ifeq ($(WITH_LTO),true) | ||||
@@ -193,6 +295,13 @@ LINK_FLAGS += -Wno-stringop-overflow | |||||
endif | endif | ||||
endif | endif | ||||
# -------------------------------------------------------------- | |||||
# Extra flags for liblo | |||||
BASE_FLAGS += -DHAVE_LIBLO | |||||
BASE_FLAGS += $(LIBLO_FLAGS) | |||||
LINK_FLAGS += $(LIBLO_LIBS) | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# fallback path to resource files | # fallback path to resource files | ||||
@@ -17,7 +17,7 @@ | |||||
#include "RemoteUI.hpp" | #include "RemoteUI.hpp" | ||||
// #include <asset.hpp> | |||||
#include <asset.hpp> | |||||
// #include <random.hpp> | // #include <random.hpp> | ||||
#include <patch.hpp> | #include <patch.hpp> | ||||
#include <settings.hpp> | #include <settings.hpp> | ||||
@@ -26,66 +26,293 @@ | |||||
#include <app/Scene.hpp> | #include <app/Scene.hpp> | ||||
#include <engine/Engine.hpp> | #include <engine/Engine.hpp> | ||||
#include "AsyncDialog.hpp" | |||||
#include "WindowParameters.hpp" | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
namespace rack { | |||||
namespace app { | |||||
widget::Widget* createMenuBar(bool isStandalone); | |||||
} | |||||
namespace window { | |||||
void WindowSetPluginRemote(Window* window, NanoTopLevelWidget* tlw); | |||||
void WindowSetMods(Window* window, int mods); | |||||
void WindowSetInternalSize(rack::window::Window* window, math::Vec size); | |||||
} | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
CardinalRemoteUI::CardinalRemoteUI(Window& window, const std::string& templatePath) | CardinalRemoteUI::CardinalRemoteUI(Window& window, const std::string& templatePath) | ||||
: NanoTopLevelWidget(window), | |||||
context(nullptr) | |||||
: NanoTopLevelWidget(window) | |||||
{ | { | ||||
// create unique temporary path for this instance | |||||
try { | |||||
char uidBuf[24]; | |||||
const std::string tmp = rack::system::getTempDirectory(); | |||||
CardinalPluginContext& context(*static_cast<CardinalPluginContext*>(rack::contextGet())); | |||||
context.nativeWindowId = getWindow().getNativeWindowHandle(); | |||||
context.tlw = this; | |||||
for (int i=1;; ++i) | |||||
{ | |||||
std::snprintf(uidBuf, sizeof(uidBuf), "CardinalRemote.%04d", i); | |||||
const std::string trypath = rack::system::join(tmp, uidBuf); | |||||
if (! rack::system::exists(trypath)) | |||||
{ | |||||
if (rack::system::createDirectories(trypath)) | |||||
autosavePath = trypath; | |||||
break; | |||||
} | |||||
} | |||||
} DISTRHO_SAFE_EXCEPTION("create unique temporary path"); | |||||
window.setIgnoringKeyRepeat(true); | |||||
context.nativeWindowId = window.getNativeWindowHandle(); | |||||
rack::contextSet(&context); | |||||
const double scaleFactor = getScaleFactor(); | |||||
context.bufferSize = 512; | |||||
rack::settings::sampleRate = context.sampleRate = 48000; | |||||
setGeometryConstraints(648 * scaleFactor, 538 * scaleFactor); | |||||
context.engine = new rack::engine::Engine; | |||||
context.engine->setSampleRate(context.sampleRate); | |||||
if (scaleFactor != 1.0) | |||||
setSize(DISTRHO_UI_DEFAULT_WIDTH * scaleFactor, DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor); | |||||
context.history = new rack::history::State; | |||||
context.patch = new rack::patch::Manager; | |||||
context.patch->autosavePath = autosavePath; | |||||
context.patch->templatePath = templatePath; | |||||
rack::window::WindowSetPluginRemote(context.window, this); | |||||
context.event = new rack::widget::EventState; | |||||
context.scene = new rack::app::Scene; | |||||
context.event->rootWidget = context.scene; | |||||
context.window = new rack::window::Window; | |||||
if (rack::widget::Widget* const menuBar = context.scene->menuBar) | |||||
{ | |||||
context.scene->removeChild(menuBar); | |||||
delete menuBar; | |||||
} | |||||
context.patch->loadTemplate(); | |||||
context.scene->rackScroll->reset(); | |||||
context.scene->menuBar = rack::app::createMenuBar(true); | |||||
context.scene->addChildBelow(context.scene->menuBar, context.scene->rackScroll); | |||||
context.nativeWindowId = getWindow().getNativeWindowHandle(); | |||||
// hide "Browse VCV Library" button | |||||
rack::widget::Widget* const browser = context.scene->browser->children.back(); | |||||
rack::widget::Widget* const headerLayout = browser->children.front(); | |||||
rack::widget::Widget* const libraryButton = headerLayout->children.back(); | |||||
libraryButton->hide(); | |||||
// Report to user if something is wrong with the installation | |||||
std::string errorMessage; | |||||
if (rack::asset::systemDir.empty()) | |||||
{ | |||||
errorMessage = "Failed to locate Cardinal plugin bundle.\n" | |||||
"Install Cardinal with its plugin bundle folder intact and try again."; | |||||
} | |||||
else if (! rack::system::exists(rack::asset::systemDir)) | |||||
{ | |||||
errorMessage = rack::string::f("System directory \"%s\" does not exist. " | |||||
"Make sure Cardinal was downloaded and installed correctly.", | |||||
rack::asset::systemDir.c_str()); | |||||
} | |||||
if (! errorMessage.empty()) | |||||
{ | |||||
static bool shown = false; | |||||
if (! shown) | |||||
{ | |||||
shown = true; | |||||
asyncDialog::create(errorMessage.c_str()); | |||||
} | |||||
} | |||||
context.window->step(); | |||||
// WindowParametersSetCallback(context.window, this); | |||||
} | } | ||||
CardinalRemoteUI::~CardinalRemoteUI() | CardinalRemoteUI::~CardinalRemoteUI() | ||||
{ | { | ||||
rack::contextSet(&context); | |||||
CardinalPluginContext& context(*static_cast<CardinalPluginContext*>(rack::contextGet())); | |||||
context.nativeWindowId = 0; | context.nativeWindowId = 0; | ||||
context.patch->clear(); | |||||
if (! autosavePath.empty()) | |||||
rack::system::removeRecursively(autosavePath); | |||||
} | } | ||||
void CardinalRemoteUI::onNanoDisplay() | void CardinalRemoteUI::onNanoDisplay() | ||||
{ | { | ||||
rack::contextSet(&context); | |||||
CardinalPluginContext& context(*static_cast<CardinalPluginContext*>(rack::contextGet())); | |||||
context.window->step(); | context.window->step(); | ||||
// TODO | |||||
repaint(); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
static int glfwMods(const uint mod) noexcept | |||||
{ | |||||
int mods = 0; | |||||
if (mod & kModifierControl) | |||||
mods |= GLFW_MOD_CONTROL; | |||||
if (mod & kModifierShift) | |||||
mods |= GLFW_MOD_SHIFT; | |||||
if (mod & kModifierAlt) | |||||
mods |= GLFW_MOD_ALT; | |||||
if (mod & kModifierSuper) | |||||
mods |= GLFW_MOD_SUPER; | |||||
/* | |||||
if (glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS) | |||||
mods |= GLFW_MOD_SHIFT; | |||||
if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) | |||||
mods |= GLFW_MOD_CONTROL; | |||||
if (glfwGetKey(win, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS) | |||||
mods |= GLFW_MOD_ALT; | |||||
if (glfwGetKey(win, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS) | |||||
mods |= GLFW_MOD_SUPER; | |||||
*/ | |||||
return mods; | |||||
} | |||||
bool CardinalRemoteUI::onMouse(const MouseEvent& ev) | |||||
{ | |||||
if (ev.press) | |||||
getWindow().focus(); | |||||
const int action = ev.press ? GLFW_PRESS : GLFW_RELEASE; | |||||
int mods = glfwMods(ev.mod); | |||||
int button; | |||||
switch (ev.button) | |||||
{ | |||||
case 1: button = GLFW_MOUSE_BUTTON_LEFT; break; | |||||
case 2: button = GLFW_MOUSE_BUTTON_RIGHT; break; | |||||
case 3: button = GLFW_MOUSE_BUTTON_MIDDLE; break; | |||||
default: | |||||
button = ev.button; | |||||
break; | |||||
} | |||||
#ifdef DISTRHO_OS_MAC | |||||
// Remap Ctrl-left click to right click on macOS | |||||
if (button == GLFW_MOUSE_BUTTON_LEFT && (mods & RACK_MOD_MASK) == GLFW_MOD_CONTROL) { | |||||
button = GLFW_MOUSE_BUTTON_RIGHT; | |||||
mods &= ~GLFW_MOD_CONTROL; | |||||
} | |||||
// Remap Ctrl-shift-left click to middle click on macOS | |||||
if (button == GLFW_MOUSE_BUTTON_LEFT && (mods & RACK_MOD_MASK) == (GLFW_MOD_CONTROL | GLFW_MOD_SHIFT)) { | |||||
button = GLFW_MOUSE_BUTTON_MIDDLE; | |||||
mods &= ~(GLFW_MOD_CONTROL | GLFW_MOD_SHIFT); | |||||
} | |||||
#endif | |||||
CardinalPluginContext* context = static_cast<CardinalPluginContext*>(rack::contextGet()); | |||||
return context->event->handleButton(lastMousePos, button, action, mods); | |||||
} | |||||
bool CardinalRemoteUI::onMotion(const MotionEvent& ev) | |||||
{ | |||||
const rack::math::Vec mousePos = rack::math::Vec(ev.pos.getX(), ev.pos.getY()).div(getScaleFactor()).round(); | |||||
const rack::math::Vec mouseDelta = mousePos.minus(lastMousePos); | |||||
lastMousePos = mousePos; | |||||
CardinalPluginContext* context = static_cast<CardinalPluginContext*>(rack::contextGet()); | |||||
return context->event->handleHover(mousePos, mouseDelta); | |||||
} | |||||
bool CardinalRemoteUI::onScroll(const ScrollEvent& ev) | |||||
{ | |||||
rack::math::Vec scrollDelta = rack::math::Vec(ev.delta.getX(), ev.delta.getY()); | |||||
#ifndef DISTRHO_OS_MAC | |||||
scrollDelta = scrollDelta.mult(50.0); | |||||
#endif | |||||
const int mods = glfwMods(ev.mod); | |||||
CardinalPluginContext* context = static_cast<CardinalPluginContext*>(rack::contextGet()); | |||||
return context->event->handleScroll(lastMousePos, scrollDelta); | |||||
} | } | ||||
bool CardinalRemoteUI::onCharacterInput(const CharacterInputEvent& ev) | |||||
{ | |||||
if (ev.character < ' ' || ev.character >= kKeyDelete) | |||||
return false; | |||||
const int mods = glfwMods(ev.mod); | |||||
CardinalPluginContext* context = static_cast<CardinalPluginContext*>(rack::contextGet()); | |||||
return context->event->handleText(lastMousePos, ev.character); | |||||
} | |||||
bool CardinalRemoteUI::onKeyboard(const KeyboardEvent& ev) | |||||
{ | |||||
const int action = ev.press ? GLFW_PRESS : GLFW_RELEASE; | |||||
const int mods = glfwMods(ev.mod); | |||||
/* These are unsupported in pugl right now | |||||
#define GLFW_KEY_KP_0 320 | |||||
#define GLFW_KEY_KP_1 321 | |||||
#define GLFW_KEY_KP_2 322 | |||||
#define GLFW_KEY_KP_3 323 | |||||
#define GLFW_KEY_KP_4 324 | |||||
#define GLFW_KEY_KP_5 325 | |||||
#define GLFW_KEY_KP_6 326 | |||||
#define GLFW_KEY_KP_7 327 | |||||
#define GLFW_KEY_KP_8 328 | |||||
#define GLFW_KEY_KP_9 329 | |||||
#define GLFW_KEY_KP_DECIMAL 330 | |||||
#define GLFW_KEY_KP_DIVIDE 331 | |||||
#define GLFW_KEY_KP_MULTIPLY 332 | |||||
#define GLFW_KEY_KP_SUBTRACT 333 | |||||
#define GLFW_KEY_KP_ADD 334 | |||||
#define GLFW_KEY_KP_ENTER 335 | |||||
#define GLFW_KEY_KP_EQUAL 336 | |||||
*/ | |||||
int key; | |||||
switch (ev.key) | |||||
{ | |||||
case '\r': key = GLFW_KEY_ENTER; break; | |||||
case '\t': key = GLFW_KEY_TAB; break; | |||||
case kKeyBackspace: key = GLFW_KEY_BACKSPACE; break; | |||||
case kKeyEscape: key = GLFW_KEY_ESCAPE; break; | |||||
case kKeyDelete: key = GLFW_KEY_DELETE; break; | |||||
case kKeyF1: key = GLFW_KEY_F1; break; | |||||
case kKeyF2: key = GLFW_KEY_F2; break; | |||||
case kKeyF3: key = GLFW_KEY_F3; break; | |||||
case kKeyF4: key = GLFW_KEY_F4; break; | |||||
case kKeyF5: key = GLFW_KEY_F5; break; | |||||
case kKeyF6: key = GLFW_KEY_F6; break; | |||||
case kKeyF7: key = GLFW_KEY_F7; break; | |||||
case kKeyF8: key = GLFW_KEY_F8; break; | |||||
case kKeyF9: key = GLFW_KEY_F9; break; | |||||
case kKeyF10: key = GLFW_KEY_F10; break; | |||||
case kKeyF11: key = GLFW_KEY_F11; break; | |||||
case kKeyF12: key = GLFW_KEY_F12; break; | |||||
case kKeyLeft: key = GLFW_KEY_LEFT; break; | |||||
case kKeyUp: key = GLFW_KEY_UP; break; | |||||
case kKeyRight: key = GLFW_KEY_RIGHT; break; | |||||
case kKeyDown: key = GLFW_KEY_DOWN; break; | |||||
case kKeyPageUp: key = GLFW_KEY_PAGE_UP; break; | |||||
case kKeyPageDown: key = GLFW_KEY_PAGE_DOWN; break; | |||||
case kKeyHome: key = GLFW_KEY_HOME; break; | |||||
case kKeyEnd: key = GLFW_KEY_END; break; | |||||
case kKeyInsert: key = GLFW_KEY_INSERT; break; | |||||
case kKeyShiftL: key = GLFW_KEY_LEFT_SHIFT; break; | |||||
case kKeyShiftR: key = GLFW_KEY_RIGHT_SHIFT; break; | |||||
case kKeyControlL: key = GLFW_KEY_LEFT_CONTROL; break; | |||||
case kKeyControlR: key = GLFW_KEY_RIGHT_CONTROL; break; | |||||
case kKeyAltL: key = GLFW_KEY_LEFT_ALT; break; | |||||
case kKeyAltR: key = GLFW_KEY_RIGHT_ALT; break; | |||||
case kKeySuperL: key = GLFW_KEY_LEFT_SUPER; break; | |||||
case kKeySuperR: key = GLFW_KEY_RIGHT_SUPER; break; | |||||
case kKeyMenu: key = GLFW_KEY_MENU; break; | |||||
case kKeyCapsLock: key = GLFW_KEY_CAPS_LOCK; break; | |||||
case kKeyScrollLock: key = GLFW_KEY_SCROLL_LOCK; break; | |||||
case kKeyNumLock: key = GLFW_KEY_NUM_LOCK; break; | |||||
case kKeyPrintScreen: key = GLFW_KEY_PRINT_SCREEN; break; | |||||
case kKeyPause: key = GLFW_KEY_PAUSE; break; | |||||
default: | |||||
// glfw expects uppercase | |||||
if (ev.key >= 'a' && ev.key <= 'z') | |||||
key = ev.key - ('a' - 'A'); | |||||
else | |||||
key = ev.key; | |||||
break; | |||||
} | |||||
CardinalPluginContext* context = static_cast<CardinalPluginContext*>(rack::contextGet()); | |||||
return context->event->handleKey(lastMousePos, key, ev.keycode, action, mods); | |||||
} | |||||
void CardinalRemoteUI::onResize(const ResizeEvent& ev) | |||||
{ | |||||
NanoTopLevelWidget::onResize(ev); | |||||
CardinalPluginContext* context = static_cast<CardinalPluginContext*>(rack::contextGet()); | |||||
if (context->window != nullptr) | |||||
WindowSetInternalSize(context->window, rack::math::Vec(ev.size.getWidth(), ev.size.getHeight())); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- |
@@ -20,10 +20,11 @@ | |||||
#include "NanoVG.hpp" | #include "NanoVG.hpp" | ||||
#include "PluginContext.hpp" | #include "PluginContext.hpp" | ||||
#include <app/common.hpp> | |||||
class CardinalRemoteUI : public NanoTopLevelWidget | class CardinalRemoteUI : public NanoTopLevelWidget | ||||
{ | { | ||||
CardinalPluginContext context; | |||||
std::string autosavePath; | |||||
rack::math::Vec lastMousePos; | |||||
public: | public: | ||||
explicit CardinalRemoteUI(Window& window, const std::string& templatePath); | explicit CardinalRemoteUI(Window& window, const std::string& templatePath); | ||||
@@ -31,6 +32,12 @@ public: | |||||
protected: | protected: | ||||
void onNanoDisplay() override; | void onNanoDisplay() override; | ||||
bool onMouse(const MouseEvent& ev) override; | |||||
bool onMotion(const MotionEvent& ev) override; | |||||
bool onScroll(const ScrollEvent& ev) override; | |||||
bool onCharacterInput(const CharacterInputEvent& ev) override; | |||||
bool onKeyboard(const KeyboardEvent& ev) override; | |||||
void onResize(const ResizeEvent& ev) override; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CardinalRemoteUI) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CardinalRemoteUI) | ||||
}; | }; |
@@ -20,13 +20,19 @@ | |||||
#include "RemoteUI.hpp" | #include "RemoteUI.hpp" | ||||
#include <asset.hpp> | #include <asset.hpp> | ||||
#include <patch.hpp> | |||||
#include <random.hpp> | #include <random.hpp> | ||||
#include <settings.hpp> | #include <settings.hpp> | ||||
#include <system.hpp> | #include <system.hpp> | ||||
#include <app/Browser.hpp> | #include <app/Browser.hpp> | ||||
#include <app/Scene.hpp> | |||||
#include <engine/Engine.hpp> | |||||
#include <ui/common.hpp> | #include <ui/common.hpp> | ||||
#include "PluginContext.hpp" | |||||
namespace rack { | namespace rack { | ||||
namespace plugin { | namespace plugin { | ||||
void initStaticPlugins(); | void initStaticPlugins(); | ||||
@@ -34,6 +40,26 @@ namespace plugin { | |||||
} | } | ||||
} | } | ||||
START_NAMESPACE_DISTRHO | |||||
bool isUsingNativeAudio() noexcept { return false; } | |||||
bool supportsAudioInput() { return false; } | |||||
bool supportsBufferSizeChanges() { return false; } | |||||
bool supportsMIDI() { return false; } | |||||
bool isAudioInputEnabled() { return false; } | |||||
bool isMIDIEnabled() { return false; } | |||||
uint getBufferSize() { return 0; } | |||||
bool requestAudioInput() { return false; } | |||||
bool requestBufferSizeChange(uint) { return false; } | |||||
bool requestMIDI() { return false; } | |||||
const char* getPluginFormatName() noexcept { return "Remote"; } | |||||
uint32_t Plugin::getBufferSize() const noexcept { return 128; } | |||||
double Plugin::getSampleRate() const noexcept { return 48000; } | |||||
bool Plugin::writeMidiEvent(const MidiEvent&) noexcept { return false; } | |||||
END_NAMESPACE_DISTRHO | |||||
int main(const int argc, const char* argv[]) | int main(const int argc, const char* argv[]) | ||||
{ | { | ||||
using namespace rack; | using namespace rack; | ||||
@@ -42,7 +68,6 @@ int main(const int argc, const char* argv[]) | |||||
settings::autoCheckUpdates = false; | settings::autoCheckUpdates = false; | ||||
settings::autosaveInterval = 0; | settings::autosaveInterval = 0; | ||||
settings::devMode = true; | settings::devMode = true; | ||||
settings::discordUpdateActivity = false; | |||||
settings::isPlugin = true; | settings::isPlugin = true; | ||||
settings::skipLoadOnLaunch = true; | settings::skipLoadOnLaunch = true; | ||||
settings::showTipsOnLaunch = false; | settings::showTipsOnLaunch = false; | ||||
@@ -131,17 +156,68 @@ int main(const int argc, const char* argv[]) | |||||
INFO("Initializing plugin browser DB"); | INFO("Initializing plugin browser DB"); | ||||
app::browserInit(); | app::browserInit(); | ||||
// create unique temporary path for this instance | |||||
std::string autosavePath; | |||||
try { | |||||
char uidBuf[24]; | |||||
const std::string tmp = rack::system::getTempDirectory(); | |||||
for (int i=1;; ++i) | |||||
{ | |||||
std::snprintf(uidBuf, sizeof(uidBuf), "CardinalRemote.%04d", i); | |||||
const std::string trypath = rack::system::join(tmp, uidBuf); | |||||
if (! rack::system::exists(trypath)) | |||||
{ | |||||
if (rack::system::createDirectories(trypath)) | |||||
autosavePath = trypath; | |||||
break; | |||||
} | |||||
} | |||||
} DISTRHO_SAFE_EXCEPTION("create unique temporary path"); | |||||
CardinalPluginContext context(nullptr); | |||||
rack::contextSet(&context); | |||||
context.bufferSize = 512; | |||||
rack::settings::sampleRate = context.sampleRate = 48000; | |||||
context.engine = new rack::engine::Engine; | |||||
context.engine->setSampleRate(context.sampleRate); | |||||
context.history = new rack::history::State; | |||||
context.patch = new rack::patch::Manager; | |||||
context.patch->autosavePath = autosavePath; | |||||
context.patch->templatePath = templatePath; | |||||
context.event = new rack::widget::EventState; | |||||
context.scene = new rack::app::Scene; | |||||
context.event->rootWidget = context.scene; | |||||
context.window = new rack::window::Window; | |||||
context.patch->loadTemplate(); | |||||
context.scene->rackScroll->reset(); | |||||
Application app; | Application app; | ||||
Window win(app); | Window win(app); | ||||
win.setResizable(true); | |||||
win.setTitle("CardinalRemote"); | win.setTitle("CardinalRemote"); | ||||
ScopedPointer<CardinalRemoteUI> remoteUI; | ScopedPointer<CardinalRemoteUI> remoteUI; | ||||
{ | { | ||||
const Window::ScopedGraphicsContext sgc(win); | |||||
remoteUI = new CardinalRemoteUI(win, templatePath); | remoteUI = new CardinalRemoteUI(win, templatePath); | ||||
} | } | ||||
win.show(); | |||||
app.exec(); | app.exec(); | ||||
context.patch->clear(); | |||||
if (! autosavePath.empty()) | |||||
rack::system::removeRecursively(autosavePath); | |||||
INFO("Clearing asset paths"); | INFO("Clearing asset paths"); | ||||
asset::bundlePath.clear(); | asset::bundlePath.clear(); | ||||
asset::systemDir.clear(); | asset::systemDir.clear(); | ||||
@@ -67,40 +67,6 @@ START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
bool CardinalPluginContext::addIdleCallback(IdleCallback* const cb) const | |||||
{ | |||||
if (ui == nullptr) | |||||
return false; | |||||
ui->addIdleCallback(cb); | |||||
return true; | |||||
} | |||||
void CardinalPluginContext::removeIdleCallback(IdleCallback* const cb) const | |||||
{ | |||||
if (ui == nullptr) | |||||
return; | |||||
ui->removeIdleCallback(cb); | |||||
} | |||||
void handleHostParameterDrag(const CardinalPluginContext* pcontext, uint index, bool started) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(pcontext->ui != nullptr,); | |||||
if (started) | |||||
{ | |||||
pcontext->ui->editParameter(index, true); | |||||
pcontext->ui->setParameterValue(index, pcontext->parameters[index]); | |||||
} | |||||
else | |||||
{ | |||||
pcontext->ui->editParameter(index, false); | |||||
} | |||||
} | |||||
// ----------------------------------------------------------------------------------------------------------- | |||||
#ifdef DISTRHO_OS_WASM | #ifdef DISTRHO_OS_WASM | ||||
struct WasmWelcomeDialog : rack::widget::OpaqueWidget | struct WasmWelcomeDialog : rack::widget::OpaqueWidget | ||||
{ | { | ||||
@@ -64,13 +64,14 @@ struct CardinalPluginContext : rack::Context { | |||||
uint32_t midiEventCount; | uint32_t midiEventCount; | ||||
Plugin* const plugin; | Plugin* const plugin; | ||||
#ifndef HEADLESS | #ifndef HEADLESS | ||||
NanoTopLevelWidget* tlw; | |||||
UI* ui; | UI* ui; | ||||
#endif | #endif | ||||
CardinalPluginContext(Plugin* const p) | CardinalPluginContext(Plugin* const p) | ||||
: bufferSize(p->getBufferSize()), | |||||
: bufferSize(p != nullptr ? p->getBufferSize() : 0), | |||||
processCounter(0), | processCounter(0), | ||||
sampleRate(p->getSampleRate()), | |||||
sampleRate(p != nullptr ? p->getSampleRate() : 0.0), | |||||
#if CARDINAL_VARIANT_MAIN | #if CARDINAL_VARIANT_MAIN | ||||
variant(kCardinalVariantMain), | variant(kCardinalVariantMain), | ||||
#elif CARDINAL_VARIANT_FX | #elif CARDINAL_VARIANT_FX | ||||
@@ -105,6 +106,7 @@ struct CardinalPluginContext : rack::Context { | |||||
midiEventCount(0), | midiEventCount(0), | ||||
plugin(p) | plugin(p) | ||||
#ifndef HEADLESS | #ifndef HEADLESS | ||||
, tlw(nullptr) | |||||
, ui(nullptr) | , ui(nullptr) | ||||
#endif | #endif | ||||
{ | { | ||||
@@ -169,6 +171,7 @@ public: | |||||
filebrowseraction(), | filebrowseraction(), | ||||
filebrowserhandle(nullptr) | filebrowserhandle(nullptr) | ||||
{ | { | ||||
context->tlw = this; | |||||
context->ui = this; | context->ui = this; | ||||
} | } | ||||
@@ -177,6 +180,7 @@ public: | |||||
if (filebrowserhandle != nullptr) | if (filebrowserhandle != nullptr) | ||||
fileBrowserClose(filebrowserhandle); | fileBrowserClose(filebrowserhandle); | ||||
context->tlw = nullptr; | |||||
context->ui = nullptr; | context->ui = nullptr; | ||||
} | } | ||||
}; | }; | ||||
@@ -30,10 +30,10 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow*) | |||||
{ | { | ||||
CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP); | CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP); | ||||
DISTRHO_SAFE_ASSERT_RETURN(context != nullptr, nullptr); | DISTRHO_SAFE_ASSERT_RETURN(context != nullptr, nullptr); | ||||
DISTRHO_SAFE_ASSERT_RETURN(context->ui != nullptr, nullptr); | |||||
DISTRHO_SAFE_ASSERT_RETURN(context->tlw != nullptr, nullptr); | |||||
size_t dataSize; | size_t dataSize; | ||||
return static_cast<const char*>(context->ui->getClipboard(dataSize)); | |||||
return static_cast<const char*>(context->tlw->getClipboard(dataSize)); | |||||
} | } | ||||
GLFWAPI void glfwSetClipboardString(GLFWwindow*, const char* const text) | GLFWAPI void glfwSetClipboardString(GLFWwindow*, const char* const text) | ||||
@@ -42,9 +42,9 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow*, const char* const text) | |||||
CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP); | CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP); | ||||
DISTRHO_SAFE_ASSERT_RETURN(context != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(context != nullptr,); | ||||
DISTRHO_SAFE_ASSERT_RETURN(context->ui != nullptr,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(context->tlw != nullptr,); | |||||
context->ui->setClipboard(nullptr, text, std::strlen(text)+1); | |||||
context->tlw->setClipboard(nullptr, text, std::strlen(text)+1); | |||||
} | } | ||||
GLFWAPI GLFWcursor* glfwCreateStandardCursor(const int shape) | GLFWAPI GLFWcursor* glfwCreateStandardCursor(const int shape) | ||||
@@ -91,18 +91,18 @@ GLFWAPI void glfwSetCursor(GLFWwindow*, GLFWcursor* const cursor) | |||||
{ | { | ||||
CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP); | CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP); | ||||
DISTRHO_SAFE_ASSERT_RETURN(context != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(context != nullptr,); | ||||
DISTRHO_SAFE_ASSERT_RETURN(context->ui != nullptr,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(context->tlw != nullptr,); | |||||
context->ui->setCursor(cursor != nullptr ? cursor->cursorId : kMouseCursorArrow); | |||||
context->tlw->setCursor(cursor != nullptr ? cursor->cursorId : kMouseCursorArrow); | |||||
} | } | ||||
GLFWAPI double glfwGetTime(void) | GLFWAPI double glfwGetTime(void) | ||||
{ | { | ||||
CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP); | CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP); | ||||
DISTRHO_SAFE_ASSERT_RETURN(context != nullptr, 0.0); | DISTRHO_SAFE_ASSERT_RETURN(context != nullptr, 0.0); | ||||
DISTRHO_SAFE_ASSERT_RETURN(context->ui != nullptr, 0.0); | |||||
DISTRHO_SAFE_ASSERT_RETURN(context->tlw != nullptr, 0.0); | |||||
return context->ui->getApp().getTime(); | |||||
return context->tlw->getApp().getTime(); | |||||
} | } | ||||
GLFWAPI const char* glfwGetKeyName(const int key, int) | GLFWAPI const char* glfwGetKeyName(const int key, int) | ||||
@@ -145,6 +145,7 @@ struct Window::Internal { | |||||
std::string lastWindowTitle; | std::string lastWindowTitle; | ||||
DISTRHO_NAMESPACE::UI* ui = nullptr; | DISTRHO_NAMESPACE::UI* ui = nullptr; | ||||
DGL_NAMESPACE::NanoTopLevelWidget* tlw = nullptr; | |||||
DISTRHO_NAMESPACE::WindowParameters params; | DISTRHO_NAMESPACE::WindowParameters params; | ||||
DISTRHO_NAMESPACE::WindowParametersCallback* callback = nullptr; | DISTRHO_NAMESPACE::WindowParametersCallback* callback = nullptr; | ||||
DGL_NAMESPACE::Application hiddenApp; | DGL_NAMESPACE::Application hiddenApp; | ||||
@@ -238,6 +239,112 @@ Window::Window() { | |||||
#endif | #endif | ||||
} | } | ||||
void WindowSetPluginRemote(Window* const window, NanoTopLevelWidget* const tlw) | |||||
{ | |||||
// if nanovg context failed, init only bare minimum | |||||
if (window->vg == nullptr) | |||||
{ | |||||
if (tlw != nullptr) | |||||
{ | |||||
window->internal->tlw = tlw; | |||||
window->internal->size = rack::math::Vec(tlw->getWidth(), tlw->getHeight()); | |||||
} | |||||
else | |||||
{ | |||||
window->internal->tlw = nullptr; | |||||
window->internal->callback = nullptr; | |||||
} | |||||
return; | |||||
} | |||||
if (tlw != nullptr) | |||||
{ | |||||
const GLubyte* vendor = glGetString(GL_VENDOR); | |||||
const GLubyte* renderer = glGetString(GL_RENDERER); | |||||
const GLubyte* version = glGetString(GL_VERSION); | |||||
INFO("Renderer: %s %s", vendor, renderer); | |||||
INFO("OpenGL: %s", version); | |||||
window->internal->tlw = tlw; | |||||
window->internal->size = rack::math::Vec(tlw->getWidth(), tlw->getHeight()); | |||||
// Set up NanoVG | |||||
window->internal->r_vg = tlw->getContext(); | |||||
#ifdef NANOVG_GLES2 | |||||
window->internal->r_fbVg = nvgCreateSharedGLES2(window->internal->r_vg, NVG_ANTIALIAS); | |||||
#else | |||||
window->internal->r_fbVg = nvgCreateSharedGL2(window->internal->r_vg, NVG_ANTIALIAS); | |||||
#endif | |||||
// swap contexts | |||||
window->internal->o_vg = window->vg; | |||||
window->internal->o_fbVg = window->fbVg; | |||||
window->vg = window->internal->r_vg; | |||||
window->fbVg = window->internal->r_fbVg; | |||||
// also for fonts and images | |||||
window->uiFont->vg = window->vg; | |||||
window->uiFont->handle = loadFallbackFont(window->vg); | |||||
for (auto& font : window->internal->fontCache) | |||||
{ | |||||
font.second->vg = window->vg; | |||||
font.second->ohandle = font.second->handle; | |||||
font.second->handle = nvgCreateFont(window->vg, | |||||
font.second->ofilename.c_str(), font.second->ofilename.c_str()); | |||||
} | |||||
for (auto& image : window->internal->imageCache) | |||||
{ | |||||
image.second->vg = window->vg; | |||||
image.second->ohandle = image.second->handle; | |||||
image.second->handle = nvgCreateImage(window->vg, image.second->ofilename.c_str(), | |||||
NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); | |||||
} | |||||
// Init settings | |||||
WindowParametersRestore(window); | |||||
widget::Widget::ContextCreateEvent e; | |||||
APP->scene->onContextCreate(e); | |||||
} | |||||
else | |||||
{ | |||||
widget::Widget::ContextDestroyEvent e; | |||||
APP->scene->onContextDestroy(e); | |||||
// swap contexts | |||||
window->uiFont->vg = window->internal->o_vg; | |||||
window->vg = window->internal->o_vg; | |||||
window->fbVg = window->internal->o_fbVg; | |||||
window->internal->o_vg = nullptr; | |||||
window->internal->o_fbVg = nullptr; | |||||
// also for fonts and images | |||||
window->uiFont->vg = window->vg; | |||||
window->uiFont->handle = loadFallbackFont(window->vg); | |||||
for (auto& font : window->internal->fontCache) | |||||
{ | |||||
font.second->vg = window->vg; | |||||
font.second->handle = font.second->ohandle; | |||||
font.second->ohandle = -1; | |||||
} | |||||
for (auto& image : window->internal->imageCache) | |||||
{ | |||||
image.second->vg = window->vg; | |||||
image.second->handle = image.second->ohandle; | |||||
image.second->ohandle = -1; | |||||
} | |||||
#if defined NANOVG_GLES2 | |||||
nvgDeleteGLES2(window->internal->r_fbVg); | |||||
#else | |||||
nvgDeleteGL2(window->internal->r_fbVg); | |||||
#endif | |||||
window->internal->tlw = nullptr; | |||||
window->internal->callback = nullptr; | |||||
} | |||||
} | |||||
void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) | void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) | ||||
{ | { | ||||
// if nanovg context failed, init only bare minimum | // if nanovg context failed, init only bare minimum | ||||
@@ -264,6 +371,7 @@ void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) | |||||
INFO("Renderer: %s %s", vendor, renderer); | INFO("Renderer: %s %s", vendor, renderer); | ||||
INFO("OpenGL: %s", version); | INFO("OpenGL: %s", version); | ||||
window->internal->tlw = ui; | |||||
window->internal->ui = ui; | window->internal->ui = ui; | ||||
window->internal->size = rack::math::Vec(ui->getWidth(), ui->getHeight()); | window->internal->size = rack::math::Vec(ui->getWidth(), ui->getHeight()); | ||||
@@ -339,6 +447,7 @@ void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) | |||||
nvgDeleteGL2(window->internal->r_fbVg); | nvgDeleteGL2(window->internal->r_fbVg); | ||||
#endif | #endif | ||||
window->internal->tlw = nullptr; | |||||
window->internal->ui = nullptr; | window->internal->ui = nullptr; | ||||
window->internal->callback = nullptr; | window->internal->callback = nullptr; | ||||
} | } | ||||
@@ -384,8 +493,8 @@ void Window::setSize(math::Vec size) { | |||||
size = size.max(WINDOW_SIZE_MIN); | size = size.max(WINDOW_SIZE_MIN); | ||||
internal->size = size; | internal->size = size; | ||||
if (DISTRHO_NAMESPACE::UI* const ui = internal->ui) | |||||
ui->setSize(internal->size.x, internal->size.y); | |||||
if (DGL_NAMESPACE::NanoTopLevelWidget* const tlw = internal->ui) | |||||
tlw->setSize(internal->size.x, internal->size.y); | |||||
} | } | ||||
void WindowSetInternalSize(rack::window::Window* const window, math::Vec size) { | void WindowSetInternalSize(rack::window::Window* const window, math::Vec size) { | ||||
@@ -453,7 +562,7 @@ static void Window__writeImagePNG(void* context, void* data, int size) { | |||||
void Window::step() { | void Window::step() { | ||||
DISTRHO_SAFE_ASSERT_RETURN(internal->ui != nullptr,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(internal->tlw != nullptr,); | |||||
if (vg == nullptr) | if (vg == nullptr) | ||||
return; | return; | ||||
@@ -480,12 +589,12 @@ void Window::step() { | |||||
windowTitle += system::getFilename(APP->patch->path); | windowTitle += system::getFilename(APP->patch->path); | ||||
} | } | ||||
if (windowTitle != internal->lastWindowTitle) { | if (windowTitle != internal->lastWindowTitle) { | ||||
internal->ui->getWindow().setTitle(windowTitle.c_str()); | |||||
internal->tlw->getWindow().setTitle(windowTitle.c_str()); | |||||
internal->lastWindowTitle = windowTitle; | internal->lastWindowTitle = windowTitle; | ||||
} | } | ||||
// Get desired pixel ratio | // Get desired pixel ratio | ||||
float newPixelRatio = internal->ui->getScaleFactor(); | |||||
float newPixelRatio = internal->tlw->getScaleFactor(); | |||||
if (newPixelRatio != pixelRatio) { | if (newPixelRatio != pixelRatio) { | ||||
pixelRatio = newPixelRatio; | pixelRatio = newPixelRatio; | ||||
APP->event->handleDirty(); | APP->event->handleDirty(); | ||||
@@ -504,8 +613,8 @@ void Window::step() { | |||||
#endif | #endif | ||||
// Get framebuffer/window ratio | // Get framebuffer/window ratio | ||||
int winWidth = internal->ui->getWidth(); | |||||
int winHeight = internal->ui->getHeight(); | |||||
int winWidth = internal->tlw->getWidth(); | |||||
int winHeight = internal->tlw->getHeight(); | |||||
int fbWidth = winWidth;// * newPixelRatio; | int fbWidth = winWidth;// * newPixelRatio; | ||||
int fbHeight = winHeight;// * newPixelRatio; | int fbHeight = winHeight;// * newPixelRatio; | ||||
windowRatio = (float)fbWidth / winWidth; | windowRatio = (float)fbWidth / winWidth; | ||||
@@ -599,9 +708,9 @@ void Window::screenshotModules(const std::string&, float) { | |||||
void Window::close() { | void Window::close() { | ||||
DISTRHO_SAFE_ASSERT_RETURN(internal->ui != nullptr,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(internal->tlw != nullptr,); | |||||
internal->ui->getWindow().close(); | |||||
internal->tlw->getWindow().close(); | |||||
} | } | ||||
@@ -610,7 +719,7 @@ void Window::cursorLock() { | |||||
if (!settings::allowCursorLock) | if (!settings::allowCursorLock) | ||||
return; | return; | ||||
emscripten_request_pointerlock(internal->ui->getWindow().getApp().getClassName(), false); | |||||
emscripten_request_pointerlock(internal->tlw->getWindow().getApp().getClassName(), false); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -643,7 +752,7 @@ int Window::getMods() { | |||||
void Window::setFullScreen(const bool fullscreen) { | void Window::setFullScreen(const bool fullscreen) { | ||||
#ifdef DISTRHO_OS_WASM | #ifdef DISTRHO_OS_WASM | ||||
if (fullscreen) | if (fullscreen) | ||||
emscripten_request_fullscreen(internal->ui->getWindow().getApp().getClassName(), false); | |||||
emscripten_request_fullscreen(internal->tlw->getWindow().getApp().getClassName(), false); | |||||
else | else | ||||
emscripten_exit_fullscreen(); | emscripten_exit_fullscreen(); | ||||
#endif | #endif | ||||