DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

commit 8904662794f5a201321033ddc305f9211eeb60a7
parent a1926680fdc76cd72b61e4212f68c9abe202c36a
Author: falkTX <falktx@falktx.com>
Date:   Fri,  1 Oct 2021 21:49:25 +0100

VST3: Implement view timer handler, hook into host run loop

Signed-off-by: falkTX <falktx@falktx.com>

Diffstat:
MMakefile.plugins.mk | 3+--
Mdistrho/src/DistrhoPluginVST3.cpp | 6++++++
Mdistrho/src/DistrhoUIVST3.cpp | 284+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mdistrho/src/travesty/view.h | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
4 files changed, 252 insertions(+), 125 deletions(-)

diff --git a/Makefile.plugins.mk b/Makefile.plugins.mk @@ -399,8 +399,7 @@ $(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o endif -@mkdir -p $(shell dirname $@) @echo "Creating VST3 plugin for $(NAME)" - # NOTE TESTING -lpthread is for testing, remove later - $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) -lpthread $(SYMBOLS_VST3) -o $@ + $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST3) -o $@ # --------------------------------------------------------------------------------------------------------------------- diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp @@ -140,6 +140,8 @@ const char* tuid2str(const v3_tuid iid) return "{v3_connection_point_iid}"; if (v3_tuid_match(iid, v3_edit_controller_iid)) return "{v3_edit_controller}"; + if (v3_tuid_match(iid, v3_event_handler_iid)) + return "{v3_event_handler_iid}"; if (v3_tuid_match(iid, v3_event_list_iid)) return "{v3_event_list}"; if (v3_tuid_match(iid, v3_funknown_iid)) @@ -172,6 +174,10 @@ const char* tuid2str(const v3_tuid iid) return "{v3_plugin_view_parameter_finder}"; if (v3_tuid_match(iid, v3_process_context_requirements_iid)) return "{v3_process_context_requirements}"; + if (v3_tuid_match(iid, v3_run_loop_iid)) + return "{v3_run_loop_iid}"; + if (v3_tuid_match(iid, v3_timer_handler_iid)) + return "{v3_timer_handler_iid}"; if (std::memcmp(iid, dpf_tuid_class, sizeof(dpf_tuid)) == 0) return "{dpf_tuid_class}"; diff --git a/distrho/src/DistrhoUIVST3.cpp b/distrho/src/DistrhoUIVST3.cpp @@ -18,9 +18,6 @@ #include <atomic> -// TESTING awful idea dont reuse -#include "../extra/Thread.hpp" - #include "travesty/edit_controller.h" #include "travesty/host.h" #include "travesty/view.h" @@ -32,7 +29,6 @@ * - host-side resize * - oddities with init and size callback (triggered too early?) * - win/mac native idle loop - * - linux runloop */ START_NAMESPACE_DISTRHO @@ -73,7 +69,7 @@ struct ScopedUTF16String { * * The low-level VST3 stuff comes after. */ -class UIVst3 : public Thread +class UIVst3 { public: UIVst3(v3_plugin_view** const view, @@ -99,34 +95,14 @@ public: fReadyForPluginData(false), fScaleFactor(scaleFactor) { - // TESTING awful idea dont reuse - startThread(); } - ~UIVst3() override + ~UIVst3() { - stopThread(5000); - if (fConnection != nullptr) disconnect(); } - // TESTING awful idea dont reuse - void run() override - { - while (! shouldThreadExit()) - { - if (fReadyForPluginData) - { - fReadyForPluginData = false; - requestMorePluginData(); - } - - fUI.plugin_idle(); - d_msleep(50); - } - } - // ---------------------------------------------------------------------------------------------------------------- // v3_plugin_view interface calls @@ -194,19 +170,6 @@ public: } // ---------------------------------------------------------------------------------------------------------------- - // v3_plugin_view_content_scale_steinberg interface calls - - v3_result setContentScaleFactor(const float factor) - { - if (d_isEqual(fScaleFactor, factor)) - return V3_OK; - - fScaleFactor = factor; - fUI.notifyScaleFactorChanged(factor); - return V3_OK; - } - - // ---------------------------------------------------------------------------------------------------------------- // v3_connection_point interface calls void connect(v3_connection_point** const point) noexcept @@ -345,6 +308,33 @@ public: } // ---------------------------------------------------------------------------------------------------------------- + // v3_plugin_view_content_scale_steinberg interface calls + + v3_result setContentScaleFactor(const float factor) + { + if (d_isEqual(fScaleFactor, factor)) + return V3_OK; + + fScaleFactor = factor; + fUI.notifyScaleFactorChanged(factor); + return V3_OK; + } + + // ---------------------------------------------------------------------------------------------------------------- + // v3_timer_handler interface calls + + void onTimer() + { + if (fReadyForPluginData) + { + fReadyForPluginData = false; + requestMorePluginData(); + } + + fUI.plugin_idle(); + } + + // ---------------------------------------------------------------------------------------------------------------- private: // Plugin UI @@ -534,7 +524,91 @@ private: */ // -------------------------------------------------------------------------------------------------------------------- -// dpf_ +// dpf_ui_connection_point + +struct dpf_ui_connection_point : v3_connection_point_cpp { + ScopedPointer<UIVst3>& uivst3; + v3_connection_point** other; + + dpf_ui_connection_point(ScopedPointer<UIVst3>& v) + : uivst3(v), + other(nullptr) + { + static const uint8_t* kSupportedInterfaces[] = { + v3_funknown_iid, + v3_connection_point_iid + }; + + // ------------------------------------------------------------------------------------------------------------ + // v3_funknown + + query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result + { + d_stdout("dpf_ui_connection_point::query_interface => %p %s %p", self, tuid2str(iid), iface); + *iface = NULL; + DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); + + for (const uint8_t* interface_iid : kSupportedInterfaces) + { + if (v3_tuid_match(interface_iid, iid)) + { + *iface = self; + return V3_OK; + } + } + + return V3_NO_INTERFACE; + }; + + // there is only a single instance of this, so we don't have to care here + ref = []V3_API(void*) -> uint32_t { return 1; }; + unref = []V3_API(void*) -> uint32_t { return 0; }; + + // ------------------------------------------------------------------------------------------------------------ + // v3_connection_point + + point.connect = []V3_API(void* self, v3_connection_point** other) -> v3_result + { + d_stdout("dpf_ui_connection_point::connect => %p %p", self, other); + dpf_ui_connection_point* const point = *(dpf_ui_connection_point**)self; + DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED); + DISTRHO_SAFE_ASSERT_RETURN(point->other == nullptr, V3_INVALID_ARG); + + point->other = other; + + if (UIVst3* const uivst3 = point->uivst3) + uivst3->connect(other); + + return V3_OK; + }; + + point.disconnect = []V3_API(void* self, v3_connection_point** other) -> v3_result + { + d_stdout("dpf_ui_connection_point::disconnect => %p %p", self, other); + dpf_ui_connection_point* const point = *(dpf_ui_connection_point**)self; + DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED); + DISTRHO_SAFE_ASSERT_RETURN(point->other != nullptr, V3_INVALID_ARG); + + point->other = nullptr; + + if (UIVst3* const uivst3 = point->uivst3) + uivst3->disconnect(); + + return V3_OK; + }; + + point.notify = []V3_API(void* self, v3_message** message) -> v3_result + { + dpf_ui_connection_point* const point = *(dpf_ui_connection_point**)self; + DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED); + + UIVst3* const uivst3 = point->uivst3; + DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); + + return uivst3->notify(message); + }; + } +}; // -------------------------------------------------------------------------------------------------------------------- // dpf_plugin_view_content_scale @@ -603,89 +677,59 @@ struct dpf_plugin_view_content_scale : v3_plugin_view_content_scale_cpp { }; // -------------------------------------------------------------------------------------------------------------------- -// dpf_ui_connection_point +// dpf_timer_handler -struct dpf_ui_connection_point : v3_connection_point_cpp { +struct dpf_timer_handler : v3_timer_handler_cpp { ScopedPointer<UIVst3>& uivst3; - v3_connection_point** other; - dpf_ui_connection_point(ScopedPointer<UIVst3>& v) - : uivst3(v), - other(nullptr) + dpf_timer_handler(ScopedPointer<UIVst3>& v) + : uivst3(v) { + query_interface = query_interface_fn; + ref = ref_fn; + unref = unref_fn; + handler.on_timer = on_timer; + } + + // ---------------------------------------------------------------------------------------------------------------- + // v3_funknown + + static v3_result V3_API query_interface_fn(void* self, const v3_tuid iid, void** iface) + { + d_stdout("dpf_plugin_view_content_scale::query_interface => %p %s %p", self, tuid2str(iid), iface); + *iface = NULL; + DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); + static const uint8_t* kSupportedInterfaces[] = { v3_funknown_iid, - v3_connection_point_iid + v3_plugin_view_content_scale_iid }; - // ------------------------------------------------------------------------------------------------------------ - // v3_funknown - - query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result + for (const uint8_t* interface_iid : kSupportedInterfaces) { - d_stdout("dpf_ui_connection_point::query_interface => %p %s %p", self, tuid2str(iid), iface); - *iface = NULL; - DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); - - for (const uint8_t* interface_iid : kSupportedInterfaces) + if (v3_tuid_match(interface_iid, iid)) { - if (v3_tuid_match(interface_iid, iid)) - { - *iface = self; - return V3_OK; - } + *iface = self; + return V3_OK; } + } - return V3_NO_INTERFACE; - }; - - // there is only a single instance of this, so we don't have to care here - ref = []V3_API(void*) -> uint32_t { return 1; }; - unref = []V3_API(void*) -> uint32_t { return 0; }; - - // ------------------------------------------------------------------------------------------------------------ - // v3_connection_point - - point.connect = []V3_API(void* self, v3_connection_point** other) -> v3_result - { - d_stdout("dpf_ui_connection_point::connect => %p %p", self, other); - dpf_ui_connection_point* const point = *(dpf_ui_connection_point**)self; - DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED); - DISTRHO_SAFE_ASSERT_RETURN(point->other == nullptr, V3_INVALID_ARG); - - point->other = other; - - if (UIVst3* const uivst3 = point->uivst3) - uivst3->connect(other); - - return V3_OK; - }; - - point.disconnect = []V3_API(void* self, v3_connection_point** other) -> v3_result - { - d_stdout("dpf_ui_connection_point::disconnect => %p %p", self, other); - dpf_ui_connection_point* const point = *(dpf_ui_connection_point**)self; - DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED); - DISTRHO_SAFE_ASSERT_RETURN(point->other != nullptr, V3_INVALID_ARG); - - point->other = nullptr; - - if (UIVst3* const uivst3 = point->uivst3) - uivst3->disconnect(); + return V3_NO_INTERFACE; + } - return V3_OK; - }; + // there is only a single instance of this, so we don't have to care here + static uint32_t V3_API ref_fn(void*) { return 1; }; + static uint32_t V3_API unref_fn(void*) { return 0; }; - point.notify = []V3_API(void* self, v3_message** message) -> v3_result - { - dpf_ui_connection_point* const point = *(dpf_ui_connection_point**)self; - DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED); + // ---------------------------------------------------------------------------------------------------------------- + // v3_timer_handler - UIVst3* const uivst3 = point->uivst3; - DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); + static void V3_API on_timer(void* self) + { + dpf_timer_handler* const handler = *(dpf_timer_handler**)self; + DISTRHO_SAFE_ASSERT_RETURN(handler != nullptr,); - return uivst3->notify(message); - }; + handler->uivst3->onTimer(); } }; @@ -695,8 +739,9 @@ struct dpf_ui_connection_point : v3_connection_point_cpp { struct dpf_plugin_view : v3_plugin_view_cpp { std::atomic<int> refcounter; ScopedPointer<dpf_plugin_view>* self; - ScopedPointer<dpf_plugin_view_content_scale> scale; ScopedPointer<dpf_ui_connection_point> connection; + ScopedPointer<dpf_plugin_view_content_scale> scale; + ScopedPointer<dpf_timer_handler> timer; ScopedPointer<UIVst3> uivst3; // cached values v3_host_application** const host; @@ -824,6 +869,13 @@ struct dpf_plugin_view : v3_plugin_view_cpp { { if (std::strcmp(kSupportedPlatforms[i], platform_type) == 0) { + // find host run loop to plug ourselves into (required) + DISTRHO_SAFE_ASSERT_RETURN(view->frame != nullptr, V3_INVALID_ARG); + + v3_run_loop** runloop = nullptr; + v3_cpp_obj_query_interface(view->frame, v3_run_loop_iid, &runloop); + DISTRHO_SAFE_ASSERT_RETURN(runloop != nullptr, V3_INVALID_ARG); + const float scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f; view->uivst3 = new UIVst3((v3_plugin_view**)view->self, view->host, @@ -837,6 +889,11 @@ struct dpf_plugin_view : v3_plugin_view_cpp { view->uivst3->connect(point->other); view->uivst3->setFrame(view->frame); + + // register a timer host run loop stuff + view->timer = new dpf_timer_handler(view->uivst3); + v3_cpp_obj(runloop)->register_timer(runloop, (v3_timer_handler**)&view->timer, 16); + return V3_OK; } } @@ -850,6 +907,17 @@ struct dpf_plugin_view : v3_plugin_view_cpp { dpf_plugin_view* const view = *(dpf_plugin_view**)self; DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_INVALID_ARG); + + // unregister our timer as needed + if (view->timer != nullptr) + { + v3_run_loop** runloop = nullptr; + if (v3_cpp_obj_query_interface(view->host, v3_run_loop_iid, &runloop) == V3_OK && runloop != nullptr) + v3_cpp_obj(runloop)->unregister_timer(runloop, (v3_timer_handler**)&view->timer); + + view->timer = nullptr; + } + view->uivst3 = nullptr; return V3_OK; }; diff --git a/distrho/src/travesty/view.h b/distrho/src/travesty/view.h @@ -50,18 +50,18 @@ struct v3_plugin_frame; struct v3_plugin_view { struct v3_funknown; - v3_result (V3_API *is_platform_type_supported)(void* self, const char* platform_type); - v3_result (V3_API *attached)(void* self, void* parent, const char* platform_type); - v3_result (V3_API *removed)(void* self); - v3_result (V3_API *on_wheel)(void* self, float distance); - v3_result (V3_API *on_key_down)(void* self, int16_t key_char, int16_t key_code, int16_t modifiers); - v3_result (V3_API *on_key_up)(void* self, int16_t key_char, int16_t key_code, int16_t modifiers); - v3_result (V3_API *get_size)(void* self, struct v3_view_rect*); - v3_result (V3_API *on_size)(void* self, struct v3_view_rect*); - v3_result (V3_API *on_focus)(void* self, v3_bool state); - v3_result (V3_API *set_frame)(void* self, struct v3_plugin_frame**); - v3_result (V3_API *can_resize)(void* self); - v3_result (V3_API *check_size_constraint)(void* self, struct v3_view_rect*); + v3_result (V3_API* is_platform_type_supported)(void* self, const char* platform_type); + v3_result (V3_API* attached)(void* self, void* parent, const char* platform_type); + v3_result (V3_API* removed)(void* self); + v3_result (V3_API* on_wheel)(void* self, float distance); + v3_result (V3_API* on_key_down)(void* self, int16_t key_char, int16_t key_code, int16_t modifiers); + v3_result (V3_API* on_key_up)(void* self, int16_t key_char, int16_t key_code, int16_t modifiers); + v3_result (V3_API* get_size)(void* self, struct v3_view_rect*); + v3_result (V3_API* on_size)(void* self, struct v3_view_rect*); + v3_result (V3_API* on_focus)(void* self, v3_bool state); + v3_result (V3_API* set_frame)(void* self, struct v3_plugin_frame**); + v3_result (V3_API* can_resize)(void* self); + v3_result (V3_API* check_size_constraint)(void* self, struct v3_view_rect*); }; static constexpr const v3_tuid v3_plugin_view_iid = @@ -74,7 +74,7 @@ static constexpr const v3_tuid v3_plugin_view_iid = struct v3_plugin_frame { struct v3_funknown; - v3_result (V3_API *resize_view)(void* self, struct v3_plugin_view**, struct v3_view_rect*); + v3_result (V3_API* resize_view)(void* self, struct v3_plugin_view**, struct v3_view_rect*); }; static constexpr const v3_tuid v3_plugin_frame_iid = @@ -88,7 +88,7 @@ static constexpr const v3_tuid v3_plugin_frame_iid = struct v3_plugin_view_content_scale { struct v3_funknown; - v3_result (V3_API *set_content_scale_factor)(void* self, float factor); + v3_result (V3_API* set_content_scale_factor)(void* self, float factor); }; static constexpr const v3_tuid v3_plugin_view_content_scale_iid = @@ -101,12 +101,54 @@ static constexpr const v3_tuid v3_plugin_view_content_scale_iid = struct v3_plugin_view_parameter_finder { struct v3_funknown; - v3_result (V3_API *find_parameter)(void* self, int32_t x, int32_t y, v3_param_id *); + v3_result (V3_API* find_parameter)(void* self, int32_t x, int32_t y, v3_param_id *); }; static constexpr const v3_tuid v3_plugin_view_parameter_finder_iid = V3_ID(0x0F618302, 0x215D4587, 0xA512073C, 0x77B9D383); +/** + * linux event handler + */ + +struct v3_event_handler { + struct v3_funknown; + + void (V3_API* on_fd_is_set)(void* self, int fd); +}; + +static constexpr const v3_tuid v3_event_handler_iid = + V3_ID(0x561E65C9, 0x13A0496F, 0x813A2C35, 0x654D7983); + +/** + * linux timer handler + */ + +struct v3_timer_handler { + struct v3_funknown; + + void (V3_API* on_timer)(void* self); +}; + +static constexpr const v3_tuid v3_timer_handler_iid = + V3_ID(0x10BDD94F, 0x41424774, 0x821FAD8F, 0xECA72CA9); + +/** + * linux host run loop + */ + +struct v3_run_loop { + struct v3_funknown; + + v3_result (V3_API* register_event_handler)(void* self, v3_event_handler** handler, int fd); + v3_result (V3_API* unregister_event_handler)(void* self, v3_event_handler** handler); + v3_result (V3_API* register_timer)(void* self, v3_timer_handler** handler, uint64_t ms); + v3_result (V3_API* unregister_timer)(void* self, v3_timer_handler** handler); +}; + +static constexpr const v3_tuid v3_run_loop_iid = + V3_ID(0x18C35366, 0x97764F1A, 0x9C5B8385, 0x7A871389); + #ifdef __cplusplus /** @@ -129,4 +171,16 @@ struct v3_plugin_view_parameter_finder_cpp : v3_funknown { v3_plugin_view_parameter_finder finder; }; +struct v3_event_handler_cpp : v3_funknown { + v3_event_handler handler; +}; + +struct v3_timer_handler_cpp : v3_funknown { + v3_timer_handler handler; +}; + +struct v3_run_loop_cpp : v3_funknown { + v3_run_loop loop; +}; + #endif