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>
|
||||
#endif
|
||||
|
||||
#ifdef CARDINAL_INIT_OSC_THREAD
|
||||
#ifdef HAVE_LIBLO
|
||||
# include <lo/lo.h>
|
||||
#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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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_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");
|
||||
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_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");
|
||||
return 0;
|
||||
}
|
||||
|
@ -344,6 +344,7 @@ static int osc_host_param_handler(const char*, const char* types, lo_arg** argv,
|
|||
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)
|
||||
{
|
||||
d_debug("osc_screenshot_handler()");
|
||||
|
@ -368,11 +369,12 @@ static int osc_screenshot_handler(const char*, const char* types, lo_arg** argv,
|
|||
}
|
||||
|
||||
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");
|
||||
return 0;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -575,23 +577,20 @@ Initializer::Initializer(const CardinalBasePlugin* const plugin, const CardinalB
|
|||
|
||||
loadSettings(isRealInstance);
|
||||
|
||||
#ifdef CARDINAL_INIT_OSC_THREAD
|
||||
#if defined(CARDINAL_INIT_OSC_THREAD)
|
||||
INFO("Initializing OSC Remote control");
|
||||
const char* port;
|
||||
if (const char* const portEnv = std::getenv("CARDINAL_REMOTE_HOST_PORT"))
|
||||
port = portEnv;
|
||||
else
|
||||
port = CARDINAL_DEFAULT_REMOTE_PORT;
|
||||
oscServerThread = lo_server_thread_new_with_proto(port, LO_UDP, osc_error_handler);
|
||||
DISTRHO_SAFE_ASSERT_RETURN(oscServerThread != nullptr,);
|
||||
|
||||
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);
|
||||
startRemoteServer(port);
|
||||
#elif defined(HAVE_LIBLO)
|
||||
if (isStandalone()) {
|
||||
INFO("OSC Remote control is available on request");
|
||||
} else {
|
||||
INFO("OSC Remote control is not available on plugin variants");
|
||||
}
|
||||
#else
|
||||
INFO("OSC Remote control is not enabled in this build");
|
||||
#endif
|
||||
|
@ -601,14 +600,8 @@ Initializer::~Initializer()
|
|||
{
|
||||
using namespace rack;
|
||||
|
||||
#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 = nullptr;
|
||||
}
|
||||
#ifdef HAVE_LIBLO
|
||||
stopRemoteServer();
|
||||
#endif
|
||||
|
||||
if (shouldSaveSettings)
|
||||
|
@ -670,6 +663,81 @@ void Initializer::loadSettings(const bool isRealInstance)
|
|||
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
|
||||
|
|
|
@ -87,6 +87,7 @@ void openBrowser(const std::string& url);
|
|||
# define CARDINAL_INIT_OSC_THREAD
|
||||
#endif
|
||||
|
||||
typedef void* lo_server;
|
||||
typedef void* lo_server_thread;
|
||||
|
||||
START_NAMESPACE_DISTRHO
|
||||
|
@ -97,10 +98,6 @@ struct CardinalPluginContext;
|
|||
|
||||
struct Initializer
|
||||
{
|
||||
#ifdef CARDINAL_INIT_OSC_THREAD
|
||||
lo_server_thread oscServerThread = nullptr;
|
||||
CardinalBasePlugin* remotePluginInstance = nullptr;
|
||||
#endif
|
||||
std::string templatePath;
|
||||
std::string factoryTemplatePath;
|
||||
bool shouldSaveSettings = false;
|
||||
|
@ -108,6 +105,18 @@ struct Initializer
|
|||
Initializer(const CardinalBasePlugin* plugin, const CardinalBaseUI* ui);
|
||||
~Initializer();
|
||||
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
|
||||
|
|
|
@ -167,7 +167,6 @@ struct ScopedContext {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
class CardinalPlugin : public CardinalBasePlugin
|
||||
|
@ -333,7 +332,7 @@ public:
|
|||
|
||||
~CardinalPlugin() override
|
||||
{
|
||||
#ifdef CARDINAL_INIT_OSC_THREAD
|
||||
#ifdef HAVE_LIBLO
|
||||
if (fInitializer->remotePluginInstance == this)
|
||||
fInitializer->remotePluginInstance = nullptr;
|
||||
#endif
|
||||
|
@ -359,6 +358,37 @@ public:
|
|||
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:
|
||||
/* --------------------------------------------------------------------------------------------------------
|
||||
* Information */
|
||||
|
|
|
@ -218,6 +218,12 @@ public:
|
|||
context(new CardinalPluginContext(this)) {}
|
||||
~CardinalBasePlugin() override {}
|
||||
|
||||
#ifdef HAVE_LIBLO
|
||||
virtual bool startRemoteServer(const char* port) = 0;
|
||||
virtual void stopRemoteServer() = 0;
|
||||
virtual void stepRemoteServer() = 0;
|
||||
#endif
|
||||
|
||||
#ifndef HEADLESS
|
||||
friend class CardinalUI;
|
||||
#endif
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
|
||||
#include "../CardinalCommon.hpp"
|
||||
#include "../CardinalRemote.hpp"
|
||||
#include "../PluginContext.hpp"
|
||||
#include "DistrhoPlugin.hpp"
|
||||
#include "DistrhoStandaloneUtils.hpp"
|
||||
|
||||
|
@ -729,6 +730,10 @@ struct ViewButton : MenuButton {
|
|||
|
||||
|
||||
struct EngineButton : MenuButton {
|
||||
#ifdef HAVE_LIBLO
|
||||
bool remoteServerStarted = false;
|
||||
#endif
|
||||
|
||||
void onAction(const ActionEvent& e) override {
|
||||
ui::Menu* menu = createMenu();
|
||||
menu->cornerFlags = BND_CORNER_TOP;
|
||||
|
@ -741,6 +746,34 @@ struct EngineButton : MenuButton {
|
|||
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 (supportsAudioInput()) {
|
||||
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