vst3: dsp->ui communication using a separated thread to handle allocation and notification

This commit is contained in:
Paolo Marrone 2025-06-04 18:31:31 +02:00
parent 5f693136a8
commit 0aa6d08288
5 changed files with 135 additions and 40 deletions

View File

@ -68,7 +68,7 @@ BUILD_DATA_DIR := build/$(BUNDLE_DIR)/Contents/Resources
-include $(MKINC_DIR)/vars-pre.mk -include $(MKINC_DIR)/vars-pre.mk
CFLAGS := -O3 -Wall -Wpedantic -Wextra CFLAGS := -O3 -std=c11 -Wall -Wpedantic -Wextra
CFLAGS_ALL := -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) -fPIC -fvisibility=hidden $(CFLAGS_EXTRA) $(CFLAGS) CFLAGS_ALL := -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) -fPIC -fvisibility=hidden $(CFLAGS_EXTRA) $(CFLAGS)
LDFLAGS := LDFLAGS :=

View File

@ -270,4 +270,5 @@ static size_t parameterInfoToDataIndex[DATA_PRODUCT_PARAMETERS_N] = {
{{?it.product.messaging}} {{?it.product.messaging}}
#define DATA_MESSAGING 1 #define DATA_MESSAGING 1
#define DATA_MESSAGING_MAX {{=it.product.messaging.maxSize}}
{{?}} {{?}}

View File

@ -66,6 +66,10 @@
# endif # endif
#endif #endif
#ifdef DATA_MESSAGING
# include <threads.h>
#endif
// COM in C doc: // COM in C doc:
// https://github.com/rubberduck-vba/Rubberduck/wiki/COM-in-plain-C // https://github.com/rubberduck-vba/Rubberduck/wiki/COM-in-plain-C
// https://devblogs.microsoft.com/oldnewthing/20040205-00/?p=40733 // https://devblogs.microsoft.com/oldnewthing/20040205-00/?p=40733
@ -311,8 +315,18 @@ typedef struct pluginInstance {
void * mem; void * mem;
struct Steinberg_IBStream * state; struct Steinberg_IBStream * state;
#ifdef DATA_MESSAGING
Steinberg_Vst_IConnectionPointVtbl *vtblIConnectionPoint; Steinberg_Vst_IConnectionPointVtbl *vtblIConnectionPoint;
Steinberg_Vst_IConnectionPoint *connectedPoint; Steinberg_Vst_IConnectionPoint *connectedPoint;
uint8_t message_data[DATA_MESSAGING_MAX];
size_t message_data_size;
char message_data_tosend; // This is to tell message_thread to send data
thrd_t message_thread;
int message_flag;
mtx_t message_mutex;
cnd_t message_cond;
#endif
} pluginInstance; } pluginInstance;
static Steinberg_Vst_IComponentVtbl pluginVtblIComponent; static Steinberg_Vst_IComponentVtbl pluginVtblIComponent;
@ -468,33 +482,13 @@ static Steinberg_Vst_IConnectionPointVtbl pluginVtblIConnectionPoint = {
}; };
# ifdef DATA_MESSAGING # ifdef DATA_MESSAGING
// Assuming this gets called by audio thread only
static char send_to_ui (void *handle, const void *data, size_t bytes) { static char send_to_ui (void *handle, const void *data, size_t bytes) {
pluginInstance *p = (pluginInstance *)handle; pluginInstance *p = (pluginInstance *)handle;
Steinberg_Vst_IConnectionPointVtbl *ov = (Steinberg_Vst_IConnectionPointVtbl*) p->connectedPoint->lpVtbl; memcpy(p->message_data, data, bytes);
p->message_data_size = bytes;
printf("gonna A ov: %p \n", (void*) ov); p->message_data_tosend = 1;
printf("gonna AA ctx: %p \n", (void*) p->context);
Steinberg_Vst_IHostApplication *app = (Steinberg_Vst_IHostApplication*) p->context;
Steinberg_Vst_IMessage *msg = NULL;
app->lpVtbl->createInstance(app, (char*) Steinberg_Vst_IMessage_iid, (char*) Steinberg_Vst_IMessage_iid, (void**)&msg);
printf("gonna AB msgp: %p \n", (void*) msg);
printf("gonna B \n");
msg->lpVtbl->setMessageID(msg, "HelloMessage");
printf("gonna C Message ID: %s \n", msg->lpVtbl->getMessageID(msg));
Steinberg_Vst_IAttributeList *alist = msg->lpVtbl->getAttributes(msg);
printf("gonna CA alist %p \n", (void*) alist);
alist->lpVtbl->setBinary(alist, "yoyoyo", data, bytes);
ov->notify(p->connectedPoint, msg);
printf("gonna Z \n");
return 0; return 0;
} }
# endif # endif
@ -514,6 +508,43 @@ static Steinberg_uint32 pluginIComponentRelease(void *thisInterface) {
return pluginRelease((pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIComponent))); return pluginRelease((pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIComponent)));
} }
int message_thread_f(void *arg) {
pluginInstance *p = (pluginInstance *) arg;
while (1) {
mtx_lock(&p->message_mutex);
while (p->message_flag == 0) {
cnd_wait(&p->message_cond, &p->message_mutex);
}
if (p->message_flag == 1) {
printf("message_thread_f: got flag 1...\n");
Steinberg_Vst_IConnectionPointVtbl *ov = (Steinberg_Vst_IConnectionPointVtbl*) p->connectedPoint->lpVtbl;
Steinberg_Vst_IHostApplication *app = (Steinberg_Vst_IHostApplication*) p->context;
Steinberg_Vst_IMessage *msg = NULL;
app->lpVtbl->createInstance(app, (char*) Steinberg_Vst_IMessage_iid, (char*) Steinberg_Vst_IMessage_iid, (void**)&msg);
msg->lpVtbl->setMessageID(msg, "HelloMessage");
Steinberg_Vst_IAttributeList *alist = msg->lpVtbl->getAttributes(msg);
alist->lpVtbl->setBinary(alist, "yoyoyo", p->message_data, p->message_data_size);
ov->notify(p->connectedPoint, msg);
p->message_flag = 0;
} else if (p->message_flag == 2) {
printf("message_thread_f: got flag 2: Exiting.\n");
mtx_unlock(&p->message_mutex);
break;
}
mtx_unlock(&p->message_mutex);
}
return 0;
}
static Steinberg_tresult pluginInitialize(void *thisInterface, struct Steinberg_FUnknown *context) { static Steinberg_tresult pluginInitialize(void *thisInterface, struct Steinberg_FUnknown *context) {
TRACE("plugin initialize\n"); TRACE("plugin initialize\n");
@ -570,6 +601,16 @@ static Steinberg_tresult pluginInitialize(void *thisInterface, struct Steinberg_
# endif # endif
#endif #endif
p->mem = NULL; p->mem = NULL;
#ifdef DATA_MESSAGING
mtx_init(&p->message_mutex, mtx_plain);
cnd_init(&p->message_cond);
if (thrd_create(&p->message_thread, message_thread_f, p) != thrd_success) {
fprintf(stderr, "Failed to create message_thread\n");
return Steinberg_kResultFalse;
}
#endif
return Steinberg_kResultOk; return Steinberg_kResultOk;
} }
@ -580,6 +621,15 @@ static Steinberg_tresult pluginTerminate(void *thisInterface) {
plugin_fini(&p->p); plugin_fini(&p->p);
if (p->mem) if (p->mem)
free(p->mem); free(p->mem);
mtx_lock(&p->message_mutex);
p->message_flag = 2;
cnd_signal(&p->message_cond);
mtx_unlock(&p->message_mutex);
thrd_join(p->message_thread, NULL);
mtx_destroy(&p->message_mutex);
cnd_destroy(&p->message_cond);
return Steinberg_kResultOk; return Steinberg_kResultOk;
} }
@ -1196,6 +1246,17 @@ static Steinberg_tresult pluginProcess(void* thisInterface, struct Steinberg_Vst
_MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode); _MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode);
#endif #endif
#ifdef DATA_MESSAGING
if (p->message_data_tosend) { // message_data_tosend is manipulated by audio thread only
if (mtx_trylock(&p->message_mutex) == thrd_success) {
p->message_flag = 1;
cnd_signal(&p->message_cond);
mtx_unlock(&p->message_mutex);
p->message_data_tosend = 0;
}
}
#endif
return Steinberg_kResultOk; return Steinberg_kResultOk;
} }
@ -2476,6 +2537,25 @@ static Steinberg_tresult controllerIConnectionPointNotify(void* thisInterface, s
(void)thisInterface; (void)thisInterface;
(void)message; (void)message;
printf("controllerIConnectionPointNotify \n"); fflush(stdout); printf("controllerIConnectionPointNotify \n"); fflush(stdout);
controller *c = (controller *)((char *)thisInterface - offsetof(controller, vtblIConnectionPoint));
printf("controllerIConnectionPointNotify A \n"); fflush(stdout);
printf("controllerIConnectionPointNotify B Message ID: %s\n", message->lpVtbl->getMessageID(message)); fflush(stdout);
Steinberg_Vst_IAttributeList *alist = message->lpVtbl->getAttributes(message);
printf("controllerIConnectionPointNotify C alist: %p\n", (void*) alist); fflush(stdout);
const void *data = NULL;
unsigned int size = 0;
alist->lpVtbl->getBinary(alist, "yoyoyo", &data, &size);
// This is tmp, TODO: fix
for (size_t i = 0; i < c->viewsCount; i++) {
plugView *v = c->views[i];
plugin_ui_receive_from_dsp(v->ui, data, size);
}
return Steinberg_kResultOk; return Steinberg_kResultOk;
} }
@ -2586,6 +2666,7 @@ static Steinberg_tresult factoryCreateInstance(void *thisInterface, Steinberg_FI
#ifdef DATA_MESSAGING #ifdef DATA_MESSAGING
p->vtblIConnectionPoint = &pluginVtblIConnectionPoint; p->vtblIConnectionPoint = &pluginVtblIConnectionPoint;
p->connectedPoint = NULL; p->connectedPoint = NULL;
p->message_data_tosend = 0;
#endif #endif
*obj = p; *obj = p;
TRACE(" instance: %p\n", (void *)p); TRACE(" instance: %p\n", (void *)p);

View File

@ -34,11 +34,30 @@ typedef struct plugin {
float z1; float z1;
float cutoff_k; float cutoff_k;
float yz1; float yz1;
int communication_state;
plugin_callbacks cbs;
} plugin; } plugin;
#if TEMPLATE_SUPPORTS_MESSAGING
#include <stdio.h>
static void plugin_receive_from_ui (plugin *instance, const void *data, size_t bytes) {
printf("plugin_receive_from_ui %ld bytes at %p: \n", bytes, data);
for (size_t i = 0; i < bytes; i++) {
printf("%d ", ((uint8_t*) data)[i]);
}
instance->communication_state = 1;
printf("\nplugin_receive_from_ui END - going to reply at next proc \n");
}
#define RANDOM_DATA_UI_SIZE 13
const uint8_t random_ui_data[RANDOM_DATA_UI_SIZE] = { 66, 69, 2, 3, 4, 5, 6, 7, 8, 9, 6, 9, 6 };
#endif
static void plugin_init(plugin *instance, const plugin_callbacks *cbs) { static void plugin_init(plugin *instance, const plugin_callbacks *cbs) {
(void)instance; instance->cbs = *cbs;
(void)cbs; instance->communication_state = 0;
} }
static void plugin_fini(plugin *instance) { static void plugin_fini(plugin *instance) {
@ -111,6 +130,12 @@ static void plugin_process(plugin *instance, const float **inputs, float **outpu
outputs[0][i] = instance->bypass ? inputs[0][i] : gain * y; outputs[0][i] = instance->bypass ? inputs[0][i] : gain * y;
instance->yz1 = outputs[0][i]; instance->yz1 = outputs[0][i];
} }
#ifdef TEMPLATE_SUPPORTS_MESSAGING
if (instance->communication_state == 1) {
instance->cbs.send_to_ui(instance->cbs.handle, random_ui_data, RANDOM_DATA_UI_SIZE);
instance->communication_state = 2;
}
#endif
} }
static void plugin_midi_msg_in(plugin *instance, size_t index, const uint8_t * data) { static void plugin_midi_msg_in(plugin *instance, size_t index, const uint8_t * data) {
@ -179,15 +204,3 @@ static int plugin_state_load(const plugin_state_callbacks *cbs, float cur_sample
cbs->unlock(cbs->handle); cbs->unlock(cbs->handle);
return 0; return 0;
} }
#include <stdio.h>
#if TEMPLATE_SUPPORTS_MESSAGING
static void plugin_receive_from_ui (plugin *instance, const void *data, size_t bytes) {
(void) instance;
printf("plugin_receive_from_ui %ld bytes at %p: \n", bytes, data);
for (size_t i = 0; i < bytes; i++) {
printf("%d ", ((uint8_t*) data)[i]);
}
printf("plugin_receive_from_ui END \n");
}
#endif

View File

@ -47,9 +47,9 @@ static void plugin_ui_receive_from_dsp (plugin_ui *instance, const void *data, s
} }
printf("plugin_ui_receive_from_ui END \n"); printf("plugin_ui_receive_from_ui END \n");
} }
#endif
#define RANDOM_DATA_SIZE 11 #define RANDOM_DATA_SIZE 11
const uint8_t random_data[RANDOM_DATA_SIZE] = { 2, 3, 4, 5, 6, 7, 8, 9, 6, 9, 6 }; const uint8_t random_data[RANDOM_DATA_SIZE] = { 2, 3, 4, 5, 6, 7, 8, 9, 6, 9, 6 };
#endif
#define WIDTH 600.0 #define WIDTH 600.0
#define HEIGHT 400.0 #define HEIGHT 400.0