modules: more ladspa improvements

Run multiple instances to fill requested channels.
Improve media name.
This commit is contained in:
Wim Taymans 2021-05-01 11:40:11 +02:00
parent 3272344df4
commit a36e5b2c0d

View file

@ -120,6 +120,7 @@ struct impl {
unsigned long control[MAX_PORTS]; unsigned long control[MAX_PORTS];
unsigned long notify[MAX_PORTS]; unsigned long notify[MAX_PORTS];
const LADSPA_Descriptor *desc; const LADSPA_Descriptor *desc;
uint32_t n_hndl;
LADSPA_Handle hndl[MAX_PORTS]; LADSPA_Handle hndl[MAX_PORTS];
LADSPA_Data control_data[MAX_PORTS]; LADSPA_Data control_data[MAX_PORTS];
LADSPA_Data notify_data[MAX_PORTS]; LADSPA_Data notify_data[MAX_PORTS];
@ -149,8 +150,7 @@ static void capture_process(void *d)
{ {
struct impl *impl = d; struct impl *impl = d;
struct pw_buffer *in, *out; struct pw_buffer *in, *out;
uint32_t i; uint32_t i, size = 0, n_hndl = impl->n_hndl;
uint32_t size = 0;
int32_t stride = 0; int32_t stride = 0;
const LADSPA_Descriptor *desc = impl->desc; const LADSPA_Descriptor *desc = impl->desc;
@ -165,20 +165,23 @@ static void capture_process(void *d)
for (i = 0; i < in->buffer->n_datas; i++) { for (i = 0; i < in->buffer->n_datas; i++) {
struct spa_data *ds = &in->buffer->datas[i]; struct spa_data *ds = &in->buffer->datas[i];
desc->connect_port(impl->hndl[0], impl->input[i], desc->connect_port(impl->hndl[i % n_hndl],
impl->input[i % impl->n_input],
SPA_MEMBER(ds->data, ds->chunk->offset, void)); SPA_MEMBER(ds->data, ds->chunk->offset, void));
size = SPA_MAX(size, ds->chunk->size); size = SPA_MAX(size, ds->chunk->size);
stride = SPA_MAX(stride, ds->chunk->stride); stride = SPA_MAX(stride, ds->chunk->stride);
} }
for (i = 0; i < out->buffer->n_datas; i++) { for (i = 0; i < out->buffer->n_datas; i++) {
struct spa_data *dd = &out->buffer->datas[i]; struct spa_data *dd = &out->buffer->datas[i];
desc->connect_port(impl->hndl[0], impl->output[i], dd->data); desc->connect_port(impl->hndl[i % n_hndl],
impl->output[i % impl->n_output], dd->data);
dd->chunk->offset = 0; dd->chunk->offset = 0;
dd->chunk->size = size; dd->chunk->size = size;
dd->chunk->stride = stride; dd->chunk->stride = stride;
} }
desc->run(impl->hndl[0], size / sizeof(float)); for (i = 0; i < n_hndl; i++)
desc->run(impl->hndl[i], size / sizeof(float));
done: done:
if (in != NULL) if (in != NULL)
@ -260,7 +263,7 @@ static int setup_streams(struct impl *impl)
struct spa_pod_builder b; struct spa_pod_builder b;
impl->capture = pw_stream_new(impl->core, impl->capture = pw_stream_new(impl->core,
"loopback capture", impl->capture_props); "ladspa capture", impl->capture_props);
impl->capture_props = NULL; impl->capture_props = NULL;
if (impl->capture == NULL) if (impl->capture == NULL)
return -errno; return -errno;
@ -270,7 +273,7 @@ static int setup_streams(struct impl *impl)
&in_stream_events, impl); &in_stream_events, impl);
impl->playback = pw_stream_new(impl->core, impl->playback = pw_stream_new(impl->core,
"loopback playback", impl->playback_props); "ladspa playback", impl->playback_props);
impl->playback_props = NULL; impl->playback_props = NULL;
if (impl->playback == NULL) if (impl->playback == NULL)
return -errno; return -errno;
@ -388,21 +391,21 @@ static const LADSPA_Descriptor *find_descriptor(LADSPA_Descriptor_Function desc_
static int load_ladspa(struct impl *impl, struct pw_properties *props) static int load_ladspa(struct impl *impl, struct pw_properties *props)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
const char *e, *p, *label; const char *e, *plugin, *label;
LADSPA_Descriptor_Function desc_func; LADSPA_Descriptor_Function desc_func;
const LADSPA_Descriptor *d; const LADSPA_Descriptor *d;
uint32_t i, j; uint32_t i, j, p;
int res; int res;
if ((e = getenv("LADSPA_PATH")) == NULL) if ((e = getenv("LADSPA_PATH")) == NULL)
e = "/usr/lib64/ladspa"; e = "/usr/lib64/ladspa";
if ((p = pw_properties_get(props, "ladspa.plugin")) == NULL) if ((plugin = pw_properties_get(props, "ladspa.plugin")) == NULL)
return -EINVAL; return -EINVAL;
if ((label = pw_properties_get(props, "ladspa.label")) == NULL) if ((label = pw_properties_get(props, "ladspa.label")) == NULL)
return -EINVAL; return -EINVAL;
snprintf(path, sizeof(path), "%s/%s.so", e, p); snprintf(path, sizeof(path), "%s/%s.so", e, plugin);
impl->handle = dlopen(path, RTLD_NOW); impl->handle = dlopen(path, RTLD_NOW);
if (impl->handle == NULL) { if (impl->handle == NULL) {
@ -425,25 +428,24 @@ static int load_ladspa(struct impl *impl, struct pw_properties *props)
res = -ENOENT; res = -ENOENT;
goto exit; goto exit;
} }
pw_properties_setf(props, "ladspa.unique-id", "%lu", d->UniqueID);
pw_properties_setf(props, "ladspa.name", "%s", d->Name);
pw_properties_setf(props, "ladspa.maker", "%s", d->Maker);
pw_properties_setf(props, "ladspa.copyright", "%s", d->Copyright);
impl->desc = d; impl->desc = d;
for (i = 0; i < d->PortCount; i++) { pw_properties_setf(props, "ladspa.unique-id", "%lu", impl->desc->UniqueID);
if (LADSPA_IS_PORT_AUDIO(d->PortDescriptors[i])) { pw_properties_setf(props, "ladspa.name", "%s", impl->desc->Name);
if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[i])) pw_properties_setf(props, "ladspa.maker", "%s", impl->desc->Maker);
impl->input[impl->n_input++] = i; pw_properties_setf(props, "ladspa.copyright", "%s", impl->desc->Copyright);
else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[i]))
impl->output[impl->n_output++] = i; for (p = 0; p < d->PortCount; p++) {
} else if (LADSPA_IS_PORT_CONTROL(d->PortDescriptors[i])) { if (LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) {
if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[i])) if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]))
impl->control[impl->n_control++] = i; impl->input[impl->n_input++] = p;
else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[i])) else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p]))
impl->notify[impl->n_notify++] = i; impl->output[impl->n_output++] = p;
} else if (LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p])) {
if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]))
impl->control[impl->n_control++] = p;
else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p]))
impl->notify[impl->n_notify++] = p;
} }
} }
if (impl->n_input == 0 || impl->n_output == 0) { if (impl->n_input == 0 || impl->n_output == 0) {
@ -451,30 +453,43 @@ static int load_ladspa(struct impl *impl, struct pw_properties *props)
res = -ENOTSUP; res = -ENOTSUP;
goto exit; goto exit;
} }
for (j = 0; j < impl->n_control; j++) {
p = impl->control[j];
impl->control_data[j] = get_default(impl, p);
pw_log_info("control (%s) %d set to %f", d->PortNames[p], p, impl->control_data[j]);
}
if (impl->capture_info.channels == 0)
impl->capture_info.channels = impl->n_input;
if (impl->playback_info.channels == 0)
impl->playback_info.channels = impl->n_output;
impl->n_hndl = impl->capture_info.channels / impl->n_input;
if (impl->n_hndl != impl->playback_info.channels / impl->n_output) {
pw_log_error("invalid channels");
res = -EINVAL;
goto exit;
}
pw_log_info("using %d instances", impl->n_hndl);
for (i = 0; i < impl->n_hndl;i++) {
if ((impl->hndl[0] = d->instantiate(d, impl->rate)) == NULL) { if ((impl->hndl[i] = d->instantiate(d, impl->rate)) == NULL) {
pw_log_error("cannot create plugin instance"); pw_log_error("cannot create plugin instance");
res = -ENOMEM; res = -ENOMEM;
goto exit; goto exit;
} }
for (i = 0; i < impl->n_control; i++) {
j = impl->control[i];
impl->control_data[i] = get_default(impl, j);
pw_log_info("control (%s) %d set to %f", d->PortNames[j], i, impl->control_data[i]);
d->connect_port(impl->hndl[0], j, &impl->control_data[i]);
}
for (i = 0; i < impl->n_notify; i++) {
j = impl->notify[i];
d->connect_port(impl->hndl[0], j, &impl->notify_data[i]);
}
for (j = 0; j < impl->n_control; j++) {
p = impl->control[j];
d->connect_port(impl->hndl[i], p, &impl->control_data[j]);
}
for (j = 0; j < impl->n_notify; j++) {
p = impl->notify[j];
d->connect_port(impl->hndl[i], p, &impl->notify_data[j]);
}
if (d->activate) if (d->activate)
d->activate(impl->hndl[0]); d->activate(impl->hndl[i]);
}
return 0; return 0;
exit: exit:
@ -658,6 +673,17 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
pw_log_error("can't load ladspa: %s", spa_strerror(res)); pw_log_error("can't load ladspa: %s", spa_strerror(res));
goto error; goto error;
} }
copy_props(impl, props, "ladspa.unique-id");
copy_props(impl, props, "ladspa.name");
copy_props(impl, props, "ladspa.maker");
copy_props(impl, props, "ladspa.copyright");
if (pw_properties_get(impl->capture_props, PW_KEY_MEDIA_NAME) == NULL)
pw_properties_setf(impl->capture_props, PW_KEY_MEDIA_NAME, "%s input",
impl->desc->Name);
if (pw_properties_get(impl->playback_props, PW_KEY_MEDIA_NAME) == NULL)
pw_properties_setf(impl->playback_props, PW_KEY_MEDIA_NAME, "%s output",
impl->desc->Name);
impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core); impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core);
if (impl->core == NULL) { if (impl->core == NULL) {