Signed-off-by: falkTX <falktx@falktx.com>tags/23.02
@@ -0,0 +1 @@ | |||||
../CardinalRemote.cpp |
@@ -42,6 +42,14 @@ | |||||
#include <app/Scene.hpp> | #include <app/Scene.hpp> | ||||
#include <window/Window.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 | #ifdef NDEBUG | ||||
# undef DEBUG | # undef DEBUG | ||||
#endif | #endif | ||||
@@ -54,12 +62,12 @@ | |||||
# include <unistd.h> | # include <unistd.h> | ||||
#endif | #endif | ||||
#ifdef DISTRHO_OS_WASM | |||||
# include <emscripten/emscripten.h> | |||||
#ifdef CARDINAL_INIT_OSC_THREAD | |||||
# include <lo/lo.h> | |||||
#endif | #endif | ||||
#ifndef DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
# error wrong build | |||||
#ifdef DISTRHO_OS_WASM | |||||
# include <emscripten/emscripten.h> | |||||
#endif | #endif | ||||
#if defined(CARDINAL_COMMON_DSP_ONLY) || defined(HEADLESS) | #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()"); | d_stdout("osc_hello_handler()"); | ||||
const lo_address source = lo_message_get_source(m); | 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; | return 0; | ||||
} | } | ||||
@@ -248,7 +257,7 @@ static int osc_load_handler(const char*, const char* types, lo_arg** argv, int a | |||||
bool ok = false; | 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; | CardinalPluginContext* const context = plugin->context; | ||||
std::vector<uint8_t> data(size); | 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); | 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; | return 0; | ||||
} | } | ||||
@@ -288,12 +297,12 @@ static int osc_screenshot_handler(const char*, const char* types, lo_arg** argv, | |||||
bool ok = false; | 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()); | ok = plugin->updateStateValue("screenshot", String::asBase64(blob, size).buffer()); | ||||
const lo_address source = lo_message_get_source(m); | 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; | return 0; | ||||
} | } | ||||
#endif | #endif | ||||
@@ -432,15 +441,13 @@ Initializer::Initializer(const CardinalBasePlugin* const plugin, const CardinalB | |||||
#ifdef CARDINAL_INIT_OSC_THREAD | #ifdef CARDINAL_INIT_OSC_THREAD | ||||
INFO("Initializing OSC Remote control"); | 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 | #else | ||||
INFO("OSC Remote control is not enabled in this build"); | INFO("OSC Remote control is not enabled in this build"); | ||||
#endif | #endif | ||||
@@ -451,12 +458,11 @@ Initializer::~Initializer() | |||||
using namespace rack; | using namespace rack; | ||||
#ifdef CARDINAL_INIT_OSC_THREAD | #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 | #endif | ||||
@@ -478,21 +484,6 @@ Initializer::~Initializer() | |||||
logger::destroy(); | 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 | ||||
@@ -21,13 +21,6 @@ | |||||
#include <string> | #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 DISTRHO_OS_WASM | ||||
# ifdef STATIC_BUILD | # ifdef STATIC_BUILD | ||||
# define CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME "welcome-wasm-mini.vcv" | # define CARDINAL_WASM_WELCOME_TEMPLATE_FILENAME "welcome-wasm-mini.vcv" | ||||
@@ -85,21 +78,17 @@ void saveAsDialogUncompressed(); | |||||
void appendSelectionContextMenu(rack::ui::Menu* menu); | void appendSelectionContextMenu(rack::ui::Menu* menu); | ||||
void openBrowser(const std::string& url); | 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 | } // namespace patchUtils | ||||
// ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
#if defined(HAVE_LIBLO) && defined(HEADLESS) && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
// && defined(HEADLESS) | |||||
#if defined(HAVE_LIBLO) | |||||
# define CARDINAL_INIT_OSC_THREAD | # define CARDINAL_INIT_OSC_THREAD | ||||
#endif | #endif | ||||
typedef void* lo_server_thread; | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
class CardinalBasePlugin; | class CardinalBasePlugin; | ||||
@@ -107,22 +96,16 @@ class CardinalBaseUI; | |||||
struct CardinalPluginContext; | struct CardinalPluginContext; | ||||
struct Initializer | struct Initializer | ||||
#ifdef CARDINAL_INIT_OSC_THREAD | |||||
: public Thread | |||||
#endif | |||||
{ | { | ||||
#ifdef CARDINAL_INIT_OSC_THREAD | #ifdef CARDINAL_INIT_OSC_THREAD | ||||
lo_server oscServer = nullptr; | |||||
CardinalBasePlugin* oscPlugin = nullptr; | |||||
lo_server_thread oscServerThread = nullptr; | |||||
CardinalBasePlugin* remotePluginInstance = nullptr; | |||||
#endif | #endif | ||||
std::string templatePath; | std::string templatePath; | ||||
std::string factoryTemplatePath; | std::string factoryTemplatePath; | ||||
Initializer(const CardinalBasePlugin* plugin, const CardinalBaseUI* ui); | Initializer(const CardinalBasePlugin* plugin, const CardinalBaseUI* ui); | ||||
~Initializer(); | ~Initializer(); | ||||
#ifdef CARDINAL_INIT_OSC_THREAD | |||||
void run() override; | |||||
#endif | |||||
}; | }; | ||||
#ifndef HEADLESS | #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 | #ifdef CARDINAL_INIT_OSC_THREAD | ||||
fInitializer->oscPlugin = this; | |||||
fInitializer->remotePluginInstance = this; | |||||
#endif | #endif | ||||
} | } | ||||
~CardinalPlugin() override | ~CardinalPlugin() override | ||||
{ | { | ||||
#ifdef CARDINAL_INIT_OSC_THREAD | #ifdef CARDINAL_INIT_OSC_THREAD | ||||
fInitializer->oscPlugin = nullptr; | |||||
if (fInitializer->remotePluginInstance == this) | |||||
fInitializer->remotePluginInstance = nullptr; | |||||
#endif | #endif | ||||
{ | { | ||||
@@ -844,9 +845,6 @@ protected: | |||||
if (std::strcmp(key, "screenshot") == 0) | if (std::strcmp(key, "screenshot") == 0) | ||||
{ | { | ||||
fState.screenshot = value; | fState.screenshot = value; | ||||
#if defined(HAVE_LIBLO) && !defined(HEADLESS) | |||||
patchUtils::sendScreenshotToRemote(value); | |||||
#endif | |||||
return; | 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 = CardinalPlugin.cpp | ||||
FILES_DSP += CardinalCommon.cpp | FILES_DSP += CardinalCommon.cpp | ||||
FILES_DSP += CardinalRemote.cpp | |||||
FILES_DSP += common.cpp | FILES_DSP += common.cpp | ||||
ifeq ($(CARDINAL_VARIANT),mini) | ifeq ($(CARDINAL_VARIANT),mini) | ||||
@@ -251,6 +252,7 @@ ifeq ($(CARDINAL_VARIANT),mini) | |||||
ifneq ($(HEADLESS),true) | ifneq ($(HEADLESS),true) | ||||
FILES_UI = CardinalUI.cpp | FILES_UI = CardinalUI.cpp | ||||
FILES_UI += CardinalCommon-UI.cpp | FILES_UI += CardinalCommon-UI.cpp | ||||
FILES_UI += CardinalRemote.cpp | |||||
FILES_UI += common.cpp | FILES_UI += common.cpp | ||||
FILES_UI += glfw.cpp | FILES_UI += glfw.cpp | ||||
FILES_UI += Window.cpp | FILES_UI += Window.cpp | ||||
@@ -25,8 +25,8 @@ | |||||
# undef DEBUG | # undef DEBUG | ||||
#endif | #endif | ||||
#include "CardinalRemote.hpp" | |||||
#include "DistrhoPlugin.hpp" | #include "DistrhoPlugin.hpp" | ||||
#include "extra/Mutex.hpp" | |||||
#ifndef HEADLESS | #ifndef HEADLESS | ||||
# include "DistrhoUI.hpp" | # include "DistrhoUI.hpp" | ||||
@@ -148,6 +148,7 @@ struct WasmRemotePatchLoadingDialog; | |||||
class CardinalBaseUI : public UI { | class CardinalBaseUI : public UI { | ||||
public: | public: | ||||
CardinalPluginContext* const context; | CardinalPluginContext* const context; | ||||
remoteUtils::RemoteDetails* remoteDetails; | |||||
bool saving; | bool saving; | ||||
bool savingUncompressed; | bool savingUncompressed; | ||||
@@ -166,6 +167,7 @@ public: | |||||
#else | #else | ||||
context(new CardinalPluginContext(nullptr)), | context(new CardinalPluginContext(nullptr)), | ||||
#endif | #endif | ||||
remoteDetails(nullptr), | |||||
saving(false), | saving(false), | ||||
savingUncompressed(false), | savingUncompressed(false), | ||||
#ifdef DISTRHO_OS_WASM | #ifdef DISTRHO_OS_WASM | ||||
@@ -180,6 +182,8 @@ public: | |||||
~CardinalBaseUI() override | ~CardinalBaseUI() override | ||||
{ | { | ||||
disconnectFromRemote(remoteDetails); | |||||
if (filebrowserhandle != nullptr) | if (filebrowserhandle != nullptr) | ||||
fileBrowserClose(filebrowserhandle); | fileBrowserClose(filebrowserhandle); | ||||
@@ -52,6 +52,7 @@ | |||||
#include <library.hpp> | #include <library.hpp> | ||||
#include "../CardinalCommon.hpp" | #include "../CardinalCommon.hpp" | ||||
#include "../CardinalRemote.hpp" | |||||
#include "DistrhoStandaloneUtils.hpp" | #include "DistrhoStandaloneUtils.hpp" | ||||
#ifdef HAVE_LIBLO | #ifdef HAVE_LIBLO | ||||
@@ -169,19 +170,20 @@ struct FileButton : MenuButton { | |||||
#ifdef HAVE_LIBLO | #ifdef HAVE_LIBLO | ||||
menu->addChild(new ui::MenuSeparator); | 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", "", | menu->addChild(createCheckMenuItem("Auto deploy to MOD", "", | ||||
[=]() {return autoDeploy;}, | |||||
[=]() {patchUtils::setRemoteAutoDeploy(!autoDeploy);} | |||||
[remoteDetails]() {return remoteDetails->autoDeploy;}, | |||||
[remoteDetails]() {remoteDetails->autoDeploy = !remoteDetails->autoDeploy;} | |||||
)); | )); | ||||
} else { | } else { | ||||
menu->addChild(createMenuItem("Connect to MOD", "", []() { | menu->addChild(createMenuItem("Connect to MOD", "", []() { | ||||
patchUtils::connectToRemote(); | |||||
remoteUtils::connectToRemote(); | |||||
})); | })); | ||||
} | } | ||||
#endif | #endif | ||||
@@ -25,10 +25,6 @@ | |||||
* the License, or (at your option) any later version. | * the License, or (at your option) any later version. | ||||
*/ | */ | ||||
#include <thread> | |||||
#include <osdialog.h> | |||||
#include <app/Scene.hpp> | #include <app/Scene.hpp> | ||||
#include <app/Browser.hpp> | #include <app/Browser.hpp> | ||||
#include <app/TipWindow.hpp> | #include <app/TipWindow.hpp> | ||||
@@ -46,17 +42,8 @@ | |||||
# undef DEBUG | # undef DEBUG | ||||
#endif | #endif | ||||
#ifdef STATIC_BUILD | |||||
# undef HAVE_LIBLO | |||||
#endif | |||||
#ifdef HAVE_LIBLO | |||||
# include <lo/lo.h> | |||||
#endif | |||||
#include "../CardinalCommon.hpp" | #include "../CardinalCommon.hpp" | ||||
#include "extra/Base64.hpp" | |||||
#include "DistrhoUtils.hpp" | |||||
#include "../CardinalRemote.hpp" | |||||
namespace rack { | namespace rack { | ||||
@@ -131,30 +118,8 @@ struct Scene::Internal { | |||||
bool heldArrowKeys[4] = {}; | bool heldArrowKeys[4] = {}; | ||||
#ifdef HAVE_LIBLO | |||||
double lastSceneChangeTime = 0.0; | double lastSceneChangeTime = 0.0; | ||||
int historyActionIndex = -1; | 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; | 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 int actionIndex = APP->history->actionIndex; | ||||
const double time = system::getTime(); | const double time = system::getTime(); | ||||
if (internal->historyActionIndex != actionIndex && time - internal->lastSceneChangeTime >= 5.0) { | if (internal->historyActionIndex != actionIndex && time - internal->lastSceneChangeTime >= 5.0) { | ||||
internal->historyActionIndex = actionIndex; | internal->historyActionIndex = actionIndex; | ||||
internal->lastSceneChangeTime = time; | internal->lastSceneChangeTime = time; | ||||
patchUtils::deployToRemote(); | |||||
remoteUtils::deployToRemote(remoteDetails); | |||||
window::generateScreenshot(); | window::generateScreenshot(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
#endif | |||||
Widget::step(); | Widget::step(); | ||||
} | } | ||||
@@ -352,7 +315,7 @@ void Scene::onHoverKey(const HoverKeyEvent& e) { | |||||
e.consume(this); | e.consume(this); | ||||
} | } | ||||
if (e.key == GLFW_KEY_F7 && (e.mods & RACK_MOD_MASK) == 0) { | if (e.key == GLFW_KEY_F7 && (e.mods & RACK_MOD_MASK) == 0) { | ||||
patchUtils::deployToRemote(); | |||||
remoteUtils::deployToRemote(remoteUtils::getRemote()); | |||||
window::generateScreenshot(); | window::generateScreenshot(); | ||||
e.consume(this); | e.consume(this); | ||||
} | } | ||||
@@ -489,94 +452,3 @@ void Scene::onPathDrop(const PathDropEvent& e) { | |||||
} // namespace app | } // namespace app | ||||
} // namespace rack | } // 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) { | static void Window__writeImagePNG(void* context, void* data, int size) { | ||||
USE_NAMESPACE_DISTRHO | 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 | ||||
#endif | #endif | ||||