From 02edfba21a505bd52c58b4d7deb7b272489ef904 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 11 Nov 2024 16:36:09 +0100 Subject: [PATCH] filter-chain: don't let plugins depend on pipewire, just spa --- .../module-filter-chain/builtin_plugin.c | 208 ++++++++++-------- .../module-filter-chain/ladspa_plugin.c | 68 ++++-- src/modules/module-filter-chain/lv2_plugin.c | 58 ++--- src/modules/module-filter-chain/sofa_plugin.c | 45 ++-- 4 files changed, 221 insertions(+), 158 deletions(-) diff --git a/src/modules/module-filter-chain/builtin_plugin.c b/src/modules/module-filter-chain/builtin_plugin.c index d42cd4039..d6a5192b7 100644 --- a/src/modules/module-filter-chain/builtin_plugin.c +++ b/src/modules/module-filter-chain/builtin_plugin.c @@ -15,10 +15,9 @@ #include #include #include +#include #include -#include - #include "plugin.h" #include "biquad.h" @@ -30,11 +29,16 @@ struct plugin { struct fc_plugin plugin; - struct dsp_ops *dsp_ops; + struct dsp_ops *dsp; + struct spa_log *log; }; struct builtin { struct plugin *plugin; + + struct dsp_ops *dsp; + struct spa_log *log; + unsigned long rate; float *port[64]; @@ -80,7 +84,7 @@ static void copy_run(void * Instance, unsigned long SampleCount) { struct builtin *impl = Instance; float *in = impl->port[1], *out = impl->port[0]; - dsp_ops_copy(impl->plugin->dsp_ops, out, in, SampleCount); + dsp_ops_copy(impl->dsp, out, in, SampleCount); } static struct fc_port copy_ports[] = { @@ -129,7 +133,7 @@ static void mixer_run(void * Instance, unsigned long SampleCount) src[n_src] = in; gains[n_src++] = gain; } - dsp_ops_mix_gain(impl->plugin->dsp_ops, out, src, gains, n_src, SampleCount); + dsp_ops_mix_gain(impl->dsp, out, src, gains, n_src, SampleCount); } static struct fc_port mixer_ports[] = { @@ -320,6 +324,8 @@ static void *bq_instantiate(const struct fc_plugin *plugin, const struct fc_desc return NULL; impl->plugin = (struct plugin *) plugin; + impl->log = impl->plugin->log; + impl->dsp = impl->plugin->dsp; impl->rate = SampleRate; impl->b0 = impl->a0 = 1.0f; impl->type = bq_type_from_name(Descriptor->name); @@ -327,19 +333,19 @@ static void *bq_instantiate(const struct fc_plugin *plugin, const struct fc_desc return impl; if (config == NULL) { - pw_log_error("biquads:bq_raw requires a config section"); + spa_log_error(impl->log, "biquads:bq_raw requires a config section"); goto error; } if (spa_json_begin_object(&it[0], config, strlen(config)) <= 0) { - pw_log_error("biquads:config section must be an object"); + spa_log_error(impl->log, "biquads:config section must be an object"); goto error; } while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "coefficients")) { if (!spa_json_is_array(val, len)) { - pw_log_error("biquads:coefficients require an array"); + spa_log_error(impl->log, "biquads:coefficients require an array"); goto error; } spa_json_enter(&it[0], &it[1]); @@ -351,48 +357,48 @@ static void *bq_instantiate(const struct fc_plugin *plugin, const struct fc_desc while ((len = spa_json_object_next(&it[2], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "rate")) { if (spa_json_parse_int(val, len, &rate) <= 0) { - pw_log_error("biquads:rate requires a number"); + spa_log_error(impl->log, "biquads:rate requires a number"); goto error; } } else if (spa_streq(key, "b0")) { if (spa_json_parse_float(val, len, &b0) <= 0) { - pw_log_error("biquads:b0 requires a float"); + spa_log_error(impl->log, "biquads:b0 requires a float"); goto error; } } else if (spa_streq(key, "b1")) { if (spa_json_parse_float(val, len, &b1) <= 0) { - pw_log_error("biquads:b1 requires a float"); + spa_log_error(impl->log, "biquads:b1 requires a float"); goto error; } } else if (spa_streq(key, "b2")) { if (spa_json_parse_float(val, len, &b2) <= 0) { - pw_log_error("biquads:b2 requires a float"); + spa_log_error(impl->log, "biquads:b2 requires a float"); goto error; } } else if (spa_streq(key, "a0")) { if (spa_json_parse_float(val, len, &a0) <= 0) { - pw_log_error("biquads:a0 requires a float"); + spa_log_error(impl->log, "biquads:a0 requires a float"); goto error; } } else if (spa_streq(key, "a1")) { if (spa_json_parse_float(val, len, &a1) <= 0) { - pw_log_error("biquads:a1 requires a float"); + spa_log_error(impl->log, "biquads:a1 requires a float"); goto error; } } else if (spa_streq(key, "a2")) { if (spa_json_parse_float(val, len, &a2) <= 0) { - pw_log_error("biquads:a0 requires a float"); + spa_log_error(impl->log, "biquads:a0 requires a float"); goto error; } } else { - pw_log_warn("biquads: ignoring coefficients key: '%s'", key); + spa_log_warn(impl->log, "biquads: ignoring coefficients key: '%s'", key); } } if (labs((long)rate - (long)SampleRate) < @@ -403,7 +409,7 @@ static void *bq_instantiate(const struct fc_plugin *plugin, const struct fc_desc } } else { - pw_log_warn("biquads: ignoring config key: '%s'", key); + spa_log_warn(impl->log, "biquads: ignoring config key: '%s'", key); } } @@ -532,7 +538,7 @@ static void bq_run(void *Instance, unsigned long samples) if (impl->freq != freq || impl->Q != Q || impl->gain != gain) bq_freq_update(impl, impl->type, freq, Q, gain); } - dsp_ops_biquad_run(impl->plugin->dsp_ops, bq, out, in, samples); + dsp_ops_biquad_run(impl->dsp, bq, out, in, samples); } /** bq_lowpass */ @@ -665,6 +671,9 @@ static const struct fc_descriptor bq_raw_desc = { /** convolve */ struct convolver_impl { struct plugin *plugin; + + struct spa_log *log; + struct dsp_ops *dsp; unsigned long rate; float *port[2]; @@ -707,7 +716,7 @@ static float *read_samples_from_sf(SNDFILE *f, SF_INFO info, float gain, int del } #endif -static float *read_closest(char **filenames, float gain, float delay_sec, int offset, +static float *read_closest(struct plugin *pl, char **filenames, float gain, float delay_sec, int offset, int length, int channel, long unsigned *rate, int *n_samples) { #ifdef HAVE_SNDFILE @@ -729,24 +738,24 @@ static float *read_closest(char **filenames, float gain, float delay_sec, int of if (labs((long)infos[i].samplerate - (long)*rate) < diff) { best = i; diff = labs((long)infos[i].samplerate - (long)*rate); - pw_log_debug("new closest match: %d", infos[i].samplerate); + spa_log_debug(pl->log, "new closest match: %d", infos[i].samplerate); } } if (fs[best] != NULL) { - pw_log_info("loading best rate:%u %s", infos[best].samplerate, filenames[best]); + spa_log_info(pl->log, "loading best rate:%u %s", infos[best].samplerate, filenames[best]); samples = read_samples_from_sf(fs[best], infos[best], gain, (int) (delay_sec * infos[best].samplerate), offset, length, channel, rate, n_samples); } else { char buf[PATH_MAX]; - pw_log_error("Can't open any sample file (CWD %s):", + spa_log_error(pl->log, "Can't open any sample file (CWD %s):", getcwd(buf, sizeof(buf))); for (i = 0; i < MAX_RATES && filenames[i] && filenames[i][0]; i++) { fs[i] = sf_open(filenames[i], SFM_READ, &infos[i]); if (fs[i] == NULL) - pw_log_error(" failed file %s: %s", filenames[i], sf_strerror(fs[i])); + spa_log_error(pl->log, " failed file %s: %s", filenames[i], sf_strerror(fs[i])); else - pw_log_warn(" unexpectedly opened file %s", filenames[i]); + spa_log_warn(pl->log, " unexpectedly opened file %s", filenames[i]); } } for (i = 0; i < MAX_RATES; i++) @@ -755,7 +764,7 @@ static float *read_closest(char **filenames, float gain, float delay_sec, int of return samples; #else - pw_log_error("compiled without sndfile support, can't load samples: " + spa_log_error(pl->log, "compiled without sndfile support, can't load samples: " "using dirac impulse"); float *samples = calloc(1, sizeof(float)); samples[0] = gain; @@ -764,7 +773,7 @@ static float *read_closest(char **filenames, float gain, float delay_sec, int of #endif } -static float *create_hilbert(const char *filename, float gain, int rate, float delay_sec, int offset, +static float *create_hilbert(struct plugin *pl, const char *filename, float gain, int rate, float delay_sec, int offset, int length, int *n_samples) { float *samples, v; @@ -795,7 +804,7 @@ static float *create_hilbert(const char *filename, float gain, int rate, float d return samples; } -static float *create_dirac(const char *filename, float gain, int rate, float delay_sec, int offset, +static float *create_dirac(struct plugin *pl, const char *filename, float gain, int rate, float delay_sec, int offset, int length, int *n_samples) { float *samples; @@ -814,7 +823,7 @@ static float *create_dirac(const char *filename, float gain, int rate, float del return samples; } -static float *resample_buffer(struct dsp_ops *dsp_ops, float *samples, int *n_samples, +static float *resample_buffer(struct plugin *pl, float *samples, int *n_samples, unsigned long in_rate, unsigned long out_rate, uint32_t quality) { #ifdef HAVE_SPA_PLUGINS @@ -828,10 +837,10 @@ static float *resample_buffer(struct dsp_ops *dsp_ops, float *samples, int *n_sa r.channels = 1; r.i_rate = in_rate; r.o_rate = out_rate; - r.cpu_flags = dsp_ops->cpu_flags; + r.cpu_flags = pl->dsp->cpu_flags; r.quality = quality; if ((res = resample_native_init(&r)) < 0) { - pw_log_error("resampling failed: %s", spa_strerror(res)); + spa_log_error(pl->log, "resampling failed: %s", spa_strerror(res)); errno = -res; return NULL; } @@ -846,11 +855,11 @@ static float *resample_buffer(struct dsp_ops *dsp_ops, float *samples, int *n_sa out_len = out_n_samples; out_buf = out_samples; - pw_log_info("Resampling filter: rate: %lu => %lu, n_samples: %u => %u, q:%u", + spa_log_info(pl->log, "Resampling filter: rate: %lu => %lu, n_samples: %u => %u, q:%u", in_rate, out_rate, in_len, out_len, quality); resample_process(&r, (void*)&in_buf, &in_len, (void*)&out_buf, &out_len); - pw_log_debug("resampled: %u -> %u samples", in_len, out_len); + spa_log_debug(pl->log, "resampled: %u -> %u samples", in_len, out_len); total_out += out_len; in_len = resample_delay(&r); @@ -861,9 +870,9 @@ static float *resample_buffer(struct dsp_ops *dsp_ops, float *samples, int *n_sa out_buf = out_samples + total_out; out_len = out_n_samples - total_out; - pw_log_debug("flushing resampler: %u in %u out", in_len, out_len); + spa_log_debug(pl->log, "flushing resampler: %u in %u out", in_len, out_len); resample_process(&r, (void*)&in_buf, &in_len, (void*)&out_buf, &out_len); - pw_log_debug("flushed: %u -> %u samples", in_len, out_len); + spa_log_debug(pl->log, "flushed: %u -> %u samples", in_len, out_len); total_out += out_len; free(in_buf); @@ -884,7 +893,7 @@ error: free(out_samples); return NULL; #else - pw_log_error("compiled without spa-plugins support, can't resample"); + spa_log_error(impl->log, "compiled without spa-plugins support, can't resample"); float *out_samples = calloc(*n_samples, sizeof(float)); memcpy(out_samples, samples, *n_samples * sizeof(float)); return out_samples; @@ -895,6 +904,7 @@ static void * convolver_instantiate(const struct fc_plugin *plugin, const struct unsigned long SampleRate, int index, const char *config) { struct convolver_impl *impl; + struct plugin *pl = (struct plugin*)plugin; float *samples; int offset = 0, length = 0, channel = index, n_samples = 0, len; uint32_t i = 0; @@ -909,31 +919,31 @@ static void * convolver_instantiate(const struct fc_plugin *plugin, const struct errno = EINVAL; if (config == NULL) { - pw_log_error("convolver: requires a config section"); + spa_log_error(pl->log, "convolver: requires a config section"); return NULL; } if (spa_json_begin_object(&it[0], config, strlen(config)) <= 0) { - pw_log_error("convolver:config must be an object"); + spa_log_error(pl->log, "convolver:config must be an object"); return NULL; } while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "blocksize")) { if (spa_json_parse_int(val, len, &blocksize) <= 0) { - pw_log_error("convolver:blocksize requires a number"); + spa_log_error(pl->log, "convolver:blocksize requires a number"); return NULL; } } else if (spa_streq(key, "tailsize")) { if (spa_json_parse_int(val, len, &tailsize) <= 0) { - pw_log_error("convolver:tailsize requires a number"); + spa_log_error(pl->log, "convolver:tailsize requires a number"); return NULL; } } else if (spa_streq(key, "gain")) { if (spa_json_parse_float(val, len, &gain) <= 0) { - pw_log_error("convolver:gain requires a number"); + spa_log_error(pl->log, "convolver:gain requires a number"); return NULL; } } @@ -942,7 +952,7 @@ static void * convolver_instantiate(const struct fc_plugin *plugin, const struct if (spa_json_parse_int(val, len, &delay_i) > 0) { delay = delay_i / (float)SampleRate; } else if (spa_json_parse_float(val, len, &delay) <= 0) { - pw_log_error("convolver:delay requires a number"); + spa_log_error(pl->log, "convolver:delay requires a number"); return NULL; } } @@ -956,7 +966,7 @@ static void * convolver_instantiate(const struct fc_plugin *plugin, const struct } } else if (spa_json_parse_stringn(val, len, v, sizeof(v)) <= 0) { - pw_log_error("convolver:filename requires a string or an array"); + spa_log_error(pl->log, "convolver:filename requires a string or an array"); return NULL; } else { filenames[0] = strdup(v); @@ -964,34 +974,34 @@ static void * convolver_instantiate(const struct fc_plugin *plugin, const struct } else if (spa_streq(key, "offset")) { if (spa_json_parse_int(val, len, &offset) <= 0) { - pw_log_error("convolver:offset requires a number"); + spa_log_error(pl->log, "convolver:offset requires a number"); return NULL; } } else if (spa_streq(key, "length")) { if (spa_json_parse_int(val, len, &length) <= 0) { - pw_log_error("convolver:length requires a number"); + spa_log_error(pl->log, "convolver:length requires a number"); return NULL; } } else if (spa_streq(key, "channel")) { if (spa_json_parse_int(val, len, &channel) <= 0) { - pw_log_error("convolver:channel requires a number"); + spa_log_error(pl->log, "convolver:channel requires a number"); return NULL; } } else if (spa_streq(key, "resample_quality")) { if (spa_json_parse_int(val, len, &resample_quality) <= 0) { - pw_log_error("convolver:resample_quality requires a number"); + spa_log_error(pl->log, "convolver:resample_quality requires a number"); return NULL; } } else { - pw_log_warn("convolver: ignoring config key: '%s'", key); + spa_log_warn(pl->log, "convolver: ignoring config key: '%s'", key); } } if (filenames[0] == NULL) { - pw_log_error("convolver:filename was not given"); + spa_log_error(pl->log, "convolver:filename was not given"); return NULL; } @@ -1001,18 +1011,17 @@ static void * convolver_instantiate(const struct fc_plugin *plugin, const struct offset = 0; if (spa_streq(filenames[0], "/hilbert")) { - samples = create_hilbert(filenames[0], gain, SampleRate, delay, offset, + samples = create_hilbert(pl, filenames[0], gain, SampleRate, delay, offset, length, &n_samples); } else if (spa_streq(filenames[0], "/dirac")) { - samples = create_dirac(filenames[0], gain, SampleRate, delay, offset, + samples = create_dirac(pl, filenames[0], gain, SampleRate, delay, offset, length, &n_samples); } else { rate = SampleRate; - samples = read_closest(filenames, gain, delay, offset, + samples = read_closest(pl, filenames, gain, delay, offset, length, channel, &rate, &n_samples); if (samples != NULL && rate != SampleRate) { - struct plugin *p = (struct plugin *) plugin; - samples = resample_buffer(p->dsp_ops, samples, &n_samples, + samples = resample_buffer(pl, samples, &n_samples, rate, SampleRate, resample_quality); } } @@ -1031,17 +1040,19 @@ static void * convolver_instantiate(const struct fc_plugin *plugin, const struct if (tailsize <= 0) tailsize = SPA_CLAMP(4096, blocksize, 32768); - pw_log_info("using n_samples:%u %d:%d blocksize delay:%f", n_samples, + spa_log_info(pl->log, "using n_samples:%u %d:%d blocksize delay:%f", n_samples, blocksize, tailsize, delay); impl = calloc(1, sizeof(*impl)); if (impl == NULL) goto error; - impl->plugin = (struct plugin *) plugin; + impl->plugin = pl; + impl->log = pl->log; + impl->dsp = pl->dsp; impl->rate = SampleRate; - impl->conv = convolver_new(impl->plugin->dsp_ops, blocksize, tailsize, samples, n_samples); + impl->conv = convolver_new(impl->dsp, blocksize, tailsize, samples, n_samples); if (impl->conv == NULL) goto error; @@ -1110,6 +1121,10 @@ static const struct fc_descriptor convolve_desc = { /** delay */ struct delay_impl { struct plugin *plugin; + + struct dsp_ops *dsp; + struct spa_log *log; + unsigned long rate; float *port[4]; @@ -1130,6 +1145,7 @@ static void delay_cleanup(void * Instance) static void *delay_instantiate(const struct fc_plugin *plugin, const struct fc_descriptor * Descriptor, unsigned long SampleRate, int index, const char *config) { + struct plugin *pl = (struct plugin*) plugin; struct delay_impl *impl; struct spa_json it[1]; const char *val; @@ -1138,24 +1154,24 @@ static void *delay_instantiate(const struct fc_plugin *plugin, const struct fc_d int len; if (config == NULL) { - pw_log_error("delay: requires a config section"); + spa_log_error(pl->log, "delay: requires a config section"); errno = EINVAL; return NULL; } if (spa_json_begin_object(&it[0], config, strlen(config)) <= 0) { - pw_log_error("delay:config must be an object"); + spa_log_error(pl->log, "delay:config must be an object"); return NULL; } while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "max-delay")) { if (spa_json_parse_float(val, len, &max_delay) <= 0) { - pw_log_error("delay:max-delay requires a number"); + spa_log_error(pl->log, "delay:max-delay requires a number"); return NULL; } } else { - pw_log_warn("delay: ignoring config key: '%s'", key); + spa_log_warn(pl->log, "delay: ignoring config key: '%s'", key); } } if (max_delay <= 0.0f) @@ -1165,10 +1181,12 @@ static void *delay_instantiate(const struct fc_plugin *plugin, const struct fc_d if (impl == NULL) return NULL; - impl->plugin = (struct plugin *) plugin; + impl->plugin = pl; + impl->dsp = pl->dsp; + impl->log = pl->log; impl->rate = SampleRate; impl->buffer_samples = SPA_ROUND_UP_N((uint32_t)(max_delay * impl->rate), 64); - pw_log_info("max-delay:%f seconds rate:%lu samples:%d", max_delay, impl->rate, impl->buffer_samples); + spa_log_info(impl->log, "max-delay:%f seconds rate:%lu samples:%d", max_delay, impl->rate, impl->buffer_samples); impl->buffer = calloc(impl->buffer_samples * 2 + 64, sizeof(float)); if (impl->buffer == NULL) { @@ -1200,7 +1218,7 @@ static void delay_run(void * Instance, unsigned long SampleCount) impl->delay_samples = SPA_CLAMP((uint32_t)(delay * impl->rate), 0u, impl->buffer_samples-1); impl->delay = delay; } - dsp_ops_delay(impl->plugin->dsp_ops, impl->buffer, &impl->ptr, impl->buffer_samples, + dsp_ops_delay(impl->dsp, impl->buffer, &impl->ptr, impl->buffer_samples, impl->delay_samples, out, in, SampleCount); } @@ -1334,7 +1352,7 @@ static void linear_run(void * Instance, unsigned long SampleCount) float *ctrl = impl->port[3], *notify = impl->port[2]; if (in != NULL && out != NULL) - dsp_ops_linear(impl->plugin->dsp_ops, out, in, mult, add, SampleCount); + dsp_ops_linear(impl->dsp, out, in, mult, add, SampleCount); if (ctrl != NULL && notify != NULL) notify[0] = ctrl[0] * mult + add; @@ -1579,7 +1597,7 @@ static void mult_run(void * Instance, unsigned long SampleCount) src[n_src++] = in; } - dsp_ops_mult(impl->plugin->dsp_ops, out, src, n_src, SampleCount); + dsp_ops_mult(impl->dsp, out, src, n_src, SampleCount); } static struct fc_port mult_ports[] = { @@ -1706,6 +1724,10 @@ static const struct fc_descriptor sine_desc = { #define PARAM_EQ_MAX 64 struct param_eq_impl { struct plugin *plugin; + + struct dsp_ops *dsp; + struct spa_log *log; + unsigned long rate; float *port[8*2]; @@ -1713,7 +1735,8 @@ struct param_eq_impl { struct biquad bq[PARAM_EQ_MAX * 8]; }; -static int load_eq_bands(const char *filename, int rate, struct biquad *bq, uint32_t max_bq, uint32_t *n_bq) +static int load_eq_bands(struct plugin *pl, const char *filename, int rate, + struct biquad *bq, uint32_t max_bq, uint32_t *n_bq) { FILE *f = NULL; char *line = NULL; @@ -1728,7 +1751,7 @@ static int load_eq_bands(const char *filename, int rate, struct biquad *bq, uint if ((f = fopen(filename, "r")) == NULL) { res = -errno; - pw_log_error("failed to open param_eq file '%s': %m", filename); + spa_log_error(pl->log, "failed to open param_eq file '%s': %m", filename); goto exit; } /* @@ -1746,7 +1769,7 @@ static int load_eq_bands(const char *filename, int rate, struct biquad *bq, uint nread = getline(&line, &linelen, f); if (nread != -1 && sscanf(line, "%*s %6s %*s", gain) == 1) { if (spa_json_parse_float(gain, strlen(gain), &vg)) { - pw_log_info("%d %s freq:0 q:1.0 gain:%f", n, + spa_log_info(pl->log, "%d %s freq:0 q:1.0 gain:%f", n, bq_name_from_type(BQ_HIGHSHELF), vg); biquad_set(&bq[n++], BQ_HIGHSHELF, 0.0f, 1.0f, vg); } @@ -1784,7 +1807,7 @@ static int load_eq_bands(const char *filename, int rate, struct biquad *bq, uint if (spa_json_parse_float(gain, strlen(gain), &vg) && spa_json_parse_float(q, strlen(q), &vq)) { - pw_log_info("%d %s freq:%d q:%f gain:%f", n, + spa_log_info(pl->log, "%d %s freq:%d q:%f gain:%f", n, bq_name_from_type(type), freq, vq, vg); biquad_set(&bq[n++], type, freq * 2.0f / rate, vq, vg); } @@ -1810,7 +1833,8 @@ exit: * { type=bq_peaking freq=1600 gain=2.3 q=2.700 } * ] */ -static int parse_filters(struct spa_json *iter, int rate, struct biquad *bq, uint32_t max_bq, uint32_t *n_bq) +static int parse_filters(struct plugin *pl, struct spa_json *iter, int rate, + struct biquad *bq, uint32_t max_bq, uint32_t *n_bq) { struct spa_json it[1]; const char *val; @@ -1826,37 +1850,37 @@ static int parse_filters(struct spa_json *iter, int rate, struct biquad *bq, uin while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "type")) { if (spa_json_parse_stringn(val, len, type_str, sizeof(type_str)) <= 0) { - pw_log_error("param_eq:type requires a string"); + spa_log_error(pl->log, "param_eq:type requires a string"); return -EINVAL; } type = bq_type_from_name(type_str); } else if (spa_streq(key, "freq")) { if (spa_json_parse_float(val, len, &freq) <= 0) { - pw_log_error("param_eq:rate requires a number"); + spa_log_error(pl->log, "param_eq:rate requires a number"); return -EINVAL; } } else if (spa_streq(key, "q")) { if (spa_json_parse_float(val, len, &q) <= 0) { - pw_log_error("param_eq:q requires a float"); + spa_log_error(pl->log, "param_eq:q requires a float"); return -EINVAL; } } else if (spa_streq(key, "gain")) { if (spa_json_parse_float(val, len, &gain) <= 0) { - pw_log_error("param_eq:gain requires a float"); + spa_log_error(pl->log, "param_eq:gain requires a float"); return -EINVAL; } } else { - pw_log_warn("param_eq: ignoring filter key: '%s'", key); + spa_log_warn(pl->log, "param_eq: ignoring filter key: '%s'", key); } } if (n == max_bq) return -ENOSPC; - pw_log_info("%d %s freq:%f q:%f gain:%f", n, + spa_log_info(pl->log, "%d %s freq:%f q:%f gain:%f", n, bq_name_from_type(type), freq, q, gain); biquad_set(&bq[n++], type, freq * 2 / rate, q, gain); } @@ -1875,6 +1899,7 @@ static int parse_filters(struct spa_json *iter, int rate, struct biquad *bq, uin static void *param_eq_instantiate(const struct fc_plugin *plugin, const struct fc_descriptor * Descriptor, unsigned long SampleRate, int index, const char *config) { + struct plugin *pl = (struct plugin *) plugin; struct spa_json it[3]; const char *val; char key[256], filename[PATH_MAX]; @@ -1883,13 +1908,13 @@ static void *param_eq_instantiate(const struct fc_plugin *plugin, const struct f uint32_t i, n_bq = 0; if (config == NULL) { - pw_log_error("param_eq: requires a config section"); + spa_log_error(pl->log, "param_eq: requires a config section"); errno = EINVAL; return NULL; } if (spa_json_begin_object(&it[0], config, strlen(config)) <= 0) { - pw_log_error("param_eq: config must be an object"); + spa_log_error(pl->log, "param_eq: config must be an object"); return NULL; } @@ -1897,7 +1922,9 @@ static void *param_eq_instantiate(const struct fc_plugin *plugin, const struct f if (impl == NULL) return NULL; - impl->plugin = (struct plugin *) plugin; + impl->plugin = pl; + impl->dsp = pl->dsp; + impl->log = pl->log; impl->rate = SampleRate; for (i = 0; i < SPA_N_ELEMENTS(impl->bq); i++) biquad_set(&impl->bq[i], BQ_NONE, 0.0f, 0.0f, 0.0f); @@ -1908,23 +1935,23 @@ static void *param_eq_instantiate(const struct fc_plugin *plugin, const struct f if (spa_strstartswith(key, "filename")) { if (spa_json_parse_stringn(val, len, filename, sizeof(filename)) <= 0) { - pw_log_error("param_eq: filename requires a string"); + spa_log_error(impl->log, "param_eq: filename requires a string"); goto error; } if (spa_atoi32(key+8, &idx, 0)) bq = &impl->bq[(SPA_CLAMP(idx, 1, 8) - 1) * PARAM_EQ_MAX]; - res = load_eq_bands(filename, impl->rate, bq, PARAM_EQ_MAX, &n_bq); + res = load_eq_bands(pl, filename, impl->rate, bq, PARAM_EQ_MAX, &n_bq); if (res < 0) { - pw_log_error("param_eq: failed to parse configuration from '%s'", filename); + spa_log_error(impl->log, "param_eq: failed to parse configuration from '%s'", filename); goto error; } - pw_log_info("loaded %d biquads for channel %d", n_bq, idx); + spa_log_info(impl->log, "loaded %d biquads for channel %d", n_bq, idx); impl->n_bq = SPA_MAX(impl->n_bq, n_bq); } else if (spa_strstartswith(key, "filters")) { if (!spa_json_is_array(val, len)) { - pw_log_error("param_eq:filters require an array"); + spa_log_error(impl->log, "param_eq:filters require an array"); goto error; } spa_json_enter(&it[0], &it[1]); @@ -1932,15 +1959,15 @@ static void *param_eq_instantiate(const struct fc_plugin *plugin, const struct f if (spa_atoi32(key+7, &idx, 0)) bq = &impl->bq[(SPA_CLAMP(idx, 1, 8) - 1) * PARAM_EQ_MAX]; - res = parse_filters(&it[1], impl->rate, bq, PARAM_EQ_MAX, &n_bq); + res = parse_filters(pl, &it[1], impl->rate, bq, PARAM_EQ_MAX, &n_bq); if (res < 0) { - pw_log_error("param_eq: failed to parse configuration"); + spa_log_error(impl->log, "param_eq: failed to parse configuration"); goto error; } - pw_log_info("parsed %d biquads for channel %d", n_bq, idx); + spa_log_info(impl->log, "parsed %d biquads for channel %d", n_bq, idx); impl->n_bq = SPA_MAX(impl->n_bq, n_bq); } else { - pw_log_warn("param_eq: ignoring config key: '%s'", key); + spa_log_warn(impl->log, "param_eq: ignoring config key: '%s'", key); } if (idx == 0) { for (i = 1; i < 8; i++) @@ -1964,7 +1991,7 @@ static void param_eq_connect_port(void * Instance, unsigned long Port, static void param_eq_run(void * Instance, unsigned long SampleCount) { struct param_eq_impl *impl = Instance; - dsp_ops_biquadn_run(impl->plugin->dsp_ops, impl->bq, impl->n_bq, PARAM_EQ_MAX, + dsp_ops_biquadn_run(impl->dsp, impl->bq, impl->n_bq, PARAM_EQ_MAX, &impl->port[8], (const float**)impl->port, 8, SampleCount); } @@ -2124,7 +2151,8 @@ struct fc_plugin *load_builtin_plugin(const struct spa_support *support, uint32_ struct plugin *impl = calloc (1, sizeof (struct plugin)); impl->plugin.make_desc = builtin_make_desc; impl->plugin.unload = builtin_plugin_unload; - impl->dsp_ops = dsp; + impl->dsp = dsp; pffft_select_cpu(dsp->cpu_flags); + impl->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); return (struct fc_plugin *) impl; } diff --git a/src/modules/module-filter-chain/ladspa_plugin.c b/src/modules/module-filter-chain/ladspa_plugin.c index bfc21dc47..a133f7a7b 100644 --- a/src/modules/module-filter-chain/ladspa_plugin.c +++ b/src/modules/module-filter-chain/ladspa_plugin.c @@ -11,15 +11,16 @@ #include #include #include - -#include -#include +#include #include "plugin.h" #include "ladspa.h" struct plugin { struct fc_plugin plugin; + + struct spa_log *log; + void *handle; LADSPA_Descriptor_Function desc_func; }; @@ -172,47 +173,70 @@ static void ladspa_unload(struct fc_plugin *plugin) free(p); } -static struct fc_plugin *ladspa_handle_load_by_path(const char *path) +static struct fc_plugin *ladspa_handle_load_by_path(struct spa_log *log, const char *path) { struct plugin *p; int res; + void *handle = NULL; + LADSPA_Descriptor_Function desc_func; - p = calloc(1, sizeof(*p)); - if (!p) - return NULL; - - p->handle = dlopen(path, RTLD_NOW); - if (!p->handle) { - pw_log_debug("failed to open '%s': %s", path, dlerror()); + handle = dlopen(path, RTLD_NOW); + if (handle == NULL) { + spa_log_debug(log, "failed to open '%s': %s", path, dlerror()); res = -ENOENT; goto exit; } - pw_log_info("successfully opened '%s'", path); + spa_log_info(log, "successfully opened '%s'", path); - p->desc_func = (LADSPA_Descriptor_Function) dlsym(p->handle, "ladspa_descriptor"); - if (!p->desc_func) { - pw_log_warn("cannot find descriptor function in '%s': %s", path, dlerror()); + desc_func = (LADSPA_Descriptor_Function) dlsym(handle, "ladspa_descriptor"); + if (desc_func == NULL) { + spa_log_warn(log, "cannot find descriptor function in '%s': %s", path, dlerror()); res = -ENOSYS; goto exit; } + + p = calloc(1, sizeof(*p)); + if (!p) { + res = -errno; + goto exit; + } + p->log = log; + p->handle = handle; + p->desc_func = desc_func; p->plugin.make_desc = ladspa_make_desc; p->plugin.unload = ladspa_unload; return &p->plugin; exit: - if (p->handle) - dlclose(p->handle); - free(p); + if (handle) + dlclose(handle); errno = -res; return NULL; } +static inline const char *split_walk(const char *str, const char *delimiter, size_t * len, const char **state) +{ + const char *s = *state ? *state : str; + + s += strspn(s, delimiter); + if (*s == '\0') + return NULL; + + *len = strcspn(s, delimiter); + *state = s + *len; + + return s; +} + struct fc_plugin *load_ladspa_plugin(const struct spa_support *support, uint32_t n_support, struct dsp_ops *dsp, const char *plugin, const struct spa_dict *info) { struct fc_plugin *pl = NULL; + struct spa_log *log; + + log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); if (plugin[0] != '/') { const char *search_dirs, *p, *state = NULL; @@ -230,7 +254,7 @@ struct fc_plugin *load_ladspa_plugin(const struct spa_support *support, uint32_t */ errno = ENAMETOOLONG; - while ((p = pw_split_walk(search_dirs, ":", &len, &state))) { + while ((p = split_walk(search_dirs, ":", &len, &state))) { int pathlen; if (len >= sizeof(path)) @@ -240,17 +264,17 @@ struct fc_plugin *load_ladspa_plugin(const struct spa_support *support, uint32_t if (pathlen < 0 || (size_t) pathlen >= sizeof(path)) continue; - pl = ladspa_handle_load_by_path(path); + pl = ladspa_handle_load_by_path(log, path); if (pl != NULL) break; } } else { - pl = ladspa_handle_load_by_path(plugin); + pl = ladspa_handle_load_by_path(log, plugin); } if (pl == NULL) - pw_log_error("failed to load plugin '%s': %s", plugin, strerror(errno)); + spa_log_error(log, "failed to load plugin '%s': %s", plugin, strerror(errno)); return pl; } diff --git a/src/modules/module-filter-chain/lv2_plugin.c b/src/modules/module-filter-chain/lv2_plugin.c index ffa35d735..0059b37c4 100644 --- a/src/modules/module-filter-chain/lv2_plugin.c +++ b/src/modules/module-filter-chain/lv2_plugin.c @@ -5,16 +5,13 @@ #include #include +#include + #include #include #include #include - -#include -#include -#include - -#include +#include #if defined __has_include # if __has_include () @@ -42,45 +39,48 @@ static struct context *_context; typedef struct URITable { - struct pw_array array; + char **data; + size_t alloc; + size_t len; } URITable; static void uri_table_init(URITable *table) { - pw_array_init(&table->array, 1024); + table->data = NULL; + table->len = table->alloc = 0; } static void uri_table_destroy(URITable *table) { - char **p; - pw_array_for_each(p, &table->array) - free(*p); - pw_array_clear(&table->array); + size_t i; + for (i = 0; i < table->len; i++) + free(table->data[i]); + free(table->data); + uri_table_init(table); } static LV2_URID uri_table_map(LV2_URID_Map_Handle handle, const char *uri) { URITable *table = (URITable*)handle; - char **p; - size_t i = 0; + size_t i; - pw_array_for_each(p, &table->array) { - i++; - if (spa_streq(*p, uri)) - goto done; - } - pw_array_add_ptr(&table->array, strdup(uri)); - i = pw_array_get_len(&table->array, char*); -done: - return i; + for (i = 0; i < table->len; i++) + if (spa_streq(table->data[i], uri)) + return i+1; + + if (table->len == table->alloc) { + table->alloc += 64; + table->data = realloc(table->data, table->alloc * sizeof(char *)); + } + table->data[table->len++] = strdup(uri); + return table->len; } static const char *uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid) { URITable *table = (URITable*)handle; - - if (urid > 0 && urid <= pw_array_get_len(&table->array, char*)) - return *pw_array_get_unchecked(&table->array, urid - 1, char*); + if (urid > 0 && urid <= table->len) + return table->data[urid-1]; return NULL; } @@ -88,6 +88,7 @@ struct context { int ref; LilvWorld *world; + struct spa_log *log; struct spa_loop *data_loop; struct spa_loop *main_loop; @@ -185,6 +186,7 @@ static struct context *context_new(const struct spa_support *support, uint32_t n c->atom_Int = context_map(c, LV2_ATOM__Int); c->atom_Float = context_map(c, LV2_ATOM__Float); + c->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); c->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop); c->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop); @@ -475,7 +477,7 @@ struct fc_plugin *pipewire__filter_chain_plugin_load(const struct spa_support *s uri = lilv_new_uri(c->world, plugin_uri); if (uri == NULL) { - pw_log_warn("invalid URI %s", plugin_uri); + spa_log_warn(c->log, "invalid URI %s", plugin_uri); res = -EINVAL; goto error_unref; } @@ -485,7 +487,7 @@ struct fc_plugin *pipewire__filter_chain_plugin_load(const struct spa_support *s lilv_node_free(uri); if (plugin == NULL) { - pw_log_warn("can't load plugin %s", plugin_uri); + spa_log_warn(c->log, "can't load plugin %s", plugin_uri); res = -EINVAL; goto error_unref; } diff --git a/src/modules/module-filter-chain/sofa_plugin.c b/src/modules/module-filter-chain/sofa_plugin.c index 799274f23..a8ed118d5 100644 --- a/src/modules/module-filter-chain/sofa_plugin.c +++ b/src/modules/module-filter-chain/sofa_plugin.c @@ -4,8 +4,7 @@ #include #include - -#include +#include #include "plugin.h" #include "convolver.h" @@ -16,7 +15,9 @@ struct plugin { struct fc_plugin plugin; - struct dsp_ops *dsp_ops; + + struct dsp_ops *dsp; + struct spa_log *log; struct spa_loop *data_loop; struct spa_loop *main_loop; uint32_t quantum_limit; @@ -24,6 +25,10 @@ struct plugin { struct spatializer_impl { struct plugin *plugin; + + struct dsp_ops *dsp; + struct spa_log *log; + unsigned long rate; float *port[6]; int n_samples, blocksize, tailsize; @@ -39,6 +44,7 @@ static void * spatializer_instantiate(const struct fc_plugin *plugin, const stru unsigned long SampleRate, int index, const char *config) { struct spatializer_impl *impl; + struct plugin *pl = (struct plugin*) plugin; struct spa_json it[1]; const char *val; char key[256]; @@ -47,12 +53,12 @@ static void * spatializer_instantiate(const struct fc_plugin *plugin, const stru errno = EINVAL; if (config == NULL) { - pw_log_error("spatializer: no config was given"); + spa_log_error(pl->log, "spatializer: no config was given"); return NULL; } if (spa_json_begin_object(&it[0], config, strlen(config)) <= 0) { - pw_log_error("spatializer: expected object in config"); + spa_log_error(pl->log, "spatializer: expected object in config"); return NULL; } @@ -62,33 +68,35 @@ static void * spatializer_instantiate(const struct fc_plugin *plugin, const stru return NULL; } - impl->plugin = (struct plugin *) plugin; + impl->plugin = pl; + impl->dsp = pl->dsp; + impl->log = pl->log; while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "blocksize")) { if (spa_json_parse_int(val, len, &impl->blocksize) <= 0) { - pw_log_error("spatializer:blocksize requires a number"); + spa_log_error(impl->log, "spatializer:blocksize requires a number"); errno = EINVAL; goto error; } } else if (spa_streq(key, "tailsize")) { if (spa_json_parse_int(val, len, &impl->tailsize) <= 0) { - pw_log_error("spatializer:tailsize requires a number"); + spa_log_error(impl->log, "spatializer:tailsize requires a number"); errno = EINVAL; goto error; } } else if (spa_streq(key, "filename")) { if (spa_json_parse_stringn(val, len, filename, sizeof(filename)) <= 0) { - pw_log_error("spatializer:filename requires a string"); + spa_log_error(impl->log, "spatializer:filename requires a string"); errno = EINVAL; goto error; } } } if (!filename[0]) { - pw_log_error("spatializer:filename was not given"); + spa_log_error(impl->log, "spatializer:filename was not given"); errno = EINVAL; goto error; } @@ -166,7 +174,7 @@ static void * spatializer_instantiate(const struct fc_plugin *plugin, const stru reason = "Internal error"; break; } - pw_log_error("Unable to load HRTF from %s: %s (%d)", filename, reason, ret); + spa_log_error(impl->log, "Unable to load HRTF from %s: %s (%d)", filename, reason, ret); goto error; } @@ -175,7 +183,7 @@ static void * spatializer_instantiate(const struct fc_plugin *plugin, const stru if (impl->tailsize <= 0) impl->tailsize = SPA_CLAMP(4096, impl->blocksize, 32768); - pw_log_info("using n_samples:%u %d:%d blocksize sofa:%s", impl->n_samples, + spa_log_info(impl->log, "using n_samples:%u %d:%d blocksize sofa:%s", impl->n_samples, impl->blocksize, impl->tailsize, filename); impl->tmp[0] = calloc(impl->plugin->quantum_limit, sizeof(float)); @@ -219,7 +227,7 @@ static void spatializer_reload(void * Instance) for (uint8_t i = 0; i < 3; i++) coords[i] = impl->port[3 + i][0]; - pw_log_info("making spatializer with %f %f %f", coords[0], coords[1], coords[2]); + spa_log_info(impl->log, "making spatializer with %f %f %f", coords[0], coords[1], coords[2]); mysofa_s2c(coords); mysofa_getfilter_float( @@ -235,23 +243,23 @@ static void spatializer_reload(void * Instance) // TODO: make use of delay if ((left_delay != 0.0f || right_delay != 0.0f) && (!isnan(left_delay) || !isnan(right_delay))) - pw_log_warn("delay dropped l: %f, r: %f", left_delay, right_delay); + spa_log_warn(impl->log, "delay dropped l: %f, r: %f", left_delay, right_delay); if (impl->l_conv[2]) convolver_free(impl->l_conv[2]); if (impl->r_conv[2]) convolver_free(impl->r_conv[2]); - impl->l_conv[2] = convolver_new(impl->plugin->dsp_ops, impl->blocksize, impl->tailsize, + impl->l_conv[2] = convolver_new(impl->dsp, impl->blocksize, impl->tailsize, left_ir, impl->n_samples); - impl->r_conv[2] = convolver_new(impl->plugin->dsp_ops, impl->blocksize, impl->tailsize, + impl->r_conv[2] = convolver_new(impl->dsp, impl->blocksize, impl->tailsize, right_ir, impl->n_samples); free(left_ir); free(right_ir); if (impl->l_conv[2] == NULL || impl->r_conv[2] == NULL) { - pw_log_error("reloading left or right convolver failed"); + spa_log_error(impl->log, "reloading left or right convolver failed"); return; } spa_loop_invoke(impl->plugin->data_loop, do_switch, 1, NULL, 0, true, impl); @@ -438,11 +446,12 @@ struct fc_plugin *pipewire__filter_chain_plugin_load(const struct spa_support *s if (spa_streq(k, "clock.quantum-limit")) spa_atou32(s, &impl->quantum_limit, 0); } - impl->dsp_ops = dsp; + impl->dsp = dsp; pffft_select_cpu(dsp->cpu_flags); impl->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop); impl->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop); + impl->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); return (struct fc_plugin *) impl; }