From e01043d24e95b066e4ad6fa727b0e8653b270a62 Mon Sep 17 00:00:00 2001 From: Stefano D'Angelo Date: Mon, 17 Jun 2024 08:18:37 +0200 Subject: [PATCH] changing plugin callbacks, breaking everything --- templates/lv2/src/lv2.c | 104 ++++++++++++++++++------ templates/vst3/src/vst3.c | 162 ++++++++++++++++++++++++++++++-------- test/plugin.h | 3 +- 3 files changed, 210 insertions(+), 59 deletions(-) diff --git a/templates/lv2/src/lv2.c b/templates/lv2/src/lv2.c index bf919d3..cefcb6e 100644 --- a/templates/lv2/src/lv2.c +++ b/templates/lv2/src/lv2.c @@ -22,7 +22,17 @@ #include typedef struct { - void * handle; + void * handle; + const char * format; + const char * (*get_bindir)(void *handle); + const char * (*get_datadir)(void *handle); +} plugin_callbacks; + +typedef struct { + void * handle; + const char * format; + const char * (*get_bindir)(void *handle); + const char * (*get_datadir)(void *handle); void (*set_parameter)(void *handle, size_t index, float value); } plugin_ui_callbacks; @@ -47,10 +57,10 @@ typedef struct { #endif #ifdef DATA_UI # include "lv2/ui/ui.h" - -# include #endif +#include + #if defined(__i386__) || defined(__x86_64__) # include # include @@ -91,6 +101,7 @@ typedef struct { float params[DATA_PRODUCT_CONTROL_INPUTS_N]; #endif void * mem; + char * bundle_path; #if DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUT_N > 0 LV2_URID_Map * map; LV2_Log_Logger logger; @@ -98,13 +109,22 @@ typedef struct { #endif } plugin_instance; +static const char * get_bundle_path_cb(void *handle) { + plugin_instance *instance = (plugin_instance *)handle; + return instance->bundle_path; +} + static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double sample_rate, const char * bundle_path, const LV2_Feature * const * features) { (void)descriptor; (void)bundle_path; plugin_instance *instance = malloc(sizeof(plugin_instance)); if (instance == NULL) - return NULL; + goto err_instance; + + instance->bundle_path = strdup(bundle_path); + if (instance->bundle_path == NULL) + goto err_bundle_path; #if DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUT_N > 0 // from https://lv2plug.in/book @@ -116,8 +136,7 @@ static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double s lv2_log_logger_set_map(&instance->logger, instance->map); if (missing) { lv2_log_error(&instance->logger, "Missing feature <%s>\n", missing); - free(instance); - return NULL; + goto err_urid; } instance->uri_midi_MidiEvent = instance->map->map(instance->map->handle, LV2_MIDI__MidiEvent); @@ -125,15 +144,21 @@ static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double s (void)features; #endif - plugin_init(&instance->p); + plugin_callbacks cbs = { + /* .handle = */ (void *)instance, + /* .format = */ "lv2", + /* .get_bindir = */ get_bundle_path_cb, + /* .get_datadir = */ get_bundle_path_cb + }; + plugin_init(&instance->p, &cbs); plugin_set_sample_rate(&instance->p, sample_rate); size_t req = plugin_mem_req(&instance->p); if (req != 0) { instance->mem = malloc(req); if (instance->mem == NULL) { - plugin_fini(&instance->p); - return NULL; + lv2_log_error(&instance->logger, "Not enough memory\n"); + goto err_mem; } plugin_mem_set(&instance->p, instance->mem); } else @@ -161,6 +186,15 @@ static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double s #endif return instance; + +err_mem: + plugin_fini(&instance->p); +err_urid: + free(instance->bundle_path); +err_bundle_path: + free(instance); +err_instance: + return NULL; } static void connect_port(LV2_Handle instance, uint32_t port, void * data_location) { @@ -286,6 +320,7 @@ static void cleanup(LV2_Handle instance) { plugin_fini(&i->p); if (i->mem) free(i->mem); + free(i->bundle_path); free(instance); } @@ -307,6 +342,7 @@ LV2_SYMBOL_EXPORT const LV2_Descriptor * lv2_descriptor(uint32_t index) { #ifdef DATA_UI typedef struct { plugin_ui * ui; + char * bundle_path; # if DATA_PRODUCT_CONTROL_INPUTS_N > 0 LV2UI_Write_Function write; LV2UI_Controller controller; @@ -320,6 +356,11 @@ typedef struct { + DATA_PRODUCT_MIDI_OUTPUTS_N ) # define CONTROL_OUTPUT_INDEX_OFFSET (CONTROL_INPUT_INDEX_OFFSET + DATA_PRODUCT_CONTROL_INPUTS_N) +static const char * ui_get_bundle_path_cb(void *handle) { + ui_instance *instance = (ui_instance *)handle; + return instance->bundle_path; +} + # if DATA_PRODUCT_CONTROL_INPUTS_N > 0 static void ui_set_parameter_cb(void *handle, size_t index, float value) { ui_instance *instance = (ui_instance *)handle; @@ -343,38 +384,51 @@ static LV2UI_Handle ui_instantiate(const LV2UI_Descriptor * descriptor, const ch } ui_instance *instance = malloc(sizeof(ui_instance)); - if (instance == NULL) { - *widget = NULL; - return NULL; - } + if (instance == NULL) + goto err_instance; + instance->bundle_path = strdup(bundle_path); + if (instance->bundle_path == NULL) + goto err_bundle_path; + + plugin_ui_callbacks cbs = { + /* .handle = */ (void *)instance, + /* .format = */ "lv2", + /* .get_bindir = */ ui_get_bundle_path_cb, + /* .get_datadir = */ ui_get_bundle_path_cb, +# if DATA_PRODUCT_CONTROL_INPUTS_N > 0 + /* .set_parameter = */ ui_set_parameter_cb +# else + /* .set_parameter = */ NULL +# endif + }; # if DATA_PRODUCT_CONTROL_INPUTS_N > 0 instance->write = write_function; instance->controller = controller; - plugin_ui_callbacks cbs = { - /* .handle = */ (void *)instance, - /* .set_parameter = */ ui_set_parameter_cb - }; - instance->ui = plugin_ui_create(has_parent, parent, &cbs); # else (void)write_function; (void)controller; - - instance->ui = plugin_ui_create(has_parent, parent, NULL); # endif - if (instance->ui == NULL) { - free(instance); - *widget = NULL; - return NULL; - } + instance->ui = plugin_ui_create(has_parent, parent, &cbs); + if (instance->ui == NULL) + goto err_create; *widget = instance->ui->widget; return instance; + +err_create: + free(instance->bundle_path); +err_bundle_path: + free(instance); +err_instance: + *widget = NULL; + return NULL; } static void ui_cleanup(LV2UI_Handle handle) { ui_instance *instance = (ui_instance *)handle; plugin_ui_free(instance->ui); + free(instance->bundle_path); free(instance); } diff --git a/templates/vst3/src/vst3.c b/templates/vst3/src/vst3.c index 9c48b07..aa63bf4 100644 --- a/templates/vst3/src/vst3.c +++ b/templates/vst3/src/vst3.c @@ -18,17 +18,21 @@ * File author: Stefano D'Angelo, Paolo Marrone */ -#include #include -#include -#include -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" -#include "vst3_c_api.h" -#pragma GCC diagnostic pop +#include typedef struct { - void * handle; + void * handle; + const char * format; + const char * (*get_bindir)(void *handle); + const char * (*get_datadir)(void *handle); +} plugin_callbacks; + +typedef struct { + void * handle; + const char * format; + const char * (*get_bindir)(void *handle); + const char * (*get_datadir)(void *handle); void (*set_parameter)(void *handle, size_t index, float value); } plugin_ui_callbacks; @@ -38,6 +42,17 @@ typedef struct { # include "plugin_ui.h" #endif +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#include "vst3_c_api.h" +#pragma GCC diagnostic pop + +#include +#include +#if defined(_WIN32) || defined(__CYGWIN__) +# include +#endif + #if defined(__i386__) || defined(__x86_64__) #include #include @@ -54,11 +69,6 @@ typedef struct { # define TRACE(...) /* do nothing */ #endif -#if defined(__i386__) || defined(__x86_64__) -#include -#include -#endif - #ifdef DATA_UI # ifdef __linux__ // Why generate the C interface when you can just not give a fuck? Thank you Steinberg! @@ -123,6 +133,22 @@ static const Steinberg_TUID Steinberg_IRunLoop_iid = SMTG_INLINE_UID (0x18C35366 # endif #endif +static char *x_asprintf(const char * restrict format, ...) { + va_list args, tmp; + va_start(args, format); + va_copy(tmp, args); + int len = vsprintf(NULL, format, tmp); + va_end(tmp); + char *s = malloc(len + 1); + if (s != NULL) + vsprintf(s, format, args); + va_end(args); + return s; +} + +static char *bindir; +static char *datadir; + static double clamp(double x, double m, double M) { return x < m ? m : (x > M ? M : x); } @@ -237,12 +263,15 @@ static Steinberg_uint32 pluginIComponentRelease(void *thisInterface) { return pluginRelease((pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIComponent))); } +//XXX + static Steinberg_tresult pluginInitialize(void *thisInterface, struct Steinberg_FUnknown *context) { TRACE("plugin initialize\n"); pluginInstance *p = (pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIComponent)); if (p->context != NULL) return Steinberg_kResultFalse; p->context = context; + //XXX plugin_init(&p->p); #if DATA_PRODUCT_PARAMETERS_N > 0 for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) { @@ -943,10 +972,6 @@ static Steinberg_ITimerHandlerVtbl timerHandlerVtblITimerHandler = { # include # include -# elif defined(_WIN32) || defined(__CYGWIN__) - -# include - # endif typedef struct plugView { @@ -1072,6 +1097,8 @@ static void plugViewTimerCb(HWND p1, UINT p2, UINT_PTR p3, DWORD p4) { } # endif +//XXX + static Steinberg_tresult plugViewAttached(void* thisInterface, void* parent, Steinberg_FIDString type) { // GUI needs to be created here, see https://forums.steinberg.net/t/vst-and-hidpi/201916/3 TRACE("plugView attached %p\n", thisInterface); @@ -1082,17 +1109,23 @@ static Steinberg_tresult plugViewAttached(void* thisInterface, void* parent, Ste plugView *v = (plugView *)((char *)thisInterface - offsetof(plugView, vtblIPlugView)); if (v->ui) return Steinberg_kInvalidArgument; -# if DATA_PRODUCT_PARAMETERS_N > 0 + plugin_ui_callbacks cbs = { /* .handle = */ (void *)v, + /* .format = */ "vst3", + /* .get_bindir = */ ui_get_bindir_cb, + /* .get_datadir = */ ui_get_datadir_cb, +# if DATA_PRODUCT_PARAMETERS_N > 0 /* .set_parameter = */ plugViewSetParameterCb - }; - v->ui = plugin_ui_create(1, parent, &cbs); # else - v->ui = plugin_ui_create(1, parent, NULL); + /* .set_parameter = */ NULL # endif + }; + //XXX + v->ui = plugin_ui_create(1, parent, &cbs); if (!v->ui) return Steinberg_kResultFalse; + # ifdef __linux__ v->display = XOpenDisplay(NULL); if (v->display == NULL) { @@ -2062,25 +2095,88 @@ Steinberg_IPluginFactory * GetPluginFactory(void) { return (Steinberg_IPluginFactory *)&factory; } -#if !defined(_WIN32) && !defined(__CYGWIN__) -# if defined(__APPLE__) -# define ENTRY bundleEntry -# define EXIT bundleExit -# else -# define ENTRY ModuleEntry -# define EXIT ModuleExit -# endif +static int refs = 0; + +static char exit() { + refs--; + if (refs == 0) { + free(bindir); + free(datadir); + return 0; + } + return 1; +} + +#if defined(_WIN32) || defined(__CYGWIN__) + +XXX int APIENTRY +DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { + (void)hInstance; + (void)lpReserved; + if (dwReason == DLL_PROCESS_ATTACH) { + if (refs == 0) { + //XXX + } + refs++; + } else if (dwReason == DLL_PROCESS_DETACH) + exit(); + return 1; +} + +#elif defined(__APPLE__) EXPORT -char ENTRY(void *handle) { - (void)handle; - +char bundleEntry(CFBundleRef ref) { + (void)ref; + if (refs == 0) { + //XXX + } + refs++; return 1; } EXPORT -char EXIT(void) { +char bundleExit(void) { + return exit(); +} + +#else + +EXPORT +char ModuleEntry(void *handle) { + (void)handle; + if (refs == 0) { + Dl_info info; + if (dladdr((void *)ModuleEntry, &info) == 0) + return 0; + char *file = realpath(info.dli_fname, NULL); + if (file == NULL) + return 0; + char *c = strrchr(file, '/'); + *c = '\0'; + bindir = strdup(file); + if (bindir == NULL) + goto err_bindir; + char *c = strrchr(file, '/'); + *c = '\0'; + datadir = x_asprintf("%s/Resources", file); + if (datadir == NULL) + goto err_datadir; + free(file); + } + refs++; return 1; + +err_datadir: + free(bindir); +err_bindir: + free(file); + return 0; +} + +EXPORT +char ModuleExit(void) { + return exit(); } #endif diff --git a/test/plugin.h b/test/plugin.h index 592a38b..ffbbb13 100644 --- a/test/plugin.h +++ b/test/plugin.h @@ -34,8 +34,9 @@ typedef struct plugin { float yz1; } plugin; -static void plugin_init(plugin *instance) { +static void plugin_init(plugin *instance, plugin_callbacks *cbs) { (void)instance; + (void)cbs; } static void plugin_fini(plugin *instance) {