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
This commit is contained in:
Wim Taymans 2024-12-03 15:43:56 +01:00
parent e42de413e8
commit 8d9269374d

View file

@ -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) {