Signed-off-by: falkTX <falktx@falktx.com>tags/23.02
@@ -1 +1 @@ | |||||
Subproject commit 564f6519b4bbf1c6cc8791a9adbb377f6cfd4984 | |||||
Subproject commit 79948069d581c64bd19bc454234550de88b459a2 |
@@ -293,6 +293,10 @@ PLUGIN_FILES += Cardinal/src/ImGuiTextEditor.cpp | |||||
PLUGIN_FILES += Cardinal/src/SassyScope.cpp | PLUGIN_FILES += Cardinal/src/SassyScope.cpp | ||||
PLUGIN_FILES += Cardinal/src/DearImGui.cpp | PLUGIN_FILES += Cardinal/src/DearImGui.cpp | ||||
PLUGIN_FILES += Cardinal/src/DearImGuiColorTextEditor.cpp | PLUGIN_FILES += Cardinal/src/DearImGuiColorTextEditor.cpp | ||||
MINIPLUGIN_FILES += Cardinal/src/ImGuiWidget.cpp | |||||
MINIPLUGIN_FILES += Cardinal/src/ImGuiTextEditor.cpp | |||||
MINIPLUGIN_FILES += Cardinal/src/DearImGui.cpp | |||||
MINIPLUGIN_FILES += Cardinal/src/DearImGuiColorTextEditor.cpp | |||||
endif | endif | ||||
ifeq ($(shell $(PKG_CONFIG) --exists fftw3f && echo true),true) | ifeq ($(shell $(PKG_CONFIG) --exists fftw3f && echo true),true) | ||||
@@ -1290,7 +1294,7 @@ endif | |||||
ifeq ($(NOPLUGINS),true) | ifeq ($(NOPLUGINS),true) | ||||
TARGETS = noplugins$(TARGET_SUFFIX).a | TARGETS = noplugins$(TARGET_SUFFIX).a | ||||
else | else | ||||
TARGETS = plugins$(TARGET_SUFFIX).a plugins-mini-headless.a | |||||
TARGETS = plugins$(TARGET_SUFFIX).a plugins-mini.a | |||||
endif | endif | ||||
all: $(TARGETS) | all: $(TARGETS) | ||||
@@ -189,6 +189,7 @@ void destroyStaticPlugins() | |||||
void updateStaticPluginsDarkMode() | void updateStaticPluginsDarkMode() | ||||
{ | { | ||||
d_stdout("TODO"); | |||||
} | } | ||||
} | } | ||||
@@ -38,6 +38,7 @@ | |||||
#include <settings.hpp> | #include <settings.hpp> | ||||
#include <string.hpp> | #include <string.hpp> | ||||
#include <system.hpp> | #include <system.hpp> | ||||
#include <app/Browser.hpp> | |||||
#include <app/Scene.hpp> | #include <app/Scene.hpp> | ||||
#include <window/Window.hpp> | #include <window/Window.hpp> | ||||
@@ -65,6 +66,27 @@ | |||||
# define HEADLESS | # define HEADLESS | ||||
#endif | #endif | ||||
#if CARDINAL_VARIANT_FX | |||||
# define CARDINAL_TEMPLATE_NAME "init/fx.vcv" | |||||
#elif CARDINAL_VARIANT_NATIVE | |||||
# define CARDINAL_TEMPLATE_NAME "init/native.vcv" | |||||
#elif CARDINAL_VARIANT_SYNTH | |||||
# define CARDINAL_TEMPLATE_NAME "init/synth.vcv" | |||||
#else | |||||
# define CARDINAL_TEMPLATE_NAME "init/main.vcv" | |||||
#endif | |||||
namespace rack { | |||||
namespace asset { | |||||
std::string patchesPath(); | |||||
void destroy(); | |||||
} | |||||
namespace plugin { | |||||
void initStaticPlugins(); | |||||
void destroyStaticPlugins(); | |||||
} | |||||
} | |||||
const std::string CARDINAL_VERSION = "22.12"; | const std::string CARDINAL_VERSION = "22.12"; | ||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
@@ -172,6 +194,284 @@ void CardinalPluginContext::writeMidiMessage(const rack::midi::Message& message, | |||||
plugin->writeMidiEvent(event); | plugin->writeMidiEvent(event); | ||||
} | } | ||||
// ----------------------------------------------------------------------------------------------------------- | |||||
#ifdef CARDINAL_INIT_OSC_THREAD | |||||
static void osc_error_handler(int num, const char* msg, const char* path) | |||||
{ | |||||
d_stderr("Cardinal OSC Error: code: %i, msg: \"%s\", path: \"%s\")", num, msg, path); | |||||
} | |||||
static int osc_fallback_handler(const char* const path, const char* const types, lo_arg**, int, lo_message, void*) | |||||
{ | |||||
d_stderr("Cardinal OSC unhandled message \"%s\" with types \"%s\"", path, types); | |||||
return 0; | |||||
} | |||||
static int osc_hello_handler(const char*, const char*, lo_arg**, int, const lo_message m, void* const self) | |||||
{ | |||||
d_stdout("osc_hello_handler()"); | |||||
const lo_address source = lo_message_get_source(m); | |||||
lo_send_from(source, static_cast<Initializer*>(self)->oscServer, LO_TT_IMMEDIATE, "/resp", "ss", "hello", "ok"); | |||||
return 0; | |||||
} | |||||
static int osc_load_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self) | |||||
{ | |||||
d_stdout("osc_load_handler()"); | |||||
DISTRHO_SAFE_ASSERT_RETURN(argc == 1, 0); | |||||
DISTRHO_SAFE_ASSERT_RETURN(types != nullptr && types[0] == 'b', 0); | |||||
const int32_t size = argv[0]->blob.size; | |||||
DISTRHO_SAFE_ASSERT_RETURN(size > 4, 0); | |||||
const uint8_t* const blob = (uint8_t*)(&argv[0]->blob.data); | |||||
DISTRHO_SAFE_ASSERT_RETURN(blob != nullptr, 0); | |||||
bool ok = false; | |||||
if (CardinalBasePlugin* const plugin = static_cast<Initializer*>(self)->oscPlugin) | |||||
{ | |||||
CardinalPluginContext* const context = plugin->context; | |||||
std::vector<uint8_t> data(size); | |||||
std::memcpy(data.data(), blob, size); | |||||
rack::contextSet(context); | |||||
rack::system::removeRecursively(context->patch->autosavePath); | |||||
rack::system::createDirectories(context->patch->autosavePath); | |||||
try { | |||||
rack::system::unarchiveToDirectory(data, context->patch->autosavePath); | |||||
context->patch->loadAutosave(); | |||||
ok = true; | |||||
} | |||||
catch (rack::Exception& e) { | |||||
WARN("%s", e.what()); | |||||
} | |||||
rack::contextSet(nullptr); | |||||
} | |||||
const lo_address source = lo_message_get_source(m); | |||||
lo_send_from(source, static_cast<Initializer*>(self)->oscServer, | |||||
LO_TT_IMMEDIATE, "/resp", "ss", "load", ok ? "ok" : "fail"); | |||||
return 0; | |||||
} | |||||
static int osc_screenshot_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self) | |||||
{ | |||||
d_stdout("osc_screenshot_handler()"); | |||||
DISTRHO_SAFE_ASSERT_RETURN(argc == 1, 0); | |||||
DISTRHO_SAFE_ASSERT_RETURN(types != nullptr && types[0] == 'b', 0); | |||||
const int32_t size = argv[0]->blob.size; | |||||
DISTRHO_SAFE_ASSERT_RETURN(size > 4, 0); | |||||
const uint8_t* const blob = (uint8_t*)(&argv[0]->blob.data); | |||||
DISTRHO_SAFE_ASSERT_RETURN(blob != nullptr, 0); | |||||
bool ok = false; | |||||
if (CardinalBasePlugin* const plugin = static_cast<Initializer*>(self)->oscPlugin) | |||||
ok = plugin->updateStateValue("screenshot", String::asBase64(blob, size).buffer()); | |||||
const lo_address source = lo_message_get_source(m); | |||||
lo_send_from(source, static_cast<Initializer*>(self)->oscServer, | |||||
LO_TT_IMMEDIATE, "/resp", "ss", "screenshot", ok ? "ok" : "fail"); | |||||
return 0; | |||||
} | |||||
#endif | |||||
Initializer::Initializer(const CardinalBasePlugin* const plugin, const CardinalBaseUI* const ui) | |||||
{ | |||||
using namespace rack; | |||||
#ifdef DISTRHO_OS_WASM | |||||
settings::allowCursorLock = true; | |||||
#else | |||||
settings::allowCursorLock = false; | |||||
#endif | |||||
settings::autoCheckUpdates = false; | |||||
settings::autosaveInterval = 0; | |||||
settings::devMode = true; | |||||
settings::isPlugin = true; | |||||
settings::skipLoadOnLaunch = true; | |||||
settings::showTipsOnLaunch = false; | |||||
settings::windowPos = math::Vec(0, 0); | |||||
#ifdef HEADLESS | |||||
settings::headless = true; | |||||
#endif | |||||
// copied from https://community.vcvrack.com/t/16-colour-cable-palette/15951 | |||||
settings::cableColors = { | |||||
color::fromHexString("#ff5252"), | |||||
color::fromHexString("#ff9352"), | |||||
color::fromHexString("#ffd452"), | |||||
color::fromHexString("#e8ff52"), | |||||
color::fromHexString("#a8ff52"), | |||||
color::fromHexString("#67ff52"), | |||||
color::fromHexString("#52ff7d"), | |||||
color::fromHexString("#52ffbe"), | |||||
color::fromHexString("#52ffff"), | |||||
color::fromHexString("#52beff"), | |||||
color::fromHexString("#527dff"), | |||||
color::fromHexString("#6752ff"), | |||||
color::fromHexString("#a852ff"), | |||||
color::fromHexString("#e952ff"), | |||||
color::fromHexString("#ff52d4"), | |||||
color::fromHexString("#ff5293"), | |||||
}; | |||||
system::init(); | |||||
logger::init(); | |||||
random::init(); | |||||
ui::init(); | |||||
if (asset::systemDir.empty()) | |||||
{ | |||||
if (const char* const bundlePath = (plugin != nullptr ? plugin->getBundlePath() : | |||||
ui != nullptr ? ui->getBundlePath() : nullptr)) | |||||
{ | |||||
if (const char* const resourcePath = getResourcePath(bundlePath)) | |||||
{ | |||||
asset::systemDir = resourcePath; | |||||
asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); | |||||
} | |||||
} | |||||
if (asset::systemDir.empty() || ! system::exists(asset::systemDir) || ! system::exists(asset::bundlePath)) | |||||
{ | |||||
#ifdef CARDINAL_PLUGIN_SOURCE_DIR | |||||
// Make system dir point to source code location as fallback | |||||
asset::systemDir = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR "Rack"; | |||||
asset::bundlePath.clear(); | |||||
// If source code dir does not exist use install target prefix as system dir | |||||
if (!system::exists(system::join(asset::systemDir, "res"))) | |||||
#endif | |||||
{ | |||||
#if defined(DISTRHO_OS_WASM) | |||||
asset::systemDir = "/resources"; | |||||
#elif defined(ARCH_MAC) | |||||
asset::systemDir = "/Library/Application Support/Cardinal"; | |||||
#elif defined(ARCH_WIN) | |||||
const std::string commonprogfiles = getSpecialPath(kSpecialPathCommonProgramFiles); | |||||
if (! commonprogfiles.empty()) | |||||
asset::systemDir = system::join(commonprogfiles, "Cardinal"); | |||||
#else | |||||
asset::systemDir = CARDINAL_PLUGIN_PREFIX "/share/cardinal"; | |||||
#endif | |||||
asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); | |||||
} | |||||
} | |||||
asset::userDir = asset::systemDir; | |||||
} | |||||
const std::string patchesPath = asset::patchesPath(); | |||||
#ifdef DISTRHO_OS_WASM | |||||
templatePath = system::join(patchesPath, CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME); | |||||
#else | |||||
templatePath = system::join(patchesPath, CARDINAL_TEMPLATE_NAME); | |||||
#endif | |||||
factoryTemplatePath = system::join(patchesPath, CARDINAL_TEMPLATE_NAME); | |||||
// Log environment | |||||
INFO("%s %s %s, compatible with Rack version %s", APP_NAME.c_str(), APP_EDITION.c_str(), CARDINAL_VERSION.c_str(), APP_VERSION.c_str()); | |||||
INFO("%s", system::getOperatingSystemInfo().c_str()); | |||||
INFO("Binary filename: %s", getBinaryFilename()); | |||||
if (plugin != nullptr) { | |||||
INFO("Bundle path: %s", plugin->getBundlePath()); | |||||
} else if (ui != nullptr) { | |||||
INFO("Bundle path: %s", ui->getBundlePath()); | |||||
} | |||||
INFO("System directory: %s", asset::systemDir.c_str()); | |||||
INFO("User directory: %s", asset::userDir.c_str()); | |||||
INFO("Template patch: %s", templatePath.c_str()); | |||||
INFO("System template patch: %s", factoryTemplatePath.c_str()); | |||||
// Report to user if something is wrong with the installation | |||||
if (asset::systemDir.empty()) | |||||
{ | |||||
d_stderr2("Failed to locate Cardinal plugin bundle.\n" | |||||
"Install Cardinal with its bundle folder intact and try again."); | |||||
} | |||||
else if (! system::exists(asset::systemDir)) | |||||
{ | |||||
d_stderr2("System directory \"%s\" does not exist.\n" | |||||
"Make sure Cardinal was downloaded and installed correctly.", asset::systemDir.c_str()); | |||||
} | |||||
INFO("Initializing plugins"); | |||||
plugin::initStaticPlugins(); | |||||
INFO("Initializing plugin browser DB"); | |||||
app::browserInit(); | |||||
#ifdef CARDINAL_INIT_OSC_THREAD | |||||
INFO("Initializing OSC Remote control"); | |||||
oscServer = lo_server_new_with_proto(REMOTE_HOST_PORT, LO_UDP, osc_error_handler); | |||||
DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr,); | |||||
lo_server_add_method(oscServer, "/hello", "", osc_hello_handler, this); | |||||
lo_server_add_method(oscServer, "/load", "b", osc_load_handler, this); | |||||
lo_server_add_method(oscServer, "/screenshot", "b", osc_screenshot_handler, this); | |||||
lo_server_add_method(oscServer, nullptr, nullptr, osc_fallback_handler, nullptr); | |||||
startThread(); | |||||
#else | |||||
INFO("OSC Remote control is not enabled in this build"); | |||||
#endif | |||||
} | |||||
Initializer::~Initializer() | |||||
{ | |||||
using namespace rack; | |||||
#ifdef CARDINAL_INIT_OSC_THREAD | |||||
if (oscServer != nullptr) | |||||
{ | |||||
stopThread(5000); | |||||
lo_server_del_method(oscServer, nullptr, nullptr); | |||||
lo_server_free(oscServer); | |||||
oscServer = nullptr; | |||||
} | |||||
#endif | |||||
INFO("Clearing asset paths"); | |||||
asset::bundlePath.clear(); | |||||
asset::systemDir.clear(); | |||||
asset::userDir.clear(); | |||||
INFO("Destroying plugins"); | |||||
plugin::destroyStaticPlugins(); | |||||
INFO("Destroying colourized assets"); | |||||
asset::destroy(); | |||||
INFO("Destroying settings"); | |||||
settings::destroy(); | |||||
INFO("Destroying logger"); | |||||
logger::destroy(); | |||||
} | |||||
#ifdef CARDINAL_INIT_OSC_THREAD | |||||
void Initializer::run() | |||||
{ | |||||
INFO("OSC Thread Listening for remote commands"); | |||||
while (! shouldThreadExit()) | |||||
{ | |||||
d_msleep(200); | |||||
while (lo_server_recv_noblock(oscServer, 0) != 0) {} | |||||
} | |||||
INFO("OSC Thread Closed"); | |||||
} | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO | ||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
@@ -15,14 +15,17 @@ | |||||
* For a full copy of the GNU General Public License see the LICENSE file. | * For a full copy of the GNU General Public License see the LICENSE file. | ||||
*/ | */ | ||||
#include <string> | |||||
#pragma once | #pragma once | ||||
#include "DistrhoUtils.hpp" | |||||
#include <string> | |||||
#ifdef HAVE_LIBLO | #ifdef HAVE_LIBLO | ||||
// # define REMOTE_HOST "localhost" | // # define REMOTE_HOST "localhost" | ||||
# define REMOTE_HOST "192.168.51.1" | # define REMOTE_HOST "192.168.51.1" | ||||
# define REMOTE_HOST_PORT "2228" | # define REMOTE_HOST_PORT "2228" | ||||
# include "extra/Thread.hpp" | |||||
#endif | #endif | ||||
#ifdef DISTRHO_OS_WASM | #ifdef DISTRHO_OS_WASM | ||||
@@ -35,6 +38,8 @@ | |||||
extern const std::string CARDINAL_VERSION; | extern const std::string CARDINAL_VERSION; | ||||
// ----------------------------------------------------------------------------------------------------------- | |||||
namespace rack { | namespace rack { | ||||
namespace ui { | namespace ui { | ||||
@@ -65,6 +70,8 @@ extern char* patchStorageSlug; | |||||
} // namespace rack | } // namespace rack | ||||
// ----------------------------------------------------------------------------------------------------------- | |||||
namespace patchUtils { | namespace patchUtils { | ||||
void loadDialog(); | void loadDialog(); | ||||
@@ -86,3 +93,37 @@ void deployToRemote(); | |||||
void sendScreenshotToRemote(const char* screenshot); | void sendScreenshotToRemote(const char* screenshot); | ||||
} // namespace patchUtils | } // namespace patchUtils | ||||
// ----------------------------------------------------------------------------------------------------------- | |||||
#if defined(HAVE_LIBLO) && defined(HEADLESS) && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
# define CARDINAL_INIT_OSC_THREAD | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | |||||
class CardinalBasePlugin; | |||||
class CardinalBaseUI; | |||||
struct Initializer | |||||
#ifdef CARDINAL_INIT_OSC_THREAD | |||||
: public Thread | |||||
#endif | |||||
{ | |||||
#ifdef CARDINAL_INIT_OSC_THREAD | |||||
lo_server oscServer = nullptr; | |||||
CardinalBasePlugin* oscPlugin = nullptr; | |||||
#endif | |||||
std::string templatePath; | |||||
std::string factoryTemplatePath; | |||||
Initializer(const CardinalBasePlugin* plugin, const CardinalBaseUI* ui); | |||||
~Initializer(); | |||||
#ifdef CARDINAL_INIT_OSC_THREAD | |||||
void run() override; | |||||
#endif | |||||
}; | |||||
END_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------------------------------------------- |
@@ -31,8 +31,8 @@ | |||||
#define DISTRHO_PLUGIN_URI "https://distrho.kx.studio/plugins/cardinal#mini" | #define DISTRHO_PLUGIN_URI "https://distrho.kx.studio/plugins/cardinal#mini" | ||||
#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.cardinal#mini" | #define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.cardinal#mini" | ||||
#define DISTRHO_PLUGIN_NAME "Cardinal FX" | |||||
#define DISTRHO_PLUGIN_LABEL "CardinalFX" | |||||
#define DISTRHO_PLUGIN_NAME "Cardinal Mini" | |||||
#define DISTRHO_PLUGIN_LABEL "CardinalMini" | |||||
#define DISTRHO_PLUGIN_HAS_UI 1 | #define DISTRHO_PLUGIN_HAS_UI 1 | ||||
#define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0 | #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0 | ||||
@@ -15,7 +15,6 @@ | |||||
* For a full copy of the GNU General Public License see the LICENSE file. | * For a full copy of the GNU General Public License see the LICENSE file. | ||||
*/ | */ | ||||
#include <asset.hpp> | |||||
#include <library.hpp> | #include <library.hpp> | ||||
#include <midi.hpp> | #include <midi.hpp> | ||||
#include <patch.hpp> | #include <patch.hpp> | ||||
@@ -24,7 +23,6 @@ | |||||
#include <settings.hpp> | #include <settings.hpp> | ||||
#include <system.hpp> | #include <system.hpp> | ||||
#include <app/Browser.hpp> | |||||
#include <app/Scene.hpp> | #include <app/Scene.hpp> | ||||
#include <engine/Engine.hpp> | #include <engine/Engine.hpp> | ||||
#include <ui/common.hpp> | #include <ui/common.hpp> | ||||
@@ -52,16 +50,6 @@ | |||||
# include "extra/SharedResourcePointer.hpp" | # include "extra/SharedResourcePointer.hpp" | ||||
#endif | #endif | ||||
#if CARDINAL_VARIANT_FX | |||||
# define CARDINAL_TEMPLATE_NAME "init/fx.vcv" | |||||
#elif CARDINAL_VARIANT_NATIVE | |||||
# define CARDINAL_TEMPLATE_NAME "init/native.vcv" | |||||
#elif CARDINAL_VARIANT_SYNTH | |||||
# define CARDINAL_TEMPLATE_NAME "init/synth.vcv" | |||||
#else | |||||
# define CARDINAL_TEMPLATE_NAME "init/main.vcv" | |||||
#endif | |||||
static const constexpr uint kCardinalStateBaseCount = 3; // patch, screenshot, comment | static const constexpr uint kCardinalStateBaseCount = 3; // patch, screenshot, comment | ||||
#ifndef HEADLESS | #ifndef HEADLESS | ||||
@@ -76,17 +64,9 @@ static const constexpr uint kCardinalStateCount = kCardinalStateBaseCount; | |||||
extern const std::string CARDINAL_VERSION; | extern const std::string CARDINAL_VERSION; | ||||
namespace rack { | namespace rack { | ||||
namespace asset { | |||||
std::string patchesPath(); | |||||
void destroy(); | |||||
} | |||||
namespace engine { | namespace engine { | ||||
void Engine_setAboutToClose(Engine*); | void Engine_setAboutToClose(Engine*); | ||||
} | } | ||||
namespace plugin { | |||||
void initStaticPlugins(); | |||||
void destroyStaticPlugins(); | |||||
} | |||||
} | } | ||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
@@ -98,6 +78,10 @@ bool d_isDiffHigherThanLimit(const T& v1, const T& v2, const T& limit) | |||||
return v1 != v2 ? (v1 > v2 ? v1 - v2 : v2 - v1) > limit : false; | return v1 != v2 ? (v1 > v2 ? v1 - v2 : v2 - v1) > limit : false; | ||||
} | } | ||||
#if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
const char* UI::getBundlePath() const noexcept { return nullptr; } | |||||
#endif | |||||
// ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
#ifdef DISTRHO_OS_WASM | #ifdef DISTRHO_OS_WASM | ||||
@@ -143,288 +127,6 @@ static char* getPatchStorageSlug() { | |||||
// ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
struct Initializer | |||||
#if defined(HAVE_LIBLO) && defined(HEADLESS) | |||||
: public Thread | |||||
#endif | |||||
{ | |||||
#if defined(HAVE_LIBLO) && defined(HEADLESS) | |||||
lo_server oscServer = nullptr; | |||||
CardinalBasePlugin* oscPlugin = nullptr; | |||||
#endif | |||||
std::string templatePath; | |||||
std::string factoryTemplatePath; | |||||
Initializer(const CardinalBasePlugin* const plugin) | |||||
{ | |||||
using namespace rack; | |||||
#ifdef DISTRHO_OS_WASM | |||||
settings::allowCursorLock = true; | |||||
#else | |||||
settings::allowCursorLock = false; | |||||
#endif | |||||
settings::autoCheckUpdates = false; | |||||
settings::autosaveInterval = 0; | |||||
settings::devMode = true; | |||||
settings::isPlugin = true; | |||||
settings::skipLoadOnLaunch = true; | |||||
settings::showTipsOnLaunch = false; | |||||
settings::windowPos = math::Vec(0, 0); | |||||
#ifdef HEADLESS | |||||
settings::headless = true; | |||||
#endif | |||||
// copied from https://community.vcvrack.com/t/16-colour-cable-palette/15951 | |||||
settings::cableColors = { | |||||
color::fromHexString("#ff5252"), | |||||
color::fromHexString("#ff9352"), | |||||
color::fromHexString("#ffd452"), | |||||
color::fromHexString("#e8ff52"), | |||||
color::fromHexString("#a8ff52"), | |||||
color::fromHexString("#67ff52"), | |||||
color::fromHexString("#52ff7d"), | |||||
color::fromHexString("#52ffbe"), | |||||
color::fromHexString("#52ffff"), | |||||
color::fromHexString("#52beff"), | |||||
color::fromHexString("#527dff"), | |||||
color::fromHexString("#6752ff"), | |||||
color::fromHexString("#a852ff"), | |||||
color::fromHexString("#e952ff"), | |||||
color::fromHexString("#ff52d4"), | |||||
color::fromHexString("#ff5293"), | |||||
}; | |||||
system::init(); | |||||
logger::init(); | |||||
random::init(); | |||||
ui::init(); | |||||
if (asset::systemDir.empty()) | |||||
{ | |||||
if (const char* const bundlePath = plugin->getBundlePath()) | |||||
{ | |||||
if (const char* const resourcePath = getResourcePath(bundlePath)) | |||||
{ | |||||
asset::systemDir = resourcePath; | |||||
asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); | |||||
} | |||||
} | |||||
if (asset::systemDir.empty() || ! system::exists(asset::systemDir) || ! system::exists(asset::bundlePath)) | |||||
{ | |||||
#ifdef CARDINAL_PLUGIN_SOURCE_DIR | |||||
// Make system dir point to source code location as fallback | |||||
asset::systemDir = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR "Rack"; | |||||
asset::bundlePath.clear(); | |||||
// If source code dir does not exist use install target prefix as system dir | |||||
if (!system::exists(system::join(asset::systemDir, "res"))) | |||||
#endif | |||||
{ | |||||
#if defined(DISTRHO_OS_WASM) | |||||
asset::systemDir = "/resources"; | |||||
#elif defined(ARCH_MAC) | |||||
asset::systemDir = "/Library/Application Support/Cardinal"; | |||||
#elif defined(ARCH_WIN) | |||||
const std::string commonprogfiles = getSpecialPath(kSpecialPathCommonProgramFiles); | |||||
if (! commonprogfiles.empty()) | |||||
asset::systemDir = system::join(commonprogfiles, "Cardinal"); | |||||
#else | |||||
asset::systemDir = CARDINAL_PLUGIN_PREFIX "/share/cardinal"; | |||||
#endif | |||||
asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); | |||||
} | |||||
} | |||||
asset::userDir = asset::systemDir; | |||||
} | |||||
const std::string patchesPath = asset::patchesPath(); | |||||
#ifdef DISTRHO_OS_WASM | |||||
templatePath = system::join(patchesPath, CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME); | |||||
#else | |||||
templatePath = system::join(patchesPath, CARDINAL_TEMPLATE_NAME); | |||||
#endif | |||||
factoryTemplatePath = system::join(patchesPath, CARDINAL_TEMPLATE_NAME); | |||||
// Log environment | |||||
INFO("%s %s %s, compatible with Rack version %s", APP_NAME.c_str(), APP_EDITION.c_str(), CARDINAL_VERSION.c_str(), APP_VERSION.c_str()); | |||||
INFO("%s", system::getOperatingSystemInfo().c_str()); | |||||
INFO("Binary filename: %s", getBinaryFilename()); | |||||
INFO("Bundle path: %s", plugin->getBundlePath()); | |||||
INFO("System directory: %s", asset::systemDir.c_str()); | |||||
INFO("User directory: %s", asset::userDir.c_str()); | |||||
INFO("Template patch: %s", templatePath.c_str()); | |||||
INFO("System template patch: %s", factoryTemplatePath.c_str()); | |||||
// Report to user if something is wrong with the installation | |||||
if (asset::systemDir.empty()) | |||||
{ | |||||
d_stderr2("Failed to locate Cardinal plugin bundle.\n" | |||||
"Install Cardinal with its bundle folder intact and try again."); | |||||
} | |||||
else if (! system::exists(asset::systemDir)) | |||||
{ | |||||
d_stderr2("System directory \"%s\" does not exist.\n" | |||||
"Make sure Cardinal was downloaded and installed correctly.", asset::systemDir.c_str()); | |||||
} | |||||
INFO("Initializing plugins"); | |||||
plugin::initStaticPlugins(); | |||||
INFO("Initializing plugin browser DB"); | |||||
app::browserInit(); | |||||
#if defined(HAVE_LIBLO) && defined(HEADLESS) | |||||
INFO("Initializing OSC Remote control"); | |||||
oscServer = lo_server_new_with_proto(REMOTE_HOST_PORT, LO_UDP, osc_error_handler); | |||||
DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr,); | |||||
lo_server_add_method(oscServer, "/hello", "", osc_hello_handler, this); | |||||
lo_server_add_method(oscServer, "/load", "b", osc_load_handler, this); | |||||
lo_server_add_method(oscServer, "/screenshot", "b", osc_screenshot_handler, this); | |||||
lo_server_add_method(oscServer, nullptr, nullptr, osc_fallback_handler, nullptr); | |||||
startThread(); | |||||
#elif defined(HEADLESS) | |||||
INFO("OSC Remote control is not enabled in this build"); | |||||
#endif | |||||
} | |||||
~Initializer() | |||||
{ | |||||
using namespace rack; | |||||
#if defined(HAVE_LIBLO) && defined(HEADLESS) | |||||
if (oscServer != nullptr) | |||||
{ | |||||
stopThread(5000); | |||||
lo_server_del_method(oscServer, nullptr, nullptr); | |||||
lo_server_free(oscServer); | |||||
oscServer = nullptr; | |||||
} | |||||
#endif | |||||
INFO("Clearing asset paths"); | |||||
asset::bundlePath.clear(); | |||||
asset::systemDir.clear(); | |||||
asset::userDir.clear(); | |||||
INFO("Destroying plugins"); | |||||
plugin::destroyStaticPlugins(); | |||||
INFO("Destroying colourized assets"); | |||||
asset::destroy(); | |||||
INFO("Destroying settings"); | |||||
settings::destroy(); | |||||
INFO("Destroying logger"); | |||||
logger::destroy(); | |||||
} | |||||
#if defined(HAVE_LIBLO) && defined(HEADLESS) | |||||
void run() override | |||||
{ | |||||
INFO("OSC Thread Listening for remote commands"); | |||||
while (! shouldThreadExit()) | |||||
{ | |||||
d_msleep(200); | |||||
while (lo_server_recv_noblock(oscServer, 0) != 0) {} | |||||
} | |||||
INFO("OSC Thread Closed"); | |||||
} | |||||
static void osc_error_handler(int num, const char* msg, const char* path) | |||||
{ | |||||
d_stderr("Cardinal OSC Error: code: %i, msg: \"%s\", path: \"%s\")", num, msg, path); | |||||
} | |||||
static int osc_fallback_handler(const char* const path, const char* const types, lo_arg**, int, lo_message, void*) | |||||
{ | |||||
d_stderr("Cardinal OSC unhandled message \"%s\" with types \"%s\"", path, types); | |||||
return 0; | |||||
} | |||||
static int osc_hello_handler(const char*, const char*, lo_arg**, int, const lo_message m, void* const self) | |||||
{ | |||||
d_stdout("osc_hello_handler()"); | |||||
const lo_address source = lo_message_get_source(m); | |||||
lo_send_from(source, static_cast<Initializer*>(self)->oscServer, LO_TT_IMMEDIATE, "/resp", "ss", "hello", "ok"); | |||||
return 0; | |||||
} | |||||
static int osc_load_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self) | |||||
{ | |||||
d_stdout("osc_load_handler()"); | |||||
DISTRHO_SAFE_ASSERT_RETURN(argc == 1, 0); | |||||
DISTRHO_SAFE_ASSERT_RETURN(types != nullptr && types[0] == 'b', 0); | |||||
const int32_t size = argv[0]->blob.size; | |||||
DISTRHO_SAFE_ASSERT_RETURN(size > 4, 0); | |||||
const uint8_t* const blob = (uint8_t*)(&argv[0]->blob.data); | |||||
DISTRHO_SAFE_ASSERT_RETURN(blob != nullptr, 0); | |||||
bool ok = false; | |||||
if (CardinalBasePlugin* const plugin = static_cast<Initializer*>(self)->oscPlugin) | |||||
{ | |||||
CardinalPluginContext* const context = plugin->context; | |||||
std::vector<uint8_t> data(size); | |||||
std::memcpy(data.data(), blob, size); | |||||
rack::contextSet(context); | |||||
rack::system::removeRecursively(context->patch->autosavePath); | |||||
rack::system::createDirectories(context->patch->autosavePath); | |||||
try { | |||||
rack::system::unarchiveToDirectory(data, context->patch->autosavePath); | |||||
context->patch->loadAutosave(); | |||||
ok = true; | |||||
} | |||||
catch (rack::Exception& e) { | |||||
WARN("%s", e.what()); | |||||
} | |||||
rack::contextSet(nullptr); | |||||
} | |||||
const lo_address source = lo_message_get_source(m); | |||||
lo_send_from(source, static_cast<Initializer*>(self)->oscServer, | |||||
LO_TT_IMMEDIATE, "/resp", "ss", "load", ok ? "ok" : "fail"); | |||||
return 0; | |||||
} | |||||
static int osc_screenshot_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self) | |||||
{ | |||||
d_stdout("osc_screenshot_handler()"); | |||||
DISTRHO_SAFE_ASSERT_RETURN(argc == 1, 0); | |||||
DISTRHO_SAFE_ASSERT_RETURN(types != nullptr && types[0] == 'b', 0); | |||||
const int32_t size = argv[0]->blob.size; | |||||
DISTRHO_SAFE_ASSERT_RETURN(size > 4, 0); | |||||
const uint8_t* const blob = (uint8_t*)(&argv[0]->blob.data); | |||||
DISTRHO_SAFE_ASSERT_RETURN(blob != nullptr, 0); | |||||
bool ok = false; | |||||
if (CardinalBasePlugin* const plugin = static_cast<Initializer*>(self)->oscPlugin) | |||||
ok = plugin->updateStateValue("screenshot", String::asBase64(blob, size).buffer()); | |||||
const lo_address source = lo_message_get_source(m); | |||||
lo_send_from(source, static_cast<Initializer*>(self)->oscServer, | |||||
LO_TT_IMMEDIATE, "/resp", "ss", "screenshot", ok ? "ok" : "fail"); | |||||
return 0; | |||||
} | |||||
#endif | |||||
}; | |||||
// ----------------------------------------------------------------------------------------------------------- | |||||
struct ScopedContext { | struct ScopedContext { | ||||
ScopedContext(const CardinalBasePlugin* const plugin) | ScopedContext(const CardinalBasePlugin* const plugin) | ||||
{ | { | ||||
@@ -479,9 +181,9 @@ public: | |||||
CardinalPlugin() | CardinalPlugin() | ||||
: CardinalBasePlugin(kModuleParameters + kWindowParameterCount + 1, 0, kCardinalStateCount), | : CardinalBasePlugin(kModuleParameters + kWindowParameterCount + 1, 0, kCardinalStateCount), | ||||
#ifdef DISTRHO_OS_WASM | #ifdef DISTRHO_OS_WASM | ||||
fInitializer(new Initializer(this)), | |||||
fInitializer(new Initializer(this, static_cast<const CardinalBaseUI*>(nullptr))), | |||||
#else | #else | ||||
fInitializer(this), | |||||
fInitializer(this, static_cast<const CardinalBaseUI*>(nullptr)), | |||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_NUM_INPUTS != 0 | #if DISTRHO_PLUGIN_NUM_INPUTS != 0 | ||||
fAudioBufferCopy(nullptr), | fAudioBufferCopy(nullptr), | ||||
@@ -571,14 +273,14 @@ public: | |||||
context->patch->templatePath = context->patch->factoryTemplatePath; | context->patch->templatePath = context->patch->factoryTemplatePath; | ||||
} | } | ||||
#if defined(HAVE_LIBLO) && defined(HEADLESS) | |||||
#ifdef CARDINAL_INIT_OSC_THREAD | |||||
fInitializer->oscPlugin = this; | fInitializer->oscPlugin = this; | ||||
#endif | #endif | ||||
} | } | ||||
~CardinalPlugin() override | ~CardinalPlugin() override | ||||
{ | { | ||||
#if defined(HAVE_LIBLO) && defined(HEADLESS) | |||||
#ifdef CARDINAL_INIT_OSC_THREAD | |||||
fInitializer->oscPlugin = nullptr; | fInitializer->oscPlugin = nullptr; | ||||
#endif | #endif | ||||
@@ -39,7 +39,6 @@ | |||||
# include <ui/Label.hpp> | # include <ui/Label.hpp> | ||||
# include <ui/MenuOverlay.hpp> | # include <ui/MenuOverlay.hpp> | ||||
# include <ui/SequentialLayout.hpp> | # include <ui/SequentialLayout.hpp> | ||||
# include "CardinalCommon.hpp" | |||||
# include <emscripten/emscripten.h> | # include <emscripten/emscripten.h> | ||||
#endif | #endif | ||||
@@ -47,15 +46,27 @@ | |||||
# undef DEBUG | # undef DEBUG | ||||
#endif | #endif | ||||
#include <Application.hpp> | |||||
#include "Application.hpp" | |||||
#include "AsyncDialog.hpp" | #include "AsyncDialog.hpp" | ||||
#include "CardinalCommon.hpp" | |||||
#include "PluginContext.hpp" | #include "PluginContext.hpp" | ||||
#include "WindowParameters.hpp" | #include "WindowParameters.hpp" | ||||
#ifndef DISTRHO_OS_WASM | |||||
# include "extra/SharedResourcePointer.hpp" | |||||
#endif | |||||
#ifndef HEADLESS | |||||
# include "extra/ScopedValueSetter.hpp" | |||||
#endif | |||||
namespace rack { | namespace rack { | ||||
namespace app { | namespace app { | ||||
widget::Widget* createMenuBar(bool isStandalone); | widget::Widget* createMenuBar(bool isStandalone); | ||||
} | } | ||||
namespace engine { | |||||
void Engine_setAboutToClose(Engine*); | |||||
} | |||||
namespace window { | namespace window { | ||||
void WindowSetPluginUI(Window* window, DISTRHO_NAMESPACE::UI* ui); | void WindowSetPluginUI(Window* window, DISTRHO_NAMESPACE::UI* ui); | ||||
void WindowSetMods(Window* window, int mods); | void WindowSetMods(Window* window, int mods); | ||||
@@ -65,7 +76,14 @@ namespace window { | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
// ----------------------------------------------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
const char* Plugin::getBundlePath() const noexcept { return nullptr; } | |||||
bool Plugin::writeMidiEvent(const MidiEvent&) noexcept { return false; } | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#ifdef DISTRHO_OS_WASM | #ifdef DISTRHO_OS_WASM | ||||
struct WasmWelcomeDialog : rack::widget::OpaqueWidget | struct WasmWelcomeDialog : rack::widget::OpaqueWidget | ||||
@@ -268,6 +286,15 @@ static void downloadRemotePatchSucceeded(const char* const filename) | |||||
class CardinalUI : public CardinalBaseUI, | class CardinalUI : public CardinalBaseUI, | ||||
public WindowParametersCallback | public WindowParametersCallback | ||||
{ | { | ||||
#if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
#ifdef DISTRHO_OS_WASM | |||||
ScopedPointer<Initializer> fInitializer; | |||||
#else | |||||
SharedResourcePointer<Initializer> fInitializer; | |||||
#endif | |||||
std::string fAutosavePath; | |||||
#endif | |||||
rack::math::Vec lastMousePos; | rack::math::Vec lastMousePos; | ||||
WindowParameters windowParameters; | WindowParameters windowParameters; | ||||
int rateLimitStep = 0; | int rateLimitStep = 0; | ||||
@@ -305,8 +332,65 @@ class CardinalUI : public CardinalBaseUI, | |||||
public: | public: | ||||
CardinalUI() | CardinalUI() | ||||
: CardinalBaseUI(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT) | |||||
: CardinalBaseUI(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT), | |||||
#if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
#ifdef DISTRHO_OS_WASM | |||||
fInitializer(new Initializer(static_cast<const CardinalBasePlugin*>(nullptr), this)), | |||||
#else | |||||
fInitializer(static_cast<const CardinalBasePlugin*>(nullptr), this), | |||||
#endif | |||||
#endif | |||||
lastMousePos() | |||||
{ | { | ||||
rack::contextSet(context); | |||||
#if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
// create unique temporary path for this instance | |||||
try { | |||||
char uidBuf[24]; | |||||
const std::string tmp = rack::system::getTempDirectory(); | |||||
for (int i=1;; ++i) | |||||
{ | |||||
std::snprintf(uidBuf, sizeof(uidBuf), "Cardinal.%04d", i); | |||||
const std::string trypath = rack::system::join(tmp, uidBuf); | |||||
if (! rack::system::exists(trypath)) | |||||
{ | |||||
if (rack::system::createDirectories(trypath)) | |||||
fAutosavePath = trypath; | |||||
break; | |||||
} | |||||
} | |||||
} DISTRHO_SAFE_EXCEPTION("create unique temporary path"); | |||||
const float sampleRate = getSampleRate(); | |||||
rack::settings::sampleRate = sampleRate; | |||||
context->bufferSize = 128; | |||||
context->sampleRate = sampleRate; | |||||
context->engine = new rack::engine::Engine; | |||||
context->engine->setSampleRate(sampleRate); | |||||
context->history = new rack::history::State; | |||||
context->patch = new rack::patch::Manager; | |||||
context->patch->autosavePath = fAutosavePath; | |||||
context->patch->templatePath = fInitializer->templatePath; | |||||
context->patch->factoryTemplatePath = fInitializer->factoryTemplatePath; | |||||
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(); | |||||
// swap to factory template after first load | |||||
context->patch->templatePath = context->patch->factoryTemplatePath; | |||||
#endif | |||||
Window& window(getWindow()); | Window& window(getWindow()); | ||||
window.setIgnoringKeyRepeat(true); | window.setIgnoringKeyRepeat(true); | ||||
@@ -319,8 +403,6 @@ public: | |||||
if (scaleFactor != 1.0) | if (scaleFactor != 1.0) | ||||
setSize(DISTRHO_UI_DEFAULT_WIDTH * scaleFactor, DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor); | setSize(DISTRHO_UI_DEFAULT_WIDTH * scaleFactor, DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor); | ||||
rack::contextSet(context); | |||||
rack::window::WindowSetPluginUI(context->window, this); | rack::window::WindowSetPluginUI(context->window, this); | ||||
if (rack::widget::Widget* const menuBar = context->scene->menuBar) | if (rack::widget::Widget* const menuBar = context->scene->menuBar) | ||||
@@ -408,6 +490,23 @@ public: | |||||
rack::window::WindowSetPluginUI(context->window, nullptr); | rack::window::WindowSetPluginUI(context->window, nullptr); | ||||
#if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
{ | |||||
const ScopedContext sc(this); | |||||
context->patch->clear(); | |||||
// do a little dance to prevent context scene deletion from saving to temp dir | |||||
#ifndef HEADLESS | |||||
const ScopedValueSetter<bool> svs(rack::settings::headless, true); | |||||
#endif | |||||
Engine_setAboutToClose(context->engine); | |||||
delete context; | |||||
} | |||||
if (! fAutosavePath.empty()) | |||||
rack::system::removeRecursively(fAutosavePath); | |||||
#endif | |||||
rack::contextSet(nullptr); | rack::contextSet(nullptr); | ||||
} | } | ||||
@@ -201,8 +201,10 @@ endif | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# Setup resources | # Setup resources | ||||
CORE_RESOURCES = patches | |||||
CORE_RESOURCES += $(subst ../Rack/res/,,$(wildcard ../Rack/res/ComponentLibrary/*.svg ../Rack/res/fonts/*.ttf)) | |||||
CORE_RESOURCES = $(subst ../Rack/res/,,$(wildcard ../Rack/res/ComponentLibrary/*.svg ../Rack/res/fonts/*.ttf)) | |||||
# ifneq ($(CARDINAL_VARIANT),mini) | |||||
CORE_RESOURCES += patches | |||||
# endif | |||||
LV2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).lv2/resources/%) | LV2_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).lv2/resources/%) | ||||
VST3_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst3/Contents/Resources/%) | VST3_RESOURCES = $(CORE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst3/Contents/Resources/%) | ||||
@@ -243,15 +245,19 @@ endif | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# mini variant UI | # mini variant UI | ||||
# ifeq ($(CARDINAL_VARIANT),mini) | |||||
# ifneq ($(HEADLESS)$(MOD_BUILD),true) | |||||
# FILES_UI = CardinalUI.cpp | |||||
# FILES_UI += glfw.cpp | |||||
# FILES_UI += Window.cpp | |||||
# EXTRA_UI_DEPENDENCIES = $(subst -headless,,$(EXTRA_DSP_DEPENDENCIES)) | |||||
# EXTRA_UI_LIBS = $(subst -headless,,$(EXTRA_DSP_LIBS)) | |||||
# endif | |||||
# endif | |||||
ifeq ($(CARDINAL_VARIANT),mini) | |||||
ifneq ($(HEADLESS)$(MOD_BUILD),true) | |||||
FILES_UI = CardinalUI.cpp | |||||
FILES_UI += CardinalCommon.cpp | |||||
FILES_UI += common.cpp | |||||
FILES_UI += glfw.cpp | |||||
FILES_UI += Window.cpp | |||||
EXTRA_UI_DEPENDENCIES = $(subst -headless,,$(EXTRA_DSP_DEPENDENCIES)) | |||||
EXTRA_UI_LIBS = -Wl,--start-group | |||||
EXTRA_UI_LIBS += $(subst -headless,,$(EXTRA_DSP_LIBS)) | |||||
EXTRA_UI_LIBS += -Wl,--end-group | |||||
endif | |||||
endif | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# Do some magic | # Do some magic | ||||
@@ -467,6 +473,7 @@ endif | |||||
all: $(TARGETS) | all: $(TARGETS) | ||||
lv2: $(LV2_RESOURCES) | lv2: $(LV2_RESOURCES) | ||||
lv2_sep: $(LV2_RESOURCES) | |||||
vst2: $(VST2_RESOURCES) | vst2: $(VST2_RESOURCES) | ||||
vst3: $(VST3_RESOURCES) | vst3: $(VST3_RESOURCES) | ||||
clap: $(CLAP_RESOURCES) | clap: $(CLAP_RESOURCES) | ||||
@@ -189,9 +189,6 @@ public: | |||||
context->tlw = nullptr; | context->tlw = nullptr; | ||||
context->ui = nullptr; | context->ui = nullptr; | ||||
#if !DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
delete context; | |||||
#endif | |||||
} | } | ||||
}; | }; | ||||
#endif | #endif | ||||
@@ -107,6 +107,13 @@ public: | |||||
initialise_variant<T>(variant); | initialise_variant<T>(variant); | ||||
} | } | ||||
template<class T1, class T2> | |||||
SharedResourcePointer(const T1* const v1, const T2* const v2) | |||||
: sharedObject(nullptr) | |||||
{ | |||||
initialise_variant2<T1, T2>(v1, v2); | |||||
} | |||||
SharedResourcePointer (const SharedResourcePointer&) | SharedResourcePointer (const SharedResourcePointer&) | ||||
: sharedObject(nullptr) | : sharedObject(nullptr) | ||||
{ | { | ||||
@@ -179,6 +186,18 @@ private: | |||||
sharedObject = holder.sharedInstance; | sharedObject = holder.sharedInstance; | ||||
} | } | ||||
template<class T1, class T2> | |||||
void initialise_variant2(const T1* const v1, const T2* const v2) | |||||
{ | |||||
SharedObjectHolder& holder = getSharedObjectHolder(); | |||||
const SpinLock::ScopedLockType sl (holder.lock); | |||||
if (++(holder.refCount) == 1) | |||||
holder.sharedInstance = new SharedObjectType(v1, v2); | |||||
sharedObject = holder.sharedInstance; | |||||
} | |||||
// There's no need to assign to a SharedResourcePointer because every | // There's no need to assign to a SharedResourcePointer because every | ||||
// instance of the class is exactly the same! | // instance of the class is exactly the same! | ||||
SharedResourcePointer& operator= (const SharedResourcePointer&) = delete; | SharedResourcePointer& operator= (const SharedResourcePointer&) = delete; | ||||
@@ -56,6 +56,7 @@ | |||||
#include "Application.hpp" | #include "Application.hpp" | ||||
#include "extra/String.hpp" | #include "extra/String.hpp" | ||||
#include "../CardinalCommon.hpp" | #include "../CardinalCommon.hpp" | ||||
#include "../PluginContext.hpp" | |||||
#include "../WindowParameters.hpp" | #include "../WindowParameters.hpp" | ||||
#ifndef DGL_NO_SHARED_RESOURCES | #ifndef DGL_NO_SHARED_RESOURCES | ||||
@@ -148,12 +149,14 @@ struct Window::Internal { | |||||
DGL_NAMESPACE::NanoTopLevelWidget* tlw = nullptr; | DGL_NAMESPACE::NanoTopLevelWidget* tlw = nullptr; | ||||
DISTRHO_NAMESPACE::WindowParameters params; | DISTRHO_NAMESPACE::WindowParameters params; | ||||
DISTRHO_NAMESPACE::WindowParametersCallback* callback = nullptr; | DISTRHO_NAMESPACE::WindowParametersCallback* callback = nullptr; | ||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
DGL_NAMESPACE::Application hiddenApp; | DGL_NAMESPACE::Application hiddenApp; | ||||
DGL_NAMESPACE::Window hiddenWindow; | DGL_NAMESPACE::Window hiddenWindow; | ||||
NVGcontext* r_vg = nullptr; | NVGcontext* r_vg = nullptr; | ||||
NVGcontext* r_fbVg = nullptr; | NVGcontext* r_fbVg = nullptr; | ||||
NVGcontext* o_vg = nullptr; | NVGcontext* o_vg = nullptr; | ||||
NVGcontext* o_fbVg = nullptr; | NVGcontext* o_fbVg = nullptr; | ||||
#endif | |||||
math::Vec size = WINDOW_SIZE_MIN; | math::Vec size = WINDOW_SIZE_MIN; | ||||
@@ -176,12 +179,16 @@ struct Window::Internal { | |||||
int fbCount = 0; | int fbCount = 0; | ||||
Internal() | Internal() | ||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
: hiddenApp(false), | : hiddenApp(false), | ||||
hiddenWindow(hiddenApp) | hiddenWindow(hiddenApp) | ||||
{ | { | ||||
hiddenWindow.setIgnoringKeyRepeat(true); | hiddenWindow.setIgnoringKeyRepeat(true); | ||||
hiddenApp.idle(); | hiddenApp.idle(); | ||||
} | } | ||||
#else | |||||
{} | |||||
#endif | |||||
}; | }; | ||||
@@ -203,12 +210,17 @@ static int loadFallbackFont(NVGcontext* const vg) | |||||
Window::Window() { | Window::Window() { | ||||
internal = new Internal; | internal = new Internal; | ||||
DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); | |||||
// Set up NanoVG | // Set up NanoVG | ||||
const int nvgFlags = NVG_ANTIALIAS; | const int nvgFlags = NVG_ANTIALIAS; | ||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); | |||||
vg = nvgCreateGL(nvgFlags); | vg = nvgCreateGL(nvgFlags); | ||||
#else | |||||
vg = static_cast<CardinalPluginContext*>(APP)->tlw->getContext(); | |||||
#endif | |||||
DISTRHO_SAFE_ASSERT_RETURN(vg != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(vg != nullptr,); | ||||
#ifdef NANOVG_GLES2 | #ifdef NANOVG_GLES2 | ||||
fbVg = nvgCreateSharedGLES2(vg, nvgFlags); | fbVg = nvgCreateSharedGLES2(vg, nvgFlags); | ||||
#else | #else | ||||
@@ -268,6 +280,7 @@ void WindowSetPluginRemote(Window* const window, NanoTopLevelWidget* const tlw) | |||||
window->internal->tlw = tlw; | window->internal->tlw = tlw; | ||||
window->internal->size = rack::math::Vec(tlw->getWidth(), tlw->getHeight()); | window->internal->size = rack::math::Vec(tlw->getWidth(), tlw->getHeight()); | ||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
// Set up NanoVG | // Set up NanoVG | ||||
window->internal->r_vg = tlw->getContext(); | window->internal->r_vg = tlw->getContext(); | ||||
#ifdef NANOVG_GLES2 | #ifdef NANOVG_GLES2 | ||||
@@ -299,6 +312,7 @@ void WindowSetPluginRemote(Window* const window, NanoTopLevelWidget* const tlw) | |||||
image.second->handle = nvgCreateImage(window->vg, image.second->ofilename.c_str(), | image.second->handle = nvgCreateImage(window->vg, image.second->ofilename.c_str(), | ||||
NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); | NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); | ||||
} | } | ||||
#endif | |||||
// Init settings | // Init settings | ||||
WindowParametersRestore(window); | WindowParametersRestore(window); | ||||
@@ -311,6 +325,7 @@ void WindowSetPluginRemote(Window* const window, NanoTopLevelWidget* const tlw) | |||||
widget::Widget::ContextDestroyEvent e; | widget::Widget::ContextDestroyEvent e; | ||||
APP->scene->onContextDestroy(e); | APP->scene->onContextDestroy(e); | ||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
// swap contexts | // swap contexts | ||||
window->uiFont->vg = window->internal->o_vg; | window->uiFont->vg = window->internal->o_vg; | ||||
window->vg = window->internal->o_vg; | window->vg = window->internal->o_vg; | ||||
@@ -338,6 +353,7 @@ void WindowSetPluginRemote(Window* const window, NanoTopLevelWidget* const tlw) | |||||
nvgDeleteGLES2(window->internal->r_fbVg); | nvgDeleteGLES2(window->internal->r_fbVg); | ||||
#else | #else | ||||
nvgDeleteGL2(window->internal->r_fbVg); | nvgDeleteGL2(window->internal->r_fbVg); | ||||
#endif | |||||
#endif | #endif | ||||
window->internal->tlw = nullptr; | window->internal->tlw = nullptr; | ||||
@@ -375,6 +391,7 @@ void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const 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()); | ||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
// Set up NanoVG | // Set up NanoVG | ||||
window->internal->r_vg = ui->getContext(); | window->internal->r_vg = ui->getContext(); | ||||
#ifdef NANOVG_GLES2 | #ifdef NANOVG_GLES2 | ||||
@@ -406,6 +423,7 @@ void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) | |||||
image.second->handle = nvgCreateImage(window->vg, image.second->ofilename.c_str(), | image.second->handle = nvgCreateImage(window->vg, image.second->ofilename.c_str(), | ||||
NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); | NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); | ||||
} | } | ||||
#endif | |||||
// Init settings | // Init settings | ||||
WindowParametersRestore(window); | WindowParametersRestore(window); | ||||
@@ -418,6 +436,7 @@ void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) | |||||
widget::Widget::ContextDestroyEvent e; | widget::Widget::ContextDestroyEvent e; | ||||
APP->scene->onContextDestroy(e); | APP->scene->onContextDestroy(e); | ||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
// swap contexts | // swap contexts | ||||
window->uiFont->vg = window->internal->o_vg; | window->uiFont->vg = window->internal->o_vg; | ||||
window->vg = window->internal->o_vg; | window->vg = window->internal->o_vg; | ||||
@@ -445,6 +464,7 @@ void WindowSetPluginUI(Window* const window, DISTRHO_NAMESPACE::UI* const ui) | |||||
nvgDeleteGLES2(window->internal->r_fbVg); | nvgDeleteGLES2(window->internal->r_fbVg); | ||||
#else | #else | ||||
nvgDeleteGL2(window->internal->r_fbVg); | nvgDeleteGL2(window->internal->r_fbVg); | ||||
#endif | |||||
#endif | #endif | ||||
window->internal->tlw = nullptr; | window->internal->tlw = nullptr; | ||||
@@ -460,9 +480,11 @@ void WindowSetMods(Window* const window, const int mods) | |||||
Window::~Window() { | Window::~Window() { | ||||
{ | { | ||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); | DGL_NAMESPACE::Window::ScopedGraphicsContext sgc(internal->hiddenWindow); | ||||
internal->hiddenWindow.close(); | internal->hiddenWindow.close(); | ||||
internal->hiddenApp.idle(); | internal->hiddenApp.idle(); | ||||
#endif | |||||
// Fonts and Images in the cache must be deleted before the NanoVG context is deleted | // Fonts and Images in the cache must be deleted before the NanoVG context is deleted | ||||
internal->fontCache.clear(); | internal->fontCache.clear(); | ||||
@@ -470,12 +492,20 @@ Window::~Window() { | |||||
if (vg != nullptr) | if (vg != nullptr) | ||||
{ | { | ||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
#if defined NANOVG_GLES2 | #if defined NANOVG_GLES2 | ||||
nvgDeleteGLES2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); | nvgDeleteGLES2(internal->o_fbVg != nullptr ? internal->o_fbVg : fbVg); | ||||
nvgDeleteGLES2(internal->o_vg != nullptr ? internal->o_vg : vg); | nvgDeleteGLES2(internal->o_vg != nullptr ? internal->o_vg : vg); | ||||
#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 | |||||
#else | |||||
#if defined NANOVG_GLES2 | |||||
nvgDeleteGLES2(fbVg); | |||||
#else | |||||
nvgDeleteGL2(fbVg); | |||||
#endif | |||||
#endif | #endif | ||||
} | } | ||||
} | } | ||||