Signed-off-by: falkTX <falktx@falktx.com>tags/23.02
| @@ -0,0 +1 @@ | |||
| ../CardinalRemote.cpp | |||
| @@ -42,6 +42,14 @@ | |||
| #include <app/Scene.hpp> | |||
| #include <window/Window.hpp> | |||
| #ifndef DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| # error wrong build | |||
| #endif | |||
| #if defined(STATIC_BUILD) || CARDINAL_VARIANT_MINI | |||
| # undef CARDINAL_INIT_OSC_THREAD | |||
| #endif | |||
| #ifdef NDEBUG | |||
| # undef DEBUG | |||
| #endif | |||
| @@ -54,12 +62,12 @@ | |||
| # include <unistd.h> | |||
| #endif | |||
| #ifdef DISTRHO_OS_WASM | |||
| # include <emscripten/emscripten.h> | |||
| #ifdef CARDINAL_INIT_OSC_THREAD | |||
| # include <lo/lo.h> | |||
| #endif | |||
| #ifndef DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| # error wrong build | |||
| #ifdef DISTRHO_OS_WASM | |||
| # include <emscripten/emscripten.h> | |||
| #endif | |||
| #if defined(CARDINAL_COMMON_DSP_ONLY) || defined(HEADLESS) | |||
| @@ -230,7 +238,8 @@ static int osc_hello_handler(const char*, const char*, lo_arg**, int, const lo_m | |||
| { | |||
| 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"); | |||
| const lo_server server = lo_server_thread_get_server(static_cast<Initializer*>(self)->oscServerThread); | |||
| lo_send_from(source, server, LO_TT_IMMEDIATE, "/resp", "ss", "hello", "ok"); | |||
| return 0; | |||
| } | |||
| @@ -248,7 +257,7 @@ static int osc_load_handler(const char*, const char* types, lo_arg** argv, int a | |||
| bool ok = false; | |||
| if (CardinalBasePlugin* const plugin = static_cast<Initializer*>(self)->oscPlugin) | |||
| if (CardinalBasePlugin* const plugin = static_cast<Initializer*>(self)->remotePluginInstance) | |||
| { | |||
| CardinalPluginContext* const context = plugin->context; | |||
| std::vector<uint8_t> data(size); | |||
| @@ -269,8 +278,8 @@ static int osc_load_handler(const char*, const char* types, lo_arg** argv, int a | |||
| } | |||
| 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"); | |||
| const lo_server server = lo_server_thread_get_server(static_cast<Initializer*>(self)->oscServerThread); | |||
| lo_send_from(source, server, LO_TT_IMMEDIATE, "/resp", "ss", "load", ok ? "ok" : "fail"); | |||
| return 0; | |||
| } | |||
| @@ -288,12 +297,12 @@ static int osc_screenshot_handler(const char*, const char* types, lo_arg** argv, | |||
| bool ok = false; | |||
| if (CardinalBasePlugin* const plugin = static_cast<Initializer*>(self)->oscPlugin) | |||
| if (CardinalBasePlugin* const plugin = static_cast<Initializer*>(self)->remotePluginInstance) | |||
| 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"); | |||
| const lo_server server = lo_server_thread_get_server(static_cast<Initializer*>(self)->oscServerThread); | |||
| lo_send_from(source, server, LO_TT_IMMEDIATE, "/resp", "ss", "screenshot", ok ? "ok" : "fail"); | |||
| return 0; | |||
| } | |||
| #endif | |||
| @@ -432,15 +441,13 @@ Initializer::Initializer(const CardinalBasePlugin* const plugin, const CardinalB | |||
| #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); | |||
| oscServerThread = lo_server_thread_new_with_proto(REMOTE_HOST_PORT, LO_UDP, osc_error_handler); | |||
| DISTRHO_SAFE_ASSERT_RETURN(oscServerThread != nullptr,); | |||
| startThread(); | |||
| lo_server_thread_add_method(oscServerThread, "/hello", "", osc_hello_handler, this); | |||
| lo_server_thread_add_method(oscServerThread, "/load", "b", osc_load_handler, this); | |||
| lo_server_thread_add_method(oscServerThread, "/screenshot", "b", osc_screenshot_handler, this); | |||
| lo_server_thread_add_method(oscServerThread, nullptr, nullptr, osc_fallback_handler, nullptr); | |||
| #else | |||
| INFO("OSC Remote control is not enabled in this build"); | |||
| #endif | |||
| @@ -451,12 +458,11 @@ Initializer::~Initializer() | |||
| using namespace rack; | |||
| #ifdef CARDINAL_INIT_OSC_THREAD | |||
| if (oscServer != nullptr) | |||
| if (oscServerThread != nullptr) | |||
| { | |||
| stopThread(5000); | |||
| lo_server_del_method(oscServer, nullptr, nullptr); | |||
| lo_server_free(oscServer); | |||
| oscServer = nullptr; | |||
| lo_server_thread_del_method(oscServerThread, nullptr, nullptr); | |||
| lo_server_thread_free(oscServerThread); | |||
| oscServerThread = nullptr; | |||
| } | |||
| #endif | |||
| @@ -478,21 +484,6 @@ Initializer::~Initializer() | |||
| 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 | |||
| @@ -21,13 +21,6 @@ | |||
| #include <string> | |||
| #ifdef HAVE_LIBLO | |||
| // # define REMOTE_HOST "localhost" | |||
| # define REMOTE_HOST "192.168.51.1" | |||
| # define REMOTE_HOST_PORT "2228" | |||
| # include "extra/Thread.hpp" | |||
| #endif | |||
| #ifdef DISTRHO_OS_WASM | |||
| # ifdef STATIC_BUILD | |||
| # define CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME "welcome-wasm-mini.vcv" | |||
| @@ -85,21 +78,17 @@ void saveAsDialogUncompressed(); | |||
| void appendSelectionContextMenu(rack::ui::Menu* menu); | |||
| void openBrowser(const std::string& url); | |||
| bool connectToRemote(); | |||
| bool isRemoteConnected(); | |||
| bool isRemoteAutoDeployed(); | |||
| void setRemoteAutoDeploy(bool autoDeploy); | |||
| void deployToRemote(); | |||
| void sendScreenshotToRemote(const char* screenshot); | |||
| } // namespace patchUtils | |||
| // ----------------------------------------------------------------------------------------------------------- | |||
| #if defined(HAVE_LIBLO) && defined(HEADLESS) && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| // && defined(HEADLESS) | |||
| #if defined(HAVE_LIBLO) | |||
| # define CARDINAL_INIT_OSC_THREAD | |||
| #endif | |||
| typedef void* lo_server_thread; | |||
| START_NAMESPACE_DISTRHO | |||
| class CardinalBasePlugin; | |||
| @@ -107,22 +96,16 @@ class CardinalBaseUI; | |||
| struct CardinalPluginContext; | |||
| struct Initializer | |||
| #ifdef CARDINAL_INIT_OSC_THREAD | |||
| : public Thread | |||
| #endif | |||
| { | |||
| #ifdef CARDINAL_INIT_OSC_THREAD | |||
| lo_server oscServer = nullptr; | |||
| CardinalBasePlugin* oscPlugin = nullptr; | |||
| lo_server_thread oscServerThread = nullptr; | |||
| CardinalBasePlugin* remotePluginInstance = 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 | |||
| }; | |||
| #ifndef HEADLESS | |||
| @@ -0,0 +1 @@ | |||
| ../CardinalRemote.cpp | |||
| @@ -0,0 +1 @@ | |||
| ../CardinalRemote.cpp | |||
| @@ -0,0 +1 @@ | |||
| ../CardinalRemote.cpp | |||
| @@ -274,14 +274,15 @@ public: | |||
| } | |||
| #ifdef CARDINAL_INIT_OSC_THREAD | |||
| fInitializer->oscPlugin = this; | |||
| fInitializer->remotePluginInstance = this; | |||
| #endif | |||
| } | |||
| ~CardinalPlugin() override | |||
| { | |||
| #ifdef CARDINAL_INIT_OSC_THREAD | |||
| fInitializer->oscPlugin = nullptr; | |||
| if (fInitializer->remotePluginInstance == this) | |||
| fInitializer->remotePluginInstance = nullptr; | |||
| #endif | |||
| { | |||
| @@ -844,9 +845,6 @@ protected: | |||
| if (std::strcmp(key, "screenshot") == 0) | |||
| { | |||
| fState.screenshot = value; | |||
| #if defined(HAVE_LIBLO) && !defined(HEADLESS) | |||
| patchUtils::sendScreenshotToRemote(value); | |||
| #endif | |||
| return; | |||
| } | |||
| @@ -0,0 +1,162 @@ | |||
| /* | |||
| * DISTRHO Cardinal Plugin | |||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| * published by the Free Software Foundation; either version 3 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the LICENSE file. | |||
| */ | |||
| #include <engine/Engine.hpp> | |||
| #include <patch.hpp> | |||
| #include <system.hpp> | |||
| #ifdef NDEBUG | |||
| # undef DEBUG | |||
| #endif | |||
| #include "CardinalRemote.hpp" | |||
| #include "PluginContext.hpp" | |||
| #include "extra/Base64.hpp" | |||
| #if defined(STATIC_BUILD) || CARDINAL_VARIANT_MINI | |||
| # undef HAVE_LIBLO | |||
| #endif | |||
| #ifdef HAVE_LIBLO | |||
| # include <lo/lo.h> | |||
| #endif | |||
| // ----------------------------------------------------------------------------------------------------------- | |||
| namespace remoteUtils { | |||
| #ifdef HAVE_LIBLO | |||
| static int osc_handler(const char* const path, const char* const types, lo_arg** argv, const int argc, lo_message, void* const self) | |||
| { | |||
| d_stdout("osc_handler(\"%s\", \"%s\", %p, %i)", path, types, argv, argc); | |||
| if (std::strcmp(path, "/resp") == 0 && argc == 2 && types[0] == 's' && types[1] == 's') | |||
| { | |||
| d_stdout("osc_handler(\"%s\", ...) - got resp | '%s' '%s'", path, &argv[0]->s, &argv[1]->s); | |||
| if (std::strcmp(&argv[0]->s, "hello") == 0 && std::strcmp(&argv[1]->s, "ok") == 0) | |||
| static_cast<RemoteDetails*>(self)->connected = true; | |||
| } | |||
| return 0; | |||
| } | |||
| #endif | |||
| RemoteDetails* getRemote() | |||
| { | |||
| CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP); | |||
| DISTRHO_SAFE_ASSERT_RETURN(context != nullptr, nullptr); | |||
| CardinalBaseUI* const ui = static_cast<CardinalBaseUI*>(context->ui); | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, nullptr); | |||
| return ui->remoteDetails; | |||
| } | |||
| bool connectToRemote() | |||
| { | |||
| CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP); | |||
| DISTRHO_SAFE_ASSERT_RETURN(context != nullptr, false); | |||
| CardinalBaseUI* const ui = static_cast<CardinalBaseUI*>(context->ui); | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false); | |||
| RemoteDetails* remoteDetails = ui->remoteDetails; | |||
| #ifdef HAVE_LIBLO | |||
| if (remoteDetails == nullptr) | |||
| { | |||
| const lo_server oscServer = lo_server_new_with_proto(nullptr, LO_UDP, nullptr); | |||
| DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr, false); | |||
| remoteDetails = new RemoteDetails; | |||
| remoteDetails->handle = oscServer; | |||
| remoteDetails->connected = false; | |||
| remoteDetails->autoDeploy = false; | |||
| lo_server_add_method(oscServer, "/resp", nullptr, osc_handler, remoteDetails); | |||
| } | |||
| if (const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT)) | |||
| { | |||
| lo_send(addr, "/hello", ""); | |||
| lo_address_free(addr); | |||
| } | |||
| #endif | |||
| return remoteDetails != nullptr; | |||
| } | |||
| void disconnectFromRemote(RemoteDetails* const remote) | |||
| { | |||
| if (remote != nullptr) | |||
| { | |||
| #ifdef HAVE_LIBLO | |||
| lo_server_free(static_cast<lo_server>(remote->handle)); | |||
| delete remote; | |||
| #endif | |||
| } | |||
| } | |||
| void idleRemote(RemoteDetails* const remote) | |||
| { | |||
| #ifdef HAVE_LIBLO | |||
| while (lo_server_recv_noblock(static_cast<lo_server>(remote->handle), 0) != 0) {} | |||
| #endif | |||
| } | |||
| void deployToRemote(RemoteDetails* const remote) | |||
| { | |||
| #ifdef HAVE_LIBLO | |||
| const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); | |||
| DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); | |||
| APP->engine->prepareSave(); | |||
| APP->patch->saveAutosave(); | |||
| APP->patch->cleanAutosave(); | |||
| std::vector<uint8_t> data(rack::system::archiveDirectory(APP->patch->autosavePath, 1)); | |||
| if (const lo_blob blob = lo_blob_new(data.size(), data.data())) | |||
| { | |||
| lo_send(addr, "/load", "b", blob); | |||
| lo_blob_free(blob); | |||
| } | |||
| lo_address_free(addr); | |||
| #endif | |||
| } | |||
| void sendScreenshotToRemote(RemoteDetails* const remote, const char* const screenshot) | |||
| { | |||
| #ifdef HAVE_LIBLO | |||
| const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); | |||
| DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); | |||
| std::vector<uint8_t> data(d_getChunkFromBase64String(screenshot)); | |||
| if (const lo_blob blob = lo_blob_new(data.size(), data.data())) | |||
| { | |||
| lo_send(addr, "/screenshot", "b", blob); | |||
| lo_blob_free(blob); | |||
| } | |||
| lo_address_free(addr); | |||
| #endif | |||
| } | |||
| } | |||
| // ----------------------------------------------------------------------------------------------------------- | |||
| @@ -0,0 +1,45 @@ | |||
| /* | |||
| * DISTRHO Cardinal Plugin | |||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| * published by the Free Software Foundation; either version 3 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the LICENSE file. | |||
| */ | |||
| #pragma once | |||
| #ifdef HAVE_LIBLO | |||
| // # define REMOTE_HOST "localhost" | |||
| # define REMOTE_HOST "192.168.51.1" | |||
| # define REMOTE_HOST_PORT "2228" | |||
| #endif | |||
| // ----------------------------------------------------------------------------------------------------------- | |||
| namespace remoteUtils { | |||
| struct RemoteDetails { | |||
| void* handle; | |||
| bool connected; | |||
| bool autoDeploy; | |||
| }; | |||
| RemoteDetails* getRemote(); | |||
| bool connectToRemote(); | |||
| void disconnectFromRemote(RemoteDetails* remote); | |||
| void idleRemote(RemoteDetails* remote); | |||
| void deployToRemote(RemoteDetails* remote); | |||
| void sendScreenshotToRemote(RemoteDetails* remote, const char* screenshot); | |||
| } | |||
| // ----------------------------------------------------------------------------------------------------------- | |||
| @@ -0,0 +1 @@ | |||
| ../CardinalRemote.cpp | |||
| @@ -96,6 +96,7 @@ endif | |||
| FILES_DSP = CardinalPlugin.cpp | |||
| FILES_DSP += CardinalCommon.cpp | |||
| FILES_DSP += CardinalRemote.cpp | |||
| FILES_DSP += common.cpp | |||
| ifeq ($(CARDINAL_VARIANT),mini) | |||
| @@ -251,6 +252,7 @@ ifeq ($(CARDINAL_VARIANT),mini) | |||
| ifneq ($(HEADLESS),true) | |||
| FILES_UI = CardinalUI.cpp | |||
| FILES_UI += CardinalCommon-UI.cpp | |||
| FILES_UI += CardinalRemote.cpp | |||
| FILES_UI += common.cpp | |||
| FILES_UI += glfw.cpp | |||
| FILES_UI += Window.cpp | |||
| @@ -25,8 +25,8 @@ | |||
| # undef DEBUG | |||
| #endif | |||
| #include "CardinalRemote.hpp" | |||
| #include "DistrhoPlugin.hpp" | |||
| #include "extra/Mutex.hpp" | |||
| #ifndef HEADLESS | |||
| # include "DistrhoUI.hpp" | |||
| @@ -148,6 +148,7 @@ struct WasmRemotePatchLoadingDialog; | |||
| class CardinalBaseUI : public UI { | |||
| public: | |||
| CardinalPluginContext* const context; | |||
| remoteUtils::RemoteDetails* remoteDetails; | |||
| bool saving; | |||
| bool savingUncompressed; | |||
| @@ -166,6 +167,7 @@ public: | |||
| #else | |||
| context(new CardinalPluginContext(nullptr)), | |||
| #endif | |||
| remoteDetails(nullptr), | |||
| saving(false), | |||
| savingUncompressed(false), | |||
| #ifdef DISTRHO_OS_WASM | |||
| @@ -180,6 +182,8 @@ public: | |||
| ~CardinalBaseUI() override | |||
| { | |||
| disconnectFromRemote(remoteDetails); | |||
| if (filebrowserhandle != nullptr) | |||
| fileBrowserClose(filebrowserhandle); | |||
| @@ -52,6 +52,7 @@ | |||
| #include <library.hpp> | |||
| #include "../CardinalCommon.hpp" | |||
| #include "../CardinalRemote.hpp" | |||
| #include "DistrhoStandaloneUtils.hpp" | |||
| #ifdef HAVE_LIBLO | |||
| @@ -169,19 +170,20 @@ struct FileButton : MenuButton { | |||
| #ifdef HAVE_LIBLO | |||
| menu->addChild(new ui::MenuSeparator); | |||
| if (patchUtils::isRemoteConnected()) { | |||
| menu->addChild(createMenuItem("Deploy to MOD", "F7", []() { | |||
| patchUtils::deployToRemote(); | |||
| remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote(); | |||
| if (remoteDetails != nullptr && remoteDetails->connected) { | |||
| menu->addChild(createMenuItem("Deploy to MOD", "F7", [remoteDetails]() { | |||
| remoteUtils::deployToRemote(remoteDetails); | |||
| })); | |||
| const bool autoDeploy = patchUtils::isRemoteAutoDeployed(); | |||
| menu->addChild(createCheckMenuItem("Auto deploy to MOD", "", | |||
| [=]() {return autoDeploy;}, | |||
| [=]() {patchUtils::setRemoteAutoDeploy(!autoDeploy);} | |||
| [remoteDetails]() {return remoteDetails->autoDeploy;}, | |||
| [remoteDetails]() {remoteDetails->autoDeploy = !remoteDetails->autoDeploy;} | |||
| )); | |||
| } else { | |||
| menu->addChild(createMenuItem("Connect to MOD", "", []() { | |||
| patchUtils::connectToRemote(); | |||
| remoteUtils::connectToRemote(); | |||
| })); | |||
| } | |||
| #endif | |||
| @@ -25,10 +25,6 @@ | |||
| * the License, or (at your option) any later version. | |||
| */ | |||
| #include <thread> | |||
| #include <osdialog.h> | |||
| #include <app/Scene.hpp> | |||
| #include <app/Browser.hpp> | |||
| #include <app/TipWindow.hpp> | |||
| @@ -46,17 +42,8 @@ | |||
| # undef DEBUG | |||
| #endif | |||
| #ifdef STATIC_BUILD | |||
| # undef HAVE_LIBLO | |||
| #endif | |||
| #ifdef HAVE_LIBLO | |||
| # include <lo/lo.h> | |||
| #endif | |||
| #include "../CardinalCommon.hpp" | |||
| #include "extra/Base64.hpp" | |||
| #include "DistrhoUtils.hpp" | |||
| #include "../CardinalRemote.hpp" | |||
| namespace rack { | |||
| @@ -131,30 +118,8 @@ struct Scene::Internal { | |||
| bool heldArrowKeys[4] = {}; | |||
| #ifdef HAVE_LIBLO | |||
| double lastSceneChangeTime = 0.0; | |||
| int historyActionIndex = -1; | |||
| bool oscAutoDeploy = false; | |||
| bool oscConnected = false; | |||
| lo_server oscServer = nullptr; | |||
| static int osc_handler(const char* const path, const char* const types, lo_arg** argv, const int argc, lo_message, void* const self) | |||
| { | |||
| d_stdout("osc_handler(\"%s\", \"%s\", %p, %i)", path, types, argv, argc); | |||
| if (std::strcmp(path, "/resp") == 0 && argc == 2 && types[0] == 's' && types[1] == 's') { | |||
| d_stdout("osc_handler(\"%s\", ...) - got resp | '%s' '%s'", path, &argv[0]->s, &argv[1]->s); | |||
| if (std::strcmp(&argv[0]->s, "hello") == 0 && std::strcmp(&argv[1]->s, "ok") == 0) | |||
| static_cast<Internal*>(self)->oscConnected = true; | |||
| } | |||
| return 0; | |||
| } | |||
| ~Internal() { | |||
| lo_server_free(oscServer); | |||
| } | |||
| #endif | |||
| }; | |||
| @@ -238,22 +203,20 @@ void Scene::step() { | |||
| rackScroll->offset += arrowDelta * arrowSpeed; | |||
| } | |||
| #ifdef HAVE_LIBLO | |||
| if (internal->oscServer != nullptr) { | |||
| while (lo_server_recv_noblock(internal->oscServer, 0) != 0) {} | |||
| if (remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote()) { | |||
| idleRemote(remoteDetails); | |||
| if (internal->oscAutoDeploy) { | |||
| if (remoteDetails->autoDeploy) { | |||
| const int actionIndex = APP->history->actionIndex; | |||
| const double time = system::getTime(); | |||
| if (internal->historyActionIndex != actionIndex && time - internal->lastSceneChangeTime >= 5.0) { | |||
| internal->historyActionIndex = actionIndex; | |||
| internal->lastSceneChangeTime = time; | |||
| patchUtils::deployToRemote(); | |||
| remoteUtils::deployToRemote(remoteDetails); | |||
| window::generateScreenshot(); | |||
| } | |||
| } | |||
| } | |||
| #endif | |||
| Widget::step(); | |||
| } | |||
| @@ -352,7 +315,7 @@ void Scene::onHoverKey(const HoverKeyEvent& e) { | |||
| e.consume(this); | |||
| } | |||
| if (e.key == GLFW_KEY_F7 && (e.mods & RACK_MOD_MASK) == 0) { | |||
| patchUtils::deployToRemote(); | |||
| remoteUtils::deployToRemote(remoteUtils::getRemote()); | |||
| window::generateScreenshot(); | |||
| e.consume(this); | |||
| } | |||
| @@ -489,94 +452,3 @@ void Scene::onPathDrop(const PathDropEvent& e) { | |||
| } // namespace app | |||
| } // namespace rack | |||
| namespace patchUtils { | |||
| bool connectToRemote() { | |||
| #ifdef HAVE_LIBLO | |||
| rack::app::Scene::Internal* const internal = APP->scene->internal; | |||
| if (internal->oscServer == nullptr) { | |||
| const lo_server oscServer = lo_server_new_with_proto(nullptr, LO_UDP, nullptr); | |||
| DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr, false); | |||
| lo_server_add_method(oscServer, "/resp", nullptr, rack::app::Scene::Internal::osc_handler, internal); | |||
| internal->oscServer = oscServer; | |||
| } | |||
| const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); | |||
| DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr, false); | |||
| lo_send(addr, "/hello", ""); | |||
| lo_address_free(addr); | |||
| return true; | |||
| #else | |||
| return false; | |||
| #endif | |||
| } | |||
| bool isRemoteConnected() { | |||
| #ifdef HAVE_LIBLO | |||
| return APP->scene->internal->oscConnected; | |||
| #else | |||
| return false; | |||
| #endif | |||
| } | |||
| bool isRemoteAutoDeployed() { | |||
| #ifdef HAVE_LIBLO | |||
| return APP->scene->internal->oscAutoDeploy; | |||
| #else | |||
| return false; | |||
| #endif | |||
| } | |||
| void setRemoteAutoDeploy(bool autoDeploy) { | |||
| #ifdef HAVE_LIBLO | |||
| APP->scene->internal->oscAutoDeploy = autoDeploy; | |||
| #endif | |||
| } | |||
| void deployToRemote() { | |||
| #ifdef HAVE_LIBLO | |||
| const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); | |||
| DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); | |||
| APP->engine->prepareSave(); | |||
| APP->patch->saveAutosave(); | |||
| APP->patch->cleanAutosave(); | |||
| std::vector<uint8_t> data(rack::system::archiveDirectory(APP->patch->autosavePath, 1)); | |||
| if (const lo_blob blob = lo_blob_new(data.size(), data.data())) { | |||
| lo_send(addr, "/load", "b", blob); | |||
| lo_blob_free(blob); | |||
| } | |||
| lo_address_free(addr); | |||
| #endif | |||
| } | |||
| void sendScreenshotToRemote(const char* const screenshot) { | |||
| #ifdef HAVE_LIBLO | |||
| const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); | |||
| DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); | |||
| std::vector<uint8_t> data(d_getChunkFromBase64String(screenshot)); | |||
| if (const lo_blob blob = lo_blob_new(data.size(), data.data())) { | |||
| lo_send(addr, "/screenshot", "b", blob); | |||
| lo_blob_free(blob); | |||
| } | |||
| lo_address_free(addr); | |||
| #endif | |||
| } | |||
| } // namespace patchUtils | |||
| @@ -584,8 +584,11 @@ static void Window__downscaleBitmap(uint8_t* pixels, int& width, int& height) { | |||
| static void Window__writeImagePNG(void* context, void* data, int size) { | |||
| USE_NAMESPACE_DISTRHO | |||
| UI* const ui = static_cast<UI*>(context); | |||
| ui->setState("screenshot", String::asBase64(data, size).buffer()); | |||
| CardinalBaseUI* const ui = static_cast<CardinalBaseUI*>(context); | |||
| if (const char* const screenshot = String::asBase64(data, size).buffer()) { | |||
| ui->setState("screenshot", screenshot); | |||
| remoteUtils::sendScreenshotToRemote(ui->remoteDetails, screenshot); | |||
| } | |||
| } | |||
| #endif | |||
| #endif | |||