From 8d9269374ddd7fc1628d9bf05c0880e82a76015d Mon Sep 17 00:00:00 2001 Message-ID: <8d9269374ddd7fc1628d9bf05c0880e82a76015d.1737052666.git.sam@gentoo.org> In-Reply-To: <1993383ddf67e296334c7916d6afc699ee6300c7.1737052666.git.sam@gentoo.org> References: <1993383ddf67e296334c7916d6afc699ee6300c7.1737052666.git.sam@gentoo.org> From: Wim Taymans Date: Tue, 3 Dec 2024 15:43:56 +0100 Subject: [PATCH 7/8] filter-chain: handle 0 length IR Make sure we copy the DSP functions in the convolver before leaving the function because we need them to clear memory. Don't store the DSP functions in the head and tail convolvers but pass them from the main convolver because the convolvers might be NULL but we still need the DSP functions to clear memory. Fixes #4433 --- src/modules/module-filter-chain/convolver.c | 96 +++++++++++---------- 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/src/modules/module-filter-chain/convolver.c b/src/modules/module-filter-chain/convolver.c index 3aa7230c0..4251c4025 100644 --- a/src/modules/module-filter-chain/convolver.c +++ b/src/modules/module-filter-chain/convolver.c @@ -11,8 +11,6 @@ #include struct convolver1 { - struct dsp_ops *dsp; - int blockSize; int segSize; int segCount; @@ -76,15 +74,15 @@ static int next_power_of_two(int val) return r; } -static void convolver1_reset(struct convolver1 *conv) +static void convolver1_reset(struct dsp_ops *dsp, struct convolver1 *conv) { int i; for (i = 0; i < conv->segCount; i++) - fft_cpx_clear(conv->dsp, conv->segments[i], conv->fftComplexSize); - dsp_ops_clear(conv->dsp, conv->overlap, conv->blockSize); - dsp_ops_clear(conv->dsp, conv->inputBuffer, conv->segSize); - fft_cpx_clear(conv->dsp, conv->pre_mult, conv->fftComplexSize); - fft_cpx_clear(conv->dsp, conv->conv, conv->fftComplexSize); + fft_cpx_clear(dsp, conv->segments[i], conv->fftComplexSize); + dsp_ops_clear(dsp, conv->overlap, conv->blockSize); + dsp_ops_clear(dsp, conv->inputBuffer, conv->segSize); + fft_cpx_clear(dsp, conv->pre_mult, conv->fftComplexSize); + fft_cpx_clear(dsp, conv->conv, conv->fftComplexSize); conv->inputBufferFill = 0; conv->current = 0; } @@ -107,16 +105,15 @@ static struct convolver1 *convolver1_new(struct dsp_ops *dsp, int block, const f if (irlen == 0) return conv; - conv->dsp = dsp; conv->blockSize = next_power_of_two(block); conv->segSize = 2 * conv->blockSize; conv->segCount = (irlen + conv->blockSize-1) / conv->blockSize; conv->fftComplexSize = (conv->segSize / 2) + 1; - conv->fft = dsp_ops_fft_new(conv->dsp, conv->segSize, true); + conv->fft = dsp_ops_fft_new(dsp, conv->segSize, true); if (conv->fft == NULL) goto error; - conv->ifft = dsp_ops_fft_new(conv->dsp, conv->segSize, true); + conv->ifft = dsp_ops_fft_new(dsp, conv->segSize, true); if (conv->ifft == NULL) goto error; @@ -134,18 +131,18 @@ static struct convolver1 *convolver1_new(struct dsp_ops *dsp, int block, const f conv->segments[i] = fft_cpx_alloc(conv->fftComplexSize); conv->segmentsIr[i] = fft_cpx_alloc(conv->fftComplexSize); - dsp_ops_copy(conv->dsp, conv->fft_buffer, &ir[i * conv->blockSize], copy); + dsp_ops_copy(dsp, conv->fft_buffer, &ir[i * conv->blockSize], copy); if (copy < conv->segSize) - dsp_ops_clear(conv->dsp, conv->fft_buffer + copy, conv->segSize - copy); + dsp_ops_clear(dsp, conv->fft_buffer + copy, conv->segSize - copy); - dsp_ops_fft_run(conv->dsp, conv->fft, 1, conv->fft_buffer, conv->segmentsIr[i]); + dsp_ops_fft_run(dsp, conv->fft, 1, conv->fft_buffer, conv->segmentsIr[i]); } conv->pre_mult = fft_cpx_alloc(conv->fftComplexSize); conv->conv = fft_cpx_alloc(conv->fftComplexSize); conv->overlap = fft_alloc(conv->blockSize); conv->inputBuffer = fft_alloc(conv->segSize); conv->scale = 1.0f / conv->segSize; - convolver1_reset(conv); + convolver1_reset(dsp, conv); return conv; error: @@ -159,7 +156,7 @@ error: return NULL; } -static void convolver1_free(struct convolver1 *conv) +static void convolver1_free(struct dsp_ops *dsp, struct convolver1 *conv) { int i; for (i = 0; i < conv->segCount; i++) { @@ -167,9 +164,9 @@ static void convolver1_free(struct convolver1 *conv) fft_cpx_free(conv->segmentsIr[i]); } if (conv->fft) - dsp_ops_fft_free(conv->dsp, conv->fft); + dsp_ops_fft_free(dsp, conv->fft); if (conv->ifft) - dsp_ops_fft_free(conv->dsp, conv->ifft); + dsp_ops_fft_free(dsp, conv->ifft); if (conv->fft_buffer) fft_free(conv->fft_buffer); free(conv->segments); @@ -181,12 +178,12 @@ static void convolver1_free(struct convolver1 *conv) free(conv); } -static int convolver1_run(struct convolver1 *conv, const float *input, float *output, int len) +static int convolver1_run(struct dsp_ops *dsp, struct convolver1 *conv, const float *input, float *output, int len) { int i, processed = 0; if (conv == NULL || conv->segCount == 0) { - dsp_ops_clear(conv->dsp, output, len); + dsp_ops_clear(dsp, output, len); return len; } @@ -194,17 +191,17 @@ static int convolver1_run(struct convolver1 *conv, const float *input, float *ou const int processing = SPA_MIN(len - processed, conv->blockSize - conv->inputBufferFill); const int inputBufferPos = conv->inputBufferFill; - dsp_ops_copy(conv->dsp, conv->inputBuffer + inputBufferPos, input + processed, processing); + dsp_ops_copy(dsp, conv->inputBuffer + inputBufferPos, input + processed, processing); if (inputBufferPos == 0 && processing < conv->blockSize) - dsp_ops_clear(conv->dsp, conv->inputBuffer + processing, conv->blockSize - processing); + dsp_ops_clear(dsp, conv->inputBuffer + processing, conv->blockSize - processing); - dsp_ops_fft_run(conv->dsp, conv->fft, 1, conv->inputBuffer, conv->segments[conv->current]); + dsp_ops_fft_run(dsp, conv->fft, 1, conv->inputBuffer, conv->segments[conv->current]); if (conv->segCount > 1) { if (conv->inputBufferFill == 0) { int indexAudio = (conv->current + 1) % conv->segCount; - dsp_ops_fft_cmul(conv->dsp, conv->fft, conv->pre_mult, + dsp_ops_fft_cmul(dsp, conv->fft, conv->pre_mult, conv->segmentsIr[1], conv->segments[indexAudio], conv->fftComplexSize, conv->scale); @@ -212,7 +209,7 @@ static int convolver1_run(struct convolver1 *conv, const float *input, float *ou for (i = 2; i < conv->segCount; i++) { indexAudio = (conv->current + i) % conv->segCount; - dsp_ops_fft_cmuladd(conv->dsp, conv->fft, + dsp_ops_fft_cmuladd(dsp, conv->fft, conv->pre_mult, conv->pre_mult, conv->segmentsIr[i], @@ -220,30 +217,30 @@ static int convolver1_run(struct convolver1 *conv, const float *input, float *ou conv->fftComplexSize, conv->scale); } } - dsp_ops_fft_cmuladd(conv->dsp, conv->fft, + dsp_ops_fft_cmuladd(dsp, conv->fft, conv->conv, conv->pre_mult, conv->segments[conv->current], conv->segmentsIr[0], conv->fftComplexSize, conv->scale); } else { - dsp_ops_fft_cmul(conv->dsp, conv->fft, + dsp_ops_fft_cmul(dsp, conv->fft, conv->conv, conv->segments[conv->current], conv->segmentsIr[0], conv->fftComplexSize, conv->scale); } - dsp_ops_fft_run(conv->dsp, conv->ifft, -1, conv->conv, conv->fft_buffer); + dsp_ops_fft_run(dsp, conv->ifft, -1, conv->conv, conv->fft_buffer); - dsp_ops_sum(conv->dsp, output + processed, conv->fft_buffer + inputBufferPos, + dsp_ops_sum(dsp, output + processed, conv->fft_buffer + inputBufferPos, conv->overlap + inputBufferPos, processing); conv->inputBufferFill += processing; if (conv->inputBufferFill == conv->blockSize) { conv->inputBufferFill = 0; - dsp_ops_copy(conv->dsp, conv->overlap, conv->fft_buffer + conv->blockSize, conv->blockSize); + dsp_ops_copy(dsp, conv->overlap, conv->fft_buffer + conv->blockSize, conv->blockSize); conv->current = (conv->current > 0) ? (conv->current - 1) : (conv->segCount - 1); } @@ -272,17 +269,18 @@ struct convolver void convolver_reset(struct convolver *conv) { + struct dsp_ops *dsp = conv->dsp; if (conv->headConvolver) - convolver1_reset(conv->headConvolver); + convolver1_reset(dsp, conv->headConvolver); if (conv->tailConvolver0) { - convolver1_reset(conv->tailConvolver0); - dsp_ops_clear(conv->dsp, conv->tailOutput0, conv->tailBlockSize); - dsp_ops_clear(conv->dsp, conv->tailPrecalculated0, conv->tailBlockSize); + convolver1_reset(dsp, conv->tailConvolver0); + dsp_ops_clear(dsp, conv->tailOutput0, conv->tailBlockSize); + dsp_ops_clear(dsp, conv->tailPrecalculated0, conv->tailBlockSize); } if (conv->tailConvolver) { - convolver1_reset(conv->tailConvolver); - dsp_ops_clear(conv->dsp, conv->tailOutput, conv->tailBlockSize); - dsp_ops_clear(conv->dsp, conv->tailPrecalculated, conv->tailBlockSize); + convolver1_reset(dsp, conv->tailConvolver); + dsp_ops_clear(dsp, conv->tailOutput, conv->tailBlockSize); + dsp_ops_clear(dsp, conv->tailPrecalculated, conv->tailBlockSize); } conv->tailInputFill = 0; conv->precalculatedPos = 0; @@ -307,10 +305,11 @@ struct convolver *convolver_new(struct dsp_ops *dsp_ops, int head_block, int tai if (conv == NULL) return NULL; + conv->dsp = dsp_ops; + if (irlen == 0) return conv; - conv->dsp = dsp_ops; conv->headBlockSize = next_power_of_two(head_block); conv->tailBlockSize = next_power_of_two(tail_block); @@ -341,12 +340,13 @@ struct convolver *convolver_new(struct dsp_ops *dsp_ops, int head_block, int tai void convolver_free(struct convolver *conv) { + struct dsp_ops *dsp = conv->dsp; if (conv->headConvolver) - convolver1_free(conv->headConvolver); + convolver1_free(dsp, conv->headConvolver); if (conv->tailConvolver0) - convolver1_free(conv->tailConvolver0); + convolver1_free(dsp, conv->tailConvolver0); if (conv->tailConvolver) - convolver1_free(conv->tailConvolver); + convolver1_free(dsp, conv->tailConvolver); fft_free(conv->tailOutput0); fft_free(conv->tailPrecalculated0); fft_free(conv->tailOutput); @@ -357,7 +357,9 @@ void convolver_free(struct convolver *conv) int convolver_run(struct convolver *conv, const float *input, float *output, int length) { - convolver1_run(conv->headConvolver, input, output, length); + struct dsp_ops *dsp = conv->dsp; + + convolver1_run(dsp, conv->headConvolver, input, output, length); if (conv->tailInput) { int processed = 0; @@ -367,21 +369,21 @@ int convolver_run(struct convolver *conv, const float *input, float *output, int int processing = SPA_MIN(remaining, conv->headBlockSize - (conv->tailInputFill % conv->headBlockSize)); if (conv->tailPrecalculated0) - dsp_ops_sum(conv->dsp, &output[processed], &output[processed], + dsp_ops_sum(dsp, &output[processed], &output[processed], &conv->tailPrecalculated0[conv->precalculatedPos], processing); if (conv->tailPrecalculated) - dsp_ops_sum(conv->dsp, &output[processed], &output[processed], + dsp_ops_sum(dsp, &output[processed], &output[processed], &conv->tailPrecalculated[conv->precalculatedPos], processing); conv->precalculatedPos += processing; - dsp_ops_copy(conv->dsp, conv->tailInput + conv->tailInputFill, input + processed, processing); + dsp_ops_copy(dsp, conv->tailInput + conv->tailInputFill, input + processed, processing); conv->tailInputFill += processing; if (conv->tailPrecalculated0 && (conv->tailInputFill % conv->headBlockSize == 0)) { int blockOffset = conv->tailInputFill - conv->headBlockSize; - convolver1_run(conv->tailConvolver0, + convolver1_run(dsp, conv->tailConvolver0, conv->tailInput + blockOffset, conv->tailOutput0 + blockOffset, conv->headBlockSize); @@ -392,7 +394,7 @@ int convolver_run(struct convolver *conv, const float *input, float *output, int if (conv->tailPrecalculated && conv->tailInputFill == conv->tailBlockSize) { SPA_SWAP(conv->tailPrecalculated, conv->tailOutput); - convolver1_run(conv->tailConvolver, conv->tailInput, + convolver1_run(dsp, conv->tailConvolver, conv->tailInput, conv->tailOutput, conv->tailBlockSize); } if (conv->tailInputFill == conv->tailBlockSize) { -- 2.48.0