From d8bd84183d317a0816ae284d6497aff4ee69904e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 16 Oct 2024 12:33:35 +0200 Subject: [PATCH] filter-chain: optimize the identity biquad Store the biquad type in the biquad, remove some unused fields. Init all the biquads with the identify before loading the channel specific biquads. We will process the max of all the channel biquads. Make sure we skip processing for the indentity ones. --- src/modules/module-filter-chain/biquad.c | 3 +- src/modules/module-filter-chain/biquad.h | 33 ++++++++++--------- .../module-filter-chain/builtin_plugin.c | 18 ++++++---- src/modules/module-filter-chain/dsp-ops-c.c | 5 +++ 4 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/modules/module-filter-chain/biquad.c b/src/modules/module-filter-chain/biquad.c index c11f76e0d..644276bb0 100644 --- a/src/modules/module-filter-chain/biquad.c +++ b/src/modules/module-filter-chain/biquad.c @@ -326,10 +326,9 @@ void biquad_set(struct biquad *bq, enum biquad_type type, double freq, double Q, double gain) { /* Clear history values. */ + bq->type = type; bq->x1 = 0; bq->x2 = 0; - bq->y1 = 0; - bq->y2 = 0; switch (type) { case BQ_LOWPASS: diff --git a/src/modules/module-filter-chain/biquad.h b/src/modules/module-filter-chain/biquad.h index 650b26395..3344598e6 100644 --- a/src/modules/module-filter-chain/biquad.h +++ b/src/modules/module-filter-chain/biquad.h @@ -10,21 +10,6 @@ extern "C" { #endif -/* The biquad filter parameters. The transfer function H(z) is (b0 + b1 * z^(-1) - * + b2 * z^(-2)) / (1 + a1 * z^(-1) + a2 * z^(-2)). The previous two inputs - * are stored in x1 and x2, and the previous two outputs are stored in y1 and - * y2. - * - * We use double during the coefficients calculation for better accuracy, but - * float is used during the actual filtering for faster computation. - */ -struct biquad { - float b0, b1, b2; - float a1, a2; - float x1, x2; - float y1, y2; -}; - /* The type of the biquad filters */ enum biquad_type { BQ_NONE, @@ -35,7 +20,23 @@ enum biquad_type { BQ_HIGHSHELF, BQ_PEAKING, BQ_NOTCH, - BQ_ALLPASS + BQ_ALLPASS, + BQ_RAW, +}; + +/* The biquad filter parameters. The transfer function H(z) is (b0 + b1 * z^(-1) + * + b2 * z^(-2)) / (1 + a1 * z^(-1) + a2 * z^(-2)). The previous two inputs + * are stored in x1 and x2, and the previous two outputs are stored in y1 and + * y2. + * + * We use double during the coefficients calculation for better accuracy, but + * float is used during the actual filtering for faster computation. + */ +struct biquad { + enum biquad_type type; + float b0, b1, b2; + float a1, a2; + float x1, x2; }; /* Initialize a biquad filter parameters from its type and parameters. diff --git a/src/modules/module-filter-chain/builtin_plugin.c b/src/modules/module-filter-chain/builtin_plugin.c index 0d2ecaa1a..ba76f3267 100644 --- a/src/modules/module-filter-chain/builtin_plugin.c +++ b/src/modules/module-filter-chain/builtin_plugin.c @@ -287,7 +287,8 @@ static void bq_raw_update(struct builtin *impl, float b0, float b1, float b2, bq->b2 = impl->b2 * a0; bq->a1 = impl->a1 * a0; bq->a2 = impl->a2 * a0; - bq->x1 = bq->x2 = bq->y1 = bq->y2 = 0.0; + bq->x1 = bq->x2 = 0.0f; + bq->type = BQ_RAW; } /* @@ -1869,8 +1870,9 @@ static void *param_eq_instantiate(const struct fc_descriptor * Descriptor, struct spa_json it[3]; const char *val; char key[256], filename[PATH_MAX]; - int i, len, res; + int len, res; struct param_eq_impl *impl; + uint32_t i, n_bq = 0; if (config == NULL) { pw_log_error("param_eq: requires a config section"); @@ -1888,6 +1890,8 @@ static void *param_eq_instantiate(const struct fc_descriptor * Descriptor, return NULL; 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); while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) { int32_t idx = 0; @@ -1901,12 +1905,13 @@ static void *param_eq_instantiate(const struct fc_descriptor * Descriptor, 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, &impl->n_bq); + res = load_eq_bands(filename, impl->rate, bq, PARAM_EQ_MAX, &n_bq); if (res < 0) { pw_log_error("param_eq: failed to parse configuration from '%s'", filename); goto error; } - pw_log_info("loaded %d biquads for channel %d", impl->n_bq, idx); + pw_log_info("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)) { @@ -1918,12 +1923,13 @@ static void *param_eq_instantiate(const struct fc_descriptor * Descriptor, 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, &impl->n_bq); + res = parse_filters(&it[1], impl->rate, bq, PARAM_EQ_MAX, &n_bq); if (res < 0) { pw_log_error("param_eq: failed to parse configuration"); goto error; } - pw_log_info("parsed %d biquads for channel %d", impl->n_bq, idx); + pw_log_info("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); } diff --git a/src/modules/module-filter-chain/dsp-ops-c.c b/src/modules/module-filter-chain/dsp-ops-c.c index 0a576ce9a..86dd9c779 100644 --- a/src/modules/module-filter-chain/dsp-ops-c.c +++ b/src/modules/module-filter-chain/dsp-ops-c.c @@ -115,6 +115,11 @@ void dsp_biquad_run_c(struct dsp_ops *ops, struct biquad *bq, float b0, b1, b2, a1, a2; uint32_t i; + if (bq->type == BQ_NONE) { + dsp_copy_c(ops, out, in, n_samples); + return; + } + x1 = bq->x1; x2 = bq->x2; b0 = bq->b0;