mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
filter-chain: make plugin wrapper
So that we can implement the internal plugins with a more expressive API than LADSPA.
This commit is contained in:
parent
e46799d43f
commit
85dd03c2d8
7 changed files with 734 additions and 424 deletions
|
|
@ -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' ],
|
||||
|
|
|
|||
|
|
@ -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' ],
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "module-filter-chain/ladspa.h"
|
||||
#include "module-filter-chain/plugin.h"
|
||||
|
||||
#include <spa/utils/result.h>
|
||||
#include <spa/utils/string.h>
|
||||
|
|
@ -100,26 +100,30 @@ static const struct spa_dict_item module_props[] = {
|
|||
|
||||
#include <pipewire/pipewire.h>
|
||||
|
||||
#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);
|
||||
|
|
|
|||
|
|
@ -24,12 +24,15 @@
|
|||
|
||||
#include <sndfile.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
291
src/modules/module-filter-chain/ladspa_plugin.c
Normal file
291
src/modules/module-filter-chain/ladspa_plugin.c
Normal file
|
|
@ -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 <dlfcn.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/utils/list.h>
|
||||
#include <spa/utils/string.h>
|
||||
|
||||
#include <pipewire/log.h>
|
||||
#include <pipewire/utils.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
112
src/modules/module-filter-chain/plugin.h
Normal file
112
src/modules/module-filter-chain/plugin.h
Normal file
|
|
@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/utils/list.h>
|
||||
#include <spa/utils/string.h>
|
||||
|
||||
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);
|
||||
Loading…
Add table
Add a link
Reference in a new issue