Browse Source

Initial code for remote push over OSC

Signed-off-by: falkTX <falktx@falktx.com>
tags/22.02
falkTX 3 years ago
parent
commit
e83d514eb6
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
3 changed files with 196 additions and 1 deletions
  1. +117
    -1
      src/CardinalPlugin.cpp
  2. +8
    -0
      src/Makefile
  3. +71
    -0
      src/override/MenuBar.cpp

+ 117
- 1
src/CardinalPlugin.cpp View File

@@ -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);


+ 8
- 0
src/Makefile View File

@@ -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



+ 71
- 0
src/override/MenuBar.cpp View File

@@ -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…
Cancel
Save