in pedalboard/juce_overrides/juce_BlockingConvolution.cpp [195:282]
void processSamplesWithAddedLatency(const float *input, float *output,
size_t numSamples) {
// Overlap-add, zero latency convolution algorithm with uniform partitioning
size_t numSamplesProcessed = 0;
auto indexStep = numInputSegments / numSegments;
auto *inputData = bufferInput.getWritePointer(0);
auto *outputTempData = bufferTempOutput.getWritePointer(0);
auto *outputData = bufferOutput.getWritePointer(0);
auto *overlapData = bufferOverlap.getWritePointer(0);
while (numSamplesProcessed < numSamples) {
auto numSamplesToProcess =
jmin(numSamples - numSamplesProcessed, blockSize - inputDataPos);
FloatVectorOperations::copy(inputData + inputDataPos,
input + numSamplesProcessed,
static_cast<int>(numSamplesToProcess));
FloatVectorOperations::copy(output + numSamplesProcessed,
outputData + inputDataPos,
static_cast<int>(numSamplesToProcess));
numSamplesProcessed += numSamplesToProcess;
inputDataPos += numSamplesToProcess;
// processing itself when needed (with latency)
if (inputDataPos == blockSize) {
// Copy input data in input segment
auto *inputSegmentData =
buffersInputSegments[currentSegment].getWritePointer(0);
FloatVectorOperations::copy(inputSegmentData, inputData,
static_cast<int>(fftSize));
fftObject->performRealOnlyForwardTransform(inputSegmentData);
prepareForConvolution(inputSegmentData);
// Complex multiplication
FloatVectorOperations::fill(outputTempData, 0,
static_cast<int>(fftSize + 1));
auto index = currentSegment;
for (size_t i = 1; i < numSegments; ++i) {
index += indexStep;
if (index >= numInputSegments)
index -= numInputSegments;
convolutionProcessingAndAccumulate(
buffersInputSegments[index].getWritePointer(0),
buffersImpulseSegments[i].getWritePointer(0), outputTempData);
}
FloatVectorOperations::copy(outputData, outputTempData,
static_cast<int>(fftSize + 1));
convolutionProcessingAndAccumulate(
inputSegmentData, buffersImpulseSegments.front().getWritePointer(0),
outputData);
updateSymmetricFrequencyDomainData(outputData);
fftObject->performRealOnlyInverseTransform(outputData);
// Add overlap
FloatVectorOperations::add(outputData, overlapData,
static_cast<int>(blockSize));
// Input buffer is empty again now
FloatVectorOperations::fill(inputData, 0.0f, static_cast<int>(fftSize));
// Extra step for segSize > blockSize
FloatVectorOperations::add(&(outputData[blockSize]),
&(overlapData[blockSize]),
static_cast<int>(fftSize - 2 * blockSize));
// Save the overlap
FloatVectorOperations::copy(overlapData, &(outputData[blockSize]),
static_cast<int>(fftSize - blockSize));
currentSegment = (currentSegment > 0) ? (currentSegment - 1)
: (numInputSegments - 1);
inputDataPos = 0;
}
}
}