From 6523ef21b43ddb9ec678e28e76e65f8ae15d442e Mon Sep 17 00:00:00 2001 From: Stefano D'Angelo Date: Fri, 10 May 2024 07:09:26 +0200 Subject: [PATCH] vst3 gui linux timer --- templates/vst3/src/vst3.c | 127 ++++++++++++++++++++++++++++++++++---- test/plugin.h | 4 +- test/vst3-make.json | 3 +- 3 files changed, 120 insertions(+), 14 deletions(-) diff --git a/templates/vst3/src/vst3.c b/templates/vst3/src/vst3.c index 2d3b57b..dc901d9 100644 --- a/templates/vst3/src/vst3.c +++ b/templates/vst3/src/vst3.c @@ -64,7 +64,7 @@ typedef struct Steinberg_ITimerHandlerVtbl Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* release) (void* thisInterface); /* methods derived from "Steinberg_ITimerHandler": */ - Steinberg_tresult (SMTG_STDMETHODCALLTYPE* onTimer) (void* thisInterface); + void (SMTG_STDMETHODCALLTYPE* onTimer) (void* thisInterface); } Steinberg_ITimerHandlerVtbl; typedef struct Steinberg_ITimerHandler @@ -82,7 +82,7 @@ typedef struct Steinberg_IEventHandlerVtbl Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* release) (void* thisInterface); /* methods derived from "Steinberg_IEventHandler": */ - Steinberg_tresult (SMTG_STDMETHODCALLTYPE* onFDIsSet) (void* thisInterface, int fd); + void (SMTG_STDMETHODCALLTYPE* onFDIsSet) (void* thisInterface, int fd); } Steinberg_IEventHandlerVtbl; typedef struct Steinberg_IEventHandler @@ -819,6 +819,7 @@ static Steinberg_uint32 pluginIProcessContextRequirementsRelease(void *thisInter TRACE("plugin IComponent release %p\n", thisInterface); return pluginRelease((pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIProcessContextRequirements))); } + static Steinberg_uint32 pluginGetProcessContextRequirements(void* thisInterface) { (void)thisInterface; @@ -837,10 +838,80 @@ static Steinberg_Vst_IProcessContextRequirementsVtbl pluginVtblIProcessContextRe }; #ifdef PLUGIN_UI +# ifdef __linux__ +typedef struct { + Steinberg_ITimerHandlerVtbl * vtblITimerHandler; + Steinberg_uint32 refs; + void * data; + void (*cb)(void *data); +} timerHandler; + +static Steinberg_tresult timerHandlerQueryInterface(void *thisInterface, const Steinberg_TUID iid, void ** obj) { + TRACE("timerHandler queryInterface %p\n", thisInterface); + // Same as above (pluginQueryInterface) + size_t offset; + if (memcmp(iid, Steinberg_FUnknown_iid, sizeof(Steinberg_TUID)) == 0 + || memcmp(iid, Steinberg_ITimerHandler_iid, sizeof(Steinberg_TUID)) == 0) + offset = offsetof(timerHandler, vtblITimerHandler); + else { + TRACE(" not supported\n"); + for (int i = 0; i < 16; i++) + TRACE(" %x", iid[i]); + TRACE("\n"); + *obj = NULL; + return Steinberg_kNoInterface; + } + timerHandler *t = (timerHandler *)((char *)thisInterface - offsetof(timerHandler, vtblITimerHandler)); + *obj = (void *)((char *)t + offset); + t->refs++; + return Steinberg_kResultOk; +} + +static Steinberg_uint32 timerHandlerAddRef(void *thisInterface) { + TRACE("timerHandler addRef %p\n", thisInterface); + timerHandler *t = (timerHandler *)((char *)thisInterface - offsetof(timerHandler, vtblITimerHandler)); + t->refs++; + return t->refs; +} + +static Steinberg_uint32 timerHandlerRelease(void *thisInterface) { + TRACE("timerHandler release %p\n", thisInterface); + timerHandler *t = (timerHandler *)((char *)thisInterface - offsetof(timerHandler, vtblITimerHandler)); + t->refs--; + if (t->refs == 0) { + TRACE(" free %p\n", (void *)t); + free(t); + return 0; + } + return t->refs; +} + +static void timerHandlerOnTimer(void* thisInterface) { + TRACE("timerHandler onTimer %p\n", thisInterface); + timerHandler *t = (timerHandler *)((char *)thisInterface - offsetof(timerHandler, vtblITimerHandler)); + t->cb(t->data); +} + +static Steinberg_ITimerHandlerVtbl timerHandlerVtblITimerHandler = { + /* FUnknown */ + /* .queryInterface = */ timerHandlerQueryInterface, + /* .addRef = */ timerHandlerAddRef, + /* .release = */ timerHandlerRelease, + + /* ITimerHandler */ + /* .onTimer = */ timerHandlerOnTimer +}; +# endif + typedef struct plugView { Steinberg_IPlugViewVtbl * vtblIPlugView; Steinberg_uint32 refs; Steinberg_IPlugFrame * frame; +# ifdef __linux__ + Steinberg_IRunLoop * runLoop; + timerHandler timer; +# endif + plugin_ui * ui; } plugView; static Steinberg_tresult plugViewQueryInterface(void *thisInterface, const Steinberg_TUID iid, void ** obj) { @@ -884,28 +955,43 @@ static Steinberg_uint32 plugViewRelease(void *thisInterface) { } static Steinberg_tresult plugViewIsPlatformTypeSupported(void* thisInterface, Steinberg_FIDString type) { + (void)thisInterface; + TRACE("plugView isPlatformTypeSupported %p %s\n", thisInterface, type); -#if defined(_WIN32) +# if defined(_WIN32) return strcmp(type, "HWND") ? Steinberg_kResultFalse : Steinberg_kResultTrue; -#elif defined(__APPLE__) && defined(__MACH__) +# elif defined(__APPLE__) && defined(__MACH__) return strcmp(type, "NSView") ? Steinberg_kResultFalse : Steinberg_kResultTrue; -#elif defined(__linux__) +# elif defined(__linux__) return strcmp(type, "X11EmbedWindowID") ? Steinberg_kResultFalse : Steinberg_kResultTrue; -#else +# else + (void)type; + return Steinberg_kResultFalse; -#endif +# endif } static Steinberg_tresult plugViewAttached(void* thisInterface, void* parent, Steinberg_FIDString type) { TRACE("plugView attached %p\n", thisInterface); - //TODO - return Steinberg_kResultFalse; + plugView *v = (plugView *)((char *)thisInterface - offsetof(plugView, vtblIPlugView)); + v->ui = plugin_ui_create(1, parent); + if (!v->ui) + return Steinberg_kResultFalse; +# ifdef __linux + if (v->runLoop->lpVtbl->registerTimer(v->runLoop, &v->timer, 20) != Steinberg_kResultOk) { + plugin_ui_free(v->ui); + return Steinberg_kResultFalse; + } +# endif + return Steinberg_kResultTrue; } static Steinberg_tresult plugViewRemoved(void* thisInterface) { TRACE("plugView removed %p\n", thisInterface); - //TODO - return Steinberg_kResultFalse; + plugView *v = (plugView *)((char *)thisInterface - offsetof(plugView, vtblIPlugView)); + v->runLoop->lpVtbl->unregisterTimer(v->runLoop, &v->timer); + plugin_ui_free(v->ui); + return Steinberg_kResultTrue; } static Steinberg_tresult plugViewOnWheel(void* thisInterface, float distance) { @@ -954,6 +1040,11 @@ static Steinberg_tresult plugViewSetFrame(void* thisInterface, struct Steinberg_ TRACE("plugView setFrame %p\n", thisInterface); plugView *v = (plugView *)((char *)thisInterface - offsetof(plugView, vtblIPlugView)); v->frame = frame; +# ifdef __linux__ + if (v->frame->lpVtbl->queryInterface(v->frame, Steinberg_IRunLoop_iid, (void **)&v->runLoop) != Steinberg_kResultOk) + return Steinberg_kResultFalse; + v->frame->lpVtbl->release(v->frame); +# endif return Steinberg_kResultTrue; } @@ -969,6 +1060,14 @@ static Steinberg_tresult plugViewCheckSizeConstraint(void* thisInterface, struct return Steinberg_kResultFalse; } +# ifdef __linux__ +static void plugViewOnTimer(void *thisInterface) { + TRACE("plugView onTimer %p\n", thisInterface); + plugView *v = (plugView *)((char *)thisInterface - offsetof(plugView, vtblIPlugView)); + plugin_ui_idle(v->ui); +} +# endif + static Steinberg_IPlugViewVtbl plugViewVtblIPlugView = { /* FUnknown */ /* .queryInterface = */ plugViewQueryInterface, @@ -1323,6 +1422,12 @@ static struct Steinberg_IPlugView* controllerCreateView(void* thisInterface, Ste view->vtblIPlugView = &plugViewVtblIPlugView; view->refs = 1; view->frame = NULL; +# ifdef __linux__ + view->timer.vtblITimerHandler = &timerHandlerVtblITimerHandler; + view->timer.refs = 1; + view->timer.cb = plugViewOnTimer; + view->timer.data = view; +# endif return (struct Steinberg_IPlugView *)view; #else diff --git a/test/plugin.h b/test/plugin.h index ed1fbc0..ae5469b 100644 --- a/test/plugin.h +++ b/test/plugin.h @@ -129,7 +129,7 @@ typedef struct { PuglView * view; } plugin_ui; -static PuglStatus onEvent(PuglView *view, const PuglEvent *event) { +static PuglStatus plugin_ui_on_event(PuglView *view, const PuglEvent *event) { switch (event->type) { case PUGL_EXPOSE: { @@ -155,7 +155,7 @@ static plugin_ui *plugin_ui_create(char has_parent, void *parent) { puglSetBackend(instance->view, puglCairoBackend()); PuglRect frame = { 0, 0, 600, 400 }; puglSetFrame(instance->view, frame); - puglSetEventFunc(instance->view, onEvent); + puglSetEventFunc(instance->view, plugin_ui_on_event); if (has_parent) { puglSetParentWindow(instance->view, (PuglNativeView)parent); } diff --git a/test/vst3-make.json b/test/vst3-make.json index 172090e..e034c40 100644 --- a/test/vst3-make.json +++ b/test/vst3-make.json @@ -1,5 +1,6 @@ { "vst3_make": { - "cflags": "-I../../../vst3_c_api" + "cflags": "-I../../../vst3_c_api $(shell pkg-config --cflags pugl-cairo-0)", + "ldflags": "$(shell pkg-config --libs pugl-cairo-0)" } }