# How does minimum-latency partitioned convolution reverb work when you receive input samples in chunks, rather than one at a time?

I'm writing a reverb system where I receive an input block of samples 480 elements long, do some operation on them, and pass the block on to the next effect.

I've been reading up on partitioned convolution reverb, and it seems to operate on the principle that you just accumulate samples until you have enough to convolve a short block of the impulse while the rest of the input comes in, getting bigger and bigger every chunk. How does this work if I can only start working on the input once it's all accumulated? How do convolution reverb plugins in DAWs work with this limitation (buffer sizes are usually lower, but never single-sample)?

For example, my impulse is 16384 samples long. I partition it into 480 + 32, then 480 + 64, 480 + 128, 480 + 256 (rounded up to 1024), etc. All the partitions add up to a length longer than it would have been if I'd just done 16384 + 480 samples (rounded up to 32768).

In my specific case, the source audio is a sample being played back at variable speed so I guess I could apply the reverb as each sample is being added to the buffer or even bake the reverb if I don't mind the room characteristics shifting with the pitch, but I'd like to understand how others do it first.

This is typically done using a segmented overlap add method or sometimes also refered to as a block convolver.

Let's assume your block size if 512 (makes the numbers a little easier).

1. Chop up your impulse response into 32 blocks of 512 samples each. Zero pad each block to 1024 samples and FFT. You know have 32 filters $$H_0(z) ... H_{31}(z)$$
2. On each new input block: zero pad to 1024 samples and FFT. Keep the most recent 32 signal spectra around, so you have $$X_N(z), X_{N-1}, ... X_{N-31}(z)$$
3. Multiply the spectra and sum them, $$Y(z) = \sum_{k=0}^{31} H_k(z) \cdot X_{N-k}(z)$$
4. Inverse FFT the result: you get 1024 time samples. The last 512 are the "overlap". Store for the next block.
5. Take the first 512 samples of your inverse FFT and add the overlap from the previous block. That's your output.

Repeat steps 2-5 for each new block.

• Thanks! The papers I read say this incurs a latency of N samples, but I'm guessing I was already incurring that latency by processing everything in blocks anyways?
– Ott
Commented Sep 17, 2019 at 1:09
• Depends on what you mean by "N". If you do block based processing, you always incur at least one block of latency no matter what you do. This algorithm doesn't incur more or less latency than any other algorithm that is done block based Commented Sep 17, 2019 at 16:20
• Okay, so I've got everything set up, but I'm getting this ugly glitch every buffer. I thought at first that it was because I wasn't trimming off the second half of the inverse fft (circular convolution...) and doing that seems to have made the effect more pronounced (though I'm pretty sure that's the correct thing to do). Could it be that I need to be using a smooth windowing function or something? Here's an audio clip of a 440hz sine ping being convolved with a 32 sample triangle from 0 to 1: we.tl/t-KM0RUbRLBg
– Ott
Commented Sep 19, 2019 at 1:49
• No window necessary if you handle the overlap correctly and properly zero pad. You need to add the the second half from IFFT buffer N-1 to the first half of buffer IFFT buffer N. Read up on "overlap add" convolution Commented Sep 20, 2019 at 14:08
• @Hilmar this answer was very helpful to me to implement uniformly partitioned convolution. However no I want to make my convolution more efficient by using a non-uniformly partitioned algorithm. I would like to use 2 different block sizes: a short one for the earliest samples, and a longer block size for the reverb tail. Could you provide similar steps? Commented Mar 18 at 11:41