diff --git a/src/daemon/filter-chain/meson.build b/src/daemon/filter-chain/meson.build index 188167528..e46f1e495 100644 --- a/src/daemon/filter-chain/meson.build +++ b/src/daemon/filter-chain/meson.build @@ -1,5 +1,6 @@ conf_files = [ [ 'demonic.conf', 'demonic.conf' ], + [ 'sink-convolver.conf', 'sink-convolver.conf' ], [ 'sink-dolby-surround.conf', 'sink-dolby-surround.conf' ], [ 'sink-eq6.conf', 'sink-eq6.conf' ], [ 'sink-matrix-spatialiser.conf', 'sink-matrix-spatialiser.conf' ], diff --git a/src/modules/meson.build b/src/modules/meson.build index 800709f0f..cf456999e 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -48,6 +48,8 @@ pipewire_module_loopback = shared_library('pipewire-module-loopback', pipewire_module_filter_chain = shared_library('pipewire-module-filter-chain', [ 'module-filter-chain.c', 'module-filter-chain/biquad.c', + 'module-filter-chain/ladspa_plugin.c', + 'module-filter-chain/builtin_plugin.c', 'module-filter-chain/kiss_fft_f32.c', 'module-filter-chain/kiss_fftr_f32.c', 'module-filter-chain/convolver.c' ], diff --git a/src/modules/module-filter-chain.c b/src/modules/module-filter-chain.c index bc9b672a4..886ba8c70 100644 --- a/src/modules/module-filter-chain.c +++ b/src/modules/module-filter-chain.c @@ -33,7 +33,7 @@ #include "config.h" -#include "module-filter-chain/ladspa.h" +#include "module-filter-chain/plugin.h" #include #include @@ -100,26 +100,30 @@ static const struct spa_dict_item module_props[] = { #include +#include "ladspa.h" + #define MAX_HNDL 64 #define MAX_PORTS 64 #define MAX_CONTROLS 256 #define MAX_SAMPLES 8192 -struct ladspa_handle { +struct plugin { struct spa_list link; int ref; + char type[64]; char path[PATH_MAX]; - void *handle; - LADSPA_Descriptor_Function desc_func; + + struct fc_plugin *plugin; struct spa_list descriptor_list; }; -struct ladspa_descriptor { +struct descriptor { struct spa_list link; int ref; - struct ladspa_handle *handle; + struct plugin *plugin; char label[256]; - const LADSPA_Descriptor *desc; + + const struct fc_descriptor *desc; uint32_t n_input; uint32_t n_output; @@ -129,7 +133,7 @@ struct ladspa_descriptor { unsigned long output[MAX_PORTS]; unsigned long control[MAX_PORTS]; unsigned long notify[MAX_PORTS]; - LADSPA_Data default_control[MAX_PORTS]; + float default_control[MAX_PORTS]; }; struct port { @@ -143,15 +147,15 @@ struct port { uint32_t n_links; uint32_t external; - LADSPA_Data control_data; - LADSPA_Data *audio_data[MAX_HNDL]; + float control_data; + float *audio_data[MAX_HNDL]; }; struct node { struct spa_list link; struct graph *graph; - struct ladspa_descriptor *desc; + struct descriptor *desc; char name[256]; @@ -161,7 +165,7 @@ struct node { struct port notify_port[MAX_PORTS]; uint32_t n_hndl; - LADSPA_Handle hndl[MAX_HNDL]; + void *hndl[MAX_HNDL]; unsigned int n_deps; unsigned int visited:1; @@ -178,14 +182,14 @@ struct link { }; struct graph_port { - const LADSPA_Descriptor *desc; - LADSPA_Handle hndl; + const struct fc_descriptor *desc; + void *hndl; uint32_t port; }; struct graph_hndl { - const LADSPA_Descriptor *desc; - LADSPA_Handle hndl; + const struct fc_descriptor *desc; + void *hndl; }; struct graph { @@ -206,8 +210,8 @@ struct graph { uint32_t n_control; struct port *control_port[MAX_CONTROLS]; - LADSPA_Data silence_data[MAX_SAMPLES]; - LADSPA_Data discard_data[MAX_SAMPLES]; + float silence_data[MAX_SAMPLES]; + float discard_data[MAX_SAMPLES]; }; struct impl { @@ -222,7 +226,7 @@ struct impl { struct spa_hook core_proxy_listener; struct spa_hook core_listener; - struct spa_list ladspa_handle_list; + struct spa_list plugin_list; struct pw_properties *capture_props; struct pw_stream *capture; @@ -242,8 +246,6 @@ struct impl { struct graph graph; }; -#include "module-filter-chain/builtin.h" - static void do_unload_module(void *obj, void *data, int res, uint32_t id) { struct impl *impl = data; @@ -313,67 +315,10 @@ done: pw_stream_queue_buffer(impl->playback, out); } -static float get_default(struct impl *impl, struct ladspa_descriptor *desc, uint32_t p) +static float get_default(struct impl *impl, struct descriptor *desc, uint32_t p) { - const LADSPA_Descriptor *d = desc->desc; - LADSPA_PortRangeHintDescriptor hint = d->PortRangeHints[p].HintDescriptor; - LADSPA_Data lower, upper, def; - - lower = d->PortRangeHints[p].LowerBound; - upper = d->PortRangeHints[p].UpperBound; - - if (LADSPA_IS_HINT_SAMPLE_RATE(hint)) { - lower *= (LADSPA_Data) impl->rate; - upper *= (LADSPA_Data) impl->rate; - } - - switch (hint & LADSPA_HINT_DEFAULT_MASK) { - case LADSPA_HINT_DEFAULT_MINIMUM: - def = lower; - break; - case LADSPA_HINT_DEFAULT_MAXIMUM: - def = upper; - break; - case LADSPA_HINT_DEFAULT_LOW: - if (LADSPA_IS_HINT_LOGARITHMIC(hint)) - def = (LADSPA_Data) exp(log(lower) * 0.75 + log(upper) * 0.25); - else - def = (LADSPA_Data) (lower * 0.75 + upper * 0.25); - break; - case LADSPA_HINT_DEFAULT_MIDDLE: - if (LADSPA_IS_HINT_LOGARITHMIC(hint)) - def = (LADSPA_Data) exp(log(lower) * 0.5 + log(upper) * 0.5); - else - def = (LADSPA_Data) (lower * 0.5 + upper * 0.5); - break; - case LADSPA_HINT_DEFAULT_HIGH: - if (LADSPA_IS_HINT_LOGARITHMIC(hint)) - def = (LADSPA_Data) exp(log(lower) * 0.25 + log(upper) * 0.75); - else - def = (LADSPA_Data) (lower * 0.25 + upper * 0.75); - break; - case LADSPA_HINT_DEFAULT_0: - def = 0; - break; - case LADSPA_HINT_DEFAULT_1: - def = 1; - break; - case LADSPA_HINT_DEFAULT_100: - def = 100; - break; - case LADSPA_HINT_DEFAULT_440: - def = 440; - break; - default: - if (upper == lower) - def = upper; - else - def = SPA_CLAMP(0.5 * upper, lower, upper); - break; - } - if (LADSPA_IS_HINT_INTEGER(hint)) - def = roundf(def); - return def; + struct fc_port *port = &desc->desc->ports[p]; + return port->get_param(port, "default"); } static struct node *find_node(struct graph *graph, const char *name) @@ -390,7 +335,7 @@ static struct port *find_port(struct node *node, const char *name, int descripto { char *col, *node_name, *port_name, *str; struct port *ports; - const LADSPA_Descriptor *d; + const struct fc_descriptor *d; uint32_t i, n_ports; str = strdupa(name); @@ -429,7 +374,7 @@ static struct port *find_port(struct node *node, const char *name, int descripto d = node->desc->desc; for (i = 0; i < n_ports; i++) { struct port *port = &ports[i]; - if (spa_streq(d->PortNames[port->p], port_name)) + if (spa_streq(d->ports[port->p].name, port_name)) return port; } return NULL; @@ -438,29 +383,22 @@ static struct port *find_port(struct node *node, const char *name, int descripto static struct spa_pod *get_prop_info(struct graph *graph, struct spa_pod_builder *b, uint32_t idx) { struct spa_pod_frame f[2]; - struct impl *impl = graph->impl; struct port *port = graph->control_port[idx]; struct node *node = port->node; - struct ladspa_descriptor *desc = node->desc; - uint32_t p = port->p; - const LADSPA_Descriptor *d = desc->desc; - LADSPA_PortRangeHintDescriptor hint = d->PortRangeHints[p].HintDescriptor; - float def, upper, lower; + struct descriptor *desc = node->desc; + const struct fc_descriptor *d = desc->desc; + struct fc_port *p = &d->ports[port->p]; + float def, min, max; char name[512]; - def = get_default(impl, desc, p); - lower = d->PortRangeHints[p].LowerBound; - upper = d->PortRangeHints[p].UpperBound; - - if (LADSPA_IS_HINT_SAMPLE_RATE(hint)) { - lower *= (LADSPA_Data) impl->rate; - upper *= (LADSPA_Data) impl->rate; - } + def = p->get_param(p, "default"); + min = p->get_param(p, "min"); + max = p->get_param(p, "max"); if (node->name[0] != '\0') - snprintf(name, sizeof(name), "%s:%s", node->name, d->PortNames[p]); + snprintf(name, sizeof(name), "%s:%s", node->name, p->name); else - snprintf(name, sizeof(name), "%s", d->PortNames[p]); + snprintf(name, sizeof(name), "%s", p->name); spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo); @@ -469,13 +407,13 @@ static struct spa_pod *get_prop_info(struct graph *graph, struct spa_pod_builder SPA_PROP_INFO_name, SPA_POD_String(name), 0); spa_pod_builder_prop(b, SPA_PROP_INFO_type, 0); - if (lower == upper) { + if (min == max) { spa_pod_builder_float(b, def); } else { spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_Range, 0); spa_pod_builder_float(b, def); - spa_pod_builder_float(b, lower); - spa_pod_builder_float(b, upper); + spa_pod_builder_float(b, min); + spa_pod_builder_float(b, max); spa_pod_builder_pop(b, &f[1]); } spa_pod_builder_prop(b, SPA_PROP_INFO_params, 0); @@ -497,13 +435,14 @@ static struct spa_pod *get_props_param(struct graph *graph, struct spa_pod_build for (i = 0; i < graph->n_control; i++) { struct port *port = graph->control_port[i]; struct node *node = port->node; - struct ladspa_descriptor *desc = node->desc; - const LADSPA_Descriptor *d = desc->desc; + struct descriptor *desc = node->desc; + const struct fc_descriptor *d = desc->desc; + struct fc_port *p = &d->ports[port->p]; if (node->name[0] != '\0') - snprintf(name, sizeof(name), "%s:%s", node->name, d->PortNames[port->p]); + snprintf(name, sizeof(name), "%s:%s", node->name, p->name); else - snprintf(name, sizeof(name), "%s", d->PortNames[port->p]); + snprintf(name, sizeof(name), "%s", p->name); spa_pod_builder_string(b, name); spa_pod_builder_float(b, port->control_data); @@ -514,7 +453,7 @@ static struct spa_pod *get_props_param(struct graph *graph, struct spa_pod_build static int set_control_value(struct node *node, const char *name, float *value) { - struct ladspa_descriptor *desc; + struct descriptor *desc; struct port *port; float old; @@ -563,7 +502,7 @@ static void graph_reset(struct graph *graph) uint32_t i; for (i = 0; i < graph->n_hndl; i++) { struct graph_hndl *hndl = &graph->hndl[i]; - const LADSPA_Descriptor *d = hndl->desc; + const struct fc_descriptor *d = hndl->desc; if (d->deactivate) d->deactivate(hndl->hndl); if (d->activate) @@ -762,21 +701,6 @@ static int setup_streams(struct impl *impl) return 0; } -static const LADSPA_Descriptor *find_descriptor(LADSPA_Descriptor_Function desc_func, - const char *label) -{ - unsigned long i; - - for (i = 0; ;i++) { - const LADSPA_Descriptor *desc = desc_func(i); - if (desc == NULL) - break; - if (spa_streq(desc->Label, label)) - return desc; - } - return NULL; -} - static uint32_t count_array(struct spa_json *json) { struct spa_json it = *json; @@ -787,139 +711,83 @@ static uint32_t count_array(struct spa_json *json) return count; } -static void ladspa_handle_unref(struct ladspa_handle *hndl) +static void plugin_unref(struct plugin *hndl) { if (--hndl->ref > 0) return; - if (hndl->handle) - dlclose(hndl->handle); + fc_plugin_free(hndl->plugin); spa_list_remove(&hndl->link); free(hndl); } -static struct ladspa_handle *ladspa_handle_load_by_path(struct impl *impl, const char *path) +static struct plugin *plugin_load(struct impl *impl, const char *type, const char *path) { - struct ladspa_handle *hndl; - int res; + struct fc_plugin *pl = NULL; + struct plugin *hndl; + int res = 0; - spa_list_for_each(hndl, &impl->ladspa_handle_list, link) { - if (spa_streq(hndl->path, path)) { + spa_list_for_each(hndl, &impl->plugin_list, link) { + if (spa_streq(hndl->type, type) && + spa_streq(hndl->path, path)) { hndl->ref++; return hndl; } } + if (spa_streq(path, "builtin")) { + pl = load_builtin_plugin(path, NULL); + } + else if (spa_streq(path, "ladspa")) { + pl = load_ladspa_plugin(path, NULL); + } + if (pl == NULL) + goto exit; + hndl = calloc(1, sizeof(*hndl)); if (!hndl) return NULL; hndl->ref = 1; + snprintf(hndl->type, sizeof(hndl->type), "%s", type); snprintf(hndl->path, sizeof(hndl->path), "%s", path); - if (!spa_streq(path, "builtin")) { - hndl->handle = dlopen(path, RTLD_NOW); - if (!hndl->handle) { - pw_log_debug("failed to open '%s': %s", path, dlerror()); - res = -ENOENT; - goto exit; - } + pw_log_info("successfully opened '%s'", path); - pw_log_info("successfully opened '%s'", path); - - hndl->desc_func = (LADSPA_Descriptor_Function) dlsym(hndl->handle, "ladspa_descriptor"); - if (!hndl->desc_func) { - pw_log_warn("cannot find descriptor function in '%s': %s", path, dlerror()); - res = -ENOSYS; - goto exit; - } - } - else { - hndl->desc_func = builtin_ladspa_descriptor; - } + hndl->plugin = pl; spa_list_init(&hndl->descriptor_list); - spa_list_append(&impl->ladspa_handle_list, &hndl->link); + spa_list_append(&impl->plugin_list, &hndl->link); return hndl; exit: - if (hndl->handle) - dlclose(hndl->handle); - - free(hndl); errno = -res; - return NULL; } -static struct ladspa_handle *ladspa_handle_load(struct impl *impl, const char *plugin) -{ - struct ladspa_handle *hndl = NULL; - - if (!spa_streq(plugin, "builtin") && plugin[0] != '/') { - const char *search_dirs, *p; - char path[PATH_MAX]; - size_t len; - - search_dirs = getenv("LADSPA_PATH"); - if (!search_dirs) - search_dirs = "/usr/lib64/ladspa"; - - /* - * set the errno for the case when `ladspa_handle_load_by_path()` - * is never called, which can only happen if the supplied - * LADSPA_PATH contains too long paths - */ - errno = ENAMETOOLONG; - - while ((p = pw_split_walk(NULL, ":", &len, &search_dirs))) { - int pathlen; - - if (len >= sizeof(path)) - continue; - - pathlen = snprintf(path, sizeof(path), "%.*s/%s.so", (int) len, p, plugin); - if (pathlen < 0 || (size_t) pathlen >= sizeof(path)) - continue; - - hndl = ladspa_handle_load_by_path(impl, path); - if (hndl) - break; - } - } - else { - hndl = ladspa_handle_load_by_path(impl, plugin); - } - - if (!hndl) - pw_log_error("failed to load plugin '%s': %s", plugin, strerror(errno)); - - return hndl; -} - -static void ladspa_descriptor_unref(struct ladspa_descriptor *desc) +static void descriptor_unref(struct descriptor *desc) { if (--desc->ref > 0) return; spa_list_remove(&desc->link); - ladspa_handle_unref(desc->handle); + plugin_unref(desc->plugin); free(desc); } -static struct ladspa_descriptor *ladspa_descriptor_load(struct impl *impl, +static struct descriptor *descriptor_load(struct impl *impl, const char *type, const char *plugin, const char *label) { - struct ladspa_handle *hndl; - struct ladspa_descriptor *desc; - const LADSPA_Descriptor *d; + struct plugin *hndl; + struct descriptor *desc; + const struct fc_descriptor *d; uint32_t i; unsigned long p; int res; - if ((hndl = ladspa_handle_load(impl, plugin)) == NULL) + if ((hndl = plugin_load(impl, type, plugin)) == NULL) return NULL; spa_list_for_each(desc, &hndl->descriptor_list, link) { @@ -933,16 +801,16 @@ static struct ladspa_descriptor *ladspa_descriptor_load(struct impl *impl, * so we need to unref handle here since we're merely reusing * thedescriptor, not creating a new one */ - ladspa_handle_unref(hndl); + plugin_unref(hndl); return desc; } } desc = calloc(1, sizeof(*desc)); desc->ref = 1; - desc->handle = hndl; + desc->plugin = hndl; - if ((d = find_descriptor(hndl->desc_func, label)) == NULL) { + if ((d = hndl->plugin->make_desc(hndl->plugin, label)) == NULL) { pw_log_error("cannot find label %s", label); res = -ENOENT; goto exit; @@ -950,27 +818,29 @@ static struct ladspa_descriptor *ladspa_descriptor_load(struct impl *impl, desc->desc = d; snprintf(desc->label, sizeof(desc->label), "%s", label); - for (p = 0; p < d->PortCount; p++) { - if (LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) { - if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p])) { + for (p = 0; p < d->n_ports; p++) { + struct fc_port *fp = &d->ports[p]; + + if (LADSPA_IS_PORT_AUDIO(fp->flags)) { + if (LADSPA_IS_PORT_INPUT(fp->flags)) { pw_log_info("using port %lu ('%s') as input %d", p, - d->PortNames[p], desc->n_input); + fp->name, desc->n_input); desc->input[desc->n_input++] = p; } - else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p])) { + else if (LADSPA_IS_PORT_OUTPUT(fp->flags)) { pw_log_info("using port %lu ('%s') as output %d", p, - d->PortNames[p], desc->n_output); + fp->name, desc->n_output); desc->output[desc->n_output++] = p; } - } else if (LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p])) { - if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p])) { + } else if (LADSPA_IS_PORT_CONTROL(fp->flags)) { + if (LADSPA_IS_PORT_INPUT(fp->flags)) { pw_log_info("using port %lu ('%s') as control %d", p, - d->PortNames[p], desc->n_control); + fp->name, desc->n_control); desc->control[desc->n_control++] = p; } - else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p])) { + else if (LADSPA_IS_PORT_OUTPUT(fp->flags)) { pw_log_info("using port %lu ('%s') as notify %d", p, - d->PortNames[p], desc->n_notify); + fp->name, desc->n_notify); desc->notify[desc->n_notify++] = p; } } @@ -984,7 +854,7 @@ static struct ladspa_descriptor *ladspa_descriptor_load(struct impl *impl, p = desc->control[i]; desc->default_control[i] = get_default(impl, desc, p); pw_log_info("control %d ('%s') default to %f", i, - d->PortNames[p], desc->default_control[i]); + d->ports[p].name, desc->default_control[i]); } spa_list_append(&hndl->descriptor_list, &desc->link); @@ -992,7 +862,7 @@ static struct ladspa_descriptor *ladspa_descriptor_load(struct impl *impl, exit: if (hndl != NULL) - ladspa_handle_unref(hndl); + plugin_unref(hndl); free(desc); errno = -res; return NULL; @@ -1071,9 +941,9 @@ static int parse_link(struct graph *graph, struct spa_json *json) pw_log_info("linking %s:%s -> %s:%s", out_port->node->name, - out_port->node->desc->desc->PortNames[out_port->p], + out_port->node->desc->desc->ports[out_port->p].name, in_port->node->name, - in_port->node->desc->desc->PortNames[in_port->p]); + in_port->node->desc->desc->ports[in_port->p].name); spa_list_append(&out_port->link_list, &link->output_link); out_port->n_links++; @@ -1110,7 +980,7 @@ static void link_free(struct link *link) static int load_node(struct graph *graph, struct spa_json *json) { struct spa_json control; - struct ladspa_descriptor *desc; + struct descriptor *desc; struct node *node; const char *val; char key[256]; @@ -1157,8 +1027,9 @@ static int load_node(struct graph *graph, struct spa_json *json) } else if (!spa_streq(type, "ladspa")) return -ENOTSUP; - pw_log_info("loading %s %s", plugin, label); - if ((desc = ladspa_descriptor_load(graph->impl, plugin, label)) == NULL) + pw_log_info("loading type:%s plugin:%s label:%s", type, plugin, label); + + if ((desc = descriptor_load(graph->impl, type, plugin, label)) == NULL) return -errno; node = calloc(1, sizeof(*node)); @@ -1213,7 +1084,7 @@ static int load_node(struct graph *graph, struct spa_json *json) static void node_free(struct node *node) { uint32_t i, j; - const LADSPA_Descriptor *d = node->desc->desc; + const struct fc_descriptor *d = node->desc->desc; spa_list_remove(&node->link); for (i = 0; i < node->n_hndl; i++) { @@ -1225,7 +1096,7 @@ static void node_free(struct node *node) d->deactivate(node->hndl[i]); d->cleanup(node->hndl[i]); } - ladspa_descriptor_unref(node->desc); + descriptor_unref(node->desc); free(node); } @@ -1243,8 +1114,8 @@ static struct node *find_next_node(struct graph *graph) static int setup_input_port(struct graph *graph, struct port *port) { - struct ladspa_descriptor *desc = port->node->desc; - const LADSPA_Descriptor *d = desc->desc; + struct descriptor *desc = port->node->desc; + const struct fc_descriptor *d = desc->desc; struct link *link; uint32_t i, n_hndl = port->node->n_hndl; @@ -1252,7 +1123,7 @@ static int setup_input_port(struct graph *graph, struct port *port) struct port *peer = link->output; for (i = 0; i < n_hndl; i++) { pw_log_info("connect input port %s[%d]:%s %p", - port->node->name, i, d->PortNames[port->p], + port->node->name, i, d->ports[port->p].name, peer->audio_data[i]); d->connect_port(port->node->hndl[i], port->p, peer->audio_data[i]); } @@ -1262,8 +1133,8 @@ static int setup_input_port(struct graph *graph, struct port *port) static int setup_output_port(struct graph *graph, struct port *port) { - struct ladspa_descriptor *desc = port->node->desc; - const LADSPA_Descriptor *d = desc->desc; + struct descriptor *desc = port->node->desc; + const struct fc_descriptor *d = desc->desc; struct link *link; uint32_t i, n_hndl = port->node->n_hndl; @@ -1277,7 +1148,7 @@ static int setup_output_port(struct graph *graph, struct port *port) } port->audio_data[i] = data; pw_log_info("connect output port %s[%d]:%s %p", - port->node->name, i, d->PortNames[port->p], + port->node->name, i, d->ports[port->p].name, port->audio_data[i]); d->connect_port(port->node->hndl[i], port->p, data); } @@ -1296,8 +1167,8 @@ static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_ uint32_t i, j, n_input, n_output, n_hndl = 0; int res; unsigned long p; - struct ladspa_descriptor *desc; - const LADSPA_Descriptor *d; + struct descriptor *desc; + const struct fc_descriptor *d; char v[256]; graph->n_input = 0; @@ -1353,7 +1224,7 @@ static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_ desc = node->desc; d = desc->desc; for (i = 0; i < n_hndl; i++) { - if ((node->hndl[i] = d->instantiate(d, impl->rate)) == NULL) { + if ((node->hndl[i] = d->instantiate(d, impl->rate, NULL)) == NULL) { pw_log_error("cannot create plugin instance"); res = -ENOMEM; goto error; @@ -1394,7 +1265,7 @@ static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_ for (j = 0; j < desc->n_input; j++) { gp = &graph->input[graph->n_input++]; pw_log_info("input port %s[%d]:%s", - first->name, i, d->PortNames[desc->input[j]]); + first->name, i, d->ports[desc->input[j]].name); gp->desc = d; gp->hndl = first->hndl[i]; gp->port = desc->input[j]; @@ -1415,19 +1286,19 @@ static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_ d = desc->desc; if (i == 0 && port->external != SPA_ID_INVALID) { pw_log_error("input port %s[%d]:%s already used as input %d, use mixer", - port->node->name, i, d->PortNames[port->p], + port->node->name, i, d->ports[port->p].name, port->external); res = -EBUSY; goto error; } if (port->n_links > 0) { pw_log_error("input port %s[%d]:%s already used by link, use mixer", - port->node->name, i, d->PortNames[port->p]); + port->node->name, i, d->ports[port->p].name); res = -EBUSY; goto error; } pw_log_info("input port %s[%d]:%s", - port->node->name, i, d->PortNames[port->p]); + port->node->name, i, d->ports[port->p].name); port->external = graph->n_input; gp->desc = d; gp->hndl = port->node->hndl[i]; @@ -1442,7 +1313,7 @@ static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_ for (j = 0; j < desc->n_output; j++) { gp = &graph->output[graph->n_output++]; pw_log_info("output port %s[%d]:%s", - last->name, i, d->PortNames[desc->output[j]]); + last->name, i, d->ports[desc->output[j]].name); gp->desc = d; gp->hndl = last->hndl[i]; gp->port = desc->output[j]; @@ -1463,19 +1334,19 @@ static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_ d = desc->desc; if (i == 0 && port->external != SPA_ID_INVALID) { pw_log_error("output port %s[%d]:%s already used as output %d, use copy", - port->node->name, i, d->PortNames[port->p], + port->node->name, i, d->ports[port->p].name, port->external); res = -EBUSY; goto error; } if (port->n_links > 0) { pw_log_error("output port %s[%d]:%s already used by link, use copy", - port->node->name, i, d->PortNames[port->p]); + port->node->name, i, d->ports[port->p].name); res = -EBUSY; goto error; } pw_log_info("output port %s[%d]:%s", - port->node->name, i, d->PortNames[port->p]); + port->node->name, i, d->ports[port->p].name); port->external = graph->n_output; gp->desc = d; gp->hndl = port->node->hndl[i]; @@ -1753,7 +1624,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) } impl->rate = 48000; impl->graph.impl = impl; - spa_list_init(&impl->ladspa_handle_list); + spa_list_init(&impl->plugin_list); if (pw_properties_get(props, PW_KEY_NODE_GROUP) == NULL) pw_properties_setf(props, PW_KEY_NODE_GROUP, "filter-chain-%u", id); diff --git a/src/modules/module-filter-chain/builtin.h b/src/modules/module-filter-chain/builtin_plugin.c similarity index 56% rename from src/modules/module-filter-chain/builtin.h rename to src/modules/module-filter-chain/builtin_plugin.c index 6001b8cc7..3f6ab926c 100644 --- a/src/modules/module-filter-chain/builtin.h +++ b/src/modules/module-filter-chain/builtin_plugin.c @@ -24,12 +24,15 @@ #include +#include "plugin.h" +#include "ladspa.h" + #include "biquad.h" #include "convolver.h" struct builtin { unsigned long rate; - LADSPA_Data *port[64]; + float *port[64]; struct biquad bq; float freq; @@ -37,8 +40,8 @@ struct builtin { float gain; }; -static LADSPA_Handle builtin_instantiate(const struct _LADSPA_Descriptor * Descriptor, - unsigned long SampleRate) +static void *builtin_instantiate(const struct fc_descriptor * Descriptor, + unsigned long SampleRate, const char *config) { struct builtin *impl; @@ -51,49 +54,48 @@ static LADSPA_Handle builtin_instantiate(const struct _LADSPA_Descriptor * Descr return impl; } -static void builtin_connect_port(LADSPA_Handle Instance, unsigned long Port, - LADSPA_Data * DataLocation) +static void builtin_connect_port(void *Instance, unsigned long Port, + float * DataLocation) { struct builtin *impl = Instance; impl->port[Port] = DataLocation; } -static void builtin_cleanup(LADSPA_Handle Instance) +static void builtin_cleanup(void * Instance) { struct builtin *impl = Instance; free(impl); } /** copy */ -static void copy_run(LADSPA_Handle Instance, unsigned long SampleCount) +static void copy_run(void * Instance, unsigned long SampleCount) { struct builtin *impl = Instance; float *in = impl->port[1], *out = impl->port[0]; memcpy(out, in, SampleCount * sizeof(float)); } -static const LADSPA_PortDescriptor copy_port_desc[] = { - LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, +static struct fc_port copy_ports[] = { + { .index = 0, + .name = "Out", + .flags = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + }, + { .index = 1, + .name = "In", + .flags = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + } }; -static const char * const copy_port_names[] = { - "Out", "In" -}; +static const struct fc_descriptor copy_desc = { + .name = "copy", -static const LADSPA_PortRangeHint copy_range_hints[] = { - { 0, }, { 0, }, -}; + //.Name = "Copy input to output", + //.Maker = "PipeWire", + //.Copyright = "MIT", + + .n_ports = 2, + .ports = copy_ports, -static const LADSPA_Descriptor copy_desc = { - .Label = "copy", - .Name = "Copy input to output", - .Maker = "PipeWire", - .Copyright = "MIT", - .PortCount = 2, - .PortDescriptors = copy_port_desc, - .PortNames = copy_port_names, - .PortRangeHints = copy_range_hints, .instantiate = builtin_instantiate, .connect_port = builtin_connect_port, .run = copy_run, @@ -101,7 +103,7 @@ static const LADSPA_Descriptor copy_desc = { }; /** mixer */ -static void mixer_run(LADSPA_Handle Instance, unsigned long SampleCount) +static void mixer_run(void * Instance, unsigned long SampleCount) { struct builtin *impl = Instance; unsigned long i; @@ -120,52 +122,63 @@ static void mixer_run(LADSPA_Handle Instance, unsigned long SampleCount) } } -static const LADSPA_PortDescriptor mixer_port_desc[] = { - LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, -}; - -static const char * const mixer_port_names[] = { - "Out", "In 1", "In 2", "Gain 1", "Gain 2" -}; - +#if 0 static const LADSPA_PortRangeHint mixer_range_hints[] = { { 0, }, { 0, }, { 0, }, { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_1, 0.0, 10.0 }, { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_1, 0.0, 10.0 } }; +#endif + +static struct fc_port mixer_ports[] = { + { .index = 0, + .name = "Out", + .flags = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + }, + { .index = 1, + .name = "In 1", + .flags = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + }, + { .index = 2, + .name = "In 2", + .flags = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + }, + { .index = 3, + .name = "Gain 1", + .flags = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + }, + { .index = 4, + .name = "Gain 2", + .flags = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + }, +}; + +static const char *mixer_get_prop(struct fc_descriptor *desc, const char *name) +{ + if (spa_streq(name, "description")) + return "Mix 2 inputs"; + if (spa_streq(name, "maker")) + return "PipeWire"; + if (spa_streq(name, "copyright")) + return "MIT"; + return NULL; +} + +static const struct fc_descriptor mixer_desc = { + .name = "mixer", + + .get_prop = mixer_get_prop, + + .n_ports = 5, + .ports = mixer_ports, -static const LADSPA_Descriptor mixer_desc = { - .Label = "mixer", - .Name = "Mix 2 inputs", - .Maker = "PipeWire", - .Copyright = "MIT", - .PortCount = 5, - .PortDescriptors = mixer_port_desc, - .PortNames = mixer_port_names, - .PortRangeHints = mixer_range_hints, .instantiate = builtin_instantiate, .connect_port = builtin_connect_port, .run = mixer_run, .cleanup = builtin_cleanup, }; - -static const LADSPA_PortDescriptor bq_port_desc[] = { - LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, -}; - -static const char * const bq_port_names[] = { - "Out", "In", "Freq", "Q", "Gain" -}; - +#if 0 static const LADSPA_PortRangeHint bq_range_hints[] = { { 0, }, { 0, }, { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | @@ -175,6 +188,30 @@ static const LADSPA_PortRangeHint bq_range_hints[] = { { LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_0, -120.0, 5.0 }, }; +#endif + +static struct fc_port bq_ports[] = { + { .index = 0, + .name = "Out", + .flags = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + }, + { .index = 1, + .name = "In", + .flags = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + }, + { .index = 2, + .name = "Freq", + .flags = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + }, + { .index = 3, + .name = "Q", + .flags = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + }, + { .index = 4, + .name = "Gain", + .flags = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + }, +}; static void bq_run(struct builtin *impl, unsigned long samples, int type) { @@ -219,21 +256,20 @@ static void bq_run(struct builtin *impl, unsigned long samples, int type) } /** bq_lowpass */ -static void bq_lowpass_run(LADSPA_Handle Instance, unsigned long SampleCount) +static void bq_lowpass_run(void * Instance, unsigned long SampleCount) { struct builtin *impl = Instance; bq_run(impl, SampleCount, BQ_LOWPASS); } -static const LADSPA_Descriptor bq_lowpass_desc = { - .Label = "bq_lowpass", - .Name = "Biquad lowpass filter", - .Maker = "PipeWire", - .Copyright = "MIT", - .PortCount = 5, - .PortDescriptors = bq_port_desc, - .PortNames = bq_port_names, - .PortRangeHints = bq_range_hints, +static const struct fc_descriptor bq_lowpass_desc = { + .name = "bq_lowpass", + //.Name = "Biquad lowpass filter", + //.Maker = "PipeWire", + //.Copyright = "MIT", + .n_ports = 5, + .ports = bq_ports, + .instantiate = builtin_instantiate, .connect_port = builtin_connect_port, .run = bq_lowpass_run, @@ -241,21 +277,19 @@ static const LADSPA_Descriptor bq_lowpass_desc = { }; /** bq_highpass */ -static void bq_highpass_run(LADSPA_Handle Instance, unsigned long SampleCount) +static void bq_highpass_run(void * Instance, unsigned long SampleCount) { struct builtin *impl = Instance; bq_run(impl, SampleCount, BQ_HIGHPASS); } -static const LADSPA_Descriptor bq_highpass_desc = { - .Label = "bq_highpass", - .Name = "Biquad highpass filter", - .Maker = "PipeWire", - .Copyright = "MIT", - .PortCount = 5, - .PortDescriptors = bq_port_desc, - .PortNames = bq_port_names, - .PortRangeHints = bq_range_hints, +static const struct fc_descriptor bq_highpass_desc = { + .name = "bq_highpass", + //.Name = "Biquad highpass filter", + //.Maker = "PipeWire", + //.Copyright = "MIT", + .n_ports = 5, + .ports = bq_ports, .instantiate = builtin_instantiate, .connect_port = builtin_connect_port, .run = bq_highpass_run, @@ -263,21 +297,19 @@ static const LADSPA_Descriptor bq_highpass_desc = { }; /** bq_bandpass */ -static void bq_bandpass_run(LADSPA_Handle Instance, unsigned long SampleCount) +static void bq_bandpass_run(void * Instance, unsigned long SampleCount) { struct builtin *impl = Instance; bq_run(impl, SampleCount, BQ_BANDPASS); } -static const LADSPA_Descriptor bq_bandpass_desc = { - .Label = "bq_bandpass", - .Name = "Biquad bandpass filter", - .Maker = "PipeWire", - .Copyright = "MIT", - .PortCount = 5, - .PortDescriptors = bq_port_desc, - .PortNames = bq_port_names, - .PortRangeHints = bq_range_hints, +static const struct fc_descriptor bq_bandpass_desc = { + .name = "bq_bandpass", + //.Name = "Biquad bandpass filter", + //.Maker = "PipeWire", + //.Copyright = "MIT", + .n_ports = 5, + .ports = bq_ports, .instantiate = builtin_instantiate, .connect_port = builtin_connect_port, .run = bq_bandpass_run, @@ -285,21 +317,19 @@ static const LADSPA_Descriptor bq_bandpass_desc = { }; /** bq_lowshelf */ -static void bq_lowshelf_run(LADSPA_Handle Instance, unsigned long SampleCount) +static void bq_lowshelf_run(void * Instance, unsigned long SampleCount) { struct builtin *impl = Instance; bq_run(impl, SampleCount, BQ_LOWSHELF); } -static const LADSPA_Descriptor bq_lowshelf_desc = { - .Label = "bq_lowshelf", - .Name = "Biquad lowshelf filter", - .Maker = "PipeWire", - .Copyright = "MIT", - .PortCount = 5, - .PortDescriptors = bq_port_desc, - .PortNames = bq_port_names, - .PortRangeHints = bq_range_hints, +static const struct fc_descriptor bq_lowshelf_desc = { + .name = "bq_lowshelf", + //.Name = "Biquad lowshelf filter", + //.Maker = "PipeWire", + //.Copyright = "MIT", + .n_ports = 5, + .ports = bq_ports, .instantiate = builtin_instantiate, .connect_port = builtin_connect_port, .run = bq_lowshelf_run, @@ -307,21 +337,19 @@ static const LADSPA_Descriptor bq_lowshelf_desc = { }; /** bq_highshelf */ -static void bq_highshelf_run(LADSPA_Handle Instance, unsigned long SampleCount) +static void bq_highshelf_run(void * Instance, unsigned long SampleCount) { struct builtin *impl = Instance; bq_run(impl, SampleCount, BQ_HIGHSHELF); } -static const LADSPA_Descriptor bq_highshelf_desc = { - .Label = "bq_highshelf", - .Name = "Biquad highshelf filter", - .Maker = "PipeWire", - .Copyright = "MIT", - .PortCount = 5, - .PortDescriptors = bq_port_desc, - .PortNames = bq_port_names, - .PortRangeHints = bq_range_hints, +static const struct fc_descriptor bq_highshelf_desc = { + .name = "bq_highshelf", + //.Name = "Biquad highshelf filter", + //.Maker = "PipeWire", + //.Copyright = "MIT", + .n_ports = 5, + .ports = bq_ports, .instantiate = builtin_instantiate, .connect_port = builtin_connect_port, .run = bq_highshelf_run, @@ -329,21 +357,19 @@ static const LADSPA_Descriptor bq_highshelf_desc = { }; /** bq_peaking */ -static void bq_peaking_run(LADSPA_Handle Instance, unsigned long SampleCount) +static void bq_peaking_run(void * Instance, unsigned long SampleCount) { struct builtin *impl = Instance; bq_run(impl, SampleCount, BQ_PEAKING); } -static const LADSPA_Descriptor bq_peaking_desc = { - .Label = "bq_peaking", - .Name = "Biquad peaking filter", - .Maker = "PipeWire", - .Copyright = "MIT", - .PortCount = 5, - .PortDescriptors = bq_port_desc, - .PortNames = bq_port_names, - .PortRangeHints = bq_range_hints, +static const struct fc_descriptor bq_peaking_desc = { + .name = "bq_peaking", + //.Name = "Biquad peaking filter", + //.Maker = "PipeWire", + //.Copyright = "MIT", + .n_ports = 5, + .ports = bq_ports, .instantiate = builtin_instantiate, .connect_port = builtin_connect_port, .run = bq_peaking_run, @@ -351,21 +377,19 @@ static const LADSPA_Descriptor bq_peaking_desc = { }; /** bq_notch */ -static void bq_notch_run(LADSPA_Handle Instance, unsigned long SampleCount) +static void bq_notch_run(void * Instance, unsigned long SampleCount) { struct builtin *impl = Instance; bq_run(impl, SampleCount, BQ_NOTCH); } -static const LADSPA_Descriptor bq_notch_desc = { - .Label = "bq_notch", - .Name = "Biquad notch filter", - .Maker = "PipeWire", - .Copyright = "MIT", - .PortCount = 5, - .PortDescriptors = bq_port_desc, - .PortNames = bq_port_names, - .PortRangeHints = bq_range_hints, +static const struct fc_descriptor bq_notch_desc = { + .name = "bq_notch", + //.Name = "Biquad notch filter", + //.Maker = "PipeWire", + //.Copyright = "MIT", + .n_ports = 5, + .ports = bq_ports, .instantiate = builtin_instantiate, .connect_port = builtin_connect_port, .run = bq_notch_run, @@ -374,21 +398,19 @@ static const LADSPA_Descriptor bq_notch_desc = { /** bq_allpass */ -static void bq_allpass_run(LADSPA_Handle Instance, unsigned long SampleCount) +static void bq_allpass_run(void * Instance, unsigned long SampleCount) { struct builtin *impl = Instance; bq_run(impl, SampleCount, BQ_ALLPASS); } -static const LADSPA_Descriptor bq_allpass_desc = { - .Label = "bq_allpass", - .Name = "Biquad allpass filter", - .Maker = "PipeWire", - .Copyright = "MIT", - .PortCount = 5, - .PortDescriptors = bq_port_desc, - .PortNames = bq_port_names, - .PortRangeHints = bq_range_hints, +static const struct fc_descriptor bq_allpass_desc = { + .name = "bq_allpass", + //.Name = "Biquad allpass filter", + //.Maker = "PipeWire", + //.Copyright = "MIT", + .n_ports = 5, + .ports = bq_ports, .instantiate = builtin_instantiate, .connect_port = builtin_connect_port, .run = bq_allpass_run, @@ -403,8 +425,8 @@ struct convolver_impl { struct convolver *conv; }; -static LADSPA_Handle convolver_instantiate(const struct _LADSPA_Descriptor * Descriptor, - unsigned long SampleRate) +static void * convolver_instantiate(const struct fc_descriptor * Descriptor, + unsigned long SampleRate, const char *config) { struct convolver_impl *impl; SF_INFO info; @@ -417,7 +439,7 @@ static LADSPA_Handle convolver_instantiate(const struct _LADSPA_Descriptor * Des spa_zero(info); f = sf_open(filename, SFM_READ, &info) ; if (f == NULL) { - pw_log_error("can't open %s", filename); + fprintf(stderr, "can't open %s", filename); return NULL; } @@ -441,54 +463,50 @@ static LADSPA_Handle convolver_instantiate(const struct _LADSPA_Descriptor * Des return impl; } -static void convolver_connect_port(LADSPA_Handle Instance, unsigned long Port, +static void convolver_connect_port(void * Instance, unsigned long Port, LADSPA_Data * DataLocation) { struct convolver_impl *impl = Instance; impl->port[Port] = DataLocation; } -static void convolver_cleanup(LADSPA_Handle Instance) +static void convolver_cleanup(void * Instance) { struct convolver_impl *impl = Instance; free(impl); } -static const LADSPA_PortDescriptor convolve_port_desc[] = { - LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, +static struct fc_port convolve_ports[] = { + { .index = 0, + .name = "Out", + .flags = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + }, + { .index = 1, + .name = "In", + .flags = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + }, }; -static const char * const convolve_port_names[] = { - "Out", "In" -}; - -static const LADSPA_PortRangeHint convolve_range_hints[] = { - { 0, }, { 0, }, -}; - -static void convolve_run(LADSPA_Handle Instance, unsigned long SampleCount) +static void convolve_run(void * Instance, unsigned long SampleCount) { struct convolver_impl *impl = Instance; convolver_run(impl->conv, impl->port[1], impl->port[0], SampleCount); } -static const LADSPA_Descriptor convolve_desc = { - .Label = "convolver", - .Name = "Convolver", - .Maker = "PipeWire", - .Copyright = "MIT", - .PortCount = 2, - .PortDescriptors = convolve_port_desc, - .PortNames = convolve_port_names, - .PortRangeHints = convolve_range_hints, +static const struct fc_descriptor convolve_desc = { + .name = "convolver", + //.Name = "Convolver", + //.Maker = "PipeWire", + //.Copyright = "MIT", + .n_ports = 2, + .ports = convolve_ports, .instantiate = convolver_instantiate, .connect_port = convolver_connect_port, .run = convolve_run, .cleanup = convolver_cleanup, }; -static const LADSPA_Descriptor * builtin_ladspa_descriptor(unsigned long Index) +static const struct fc_descriptor * builtin_descriptor(unsigned long Index) { switch(Index) { case 0: @@ -517,3 +535,24 @@ static const LADSPA_Descriptor * builtin_ladspa_descriptor(unsigned long Index) return NULL; } +static const struct fc_descriptor *builtin_make_desc(struct fc_plugin *plugin, const char *name) +{ + unsigned long i; + for (i = 0; ;i++) { + const struct fc_descriptor *d = builtin_descriptor(i); + if (d == NULL) + break; + if (spa_streq(d->name, name)) + return d; + } + return NULL; +} + +static struct fc_plugin builtin_plugin = { + .make_desc = builtin_make_desc +}; + +struct fc_plugin *load_builtin_plugin(const char *plugin, const char *config) +{ + return &builtin_plugin; +} diff --git a/src/modules/module-filter-chain/convolver.c b/src/modules/module-filter-chain/convolver.c index 89e3e196f..286ad57f0 100644 --- a/src/modules/module-filter-chain/convolver.c +++ b/src/modules/module-filter-chain/convolver.c @@ -61,7 +61,7 @@ static int next_power_of_two(int val) struct convolver *convolver_new(int block, const float *ir, int irlen) { struct convolver *conv; - int i, j; + int i; if (block == 0) return NULL; @@ -111,12 +111,6 @@ struct convolver *convolver_new(int block, const float *ir, int irlen) memset(conv->fft_buffer + copy, 0, (conv->segSize - copy) * sizeof(float)); kiss_fftr_f32(conv->fft, conv->fft_buffer, conv->segmentsIr[i]); - -// for (j = 0; j < conv->fftComplexSize; j++) { -// conv->segmentsIr[i][j].r /= conv->segSize * 2; -// conv->segmentsIr[i][j].i /= conv->segSize * 2; -// } - } conv->pre_mult = calloc(sizeof(kiss_fft_f32_cpx), conv->fftComplexSize); conv->conv = calloc(sizeof(kiss_fft_f32_cpx), conv->fftComplexSize); @@ -193,7 +187,7 @@ int convolver_run(struct convolver *conv, const float *input, float *output, int kiss_fftri_f32(conv->ifft, conv->conv, conv->fft_buffer); for (i = 0; i < conv->segSize; i++) - conv->fft_buffer[i] /= conv->segSize * 4; + conv->fft_buffer[i] /= conv->segSize * 2; Sum(output + processed, conv->fft_buffer + inputBufferPos, conv->overlap + inputBufferPos, processing); diff --git a/src/modules/module-filter-chain/ladspa_plugin.c b/src/modules/module-filter-chain/ladspa_plugin.c new file mode 100644 index 000000000..813ff98e5 --- /dev/null +++ b/src/modules/module-filter-chain/ladspa_plugin.c @@ -0,0 +1,291 @@ +/* PipeWire + * + * Copyright © 2021 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include +#include +#include + +#include +#include + +#include "plugin.h" +#include "ladspa.h" + + +struct plugin_data { + void *handle; + LADSPA_Descriptor_Function desc_func; +}; + +struct desc_data { + const LADSPA_Descriptor *d; +}; + +static void *ladspa_instantiate(const struct fc_descriptor *desc, + unsigned long SampleRate, const char *config) +{ + struct desc_data *dd = desc->user; + return dd->d->instantiate(dd->d, SampleRate); +} + +static const LADSPA_Descriptor *find_desc(LADSPA_Descriptor_Function desc_func, const char *name) +{ + unsigned long i; + for (i = 0; ;i++) { + const LADSPA_Descriptor *d = desc_func(i); + if (d == NULL) + break; + if (spa_streq(d->Label, name)) + return d; + } + return NULL; +} + +static void ladspa_free(struct fc_descriptor *desc) +{ + free(desc->ports); +} + +static const char *ladspa_get_prop(struct fc_descriptor *desc, const char *name) +{ + return NULL; +} + +static float get_default(struct fc_port *port, LADSPA_PortRangeHintDescriptor hint, + LADSPA_Data lower, LADSPA_Data upper) +{ + LADSPA_Data def; + + switch (hint & LADSPA_HINT_DEFAULT_MASK) { + case LADSPA_HINT_DEFAULT_MINIMUM: + def = lower; + break; + case LADSPA_HINT_DEFAULT_MAXIMUM: + def = upper; + break; + case LADSPA_HINT_DEFAULT_LOW: + if (LADSPA_IS_HINT_LOGARITHMIC(hint)) + def = (LADSPA_Data) exp(log(lower) * 0.75 + log(upper) * 0.25); + else + def = (LADSPA_Data) (lower * 0.75 + upper * 0.25); + break; + case LADSPA_HINT_DEFAULT_MIDDLE: + if (LADSPA_IS_HINT_LOGARITHMIC(hint)) + def = (LADSPA_Data) exp(log(lower) * 0.5 + log(upper) * 0.5); + else + def = (LADSPA_Data) (lower * 0.5 + upper * 0.5); + break; + case LADSPA_HINT_DEFAULT_HIGH: + if (LADSPA_IS_HINT_LOGARITHMIC(hint)) + def = (LADSPA_Data) exp(log(lower) * 0.25 + log(upper) * 0.75); + else + def = (LADSPA_Data) (lower * 0.25 + upper * 0.75); + break; + case LADSPA_HINT_DEFAULT_0: + def = 0; + break; + case LADSPA_HINT_DEFAULT_1: + def = 1; + break; + case LADSPA_HINT_DEFAULT_100: + def = 100; + break; + case LADSPA_HINT_DEFAULT_440: + def = 440; + break; + default: + if (upper == lower) + def = upper; + else + def = SPA_CLAMP(0.5 * upper, lower, upper); + break; + } + if (LADSPA_IS_HINT_INTEGER(hint)) + def = roundf(def); + return def; +} + +static float ladspa_port_get_param(struct fc_port *port, const char *name) +{ + struct fc_descriptor *desc = port->desc; + struct desc_data *dd = desc->user; + const LADSPA_Descriptor *d = dd->d; + unsigned long p = port->index; + LADSPA_PortRangeHintDescriptor hint = d->PortRangeHints[p].HintDescriptor; + LADSPA_Data lower, upper; + + lower = d->PortRangeHints[p].LowerBound; + upper = d->PortRangeHints[p].UpperBound; + + if (LADSPA_IS_HINT_SAMPLE_RATE(hint)) { + lower *= (LADSPA_Data) 48000.0f; + upper *= (LADSPA_Data) 48000.0f; + } + + if (spa_streq(name, "default")) { + return get_default(port, hint, lower, upper); + } + if (spa_streq(name, "min")) { + return lower; + } + if (spa_streq(name, "max")) { + return upper; + } + return 0.0f; +} + +static const struct fc_descriptor *ladspa_make_desc(struct fc_plugin *plugin, const char *name) +{ + struct plugin_data *pd = plugin->user; + struct fc_descriptor *desc; + struct desc_data *dd; + const LADSPA_Descriptor *d; + uint32_t i; + + d = find_desc(pd->desc_func, name); + if (d == NULL) + return NULL; + + desc = fc_descriptor_new(plugin, sizeof(*dd)); + dd = desc->user; + dd->d = d; + + desc->instantiate = ladspa_instantiate; + desc->cleanup = d->cleanup; + desc->connect_port = d->connect_port; + desc->activate = d->activate; + desc->deactivate = d->deactivate; + desc->run = d->run; + + desc->free = ladspa_free; + desc->get_prop = ladspa_get_prop; + + desc->name = d->Label; + desc->flags = d->Properties; + + desc->n_ports = d->PortCount; + desc->ports = calloc(desc->n_ports, sizeof(struct fc_port)); + + for (i = 0; i < desc->n_ports; i++) { + desc->ports[i].index = i; + desc->ports[i].name = d->PortNames[i]; + desc->ports[i].flags = d->PortDescriptors[i]; + desc->ports[i].get_param = ladspa_port_get_param; + } + return desc; +} + +static void ladspa_unload(struct fc_plugin *plugin) +{ + struct plugin_data *pd = plugin->user; + if (pd->handle) + dlclose(pd->handle); +} + +static struct fc_plugin *ladspa_handle_load_by_path(const char *path) +{ + struct fc_plugin *plugin; + struct plugin_data *pd; + int res; + + plugin = fc_plugin_new(sizeof(*pd)); + if (!plugin) + return NULL; + + pd = plugin->user; + + pd->handle = dlopen(path, RTLD_NOW); + if (!pd->handle) { + pw_log_debug("failed to open '%s': %s", path, dlerror()); + res = -ENOENT; + goto exit; + } + + pw_log_info("successfully opened '%s'", path); + + pd->desc_func = (LADSPA_Descriptor_Function) dlsym(pd->handle, "ladspa_descriptor"); + if (!pd->desc_func) { + pw_log_warn("cannot find descriptor function in '%s': %s", path, dlerror()); + res = -ENOSYS; + goto exit; + } + plugin->make_desc = ladspa_make_desc; + plugin->unload = ladspa_unload; + + return plugin; + +exit: + if (pd->handle) + dlclose(pd->handle); + errno = -res; + return NULL; +} + +struct fc_plugin *load_ladspa_plugin(const char *plugin, const char *config) +{ + struct fc_plugin *pl = NULL; + + if (plugin[0] != '/') { + const char *search_dirs, *p; + char path[PATH_MAX]; + size_t len; + + search_dirs = getenv("LADSPA_PATH"); + if (!search_dirs) + search_dirs = "/usr/lib64/ladspa"; + + /* + * set the errno for the case when `ladspa_handle_load_by_path()` + * is never called, which can only happen if the supplied + * LADSPA_PATH contains too long paths + */ + errno = ENAMETOOLONG; + + while ((p = pw_split_walk(NULL, ":", &len, &search_dirs))) { + int pathlen; + + if (len >= sizeof(path)) + continue; + + pathlen = snprintf(path, sizeof(path), "%.*s/%s.so", (int) len, p, plugin); + if (pathlen < 0 || (size_t) pathlen >= sizeof(path)) + continue; + + pl = ladspa_handle_load_by_path(path); + if (pl != NULL) + break; + } + } + else { + pl = ladspa_handle_load_by_path(plugin); + } + + if (pl == NULL) + pw_log_error("failed to load plugin '%s': %s", plugin, strerror(errno)); + + return pl; +} diff --git a/src/modules/module-filter-chain/plugin.h b/src/modules/module-filter-chain/plugin.h new file mode 100644 index 000000000..992cfb82a --- /dev/null +++ b/src/modules/module-filter-chain/plugin.h @@ -0,0 +1,112 @@ +/* PipeWire + * + * Copyright © 2021 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +struct fc_plugin { + void *user; + + const struct fc_descriptor *(*make_desc)(struct fc_plugin *plugin, const char *name); + void (*unload) (struct fc_plugin *plugin); +}; + +struct fc_port { + uint32_t index; + struct fc_descriptor *desc; + const char *name; + uint64_t flags; + + float (*get_param) (struct fc_port *port, const char *name); +}; + +struct fc_descriptor { + struct fc_plugin *plugin; + void *user; + + const char *name; + uint64_t flags; + + void (*free) (struct fc_descriptor *desc); + + const char *(*get_prop) (struct fc_descriptor *desc, const char *name); + + uint32_t n_ports; + struct fc_port *ports; + + void *(*instantiate) (const struct fc_descriptor *desc, + unsigned long SampleRate, const char *config); + + void (*cleanup) (void *instance); + + void (*connect_port) (void *instance, unsigned long port, float *data); + + void (*activate) (void *instance); + void (*deactivate) (void *instance); + + void (*run) (void *instance, unsigned long SampleCount); +}; + +static inline struct fc_plugin *fc_plugin_new(size_t extra) +{ + struct fc_plugin *plugin; + + plugin = calloc(1, sizeof(*plugin) + extra); + plugin->user = SPA_PTROFF(plugin, sizeof(*plugin), void); + return plugin; +} + +static inline void fc_plugin_free(struct fc_plugin *plugin) +{ + if (plugin->unload) + plugin->unload(plugin); + free(plugin); +} + +static inline struct fc_descriptor *fc_descriptor_new(struct fc_plugin *plugin, size_t extra) +{ + struct fc_descriptor *desc; + + desc = calloc(1, sizeof(*desc) + extra); + desc->plugin = plugin; + desc->user = SPA_PTROFF(desc, sizeof(*desc), void); + return desc; +} + +static inline void fc_descriptor_free(struct fc_descriptor *desc) +{ + if (desc->free) + desc->free(desc); + free(desc); +} + +struct fc_plugin *load_ladspa_plugin(const char *path, const char *config); +struct fc_plugin *load_builtin_plugin(const char *path, const char *config);