convolver: convolver1 -> partition

This commit is contained in:
Wim Taymans 2026-04-16 16:12:33 +02:00
parent d4b472d2e5
commit 37b648a3e0

View file

@ -10,7 +10,7 @@
#include <math.h>
struct convolver1 {
struct partition {
int blockSize;
int segSize;
int segCount;
@ -42,48 +42,48 @@ static int next_power_of_two(int val)
return r;
}
static void convolver1_reset(struct spa_fga_dsp *dsp, struct convolver1 *conv)
static void partition_reset(struct spa_fga_dsp *dsp, struct partition *part)
{
int i;
for (i = 0; i < conv->segCount; i++)
spa_fga_dsp_fft_memclear(dsp, conv->segments[i], conv->fftComplexSize, false);
spa_fga_dsp_fft_memclear(dsp, conv->fft_buffer[0], conv->segSize, true);
spa_fga_dsp_fft_memclear(dsp, conv->fft_buffer[1], conv->segSize, true);
spa_fga_dsp_fft_memclear(dsp, conv->inputBuffer, conv->segSize, true);
spa_fga_dsp_fft_memclear(dsp, conv->pre_mult, conv->fftComplexSize, false);
spa_fga_dsp_fft_memclear(dsp, conv->conv, conv->fftComplexSize, false);
conv->inputBufferFill = 0;
conv->current = 0;
for (i = 0; i < part->segCount; i++)
spa_fga_dsp_fft_memclear(dsp, part->segments[i], part->fftComplexSize, false);
spa_fga_dsp_fft_memclear(dsp, part->fft_buffer[0], part->segSize, true);
spa_fga_dsp_fft_memclear(dsp, part->fft_buffer[1], part->segSize, true);
spa_fga_dsp_fft_memclear(dsp, part->inputBuffer, part->segSize, true);
spa_fga_dsp_fft_memclear(dsp, part->pre_mult, part->fftComplexSize, false);
spa_fga_dsp_fft_memclear(dsp, part->conv, part->fftComplexSize, false);
part->inputBufferFill = 0;
part->current = 0;
}
static void convolver1_free(struct spa_fga_dsp *dsp, struct convolver1 *conv)
static void partition_free(struct spa_fga_dsp *dsp, struct partition *part)
{
int i;
for (i = 0; i < conv->segCount; i++) {
if (conv->segments)
spa_fga_dsp_fft_memfree(dsp, conv->segments[i]);
if (conv->segmentsIr)
spa_fga_dsp_fft_memfree(dsp, conv->segmentsIr[i]);
for (i = 0; i < part->segCount; i++) {
if (part->segments)
spa_fga_dsp_fft_memfree(dsp, part->segments[i]);
if (part->segmentsIr)
spa_fga_dsp_fft_memfree(dsp, part->segmentsIr[i]);
}
if (conv->fft)
spa_fga_dsp_fft_free(dsp, conv->fft);
if (conv->ifft)
spa_fga_dsp_fft_free(dsp, conv->ifft);
if (conv->fft_buffer[0])
spa_fga_dsp_fft_memfree(dsp, conv->fft_buffer[0]);
if (conv->fft_buffer[1])
spa_fga_dsp_fft_memfree(dsp, conv->fft_buffer[1]);
free(conv->segments);
free(conv->segmentsIr);
spa_fga_dsp_fft_memfree(dsp, conv->pre_mult);
spa_fga_dsp_fft_memfree(dsp, conv->conv);
spa_fga_dsp_fft_memfree(dsp, conv->inputBuffer);
free(conv);
if (part->fft)
spa_fga_dsp_fft_free(dsp, part->fft);
if (part->ifft)
spa_fga_dsp_fft_free(dsp, part->ifft);
if (part->fft_buffer[0])
spa_fga_dsp_fft_memfree(dsp, part->fft_buffer[0]);
if (part->fft_buffer[1])
spa_fga_dsp_fft_memfree(dsp, part->fft_buffer[1]);
free(part->segments);
free(part->segmentsIr);
spa_fga_dsp_fft_memfree(dsp, part->pre_mult);
spa_fga_dsp_fft_memfree(dsp, part->conv);
spa_fga_dsp_fft_memfree(dsp, part->inputBuffer);
free(part);
}
static struct convolver1 *convolver1_new(struct spa_fga_dsp *dsp, int block, const float *ir, int irlen)
static struct partition *partition_new(struct spa_fga_dsp *dsp, int block, const float *ir, int irlen)
{
struct convolver1 *conv;
struct partition *part;
int i;
if (block == 0)
@ -92,139 +92,139 @@ static struct convolver1 *convolver1_new(struct spa_fga_dsp *dsp, int block, con
while (irlen > 0 && fabs(ir[irlen-1]) < 0.000001f)
irlen--;
conv = calloc(1, sizeof(*conv));
if (conv == NULL)
part = calloc(1, sizeof(*part));
if (part == NULL)
return NULL;
if (irlen == 0)
return conv;
return part;
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;
part->blockSize = next_power_of_two(block);
part->segSize = 2 * part->blockSize;
part->segCount = (irlen + part->blockSize-1) / part->blockSize;
part->fftComplexSize = (part->segSize / 2) + 1;
conv->fft = spa_fga_dsp_fft_new(dsp, conv->segSize, true);
if (conv->fft == NULL)
part->fft = spa_fga_dsp_fft_new(dsp, part->segSize, true);
if (part->fft == NULL)
goto error;
conv->ifft = spa_fga_dsp_fft_new(dsp, conv->segSize, true);
if (conv->ifft == NULL)
part->ifft = spa_fga_dsp_fft_new(dsp, part->segSize, true);
if (part->ifft == NULL)
goto error;
conv->fft_buffer[0] = spa_fga_dsp_fft_memalloc(dsp, conv->segSize, true);
conv->fft_buffer[1] = spa_fga_dsp_fft_memalloc(dsp, conv->segSize, true);
if (conv->fft_buffer[0] == NULL || conv->fft_buffer[1] == NULL)
part->fft_buffer[0] = spa_fga_dsp_fft_memalloc(dsp, part->segSize, true);
part->fft_buffer[1] = spa_fga_dsp_fft_memalloc(dsp, part->segSize, true);
if (part->fft_buffer[0] == NULL || part->fft_buffer[1] == NULL)
goto error;
conv->segments = calloc(conv->segCount, sizeof(float*));
conv->segmentsIr = calloc(conv->segCount, sizeof(float*));
if (conv->segments == NULL || conv->segmentsIr == NULL)
part->segments = calloc(part->segCount, sizeof(float*));
part->segmentsIr = calloc(part->segCount, sizeof(float*));
if (part->segments == NULL || part->segmentsIr == NULL)
goto error;
for (i = 0; i < conv->segCount; i++) {
int left = irlen - (i * conv->blockSize);
int copy = SPA_MIN(conv->blockSize, left);
for (i = 0; i < part->segCount; i++) {
int left = irlen - (i * part->blockSize);
int copy = SPA_MIN(part->blockSize, left);
conv->segments[i] = spa_fga_dsp_fft_memalloc(dsp, conv->fftComplexSize, false);
conv->segmentsIr[i] = spa_fga_dsp_fft_memalloc(dsp, conv->fftComplexSize, false);
if (conv->segments[i] == NULL || conv->segmentsIr[i] == NULL)
part->segments[i] = spa_fga_dsp_fft_memalloc(dsp, part->fftComplexSize, false);
part->segmentsIr[i] = spa_fga_dsp_fft_memalloc(dsp, part->fftComplexSize, false);
if (part->segments[i] == NULL || part->segmentsIr[i] == NULL)
goto error;
spa_fga_dsp_copy(dsp, conv->fft_buffer[0], &ir[i * conv->blockSize], copy);
if (copy < conv->segSize)
spa_fga_dsp_fft_memclear(dsp, conv->fft_buffer[0] + copy, conv->segSize - copy, true);
spa_fga_dsp_copy(dsp, part->fft_buffer[0], &ir[i * part->blockSize], copy);
if (copy < part->segSize)
spa_fga_dsp_fft_memclear(dsp, part->fft_buffer[0] + copy, part->segSize - copy, true);
spa_fga_dsp_fft_run(dsp, conv->fft, 1, conv->fft_buffer[0], conv->segmentsIr[i]);
spa_fga_dsp_fft_run(dsp, part->fft, 1, part->fft_buffer[0], part->segmentsIr[i]);
}
conv->pre_mult = spa_fga_dsp_fft_memalloc(dsp, conv->fftComplexSize, false);
conv->conv = spa_fga_dsp_fft_memalloc(dsp, conv->fftComplexSize, false);
conv->inputBuffer = spa_fga_dsp_fft_memalloc(dsp, conv->segSize, true);
if (conv->pre_mult == NULL || conv->conv == NULL || conv->inputBuffer == NULL)
part->pre_mult = spa_fga_dsp_fft_memalloc(dsp, part->fftComplexSize, false);
part->conv = spa_fga_dsp_fft_memalloc(dsp, part->fftComplexSize, false);
part->inputBuffer = spa_fga_dsp_fft_memalloc(dsp, part->segSize, true);
if (part->pre_mult == NULL || part->conv == NULL || part->inputBuffer == NULL)
goto error;
conv->scale = 1.0f / conv->segSize;
convolver1_reset(dsp, conv);
part->scale = 1.0f / part->segSize;
partition_reset(dsp, part);
return conv;
return part;
error:
convolver1_free(dsp, conv);
partition_free(dsp, part);
return NULL;
}
static int convolver1_run(struct spa_fga_dsp *dsp, struct convolver1 *conv, const float *input, float *output, int len)
static int partition_run(struct spa_fga_dsp *dsp, struct partition *part, const float *input, float *output, int len)
{
int i, processed = 0;
if (conv == NULL || conv->segCount == 0) {
if (part == NULL || part->segCount == 0) {
spa_fga_dsp_fft_memclear(dsp, output, len, true);
return len;
}
int inputBufferFill = conv->inputBufferFill;
int inputBufferFill = part->inputBufferFill;
while (processed < len) {
const int processing = SPA_MIN(len - processed, conv->blockSize - inputBufferFill);
const int processing = SPA_MIN(len - processed, part->blockSize - inputBufferFill);
spa_fga_dsp_copy(dsp, conv->inputBuffer + inputBufferFill, input + processed, processing);
if (inputBufferFill == 0 && processing < conv->blockSize)
spa_fga_dsp_fft_memclear(dsp, conv->inputBuffer + processing,
conv->blockSize - processing, true);
spa_fga_dsp_fft_run(dsp, conv->fft, 1, conv->inputBuffer, conv->segments[conv->current]);
spa_fga_dsp_copy(dsp, part->inputBuffer + inputBufferFill, input + processed, processing);
if (inputBufferFill == 0 && processing < part->blockSize)
spa_fga_dsp_fft_memclear(dsp, part->inputBuffer + processing,
part->blockSize - processing, true);
spa_fga_dsp_fft_run(dsp, part->fft, 1, part->inputBuffer, part->segments[part->current]);
if (conv->segCount > 1) {
if (part->segCount > 1) {
if (inputBufferFill == 0) {
int indexAudio = conv->current;
int indexAudio = part->current;
if (++indexAudio == conv->segCount)
if (++indexAudio == part->segCount)
indexAudio = 0;
spa_fga_dsp_fft_cmul(dsp, conv->fft, conv->pre_mult,
conv->segmentsIr[1],
conv->segments[indexAudio],
conv->fftComplexSize, conv->scale);
spa_fga_dsp_fft_cmul(dsp, part->fft, part->pre_mult,
part->segmentsIr[1],
part->segments[indexAudio],
part->fftComplexSize, part->scale);
for (i = 2; i < conv->segCount; i++) {
if (++indexAudio == conv->segCount)
for (i = 2; i < part->segCount; i++) {
if (++indexAudio == part->segCount)
indexAudio = 0;
spa_fga_dsp_fft_cmuladd(dsp, conv->fft,
conv->pre_mult,
conv->pre_mult,
conv->segmentsIr[i],
conv->segments[indexAudio],
conv->fftComplexSize, conv->scale);
spa_fga_dsp_fft_cmuladd(dsp, part->fft,
part->pre_mult,
part->pre_mult,
part->segmentsIr[i],
part->segments[indexAudio],
part->fftComplexSize, part->scale);
}
}
spa_fga_dsp_fft_cmuladd(dsp, conv->fft,
conv->conv,
conv->pre_mult,
conv->segments[conv->current],
conv->segmentsIr[0],
conv->fftComplexSize, conv->scale);
spa_fga_dsp_fft_cmuladd(dsp, part->fft,
part->conv,
part->pre_mult,
part->segments[part->current],
part->segmentsIr[0],
part->fftComplexSize, part->scale);
} else {
spa_fga_dsp_fft_cmul(dsp, conv->fft,
conv->conv,
conv->segments[conv->current],
conv->segmentsIr[0],
conv->fftComplexSize, conv->scale);
spa_fga_dsp_fft_cmul(dsp, part->fft,
part->conv,
part->segments[part->current],
part->segmentsIr[0],
part->fftComplexSize, part->scale);
}
spa_fga_dsp_fft_run(dsp, conv->ifft, -1, conv->conv, conv->fft_buffer[0]);
spa_fga_dsp_fft_run(dsp, part->ifft, -1, part->conv, part->fft_buffer[0]);
spa_fga_dsp_sum(dsp, output + processed, conv->fft_buffer[0] + inputBufferFill,
conv->fft_buffer[1] + conv->blockSize + inputBufferFill, processing);
spa_fga_dsp_sum(dsp, output + processed, part->fft_buffer[0] + inputBufferFill,
part->fft_buffer[1] + part->blockSize + inputBufferFill, processing);
inputBufferFill += processing;
if (inputBufferFill == conv->blockSize) {
if (inputBufferFill == part->blockSize) {
inputBufferFill = 0;
SPA_SWAP(conv->fft_buffer[0], conv->fft_buffer[1]);
SPA_SWAP(part->fft_buffer[0], part->fft_buffer[1]);
if (conv->current == 0)
conv->current = conv->segCount;
conv->current--;
if (part->current == 0)
part->current = part->segCount;
part->current--;
}
processed += processing;
}
conv->inputBufferFill = inputBufferFill;
part->inputBufferFill = inputBufferFill;
return len;
}
@ -233,11 +233,11 @@ struct convolver
struct spa_fga_dsp *dsp;
int headBlockSize;
int tailBlockSize;
struct convolver1 *headConvolver;
struct convolver1 *tailConvolver0;
struct partition *headPartition;
struct partition *tailPartition0;
float *tailOutput0;
float *tailPrecalculated0;
struct convolver1 *tailConvolver;
struct partition *tailPartition;
float *tailOutput;
float *tailPrecalculated;
float *tailInput;
@ -248,15 +248,15 @@ void convolver_reset(struct convolver *conv)
{
struct spa_fga_dsp *dsp = conv->dsp;
if (conv->headConvolver)
convolver1_reset(dsp, conv->headConvolver);
if (conv->tailConvolver0) {
convolver1_reset(dsp, conv->tailConvolver0);
if (conv->headPartition)
partition_reset(dsp, conv->headPartition);
if (conv->tailPartition0) {
partition_reset(dsp, conv->tailPartition0);
spa_fga_dsp_fft_memclear(dsp, conv->tailOutput0, conv->tailBlockSize, true);
spa_fga_dsp_fft_memclear(dsp, conv->tailPrecalculated0, conv->tailBlockSize, true);
}
if (conv->tailConvolver) {
convolver1_reset(dsp, conv->tailConvolver);
if (conv->tailPartition) {
partition_reset(dsp, conv->tailPartition);
spa_fga_dsp_fft_memclear(dsp, conv->tailOutput, conv->tailBlockSize, true);
spa_fga_dsp_fft_memclear(dsp, conv->tailPrecalculated, conv->tailBlockSize, true);
}
@ -291,31 +291,31 @@ struct convolver *convolver_new(struct spa_fga_dsp *dsp, int head_block, int tai
conv->tailBlockSize = next_power_of_two(tail_block);
head_ir_len = SPA_MIN(irlen, conv->tailBlockSize);
conv->headConvolver = convolver1_new(dsp, conv->headBlockSize, ir, head_ir_len);
if (conv->headConvolver == NULL)
conv->headPartition = partition_new(dsp, conv->headBlockSize, ir, head_ir_len);
if (conv->headPartition == NULL)
goto error;
if (irlen > conv->tailBlockSize) {
int conv1IrLen = SPA_MIN(irlen - conv->tailBlockSize, conv->tailBlockSize);
conv->tailConvolver0 = convolver1_new(dsp, conv->headBlockSize, ir + conv->tailBlockSize, conv1IrLen);
conv->tailPartition0 = partition_new(dsp, conv->headBlockSize, ir + conv->tailBlockSize, conv1IrLen);
conv->tailOutput0 = spa_fga_dsp_fft_memalloc(dsp, conv->tailBlockSize, true);
conv->tailPrecalculated0 = spa_fga_dsp_fft_memalloc(dsp, conv->tailBlockSize, true);
if (conv->tailConvolver0 == NULL || conv->tailOutput0 == NULL ||
if (conv->tailPartition0 == NULL || conv->tailOutput0 == NULL ||
conv->tailPrecalculated0 == NULL)
goto error;
}
if (irlen > 2 * conv->tailBlockSize) {
int tailIrLen = irlen - (2 * conv->tailBlockSize);
conv->tailConvolver = convolver1_new(dsp, conv->tailBlockSize, ir + (2 * conv->tailBlockSize), tailIrLen);
conv->tailPartition = partition_new(dsp, conv->tailBlockSize, ir + (2 * conv->tailBlockSize), tailIrLen);
conv->tailOutput = spa_fga_dsp_fft_memalloc(dsp, conv->tailBlockSize, true);
conv->tailPrecalculated = spa_fga_dsp_fft_memalloc(dsp, conv->tailBlockSize, true);
if (conv->tailConvolver == NULL || conv->tailOutput == NULL ||
if (conv->tailPartition == NULL || conv->tailOutput == NULL ||
conv->tailPrecalculated == NULL)
goto error;
}
if (conv->tailConvolver0 || conv->tailConvolver) {
if (conv->tailPartition0 || conv->tailPartition) {
conv->tailInput = spa_fga_dsp_fft_memalloc(dsp, conv->tailBlockSize, true);
if (conv->tailInput == NULL)
goto error;
@ -333,12 +333,12 @@ void convolver_free(struct convolver *conv)
{
struct spa_fga_dsp *dsp = conv->dsp;
if (conv->headConvolver)
convolver1_free(dsp, conv->headConvolver);
if (conv->tailConvolver0)
convolver1_free(dsp, conv->tailConvolver0);
if (conv->tailConvolver)
convolver1_free(dsp, conv->tailConvolver);
if (conv->headPartition)
partition_free(dsp, conv->headPartition);
if (conv->tailPartition0)
partition_free(dsp, conv->tailPartition0);
if (conv->tailPartition)
partition_free(dsp, conv->tailPartition);
spa_fga_dsp_fft_memfree(dsp, conv->tailOutput0);
spa_fga_dsp_fft_memfree(dsp, conv->tailPrecalculated0);
spa_fga_dsp_fft_memfree(dsp, conv->tailOutput);
@ -351,7 +351,7 @@ int convolver_run(struct convolver *conv, const float *input, float *output, int
{
struct spa_fga_dsp *dsp = conv->dsp;
convolver1_run(dsp, conv->headConvolver, input, output, length);
partition_run(dsp, conv->headPartition, input, output, length);
if (conv->tailInput) {
int processed = 0;
@ -374,7 +374,7 @@ int convolver_run(struct convolver *conv, const float *input, float *output, int
if (conv->tailPrecalculated0 && (conv->tailInputFill % conv->headBlockSize == 0)) {
int blockOffset = conv->tailInputFill - conv->headBlockSize;
convolver1_run(dsp, conv->tailConvolver0,
partition_run(dsp, conv->tailPartition0,
conv->tailInput + blockOffset,
conv->tailOutput0 + blockOffset,
conv->headBlockSize);
@ -385,7 +385,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(dsp, conv->tailConvolver, conv->tailInput,
partition_run(dsp, conv->tailPartition, conv->tailInput,
conv->tailOutput, conv->tailBlockSize);
}
if (conv->tailInputFill == conv->tailBlockSize)