Proper OSC remote control implementation, allowed on standalones
Signed-off-by: falkTX <falktx@falktx.com>
This commit is contained in:
parent
0ad791dee0
commit
3d44fb9d79
5 changed files with 192 additions and 34 deletions
|
@ -63,7 +63,7 @@
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CARDINAL_INIT_OSC_THREAD
|
#ifdef HAVE_LIBLO
|
||||||
# include <lo/lo.h>
|
# include <lo/lo.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ void CardinalPluginContext::writeMidiMessage(const rack::midi::Message& message,
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifdef CARDINAL_INIT_OSC_THREAD
|
#ifdef HAVE_LIBLO
|
||||||
static void osc_error_handler(int num, const char* msg, const char* path)
|
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);
|
d_stderr("Cardinal OSC Error: code: %i, msg: \"%s\", path: \"%s\")", num, msg, path);
|
||||||
|
@ -245,9 +245,9 @@ static int osc_fallback_handler(const char* const path, const char* const types,
|
||||||
|
|
||||||
static int osc_hello_handler(const char*, const char*, lo_arg**, int, const lo_message m, void* const self)
|
static int osc_hello_handler(const char*, const char*, lo_arg**, int, const lo_message m, void* const self)
|
||||||
{
|
{
|
||||||
d_debug("osc_hello_handler()");
|
d_stdout("Hello received from OSC, saying hello back to them o/");
|
||||||
const lo_address source = lo_message_get_source(m);
|
const lo_address source = lo_message_get_source(m);
|
||||||
const lo_server server = lo_server_thread_get_server(static_cast<Initializer*>(self)->oscServerThread);
|
const lo_server server = static_cast<Initializer*>(self)->oscServer;
|
||||||
lo_send_from(source, server, LO_TT_IMMEDIATE, "/resp", "ss", "hello", "ok");
|
lo_send_from(source, server, LO_TT_IMMEDIATE, "/resp", "ss", "hello", "ok");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -287,7 +287,7 @@ 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);
|
||||||
const lo_server server = lo_server_thread_get_server(static_cast<Initializer*>(self)->oscServerThread);
|
const lo_server server = static_cast<Initializer*>(self)->oscServer;
|
||||||
lo_send_from(source, server, LO_TT_IMMEDIATE, "/resp", "ss", "load", ok ? "ok" : "fail");
|
lo_send_from(source, server, LO_TT_IMMEDIATE, "/resp", "ss", "load", ok ? "ok" : "fail");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -344,6 +344,7 @@ static int osc_host_param_handler(const char*, const char* types, lo_arg** argv,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ifdef CARDINAL_INIT_OSC_THREAD
|
||||||
static int osc_screenshot_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self)
|
static int osc_screenshot_handler(const char*, const char* types, lo_arg** argv, int argc, const lo_message m, void* const self)
|
||||||
{
|
{
|
||||||
d_debug("osc_screenshot_handler()");
|
d_debug("osc_screenshot_handler()");
|
||||||
|
@ -368,10 +369,11 @@ static int osc_screenshot_handler(const char*, const char* types, lo_arg** argv,
|
||||||
}
|
}
|
||||||
|
|
||||||
const lo_address source = lo_message_get_source(m);
|
const lo_address source = lo_message_get_source(m);
|
||||||
const lo_server server = lo_server_thread_get_server(static_cast<Initializer*>(self)->oscServerThread);
|
const lo_server server = static_cast<Initializer*>(self)->oscServer;
|
||||||
lo_send_from(source, server, LO_TT_IMMEDIATE, "/resp", "ss", "screenshot", ok ? "ok" : "fail");
|
lo_send_from(source, server, LO_TT_IMMEDIATE, "/resp", "ss", "screenshot", ok ? "ok" : "fail");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------
|
||||||
|
@ -575,41 +577,32 @@ Initializer::Initializer(const CardinalBasePlugin* const plugin, const CardinalB
|
||||||
|
|
||||||
loadSettings(isRealInstance);
|
loadSettings(isRealInstance);
|
||||||
|
|
||||||
#ifdef CARDINAL_INIT_OSC_THREAD
|
#if defined(CARDINAL_INIT_OSC_THREAD)
|
||||||
INFO("Initializing OSC Remote control");
|
INFO("Initializing OSC Remote control");
|
||||||
const char* port;
|
const char* port;
|
||||||
if (const char* const portEnv = std::getenv("CARDINAL_REMOTE_HOST_PORT"))
|
if (const char* const portEnv = std::getenv("CARDINAL_REMOTE_HOST_PORT"))
|
||||||
port = portEnv;
|
port = portEnv;
|
||||||
else
|
else
|
||||||
port = CARDINAL_DEFAULT_REMOTE_PORT;
|
port = CARDINAL_DEFAULT_REMOTE_PORT;
|
||||||
oscServerThread = lo_server_thread_new_with_proto(port, LO_UDP, osc_error_handler);
|
startRemoteServer(port);
|
||||||
DISTRHO_SAFE_ASSERT_RETURN(oscServerThread != nullptr,);
|
#elif defined(HAVE_LIBLO)
|
||||||
|
if (isStandalone()) {
|
||||||
lo_server_thread_add_method(oscServerThread, "/hello", "", osc_hello_handler, this);
|
INFO("OSC Remote control is available on request");
|
||||||
lo_server_thread_add_method(oscServerThread, "/host-param", "if", osc_host_param_handler, this);
|
} else {
|
||||||
lo_server_thread_add_method(oscServerThread, "/load", "b", osc_load_handler, this);
|
INFO("OSC Remote control is not available on plugin variants");
|
||||||
lo_server_thread_add_method(oscServerThread, "/param", "hif", osc_param_handler, this);
|
}
|
||||||
lo_server_thread_add_method(oscServerThread, "/screenshot", "b", osc_screenshot_handler, this);
|
#else
|
||||||
lo_server_thread_add_method(oscServerThread, nullptr, nullptr, osc_fallback_handler, nullptr);
|
|
||||||
lo_server_thread_start(oscServerThread);
|
|
||||||
#else
|
|
||||||
INFO("OSC Remote control is not enabled in this build");
|
INFO("OSC Remote control is not enabled in this build");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Initializer::~Initializer()
|
Initializer::~Initializer()
|
||||||
{
|
{
|
||||||
using namespace rack;
|
using namespace rack;
|
||||||
|
|
||||||
#ifdef CARDINAL_INIT_OSC_THREAD
|
#ifdef HAVE_LIBLO
|
||||||
if (oscServerThread != nullptr)
|
stopRemoteServer();
|
||||||
{
|
#endif
|
||||||
lo_server_thread_stop(oscServerThread);
|
|
||||||
lo_server_thread_del_method(oscServerThread, nullptr, nullptr);
|
|
||||||
lo_server_thread_free(oscServerThread);
|
|
||||||
oscServerThread = nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (shouldSaveSettings)
|
if (shouldSaveSettings)
|
||||||
{
|
{
|
||||||
|
@ -670,6 +663,81 @@ void Initializer::loadSettings(const bool isRealInstance)
|
||||||
switchDarkMode(settings::uiTheme == "dark");
|
switchDarkMode(settings::uiTheme == "dark");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBLO
|
||||||
|
bool Initializer::startRemoteServer(const char* const port)
|
||||||
|
{
|
||||||
|
#ifdef CARDINAL_INIT_OSC_THREAD
|
||||||
|
if (oscServerThread != nullptr)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if ((oscServerThread = lo_server_thread_new_with_proto(port, LO_UDP, osc_error_handler)) == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
oscServer = lo_server_thread_get_server(oscServerThread);
|
||||||
|
|
||||||
|
lo_server_thread_add_method(oscServerThread, "/hello", "", osc_hello_handler, this);
|
||||||
|
lo_server_thread_add_method(oscServerThread, "/host-param", "if", osc_host_param_handler, this);
|
||||||
|
lo_server_thread_add_method(oscServerThread, "/load", "b", osc_load_handler, this);
|
||||||
|
lo_server_thread_add_method(oscServerThread, "/param", "hif", osc_param_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);
|
||||||
|
lo_server_thread_start(oscServerThread);
|
||||||
|
#else
|
||||||
|
if (oscServer != nullptr)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if ((oscServer = lo_server_new_with_proto(port, LO_UDP, osc_error_handler)) == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
lo_server_add_method(oscServer, "/hello", "", osc_hello_handler, this);
|
||||||
|
lo_server_add_method(oscServer, "/host-param", "if", osc_host_param_handler, this);
|
||||||
|
lo_server_add_method(oscServer, "/load", "b", osc_load_handler, this);
|
||||||
|
lo_server_add_method(oscServer, "/param", "hif", osc_param_handler, this);
|
||||||
|
lo_server_add_method(oscServer, nullptr, nullptr, osc_fallback_handler, nullptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Initializer::stopRemoteServer()
|
||||||
|
{
|
||||||
|
DISTRHO_SAFE_ASSERT(remotePluginInstance == nullptr);
|
||||||
|
|
||||||
|
#ifdef CARDINAL_INIT_OSC_THREAD
|
||||||
|
if (oscServerThread != nullptr)
|
||||||
|
{
|
||||||
|
lo_server_thread_stop(oscServerThread);
|
||||||
|
lo_server_thread_del_method(oscServerThread, nullptr, nullptr);
|
||||||
|
lo_server_thread_free(oscServerThread);
|
||||||
|
oscServerThread = oscServer = nullptr;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (oscServer != nullptr)
|
||||||
|
{
|
||||||
|
lo_server_del_method(oscServer, nullptr, nullptr);
|
||||||
|
lo_server_free(oscServer);
|
||||||
|
oscServer = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Initializer::stepRemoteServer()
|
||||||
|
{
|
||||||
|
DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr,);
|
||||||
|
DISTRHO_SAFE_ASSERT_RETURN(remotePluginInstance != nullptr,);
|
||||||
|
|
||||||
|
#ifndef CARDINAL_INIT_OSC_THREAD
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (lo_server_recv_noblock(oscServer, 0) == 0)
|
||||||
|
break;
|
||||||
|
} DISTRHO_SAFE_EXCEPTION_CONTINUE("stepRemoteServer")
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif // HAVE_LIBLO
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
END_NAMESPACE_DISTRHO
|
END_NAMESPACE_DISTRHO
|
||||||
|
|
|
@ -87,6 +87,7 @@ void openBrowser(const std::string& url);
|
||||||
# define CARDINAL_INIT_OSC_THREAD
|
# define CARDINAL_INIT_OSC_THREAD
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef void* lo_server;
|
||||||
typedef void* lo_server_thread;
|
typedef void* lo_server_thread;
|
||||||
|
|
||||||
START_NAMESPACE_DISTRHO
|
START_NAMESPACE_DISTRHO
|
||||||
|
@ -97,10 +98,6 @@ struct CardinalPluginContext;
|
||||||
|
|
||||||
struct Initializer
|
struct Initializer
|
||||||
{
|
{
|
||||||
#ifdef CARDINAL_INIT_OSC_THREAD
|
|
||||||
lo_server_thread oscServerThread = nullptr;
|
|
||||||
CardinalBasePlugin* remotePluginInstance = nullptr;
|
|
||||||
#endif
|
|
||||||
std::string templatePath;
|
std::string templatePath;
|
||||||
std::string factoryTemplatePath;
|
std::string factoryTemplatePath;
|
||||||
bool shouldSaveSettings = false;
|
bool shouldSaveSettings = false;
|
||||||
|
@ -108,6 +105,18 @@ struct Initializer
|
||||||
Initializer(const CardinalBasePlugin* plugin, const CardinalBaseUI* ui);
|
Initializer(const CardinalBasePlugin* plugin, const CardinalBaseUI* ui);
|
||||||
~Initializer();
|
~Initializer();
|
||||||
void loadSettings(bool isRealInstance);
|
void loadSettings(bool isRealInstance);
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBLO
|
||||||
|
lo_server oscServer = nullptr;
|
||||||
|
#ifdef CARDINAL_INIT_OSC_THREAD
|
||||||
|
lo_server_thread oscServerThread = nullptr;
|
||||||
|
#endif
|
||||||
|
CardinalBasePlugin* remotePluginInstance = nullptr;
|
||||||
|
|
||||||
|
bool startRemoteServer(const char* port);
|
||||||
|
void stopRemoteServer();
|
||||||
|
void stepRemoteServer();
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef HEADLESS
|
#ifndef HEADLESS
|
||||||
|
|
|
@ -167,7 +167,6 @@ struct ScopedContext {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
class CardinalPlugin : public CardinalBasePlugin
|
class CardinalPlugin : public CardinalBasePlugin
|
||||||
|
@ -333,7 +332,7 @@ public:
|
||||||
|
|
||||||
~CardinalPlugin() override
|
~CardinalPlugin() override
|
||||||
{
|
{
|
||||||
#ifdef CARDINAL_INIT_OSC_THREAD
|
#ifdef HAVE_LIBLO
|
||||||
if (fInitializer->remotePluginInstance == this)
|
if (fInitializer->remotePluginInstance == this)
|
||||||
fInitializer->remotePluginInstance = nullptr;
|
fInitializer->remotePluginInstance = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
@ -359,6 +358,37 @@ public:
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBLO
|
||||||
|
bool startRemoteServer(const char* const port) override
|
||||||
|
{
|
||||||
|
if (fInitializer->remotePluginInstance != nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (fInitializer->startRemoteServer(port))
|
||||||
|
{
|
||||||
|
fInitializer->remotePluginInstance = this;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopRemoteServer() override
|
||||||
|
{
|
||||||
|
DISTRHO_SAFE_ASSERT_RETURN(fInitializer->remotePluginInstance == this,);
|
||||||
|
|
||||||
|
fInitializer->remotePluginInstance = nullptr;
|
||||||
|
fInitializer->stopRemoteServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void stepRemoteServer() override
|
||||||
|
{
|
||||||
|
DISTRHO_SAFE_ASSERT_RETURN(fInitializer->remotePluginInstance == this,);
|
||||||
|
|
||||||
|
fInitializer->stepRemoteServer();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* --------------------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------------------
|
||||||
* Information */
|
* Information */
|
||||||
|
|
|
@ -218,6 +218,12 @@ public:
|
||||||
context(new CardinalPluginContext(this)) {}
|
context(new CardinalPluginContext(this)) {}
|
||||||
~CardinalBasePlugin() override {}
|
~CardinalBasePlugin() override {}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBLO
|
||||||
|
virtual bool startRemoteServer(const char* port) = 0;
|
||||||
|
virtual void stopRemoteServer() = 0;
|
||||||
|
virtual void stepRemoteServer() = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef HEADLESS
|
#ifndef HEADLESS
|
||||||
friend class CardinalUI;
|
friend class CardinalUI;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
|
|
||||||
#include "../CardinalCommon.hpp"
|
#include "../CardinalCommon.hpp"
|
||||||
#include "../CardinalRemote.hpp"
|
#include "../CardinalRemote.hpp"
|
||||||
|
#include "../PluginContext.hpp"
|
||||||
#include "DistrhoPlugin.hpp"
|
#include "DistrhoPlugin.hpp"
|
||||||
#include "DistrhoStandaloneUtils.hpp"
|
#include "DistrhoStandaloneUtils.hpp"
|
||||||
|
|
||||||
|
@ -729,6 +730,10 @@ struct ViewButton : MenuButton {
|
||||||
|
|
||||||
|
|
||||||
struct EngineButton : MenuButton {
|
struct EngineButton : MenuButton {
|
||||||
|
#ifdef HAVE_LIBLO
|
||||||
|
bool remoteServerStarted = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
void onAction(const ActionEvent& e) override {
|
void onAction(const ActionEvent& e) override {
|
||||||
ui::Menu* menu = createMenu();
|
ui::Menu* menu = createMenu();
|
||||||
menu->cornerFlags = BND_CORNER_TOP;
|
menu->cornerFlags = BND_CORNER_TOP;
|
||||||
|
@ -741,6 +746,34 @@ struct EngineButton : MenuButton {
|
||||||
settings::cpuMeter ^= true;
|
settings::cpuMeter ^= true;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBLO
|
||||||
|
if (isStandalone()) {
|
||||||
|
CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP);
|
||||||
|
CardinalBasePlugin* const plugin = static_cast<CardinalBasePlugin*>(context->plugin);
|
||||||
|
|
||||||
|
// const bool remoteServerStarted = this->remoteServerStarted;
|
||||||
|
const std::string remoteControlText = remoteServerStarted ? " " CHECKMARK_STRING : "";
|
||||||
|
|
||||||
|
menu->addChild(createMenuItem("Enable OSC remote control", remoteControlText, [=]() {
|
||||||
|
if (remoteServerStarted) {
|
||||||
|
remoteServerStarted = false;
|
||||||
|
plugin->stopRemoteServer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async_dialog_text_input("OSC network port", CARDINAL_DEFAULT_REMOTE_PORT, [=](char* const port) {
|
||||||
|
if (port == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (plugin->startRemoteServer(port))
|
||||||
|
remoteServerStarted = true;
|
||||||
|
|
||||||
|
std::free(port);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (isUsingNativeAudio()) {
|
if (isUsingNativeAudio()) {
|
||||||
if (supportsAudioInput()) {
|
if (supportsAudioInput()) {
|
||||||
const bool enabled = isAudioInputEnabled();
|
const bool enabled = isAudioInputEnabled();
|
||||||
|
@ -782,6 +815,18 @@ struct EngineButton : MenuButton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBLO
|
||||||
|
void step() override {
|
||||||
|
MenuButton::step();
|
||||||
|
|
||||||
|
if (remoteServerStarted) {
|
||||||
|
CardinalPluginContext* const context = static_cast<CardinalPluginContext*>(APP);
|
||||||
|
CardinalBasePlugin* const plugin = static_cast<CardinalBasePlugin*>(context->plugin);
|
||||||
|
plugin->stepRemoteServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue