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.
This commit is contained in:
Wim Taymans 2024-10-16 12:33:35 +02:00
parent 3c221f49a0
commit d8bd84183d
4 changed files with 35 additions and 24 deletions

View file

@ -326,10 +326,9 @@ void biquad_set(struct biquad *bq, enum biquad_type type, double freq, double Q,
double gain) double gain)
{ {
/* Clear history values. */ /* Clear history values. */
bq->type = type;
bq->x1 = 0; bq->x1 = 0;
bq->x2 = 0; bq->x2 = 0;
bq->y1 = 0;
bq->y2 = 0;
switch (type) { switch (type) {
case BQ_LOWPASS: case BQ_LOWPASS:

View file

@ -10,21 +10,6 @@
extern "C" { extern "C" {
#endif #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 */ /* The type of the biquad filters */
enum biquad_type { enum biquad_type {
BQ_NONE, BQ_NONE,
@ -35,7 +20,23 @@ enum biquad_type {
BQ_HIGHSHELF, BQ_HIGHSHELF,
BQ_PEAKING, BQ_PEAKING,
BQ_NOTCH, 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. /* Initialize a biquad filter parameters from its type and parameters.

View file

@ -287,7 +287,8 @@ static void bq_raw_update(struct builtin *impl, float b0, float b1, float b2,
bq->b2 = impl->b2 * a0; bq->b2 = impl->b2 * a0;
bq->a1 = impl->a1 * a0; bq->a1 = impl->a1 * a0;
bq->a2 = impl->a2 * 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]; struct spa_json it[3];
const char *val; const char *val;
char key[256], filename[PATH_MAX]; char key[256], filename[PATH_MAX];
int i, len, res; int len, res;
struct param_eq_impl *impl; struct param_eq_impl *impl;
uint32_t i, n_bq = 0;
if (config == NULL) { if (config == NULL) {
pw_log_error("param_eq: requires a config section"); 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; return NULL;
impl->rate = SampleRate; 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) { while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) {
int32_t idx = 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)) if (spa_atoi32(key+8, &idx, 0))
bq = &impl->bq[(SPA_CLAMP(idx, 1, 8) - 1) * PARAM_EQ_MAX]; 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) { if (res < 0) {
pw_log_error("param_eq: failed to parse configuration from '%s'", filename); pw_log_error("param_eq: failed to parse configuration from '%s'", filename);
goto error; 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")) { else if (spa_strstartswith(key, "filters")) {
if (!spa_json_is_array(val, len)) { 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)) if (spa_atoi32(key+7, &idx, 0))
bq = &impl->bq[(SPA_CLAMP(idx, 1, 8) - 1) * PARAM_EQ_MAX]; 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) { if (res < 0) {
pw_log_error("param_eq: failed to parse configuration"); pw_log_error("param_eq: failed to parse configuration");
goto error; 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 { } else {
pw_log_warn("param_eq: ignoring config key: '%s'", key); pw_log_warn("param_eq: ignoring config key: '%s'", key);
} }

View file

@ -115,6 +115,11 @@ void dsp_biquad_run_c(struct dsp_ops *ops, struct biquad *bq,
float b0, b1, b2, a1, a2; float b0, b1, b2, a1, a2;
uint32_t i; uint32_t i;
if (bq->type == BQ_NONE) {
dsp_copy_c(ops, out, in, n_samples);
return;
}
x1 = bq->x1; x1 = bq->x1;
x2 = bq->x2; x2 = bq->x2;
b0 = bq->b0; b0 = bq->b0;