filter-chain: parse config options

Remove LADSPA dependencies, only use it in ladspa_plugin.c
Parse convolver config, like filename
This commit is contained in:
Wim Taymans 2021-08-10 23:50:24 +02:00
parent a2aaa71392
commit 44c6ec146e
7 changed files with 147 additions and 60 deletions

View file

@ -67,6 +67,8 @@ static inline void spa_json_enter(struct spa_json * iter, struct spa_json * sub)
*sub = SPA_JSON_ENTER(iter);
}
#define SPA_JSON_SAVE(iter) (struct spa_json) { (iter)->cur, (iter)->end, }
/** Get the next token. \a value points to the token and the return value
* is the length. */
static inline int spa_json_next(struct spa_json * iter, const char **value)

View file

@ -36,6 +36,10 @@ context.modules = [
type = builtin
name = convolver
label = convolver
config = {
filename = "src/modules/module-filter-chain/street2-L.wav"
blocksize = 512
}
}
]
}

View file

@ -69,6 +69,9 @@ static const struct spa_dict_item module_props[] = {
" name = <name> "
" plugin = <plugin> "
" label = <label> "
" config = { "
" <configkey> = <value> ... "
" } "
" control = { "
" <controlname> = <value> ... "
" } "
@ -100,8 +103,6 @@ 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
@ -158,6 +159,7 @@ struct node {
struct descriptor *desc;
char name[256];
char *config;
struct port input_port[MAX_PORTS];
struct port output_port[MAX_PORTS];
@ -352,16 +354,16 @@ static struct port *find_port(struct node *node, const char *name, int descripto
if (node == NULL)
return NULL;
if (LADSPA_IS_PORT_INPUT(descriptor)) {
if (LADSPA_IS_PORT_CONTROL(descriptor)) {
if (FC_IS_PORT_INPUT(descriptor)) {
if (FC_IS_PORT_CONTROL(descriptor)) {
ports = node->control_port;
n_ports = node->desc->n_control;
} else {
ports = node->input_port;
n_ports = node->desc->n_input;
}
} else if (LADSPA_IS_PORT_OUTPUT(descriptor)) {
if (LADSPA_IS_PORT_CONTROL(descriptor)) {
} else if (FC_IS_PORT_OUTPUT(descriptor)) {
if (FC_IS_PORT_CONTROL(descriptor)) {
ports = node->notify_port;
n_ports = node->desc->n_notify;
} else {
@ -382,14 +384,26 @@ 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 impl *impl = graph->impl;
struct spa_pod_frame f[2];
struct port *port = graph->control_port[idx];
struct node *node = port->node;
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];
if (p->hint & FC_HINT_SAMPLE_RATE) {
def = p->def * impl->rate;
min = p->min * impl->rate;
max = p->max * impl->rate;
} else {
def = p->def;
min = p->min;
max = p->max;
}
if (node->name[0] != '\0')
snprintf(name, sizeof(name), "%s:%s", node->name, p->name);
else
@ -402,13 +416,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 (p->min == p->max) {
spa_pod_builder_float(b, p->def);
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, p->def);
spa_pod_builder_float(b, p->min);
spa_pod_builder_float(b, p->max);
spa_pod_builder_float(b, def);
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);
@ -452,7 +466,7 @@ static int set_control_value(struct node *node, const char *name, float *value)
struct port *port;
float old;
port = find_port(node, name, LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL);
port = find_port(node, name, FC_PORT_INPUT | FC_PORT_CONTROL);
if (port == NULL)
return 0;
@ -816,24 +830,24 @@ static struct descriptor *descriptor_load(struct impl *impl, const char *type,
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)) {
if (FC_IS_PORT_AUDIO(fp->flags)) {
if (FC_IS_PORT_INPUT(fp->flags)) {
pw_log_info("using port %lu ('%s') as input %d", p,
fp->name, desc->n_input);
desc->input[desc->n_input++] = p;
}
else if (LADSPA_IS_PORT_OUTPUT(fp->flags)) {
else if (FC_IS_PORT_OUTPUT(fp->flags)) {
pw_log_info("using port %lu ('%s') as output %d", p,
fp->name, desc->n_output);
desc->output[desc->n_output++] = p;
}
} else if (LADSPA_IS_PORT_CONTROL(fp->flags)) {
if (LADSPA_IS_PORT_INPUT(fp->flags)) {
} else if (FC_IS_PORT_CONTROL(fp->flags)) {
if (FC_IS_PORT_INPUT(fp->flags)) {
pw_log_info("using port %lu ('%s') as control %d", p,
fp->name, desc->n_control);
desc->control[desc->n_control++] = p;
}
else if (LADSPA_IS_PORT_OUTPUT(fp->flags)) {
else if (FC_IS_PORT_OUTPUT(fp->flags)) {
pw_log_info("using port %lu ('%s') as notify %d", p,
fp->name, desc->n_notify);
desc->notify[desc->n_notify++] = p;
@ -863,6 +877,31 @@ exit:
return NULL;
}
/**
* {
* ...
* }
*/
static int parse_config(struct node *node, struct spa_json *config)
{
const char *val;
int len;
if ((len = spa_json_next(config, &val)) <= 0)
return len;
if (spa_json_is_null(val, len))
return 0;
if (spa_json_is_container(val, len))
len = spa_json_container_len(config, val, len);
if ((node->config = malloc(len+1)) != NULL)
spa_json_parse_string(val, len, node->config);
return 0;
}
/**
* {
* "Reverb tail" = 2.0
@ -914,12 +953,12 @@ static int parse_link(struct graph *graph, struct spa_json *json)
break;
}
def_node = spa_list_first(&graph->node_list, struct node, link);
if ((out_port = find_port(def_node, output, LADSPA_PORT_OUTPUT)) == NULL) {
if ((out_port = find_port(def_node, output, FC_PORT_OUTPUT)) == NULL) {
pw_log_error("unknown output port %s", output);
return -ENOENT;
}
def_node = spa_list_last(&graph->node_list, struct node, link);
if ((in_port = find_port(def_node, input, LADSPA_PORT_INPUT)) == NULL) {
if ((in_port = find_port(def_node, input, FC_PORT_INPUT)) == NULL) {
pw_log_error("unknown input port %s", input);
return -ENOENT;
}
@ -968,13 +1007,16 @@ static void link_free(struct link *link)
* name = rev
* plugin = g2reverb
* label = G2reverb
* control = [
* config = {
* ...
* ]
* }
* control = {
* ...
* }
*/
static int load_node(struct graph *graph, struct spa_json *json)
{
struct spa_json control;
struct spa_json control, config;
struct descriptor *desc;
struct node *node;
const char *val;
@ -984,6 +1026,7 @@ static int load_node(struct graph *graph, struct spa_json *json)
char plugin[256] = "";
char label[256] = "";
bool have_control = false;
bool have_config = false;
uint32_t i;
while (spa_json_get_string(json, key, sizeof(key)) > 0) {
@ -1013,6 +1056,9 @@ static int load_node(struct graph *graph, struct spa_json *json)
return -EINVAL;
}
have_control = true;
} else if (spa_streq("config", key)) {
config = SPA_JSON_SAVE(json);
have_config = true;
} else if (spa_json_next(json, &val) < 0)
break;
}
@ -1068,6 +1114,8 @@ static int load_node(struct graph *graph, struct spa_json *json)
port->p = desc->notify[i];
spa_list_init(&port->link_list);
}
if (have_config)
parse_config(node, &config);
if (have_control)
parse_control(node, &control);
@ -1219,7 +1267,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)) == NULL) {
if ((node->hndl[i] = d->instantiate(d, impl->rate, i, node->config)) == NULL) {
pw_log_error("cannot create plugin instance");
res = -ENOMEM;
goto error;
@ -1244,7 +1292,6 @@ static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_
}
if (d->activate)
d->activate(node->hndl[i]);
}
/* collect all control ports on the graph */
for (j = 0; j < desc->n_control; j++) {
@ -1272,7 +1319,7 @@ static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_
if (spa_streq(v, "null")) {
gp->desc = NULL;
pw_log_info("ignore input port %d", graph->n_input);
} else if ((port = find_port(first, v, LADSPA_PORT_INPUT)) == NULL) {
} else if ((port = find_port(first, v, FC_PORT_INPUT)) == NULL) {
res = -ENOENT;
pw_log_error("input port %s not found", v);
goto error;
@ -1320,7 +1367,7 @@ static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_
if (spa_streq(v, "null")) {
gp->desc = NULL;
pw_log_info("silence output port %d", graph->n_output);
} else if ((port = find_port(last, v, LADSPA_PORT_OUTPUT)) == NULL) {
} else if ((port = find_port(last, v, FC_PORT_OUTPUT)) == NULL) {
res = -ENOENT;
pw_log_error("output port %s not found", v);
goto error;

View file

@ -24,8 +24,9 @@
#include <sndfile.h>
#include <spa/utils/json.h>
#include "plugin.h"
#include "ladspa.h"
#include "biquad.h"
#include "convolver.h"
@ -41,7 +42,7 @@ struct builtin {
};
static void *builtin_instantiate(const struct fc_descriptor * Descriptor,
unsigned long SampleRate, const char *config)
unsigned long SampleRate, int index, const char *config)
{
struct builtin *impl;
@ -78,11 +79,11 @@ static void copy_run(void * Instance, unsigned long SampleCount)
static struct fc_port copy_ports[] = {
{ .index = 0,
.name = "Out",
.flags = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
.flags = FC_PORT_OUTPUT | FC_PORT_AUDIO,
},
{ .index = 1,
.name = "In",
.flags = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
.flags = FC_PORT_INPUT | FC_PORT_AUDIO,
}
};
@ -121,24 +122,24 @@ static void mixer_run(void * Instance, unsigned long SampleCount)
static struct fc_port mixer_ports[] = {
{ .index = 0,
.name = "Out",
.flags = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
.flags = FC_PORT_OUTPUT | FC_PORT_AUDIO,
},
{ .index = 1,
.name = "In 1",
.flags = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
.flags = FC_PORT_INPUT | FC_PORT_AUDIO,
},
{ .index = 2,
.name = "In 2",
.flags = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
.flags = FC_PORT_INPUT | FC_PORT_AUDIO,
},
{ .index = 3,
.name = "Gain 1",
.flags = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
.def = 1.0f, .min = 0.0f, .max = 10.0f
},
{ .index = 4,
.name = "Gain 2",
.flags = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
.def = 1.0f, .min = 0.0f, .max = 10.0f
},
};
@ -158,26 +159,26 @@ static const struct fc_descriptor mixer_desc = {
static struct fc_port bq_ports[] = {
{ .index = 0,
.name = "Out",
.flags = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
.flags = FC_PORT_OUTPUT | FC_PORT_AUDIO,
},
{ .index = 1,
.name = "In",
.flags = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
.flags = FC_PORT_INPUT | FC_PORT_AUDIO,
},
{ .index = 2,
.name = "Freq",
.flags = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
.hint = LADSPA_HINT_SAMPLE_RATE,
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
.hint = FC_HINT_SAMPLE_RATE,
.def = 0.0f, .min = 0.0f, .max = 1.0f,
},
{ .index = 3,
.name = "Q",
.flags = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
.def = 0.0f, .min = 0.0f, .max = 10.0f,
},
{ .index = 4,
.name = "Gain",
.flags = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
.def = 0.0f, .min = -120.0f, .max = 5.0f,
},
};
@ -380,22 +381,47 @@ static const struct fc_descriptor bq_allpass_desc = {
/** convolve */
struct convolver_impl {
unsigned long rate;
LADSPA_Data *port[64];
float *port[64];
struct convolver *conv;
};
static void * convolver_instantiate(const struct fc_descriptor * Descriptor,
unsigned long SampleRate, const char *config)
unsigned long SampleRate, int index, const char *config)
{
struct convolver_impl *impl;
SF_INFO info;
SNDFILE *f;
float *samples;
const char *filename;
int i, offset;
struct spa_json it[2];
const char *val;
char key[256];
char filename[PATH_MAX] = "";
int blocksize = 256;
if (config == NULL)
return NULL;
spa_json_init(&it[0], config, strlen(config));
if (spa_json_enter_object(&it[0], &it[1]) <= 0)
return NULL;
while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) {
if (spa_streq(key, "filename")) {
if (spa_json_get_string(&it[1], filename, sizeof(filename)) <= 0)
return NULL;
}
else if (spa_streq(key, "blocksize")) {
if (spa_json_get_int(&it[1], &blocksize) <= 0)
return NULL;
}
else if (spa_json_next(&it[1], &val) < 0)
break;
}
if (!filename[0])
return NULL;
filename = "src/modules/module-filter-chain/convolve.wav";
filename = "src/modules/module-filter-chain/street2-L.wav";
spa_zero(info);
f = sf_open(filename, SFM_READ, &info) ;
if (f == NULL) {
@ -415,7 +441,12 @@ static void * convolver_instantiate(const struct fc_descriptor * Descriptor,
sf_read_float(f, samples, info.frames);
impl->conv = convolver_new(256, samples, info.frames);
offset = index % info.channels;
for (i = 0; i < info.frames; i++)
samples[i] = samples[info.channels * i + offset];
impl->conv = convolver_new(blocksize, samples, info.frames);
free(samples);
sf_close(f);
@ -424,7 +455,7 @@ static void * convolver_instantiate(const struct fc_descriptor * Descriptor,
}
static void convolver_connect_port(void * Instance, unsigned long Port,
LADSPA_Data * DataLocation)
float * DataLocation)
{
struct convolver_impl *impl = Instance;
impl->port[Port] = DataLocation;
@ -439,11 +470,11 @@ static void convolver_cleanup(void * Instance)
static struct fc_port convolve_ports[] = {
{ .index = 0,
.name = "Out",
.flags = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
.flags = FC_PORT_OUTPUT | FC_PORT_AUDIO,
},
{ .index = 1,
.name = "In",
.flags = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
.flags = FC_PORT_INPUT | FC_PORT_AUDIO,
},
};

View file

@ -81,10 +81,6 @@ struct convolver *convolver_new(int block, const float *ir, int irlen)
conv->segCount = (irlen + conv->blockSize-1) / conv->blockSize;
conv->fftComplexSize = (conv->segSize / 2) + 1;
fprintf(stderr, "blockSize:%d segSize:%d segCount:%d fftComplexSize:%d\n",
conv->blockSize, conv->segSize, conv->segCount,
conv->fftComplexSize);
conv->fft = kiss_fftr_f32_alloc(conv->segSize, 0, NULL, NULL);
if (conv->fft == NULL)
return NULL;
@ -156,9 +152,6 @@ int convolver_run(struct convolver *conv, const float *input, float *output, int
const int processing = SPA_MIN(len - processed, conv->blockSize - conv->inputBufferFill);
const int inputBufferPos = conv->inputBufferFill;
fprintf(stderr, "len:%d processing:%d fill:%d processed:%d\n",
len, processing, inputBufferPos, processed);
memcpy(conv->inputBuffer + inputBufferPos, input + processed, processing * sizeof(float));
memcpy(conv->fft_buffer, conv->inputBuffer, conv->blockSize * sizeof(float));

View file

@ -48,7 +48,7 @@ struct descriptor {
};
static void *ladspa_instantiate(const struct fc_descriptor *desc,
unsigned long SampleRate, const char *config)
unsigned long SampleRate, int index, const char *config)
{
struct descriptor *d = (struct descriptor *)desc;
return d->d->instantiate(d->d, SampleRate);

View file

@ -40,14 +40,24 @@ struct fc_plugin {
struct fc_port {
uint32_t index;
const char *name;
#define FC_PORT_INPUT (1ULL << 0)
#define FC_PORT_OUTPUT (1ULL << 1)
#define FC_PORT_CONTROL (1ULL << 2)
#define FC_PORT_AUDIO (1ULL << 3)
uint64_t flags;
#define FC_HINT_SAMPLE_RATE (1ULL << 3)
uint64_t hint;
float def;
float min;
float max;
};
#define FC_IS_PORT_INPUT(x) ((x) & FC_PORT_INPUT)
#define FC_IS_PORT_OUTPUT(x) ((x) & FC_PORT_OUTPUT)
#define FC_IS_PORT_CONTROL(x) ((x) & FC_PORT_CONTROL)
#define FC_IS_PORT_AUDIO(x) ((x) & FC_PORT_AUDIO)
struct fc_descriptor {
const char *name;
uint64_t flags;
@ -58,7 +68,7 @@ struct fc_descriptor {
struct fc_port *ports;
void *(*instantiate) (const struct fc_descriptor *desc,
unsigned long SampleRate, const char *config);
unsigned long SampleRate, int index, const char *config);
void (*cleanup) (void *instance);