Initial code for remote push over OSC
Signed-off-by: falkTX <falktx@falktx.com>
This commit is contained in:
parent
a00020e597
commit
e83d514eb6
3 changed files with 196 additions and 1 deletions
|
@ -33,6 +33,11 @@
|
|||
# undef DEBUG
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBLO
|
||||
# include <lo/lo.h>
|
||||
# include "extra/Thread.hpp"
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "DistrhoPluginUtils.hpp"
|
||||
|
@ -41,6 +46,8 @@
|
|||
#include "extra/Base64.hpp"
|
||||
#include "extra/SharedResourcePointer.hpp"
|
||||
|
||||
#define REMOTE_HOST_PORT "2228"
|
||||
|
||||
namespace rack {
|
||||
namespace plugin {
|
||||
void initStaticPlugins();
|
||||
|
@ -57,7 +64,16 @@ START_NAMESPACE_DISTRHO
|
|||
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
struct Initializer {
|
||||
struct Initializer
|
||||
#ifdef HAVE_LIBLO
|
||||
: public Thread
|
||||
#endif
|
||||
{
|
||||
#ifdef HAVE_LIBLO
|
||||
lo_server oscServer = nullptr;
|
||||
CardinalBasePlugin* oscPlugin = nullptr;
|
||||
#endif
|
||||
|
||||
Initializer(const CardinalBasePlugin* const plugin)
|
||||
{
|
||||
using namespace rack;
|
||||
|
@ -136,12 +152,33 @@ struct Initializer {
|
|||
|
||||
INFO("Initializing plugins");
|
||||
plugin::initStaticPlugins();
|
||||
|
||||
#ifdef HAVE_LIBLO
|
||||
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, nullptr, nullptr, osc_fallback_handler, nullptr);
|
||||
|
||||
startThread();
|
||||
#endif
|
||||
}
|
||||
|
||||
~Initializer()
|
||||
{
|
||||
using namespace rack;
|
||||
|
||||
#ifdef HAVE_LIBLO
|
||||
if (oscServer != nullptr)
|
||||
{
|
||||
stopThread(5000);
|
||||
lo_server_del_method(oscServer, nullptr, nullptr);
|
||||
lo_server_free(oscServer);
|
||||
oscServer = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
INFO("Destroying plugins");
|
||||
plugin::destroyStaticPlugins();
|
||||
|
||||
|
@ -154,6 +191,77 @@ struct Initializer {
|
|||
INFO("Destroying logger");
|
||||
logger::destroy();
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBLO
|
||||
void run() override
|
||||
{
|
||||
while (! shouldThreadExit())
|
||||
{
|
||||
d_msleep(200);
|
||||
while (lo_server_recv_noblock(oscServer, 0) != 0) {}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
const MutexLocker cml(context->mutex);
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
|
@ -247,6 +355,10 @@ public:
|
|||
context->patch->loadTemplate();
|
||||
context->engine->startFallbackThread();
|
||||
|
||||
#ifdef HAVE_LIBLO
|
||||
fInitializer->oscPlugin = this;
|
||||
#endif
|
||||
|
||||
#if defined(__MOD_DEVICES__) && !defined(HEADLESS)
|
||||
context->window = new rack::window::Window;
|
||||
rack::window::WindowInit(context->window, this);
|
||||
|
@ -260,6 +372,10 @@ public:
|
|||
|
||||
~CardinalPlugin() override
|
||||
{
|
||||
#ifdef HAVE_LIBLO
|
||||
fInitializer->oscPlugin = nullptr;
|
||||
#endif
|
||||
|
||||
{
|
||||
const MutexLocker cml(context->mutex);
|
||||
rack::contextSet(context);
|
||||
|
|
|
@ -187,6 +187,14 @@ ifeq ($(WITH_LTO),true)
|
|||
LINK_FLAGS += -fno-strict-aliasing -flto -Werror=odr -Werror=lto-type-mismatch
|
||||
endif
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# optional liblo
|
||||
|
||||
ifeq ($(HAVE_LIBLO),true)
|
||||
BASE_FLAGS += $(LIBLO_FLAGS)
|
||||
LINK_FLAGS += $(LIBLO_LIBS)
|
||||
endif
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# fallback path to resource files
|
||||
|
||||
|
|
|
@ -57,9 +57,16 @@
|
|||
# undef DEBUG
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBLO
|
||||
# include <lo/lo.h>
|
||||
#endif
|
||||
|
||||
#include <Window.hpp>
|
||||
#include "../PluginContext.hpp"
|
||||
|
||||
// #define REMOTE_HOST "localhost"
|
||||
#define REMOTE_HOST "192.168.51.1"
|
||||
#define REMOTE_HOST_PORT "2228"
|
||||
|
||||
namespace rack {
|
||||
namespace app {
|
||||
|
@ -92,6 +99,27 @@ struct FileButton : MenuButton {
|
|||
Window& window;
|
||||
const bool isStandalone;
|
||||
|
||||
#ifdef HAVE_LIBLO
|
||||
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<FileButton*>(self)->oscConnected = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
~FileButton() {
|
||||
lo_server_free(oscServer);
|
||||
}
|
||||
#endif
|
||||
|
||||
FileButton(Window& win, const bool standalone)
|
||||
: MenuButton(), window(win), isStandalone(standalone) {}
|
||||
|
||||
|
@ -127,6 +155,40 @@ struct FileButton : MenuButton {
|
|||
}));
|
||||
*/
|
||||
|
||||
#ifdef HAVE_LIBLO
|
||||
if (oscServer == nullptr || !oscConnected) {
|
||||
menu->addChild(createMenuItem("Connect to MOD", "", [this]() {
|
||||
if (oscServer == nullptr) {
|
||||
oscServer = lo_server_new_with_proto(nullptr, LO_UDP, nullptr);
|
||||
DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr,);
|
||||
lo_server_add_method(oscServer, "/resp", nullptr, osc_handler, this);
|
||||
}
|
||||
const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT);
|
||||
DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,);
|
||||
lo_send(addr, "/hello", "");
|
||||
lo_address_free(addr);
|
||||
}));
|
||||
} else {
|
||||
menu->addChild(createMenuItem("Deploy to MOD", "", []() {
|
||||
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
|
||||
|
||||
menu->addChild(createMenuItem("Revert", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+O", []() {
|
||||
// APP->patch->revertDialog();
|
||||
APP->patch->loadAction(APP->patch->path);
|
||||
|
@ -140,6 +202,15 @@ struct FileButton : MenuButton {
|
|||
}));
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBLO
|
||||
void step() override {
|
||||
MenuButton::step();
|
||||
if (oscServer != nullptr) {
|
||||
while (lo_server_recv_noblock(oscServer, 0) != 0) {}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue