From df88cc213e9ac732fcd3980d58190332aa22a73f Mon Sep 17 00:00:00 2001 From: Stefano D'Angelo Date: Sun, 12 May 2024 13:10:55 +0200 Subject: [PATCH] lv2 plugin parameter write cb in place --- templates/lv2/src/data.h | 6 +++ templates/lv2/src/lv2.c | 48 ++++++++++++++++----- test/plugin.h | 90 +++++++++++++++++++++++++++++----------- 3 files changed, 108 insertions(+), 36 deletions(-) diff --git a/templates/lv2/src/data.h b/templates/lv2/src/data.h index 2c49854..3fe1ace 100644 --- a/templates/lv2/src/data.h +++ b/templates/lv2/src/data.h @@ -68,4 +68,10 @@ static uint32_t param_out_index[DATA_PRODUCT_CONTROL_OUTPUTS_N] = { {{?it.lv2.ui}} #define DATA_LV2_UI_URI "{{=it.tibia.CGetUTF8StringLiteral(it.tibia.lv2.expandURI(it.lv2.ui.uri))}}" #define DATA_UI_USER_RESIZABLE {{=it.product.ui.userResizable ? 1 : 0}} + +#if DATA_PRODUCT_CONTROL_INPUTS_N > 0 +static uint32_t index_to_param[DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N] = { + {{~it.tibia.lv2.ports.filter(x => x.type == "control").map((e, i) => ({ i: i, pi: e.paramIndex })).sort((a, b) => a.pi - b.pi) :p}}{{=p.i + it.tibia.lv2.ports.filter(x => x.type != "control").length}}, {{~}} +}; +#endif {{?}} diff --git a/templates/lv2/src/lv2.c b/templates/lv2/src/lv2.c index 71756be..db37e35 100644 --- a/templates/lv2/src/lv2.c +++ b/templates/lv2/src/lv2.c @@ -21,6 +21,11 @@ #include #include +typedef struct { + void * handle; + void (*set_parameter)(void *handle, size_t index, float value); +} plugin_ui_callbacks; + #define TEMPLATE_HAS_UI #include "data.h" #include "plugin.h" @@ -267,7 +272,6 @@ static void run(LV2_Handle instance, uint32_t sample_count) { _MM_SET_FLUSH_ZERO_MODE(flush_zero_mode); _MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode); #endif - } static void cleanup(LV2_Handle instance) { @@ -294,13 +298,17 @@ LV2_SYMBOL_EXPORT const LV2_Descriptor * lv2_descriptor(uint32_t index) { } #ifdef PLUGIN_UI -#include - typedef struct { - Display * display; - Window window; + plugin_ui * ui; + LV2UI_Write_Function write; + LV2UI_Controller controller; } ui_instance; +static void ui_set_parameter_cb(void *handle, size_t index, float value) { + ui_instance *instance = (ui_instance *)handle; + instance->write(instance->controller, index_to_param[index], sizeof(float), 0, &value); +} + static LV2UI_Handle ui_instantiate(const LV2UI_Descriptor * descriptor, const char * plugin_uri, const char * bundle_path, LV2UI_Write_Function write_function, LV2UI_Controller controller, LV2UI_Widget * widget, const LV2_Feature * const * features) { char has_parent = 0; void *parent = NULL; @@ -312,17 +320,33 @@ static LV2UI_Handle ui_instantiate(const LV2UI_Descriptor * descriptor, const ch // TODO... } - plugin_ui *instance = plugin_ui_create(has_parent, parent); + ui_instance *instance = malloc(sizeof(ui_instance)); if (instance == NULL) { *widget = NULL; return NULL; } - *widget = instance->widget; + + plugin_ui_callbacks cbs = { + /* .handle = */ (void *)instance, + /* .set_parameter = */ ui_set_parameter_cb + }; + instance->write = write_function; + instance->controller = controller; + instance->ui = plugin_ui_create(has_parent, parent, &cbs); + if (instance->ui == NULL) { + free(instance); + *widget = NULL; + return NULL; + } + + *widget = instance->ui->widget; return instance; } static void ui_cleanup(LV2UI_Handle handle) { - plugin_ui_free((plugin_ui *)handle); + ui_instance *instance = (ui_instance *)handle; + plugin_ui_free(instance->ui); + free(instance); } #define CONTROL_INPUT_INDEX_OFFSET ( \ @@ -333,14 +357,16 @@ static void ui_cleanup(LV2UI_Handle handle) { #define CONTROL_OUTPUT_INDEX_OFFSET (CONTROL_INPUT_INDEX_OFFSET + DATA_PRODUCT_CONTROL_INPUTS_N) static void ui_port_event(LV2UI_Handle handle, uint32_t port_index, uint32_t buffer_size, uint32_t format, const void * buffer) { + ui_instance *instance = (ui_instance *)handle; if (port_index < CONTROL_OUTPUT_INDEX_OFFSET) - plugin_ui_set_parameter((plugin_ui *)handle, param_data[port_index - CONTROL_INPUT_INDEX_OFFSET].index, *((float *)buffer)); + plugin_ui_set_parameter(instance->ui, param_data[port_index - CONTROL_INPUT_INDEX_OFFSET].index, *((float *)buffer)); else - plugin_ui_set_parameter((plugin_ui *)handle, param_out_index[port_index - CONTROL_OUTPUT_INDEX_OFFSET], *((float *)buffer)); + plugin_ui_set_parameter(instance->ui, param_out_index[port_index - CONTROL_OUTPUT_INDEX_OFFSET], *((float *)buffer)); } static int ui_idle(LV2UI_Handle handle) { - plugin_ui_idle((plugin_ui *)handle); + ui_instance *instance = (ui_instance *)handle; + plugin_ui_idle(instance->ui); return 0; } diff --git a/test/plugin.h b/test/plugin.h index 72fb8ad..8c16a58 100644 --- a/test/plugin.h +++ b/test/plugin.h @@ -124,15 +124,24 @@ static void plugin_midi_msg_in(plugin *instance, size_t index, const uint8_t * d # include typedef struct { - void * widget; - PuglWorld * world; - PuglView * view; + void * widget; + PuglWorld * world; + PuglView * view; - float gain; - float delay; - float cutoff; - char bypass; - float y_z1; + double fw; + double fh; + double x; + double y; + double w; + double h; + + float gain; + float delay; + float cutoff; + char bypass; + float y_z1; + + plugin_ui_callbacks cbs; } plugin_ui; #define WIDTH 600.0 @@ -145,27 +154,32 @@ static void plugin_ui_get_default_size(uint32_t *width, uint32_t *height) { *height = HEIGHT; } -static void plugin_ui_draw(plugin_ui *instance) { +static void plugin_ui_update_geometry(plugin_ui *instance) { PuglRect frame = puglGetFrame(instance->view); + instance->fw = frame.width; + instance->fh = frame.height; if (frame.width == 0 || frame.height == 0) return; - double x, y, w, h; - double fw = frame.width; - double fh = frame.height; - if (fw / fh > RATIO) { - w = RATIO * fh; - h = fh; - x = (fw - w) / 2; - y = 0.0; + if (instance->fw / instance->fh > RATIO) { + instance->w = RATIO * instance->fh; + instance->h = instance->fh; + instance->x = 0.5 * (instance->fw - instance->w); + instance->y = 0.0; } else { - w = fw; - h = INV_RATIO * fw; - x = 0.0; - y = (fh - h) / 2; + instance->w = instance->fw; + instance->h = INV_RATIO * instance->fw; + instance->x = 0.0; + instance->y = 0.5 * (instance->fh - instance->h); } +} +static void plugin_ui_draw(plugin_ui *instance) { cairo_t *cr = (cairo_t *)puglGetContext(instance->view); + double x = instance->x; + double y = instance->y; + double w = instance->w; + double h = instance->h; cairo_set_line_width(cr, 0.005 * h); @@ -220,14 +234,39 @@ static void plugin_ui_draw(plugin_ui *instance) { cairo_set_source_rgb(cr, 0.5, 0.5, 0.5); cairo_rectangle(cr, x + 0.1 * w, y + 0.75 * h, 0.8 * w * instance->y_z1, 0.1 * h); cairo_fill(cr); - - return 0; } static PuglStatus plugin_ui_on_event(PuglView *view, const PuglEvent *event) { switch (event->type) { + case PUGL_CONFIGURE: + { + plugin_ui *instance = (plugin_ui *)puglGetHandle(view); + plugin_ui_update_geometry(instance); + } + break; + case PUGL_BUTTON_RELEASE: + { + plugin_ui *instance = (plugin_ui *)puglGetHandle(view); + PuglRect frame = puglGetFrame(view); + const PuglButtonEvent *ev = (const PuglButtonEvent *)event; + double x = instance->x; + double y = instance->y; + double w = instance->w; + double h = instance->h; + + if (ev->x >= x + 0.1 * w && ev->x <= x + 0.9 * w + && ev->y >= y + 0.15 * h && ev->y <= y + 0.25 * h) { + instance->gain = (float)((ev->x - (x + 0.1 * w)) / (0.8 * w)); + instance->cbs.set_parameter(instance->cbs.handle, 0, -60.f + 80.f * instance->gain); + puglPostRedisplay(instance->view); + } + } + break; case PUGL_EXPOSE: - plugin_ui_draw((plugin_ui *)puglGetHandle(view)); + { + plugin_ui *instance = (plugin_ui *)puglGetHandle(view); + plugin_ui_draw(instance); + } break; default: break; @@ -235,7 +274,7 @@ static PuglStatus plugin_ui_on_event(PuglView *view, const PuglEvent *event) { return PUGL_SUCCESS; } -static plugin_ui *plugin_ui_create(char has_parent, void *parent) { +static plugin_ui *plugin_ui_create(char has_parent, void *parent, plugin_ui_callbacks *cbs) { plugin_ui *instance = malloc(sizeof(plugin_ui)); if (instance == NULL) return NULL; @@ -257,6 +296,7 @@ static plugin_ui *plugin_ui_create(char has_parent, void *parent) { puglShow(instance->view, PUGL_SHOW_RAISE); puglSetHandle(instance->view, instance); instance->widget = (void *)puglGetNativeView(instance->view); + instance->cbs = *cbs; return instance; }