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:
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