From 816860e0f550783be9daf0c1093f58c5b7d9b904 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Thu, 13 Jun 2024 21:05:06 +0200 Subject: [PATCH] VST3: move runloop into backend (1/3) --- libs/ardour/vst3_plugin.cc | 146 ++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 2 deletions(-) diff --git a/libs/ardour/vst3_plugin.cc b/libs/ardour/vst3_plugin.cc index 48cc24e09c..865dabaf14 100644 --- a/libs/ardour/vst3_plugin.cc +++ b/libs/ardour/vst3_plugin.cc @@ -19,6 +19,8 @@ #include "pbd/gstdio_compat.h" #include +#include + #include "pbd/basename.h" #include "pbd/compose.h" #include "pbd/convert.h" @@ -54,6 +56,146 @@ using namespace Temporal; using namespace Steinberg; using namespace Presonus; +#if SMTG_OS_LINUX +class AVST3Runloop : public Linux::IRunLoop +{ +private: + struct EventHandler + { + EventHandler (Linux::IEventHandler* handler = 0, GIOChannel* gio_channel = 0, guint source_id = 0) + : _handler (handler) + , _gio_channel (gio_channel) + , _source_id (source_id) + {} + + bool operator== (EventHandler const& other) { + return other._handler == _handler && other._gio_channel == _gio_channel && other._source_id == _source_id; + } + Linux::IEventHandler* _handler; + GIOChannel* _gio_channel; + guint _source_id; + }; + + boost::unordered_map _event_handlers; + boost::unordered_map _timer_handlers; + + static gboolean event (GIOChannel* source, GIOCondition condition, gpointer data) + { + Linux::IEventHandler* handler = reinterpret_cast (data); + handler->onFDIsSet (g_io_channel_unix_get_fd (source)); + if (condition & ~G_IO_IN) { + /* remove on error */ + return false; + } else { + return true; + } + } + + static gboolean timeout (gpointer data) + { + Linux::ITimerHandler* handler = reinterpret_cast (data); + handler->onTimer (); + return true; + } + +public: + ~AVST3Runloop () + { + clear (); + } + + void clear () { + Glib::Threads::Mutex::Lock lm (_lock); + for (boost::unordered_map::const_iterator it = _event_handlers.begin (); it != _event_handlers.end (); ++it) { + g_source_remove (it->second._source_id); + g_io_channel_unref (it->second._gio_channel); + } + for (boost::unordered_map::const_iterator it = _timer_handlers.begin (); it != _timer_handlers.end (); ++it) { + g_source_remove (it->first); + } + _event_handlers.clear (); + _timer_handlers.clear (); + } + + /* VST3 IRunLoop interface */ + tresult registerEventHandler (Linux::IEventHandler* handler, FileDescriptor fd) SMTG_OVERRIDE + { + if (!handler || _event_handlers.find(fd) != _event_handlers.end()) { + return kInvalidArgument; + } + + Glib::Threads::Mutex::Lock lm (_lock); + GIOChannel* gio_channel = g_io_channel_unix_new (fd); + guint id = g_io_add_watch (gio_channel, (GIOCondition) (G_IO_IN /*| G_IO_OUT*/ | G_IO_ERR | G_IO_HUP), event, handler); + _event_handlers[fd] = EventHandler (handler, gio_channel, id); + return kResultTrue; + } + + tresult unregisterEventHandler (Linux::IEventHandler* handler) SMTG_OVERRIDE + { + if (!handler) { + return kInvalidArgument; + } + + tresult rv = false; + Glib::Threads::Mutex::Lock lm (_lock); + for (boost::unordered_map::const_iterator it = _event_handlers.begin (); it != _event_handlers.end ();) { + if (it->second._handler == handler) { + g_source_remove (it->second._source_id); + g_io_channel_unref (it->second._gio_channel); + it = _event_handlers.erase (it); + rv = kResultTrue; + } else { + ++it; + } + } + return rv; + } + + tresult registerTimer (Linux::ITimerHandler* handler, TimerInterval milliseconds) SMTG_OVERRIDE + { + if (!handler || milliseconds == 0) { + return kInvalidArgument; + } + Glib::Threads::Mutex::Lock lm (_lock); + guint id = g_timeout_add_full (G_PRIORITY_HIGH_IDLE, milliseconds, timeout, handler, NULL); + _timer_handlers[id] = handler; + return kResultTrue; + + } + + tresult unregisterTimer (Linux::ITimerHandler* handler) SMTG_OVERRIDE + { + if (!handler) { + return kInvalidArgument; + } + + tresult rv = false; + Glib::Threads::Mutex::Lock lm (_lock); + for (boost::unordered_map::const_iterator it = _timer_handlers.begin (); it != _timer_handlers.end ();) { + if (it->second == handler) { + g_source_remove (it->first); + it = _timer_handlers.erase (it); + rv = kResultTrue; + } else { + ++it; + } + } + return rv; + } + + uint32 PLUGIN_API addRef () SMTG_OVERRIDE { return 1; } + uint32 PLUGIN_API release () SMTG_OVERRIDE { return 1; } + tresult queryInterface (const TUID, void**) SMTG_OVERRIDE { return kNoInterface; } + +private: + Glib::Threads::Mutex _lock; +}; + +AVST3Runloop static_runloop; + +#endif + VST3Plugin::VST3Plugin (AudioEngine& engine, Session& session, VST3PI* plug) : Plugin (engine, session) , _plug (plug) @@ -1505,8 +1647,8 @@ VST3PI::queryInterface (const TUID _iid, void** obj) QUERY_INTERFACE (_iid, obj, IPlugFrame::iid, IPlugFrame) #if SMTG_OS_LINUX - if (_run_loop && FUnknownPrivate::iidEqual (_iid, Linux::IRunLoop::iid)) { - *obj = _run_loop; + if (FUnknownPrivate::iidEqual (_iid, Linux::IRunLoop::iid)) { + *obj = &static_runloop; return kResultOk; } #endif