diff --git a/spa/plugins/audioconvert/channelmix-ops-c.c b/spa/plugins/audioconvert/channelmix-ops-c.c index 6bf92763e..63947aa5f 100644 --- a/spa/plugins/audioconvert/channelmix-ops-c.c +++ b/spa/plugins/audioconvert/channelmix-ops-c.c @@ -78,10 +78,8 @@ channelmix_f32_n_m_c(struct channelmix *mix, void * SPA_RESTRICT dst[], d[i][n] = sum; } } - for (i = 0; i < n_dst; i++) { - if (mix->lr4_info[i] > 0) - lr4_process(&mix->lr4[i], d[i], n_samples); - } + for (i = 0; i < n_dst; i++) + lr4_process(&mix->lr4[i], d[i], d[i], 1.0f, n_samples); } } @@ -253,22 +251,20 @@ channelmix_f32_2_3p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[], float c = s[0][n] + s[1][n]; d[0][n] = s[0][n]; d[1][n] = s[1][n]; - d[2][n] = c * v2; - d[3][n] = c * v3; + d[2][n] = c; } - if (v3 > 0.0f) - lr4_process(&mix->lr4[3], d[3], n_samples); + lr4_process(&mix->lr4[3], d[3], d[2], v3, n_samples); + lr4_process(&mix->lr4[2], d[2], d[2], v2, n_samples); } else { for (n = 0; n < n_samples; n++) { float c = s[0][n] + s[1][n]; d[0][n] = s[0][n] * v0; d[1][n] = s[1][n] * v1; - d[2][n] = c * v2; - d[3][n] = c * v3; + d[2][n] = c; } - if (v3 > 0.0f) - lr4_process(&mix->lr4[3], d[3], n_samples); + lr4_process(&mix->lr4[3], d[3], d[2], v3, n_samples); + lr4_process(&mix->lr4[2], d[2], d[2], v2, n_samples); } } @@ -296,24 +292,22 @@ channelmix_f32_2_5p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[], float c = s[0][n] + s[1][n]; d[0][n] = d[4][n] = s[0][n]; d[1][n] = d[5][n] = s[1][n]; - d[2][n] = c * v2; - d[3][n] = c * v3; + d[2][n] = c; } - if (v3 > 0.0f) - lr4_process(&mix->lr4[3], d[3], n_samples); + lr4_process(&mix->lr4[3], d[3], d[2], v3, n_samples); + lr4_process(&mix->lr4[2], d[2], d[2], v2, n_samples); } else { for (n = 0; n < n_samples; n++) { float c = s[0][n] + s[1][n]; d[0][n] = s[0][n] * v0; d[1][n] = s[1][n] * v1; - d[2][n] = c * v2; - d[3][n] = c * v3; + d[2][n] = c; d[4][n] = s[0][n] * v4; d[5][n] = s[1][n] * v5; } - if (v3 > 0.0f) - lr4_process(&mix->lr4[3], d[3], n_samples); + lr4_process(&mix->lr4[3], d[3], d[2], v3, n_samples); + lr4_process(&mix->lr4[2], d[2], d[2], v2, n_samples); } } @@ -343,26 +337,24 @@ channelmix_f32_2_7p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[], float c = s[0][n] + s[1][n]; d[0][n] = d[4][n] = d[6][n] = s[0][n]; d[1][n] = d[5][n] = d[7][n] = s[1][n]; - d[2][n] = c * v2; - d[3][n] = c * v3; + d[2][n] = c; } - if (v3 > 0.0f) - lr4_process(&mix->lr4[3], d[3], n_samples); + lr4_process(&mix->lr4[3], d[3], d[2], v3, n_samples); + lr4_process(&mix->lr4[2], d[2], d[2], v2, n_samples); } else { for (n = 0; n < n_samples; n++) { float c = s[0][n] + s[1][n]; d[0][n] = s[0][n] * v0; d[1][n] = s[1][n] * v1; - d[2][n] = c * v2; - d[3][n] = c * v3; + d[2][n] = c; d[4][n] = s[0][n] * v4; d[5][n] = s[1][n] * v5; d[6][n] = s[0][n] * v6; d[7][n] = s[1][n] * v7; } - if (v3 > 0.0f) - lr4_process(&mix->lr4[3], d[3], n_samples); + lr4_process(&mix->lr4[3], d[3], d[2], v3, n_samples); + lr4_process(&mix->lr4[2], d[2], d[2], v2, n_samples); } } diff --git a/spa/plugins/audioconvert/channelmix-ops.c b/spa/plugins/audioconvert/channelmix-ops.c index defcc0fce..199d14361 100644 --- a/spa/plugins/audioconvert/channelmix-ops.c +++ b/spa/plugins/audioconvert/channelmix-ops.c @@ -457,9 +457,8 @@ done: if (i == _CH(LFE) && mix->lfe_cutoff > 0.0f) { spa_log_debug(mix->log, "channel %d is LFE", ic); lr4_set(&mix->lr4[ic], BQ_LOWPASS, mix->lfe_cutoff / mix->freq); - mix->lr4_info[ic] = 1; } else { - mix->lr4_info[ic] = 0; + mix->lr4[ic].active = false; } ic++; } diff --git a/spa/plugins/audioconvert/channelmix-ops.h b/spa/plugins/audioconvert/channelmix-ops.h index 48a26d4fb..29a7fec81 100644 --- a/spa/plugins/audioconvert/channelmix-ops.h +++ b/spa/plugins/audioconvert/channelmix-ops.h @@ -69,7 +69,6 @@ struct channelmix { float freq; /* sample frequency */ float lfe_cutoff; /* in Hz, 0 is disabled */ - uint32_t lr4_info[SPA_AUDIO_MAX_CHANNELS]; struct lr4 lr4[SPA_AUDIO_MAX_CHANNELS]; void (*process) (struct channelmix *mix, void * SPA_RESTRICT dst[], diff --git a/spa/plugins/audioconvert/crossover.c b/spa/plugins/audioconvert/crossover.c index 046c16a02..1ce1d221d 100644 --- a/spa/plugins/audioconvert/crossover.c +++ b/spa/plugins/audioconvert/crossover.c @@ -5,6 +5,9 @@ #include "config.h" +#include +#include + #include "crossover.h" void lr4_set(struct lr4 *lr4, enum biquad_type type, float freq) @@ -16,9 +19,10 @@ void lr4_set(struct lr4 *lr4, enum biquad_type type, float freq) lr4->y2 = 0; lr4->z1 = 0; lr4->z2 = 0; + lr4->active = true; } -void lr4_process(struct lr4 *lr4, float *data, int samples) +void lr4_process(struct lr4 *lr4, float *dst, const float *src, const float vol, int samples) { float lx1 = lr4->x1; float lx2 = lr4->x2; @@ -31,11 +35,22 @@ void lr4_process(struct lr4 *lr4, float *data, int samples) float lb2 = lr4->bq.b2; float la1 = lr4->bq.a1; float la2 = lr4->bq.a2; - int i; + + if (vol == 0.0f) { + memset(dst, 0, samples * sizeof(float)); + return; + } else if (!lr4->active) { + if (src != dst || vol != 1.0f) { + for (i = 0; i < samples; i++) + dst[i] = src[i] * vol; + } + return; + } + for (i = 0; i < samples; i++) { float x, y, z; - x = data[i]; + x = src[i]; y = lb0*x + lb1*lx1 + lb2*lx2 - la1*ly1 - la2*ly2; z = lb0*y + lb1*ly1 + lb2*ly2 - la1*lz1 - la2*lz2; lx2 = lx1; @@ -44,13 +59,14 @@ void lr4_process(struct lr4 *lr4, float *data, int samples) ly1 = y; lz2 = lz1; lz1 = z; - data[i] = z; + dst[i] = z * vol; } - - lr4->x1 = lx1; - lr4->x2 = lx2; - lr4->y1 = ly1; - lr4->y2 = ly2; - lr4->z1 = lz1; - lr4->z2 = lz2; +#define F(x) (-FLT_MIN < (x) && (x) < FLT_MIN ? 0.0f : (x)) + lr4->x1 = F(lx1); + lr4->x2 = F(lx2); + lr4->y1 = F(ly1); + lr4->y2 = F(ly2); + lr4->z1 = F(lz1); + lr4->z2 = F(lz2); +#undef F } diff --git a/spa/plugins/audioconvert/crossover.h b/spa/plugins/audioconvert/crossover.h index f18695ddd..b6f458baf 100644 --- a/spa/plugins/audioconvert/crossover.h +++ b/spa/plugins/audioconvert/crossover.h @@ -6,6 +6,8 @@ #ifndef CROSSOVER_H_ #define CROSSOVER_H_ +#include + #include "biquad.h" /* An LR4 filter is two biquads with the same parameters connected in series: * @@ -19,10 +21,11 @@ struct lr4 { float x1, x2; float y1, y2; float z1, z2; + bool active; }; void lr4_set(struct lr4 *lr4, enum biquad_type type, float freq); -void lr4_process(struct lr4 *lr4, float *data, int samples); +void lr4_process(struct lr4 *lr4, float *dst, const float *src, const float vol, int samples); #endif /* CROSSOVER_H_ */