diff --git a/libs/ardour/vst3_host.cc b/libs/ardour/vst3_host.cc index 0ba39bc82f..f690d95a09 100644 --- a/libs/ardour/vst3_host.cc +++ b/libs/ardour/vst3_host.cc @@ -29,6 +29,11 @@ #include "pbd/compose.h" #endif +#if SMTG_OS_LINUX +#include +#include +#endif + using namespace Steinberg; DEF_CLASS_IID (FUnknown) @@ -77,6 +82,143 @@ DEF_CLASS_IID (Presonus::IPlugInViewScaling) #if SMTG_OS_LINUX DEF_CLASS_IID (Linux::IRunLoop); + +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 std::string @@ -467,6 +609,13 @@ HostApplication::queryInterface (const char* _iid, void** obj) QUERY_INTERFACE (_iid, obj, FUnknown::iid, IHostApplication) QUERY_INTERFACE (_iid, obj, IHostApplication::iid, IHostApplication) +#if SMTG_OS_LINUX + if (FUnknownPrivate::iidEqual (_iid, Linux::IRunLoop::iid)) { + *obj = &static_runloop; + return kResultOk; + } +#endif + if (_plug_interface_support && _plug_interface_support->queryInterface (_iid, obj) == kResultTrue) { return kResultOk; } diff --git a/libs/ardour/vst3_plugin.cc b/libs/ardour/vst3_plugin.cc index 66eb37f5d2..2360efb9b0 100644 --- a/libs/ardour/vst3_plugin.cc +++ b/libs/ardour/vst3_plugin.cc @@ -21,8 +21,6 @@ #include "pbd/gstdio_compat.h" #include -#include - #include "pbd/basename.h" #include "pbd/compose.h" #include "pbd/convert.h" @@ -58,146 +56,6 @@ 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) @@ -1221,6 +1079,14 @@ VST3PluginInfo::load (Session& session) if (!m) { DEBUG_TRACE (DEBUG::VST3Config, string_compose ("VST3 Loading: %1\n", path)); m = VST3PluginModule::load (path); +#if SMTG_OS_LINUX + IPluginFactory* factory = m->factory (); + IPtr factory3 = FUnknownPtr (factory); + if (factory3) { + DEBUG_TRACE (DEBUG::VST3Config, "VST3 detected IPluginFactory3, setting Linux runloop host context\n"); + factory3->setHostContext ((FUnknown*) HostApplication::getHostContext ()); + } +#endif } PluginPtr plugin; Steinberg::VST3PI* plug = new VST3PI (m, unique_id); @@ -1425,14 +1291,6 @@ VST3PI::VST3PI (std::shared_ptr m, std::string unique_ throw failed_constructor (); } -#if SMTG_OS_LINUX - IPtr factory3 = FUnknownPtr (factory); - if (factory3) { - Vst::IComponentHandler* ctx = this; - factory3->setHostContext ((FUnknown*) ctx); - } -#endif - /* prepare process context */ memset (&_context, 0, sizeof (Vst::ProcessContext)); @@ -1659,13 +1517,6 @@ VST3PI::queryInterface (const TUID _iid, void** obj) QUERY_INTERFACE (_iid, obj, IPlugFrame::iid, IPlugFrame) -#if SMTG_OS_LINUX - if (FUnknownPrivate::iidEqual (_iid, Linux::IRunLoop::iid)) { - *obj = &static_runloop; - return kResultOk; - } -#endif - if (DEBUG_ENABLED (DEBUG::VST3Config)) { char fuid[33]; FUID::fromTUID (_iid).toString (fuid);