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 <wtaymans@redhat.com>
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 <math.h>
 
 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

