lv2 plugin parameter write cb in place

This commit is contained in:
Stefano D'Angelo 2024-05-12 13:10:55 +02:00
parent b6500cddff
commit df88cc213e
3 changed files with 108 additions and 36 deletions

View File

@ -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
{{?}}

View File

@ -21,6 +21,11 @@
#include <stdlib.h>
#include <stdint.h>
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 <X11/Xlib.h>
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;
}

View File

@ -124,15 +124,24 @@ static void plugin_midi_msg_in(plugin *instance, size_t index, const uint8_t * d
# include <cairo.h>
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;
}