filter-chain: implement convoler_reset

To reset the state of the convolver.
This commit is contained in:
Wim Taymans 2021-10-13 18:36:20 +02:00
parent 0d1f7be0e9
commit 6e818480c1
3 changed files with 73 additions and 26 deletions

View file

@ -691,6 +691,12 @@ static struct fc_port convolve_ports[] = {
}, },
}; };
static void convolver_deactivate(void * Instance)
{
struct convolver_impl *impl = Instance;
convolver_reset(impl->conv);
}
static void convolve_run(void * Instance, unsigned long SampleCount) static void convolve_run(void * Instance, unsigned long SampleCount)
{ {
struct convolver_impl *impl = Instance; struct convolver_impl *impl = Instance;
@ -705,6 +711,7 @@ static const struct fc_descriptor convolve_desc = {
.instantiate = convolver_instantiate, .instantiate = convolver_instantiate,
.connect_port = convolver_connect_port, .connect_port = convolver_connect_port,
.deactivate = convolver_deactivate,
.run = convolve_run, .run = convolve_run,
.cleanup = convolver_cleanup, .cleanup = convolver_cleanup,
}; };

View file

@ -61,21 +61,32 @@ struct convolver1 {
float scale; float scale;
}; };
static inline void fft_copy(void *dst, const void *src, int size)
{
memcpy(dst, src, size * sizeof(float));
}
static void fft_clear(void *data, int size)
{
memset(data, 0, size * sizeof(float));
}
static void *fft_alloc(int size) static void *fft_alloc(int size)
{ {
void *d; return pffft_aligned_malloc(size * sizeof(float));
d = pffft_aligned_malloc(size);
memset(d, 0, size);
return d;
} }
static void fft_free(void *data) static void fft_free(void *data)
{ {
pffft_aligned_free(data); pffft_aligned_free(data);
} }
static void fft_cpx_clear(struct fft_cpx *cpx, int size)
{
fft_clear(cpx->v, size * 2);
}
static void fft_cpx_init(struct fft_cpx *cpx, int size) static void fft_cpx_init(struct fft_cpx *cpx, int size)
{ {
cpx->v = fft_alloc(size * 2 * sizeof(float)); cpx->v = fft_alloc(size * 2);
} }
static void fft_cpx_free(struct fft_cpx *cpx) static void fft_cpx_free(struct fft_cpx *cpx)
@ -132,6 +143,19 @@ static inline void fft_sum(float *r, const float *a, const float *b,int len)
pffft_sum(a, b, r, len); pffft_sum(a, b, r, len);
} }
static void convolver1_reset(struct convolver1 *conv)
{
int i;
for (i = 0; i < conv->segCount; i++)
fft_cpx_clear(&conv->segments[i], conv->fftComplexSize);
fft_clear(conv->overlap, conv->blockSize);
fft_clear(conv->inputBuffer, conv->segSize);
fft_cpx_clear(&conv->pre_mult, conv->fftComplexSize);
fft_cpx_clear(&conv->conv, conv->fftComplexSize);
conv->inputBufferFill = 0;
conv->current = 0;
}
static struct convolver1 *convolver1_new(int block, const float *ir, int irlen) static struct convolver1 *convolver1_new(int block, const float *ir, int irlen)
{ {
struct convolver1 *conv; struct convolver1 *conv;
@ -162,7 +186,7 @@ static struct convolver1 *convolver1_new(int block, const float *ir, int irlen)
if (conv->ifft == NULL) if (conv->ifft == NULL)
return NULL; return NULL;
conv->fft_buffer = fft_alloc(sizeof(float) * conv->segSize); conv->fft_buffer = fft_alloc(conv->segSize);
if (conv->fft_buffer == NULL) if (conv->fft_buffer == NULL)
return NULL; return NULL;
@ -176,19 +200,18 @@ static struct convolver1 *convolver1_new(int block, const float *ir, int irlen)
fft_cpx_init(&conv->segments[i], conv->fftComplexSize); fft_cpx_init(&conv->segments[i], conv->fftComplexSize);
fft_cpx_init(&conv->segmentsIr[i], conv->fftComplexSize); fft_cpx_init(&conv->segmentsIr[i], conv->fftComplexSize);
memcpy(conv->fft_buffer, &ir[i * conv->blockSize], copy * sizeof(float)); fft_copy(conv->fft_buffer, &ir[i * conv->blockSize], copy);
if (copy < conv->segSize) if (copy < conv->segSize)
memset(conv->fft_buffer + copy, 0, (conv->segSize - copy) * sizeof(float)); fft_clear(conv->fft_buffer + copy, conv->segSize - copy);
fft_run(conv->fft, conv->fft_buffer, &conv->segmentsIr[i]); fft_run(conv->fft, conv->fft_buffer, &conv->segmentsIr[i]);
} }
fft_cpx_init(&conv->pre_mult, conv->fftComplexSize); fft_cpx_init(&conv->pre_mult, conv->fftComplexSize);
fft_cpx_init(&conv->conv, conv->fftComplexSize); fft_cpx_init(&conv->conv, conv->fftComplexSize);
conv->overlap = fft_alloc(sizeof(float) * conv->blockSize); conv->overlap = fft_alloc(conv->blockSize);
conv->inputBuffer = fft_alloc(sizeof(float) * conv->segSize); conv->inputBuffer = fft_alloc(conv->segSize);
conv->inputBufferFill = 0;
conv->current = 0;
conv->scale = 1.0f / conv->segSize; conv->scale = 1.0f / conv->segSize;
convolver1_reset(conv);
return conv; return conv;
} }
@ -217,7 +240,7 @@ static int convolver1_run(struct convolver1 *conv, const float *input, float *ou
int i, processed = 0; int i, processed = 0;
if (conv->segCount == 0) { if (conv->segCount == 0) {
memset(output, 0, len * sizeof(float)); fft_clear(output, len);
return len; return len;
} }
@ -225,10 +248,9 @@ 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 processing = SPA_MIN(len - processed, conv->blockSize - conv->inputBufferFill);
const int inputBufferPos = conv->inputBufferFill; const int inputBufferPos = conv->inputBufferFill;
memcpy(conv->inputBuffer + inputBufferPos, input + processed, processing * sizeof(float)); fft_copy(conv->inputBuffer + inputBufferPos, input + processed, processing);
if (inputBufferPos == 0 && processing < conv->blockSize) if (inputBufferPos == 0 && processing < conv->blockSize)
memset(conv->inputBuffer + processing, 0, fft_clear(conv->inputBuffer + processing, conv->blockSize - processing);
sizeof(float) * (conv->blockSize - processing));
fft_run(conv->fft, conv->inputBuffer, &conv->segments[conv->current]); fft_run(conv->fft, conv->inputBuffer, &conv->segments[conv->current]);
@ -274,7 +296,7 @@ static int convolver1_run(struct convolver1 *conv, const float *input, float *ou
if (conv->inputBufferFill == conv->blockSize) { if (conv->inputBufferFill == conv->blockSize) {
conv->inputBufferFill = 0; conv->inputBufferFill = 0;
memcpy(conv->overlap, conv->fft_buffer + conv->blockSize, conv->blockSize * sizeof(float)); fft_copy(conv->overlap, conv->fft_buffer + conv->blockSize, conv->blockSize);
conv->current = (conv->current > 0) ? (conv->current - 1) : (conv->segCount - 1); conv->current = (conv->current > 0) ? (conv->current - 1) : (conv->segCount - 1);
} }
@ -300,6 +322,24 @@ struct convolver
int precalculatedPos; int precalculatedPos;
}; };
void convolver_reset(struct convolver *conv)
{
if (conv->headConvolver)
convolver1_reset(conv->headConvolver);
if (conv->tailConvolver0) {
convolver1_reset(conv->tailConvolver0);
fft_clear(conv->tailOutput0, conv->tailBlockSize);
fft_clear(conv->tailPrecalculated0, conv->tailBlockSize);
}
if (conv->tailConvolver) {
convolver1_reset(conv->tailConvolver);
fft_clear(conv->tailOutput, conv->tailBlockSize);
fft_clear(conv->tailPrecalculated, conv->tailBlockSize);
}
conv->tailInputFill = 0;
conv->precalculatedPos = 0;
}
struct convolver *convolver_new(int head_block, int tail_block, const float *ir, int irlen) struct convolver *convolver_new(int head_block, int tail_block, const float *ir, int irlen)
{ {
struct convolver *conv; struct convolver *conv;
@ -331,22 +371,21 @@ struct convolver *convolver_new(int head_block, int tail_block, const float *ir,
if (irlen > conv->tailBlockSize) { if (irlen > conv->tailBlockSize) {
int conv1IrLen = SPA_MIN(irlen - conv->tailBlockSize, conv->tailBlockSize); int conv1IrLen = SPA_MIN(irlen - conv->tailBlockSize, conv->tailBlockSize);
conv->tailConvolver0 = convolver1_new(conv->headBlockSize, ir + conv->tailBlockSize, conv1IrLen); conv->tailConvolver0 = convolver1_new(conv->headBlockSize, ir + conv->tailBlockSize, conv1IrLen);
conv->tailOutput0 = fft_alloc(conv->tailBlockSize * sizeof(float)); conv->tailOutput0 = fft_alloc(conv->tailBlockSize);
conv->tailPrecalculated0 = fft_alloc(conv->tailBlockSize * sizeof(float)); conv->tailPrecalculated0 = fft_alloc(conv->tailBlockSize);
} }
if (irlen > 2 * conv->tailBlockSize) { if (irlen > 2 * conv->tailBlockSize) {
int tailIrLen = irlen - (2 * conv->tailBlockSize); int tailIrLen = irlen - (2 * conv->tailBlockSize);
conv->tailConvolver = convolver1_new(conv->tailBlockSize, ir + (2 * conv->tailBlockSize), tailIrLen); conv->tailConvolver = convolver1_new(conv->tailBlockSize, ir + (2 * conv->tailBlockSize), tailIrLen);
conv->tailOutput = fft_alloc(conv->tailBlockSize * sizeof(float)); conv->tailOutput = fft_alloc(conv->tailBlockSize);
conv->tailPrecalculated = fft_alloc(conv->tailBlockSize * sizeof(float)); conv->tailPrecalculated = fft_alloc(conv->tailBlockSize);
} }
if (conv->tailConvolver0 || conv->tailConvolver) if (conv->tailConvolver0 || conv->tailConvolver)
conv->tailInput = fft_alloc(conv->tailBlockSize * sizeof(float)); conv->tailInput = fft_alloc(conv->tailBlockSize);
conv->tailInputFill = 0; convolver_reset(conv);
conv->precalculatedPos = 0;
return conv; return conv;
} }
@ -400,7 +439,7 @@ int convolver_run(struct convolver *conv, const float *input, float *output, int
} }
conv->precalculatedPos += processing; conv->precalculatedPos += processing;
memcpy(conv->tailInput + conv->tailInputFill, input + processed, processing * sizeof(float)); fft_copy(conv->tailInput + conv->tailInputFill, input + processed, processing);
conv->tailInputFill += processing; conv->tailInputFill += processing;
if (conv->tailPrecalculated0 && (conv->tailInputFill % conv->headBlockSize == 0)) { if (conv->tailPrecalculated0 && (conv->tailInputFill % conv->headBlockSize == 0)) {

View file

@ -28,4 +28,5 @@
struct convolver *convolver_new(int block, int tail, const float *ir, int irlen); struct convolver *convolver_new(int block, int tail, const float *ir, int irlen);
void convolver_free(struct convolver *conv); void convolver_free(struct convolver *conv);
void convolver_reset(struct convolver *conv);
int convolver_run(struct convolver *conv, const float *input, float *output, int length); int convolver_run(struct convolver *conv, const float *input, float *output, int length);