0
votes

In short

I am trying to make an equalizer in C++. I must process the audio in blocks of (usually) 256 samples. I use an FFT to obtain the spectrum of the sample block. I process the frequencies and then use an IFFT to obtain the processed audio block in the time-domain. I am using the code provided in the related question: FFT in a single C-file.

For a low-pass filter, setting the lower coefficients to zero should remove the low frequencies. However, in the processed audio, I get a changed spectrum, rather than a low-pass filter (the audio contains a buzzing sound).

I have read the following related articles:

Am I doing something incorrectly? Is the block size too small to obtain a reasonable frequency resolution?

I am familiar with the mathematics of the Fourier transform. However, I do not know the details of the FFT and IFFT transforms. It is possible that the provided code is not implemented correctly. However, when the FFT is done and then an IFFT on the result of the FFT, the original audio block is correctly reconstructed.

Details

I am writing a VST and am doing all the processing in the processReplacing() method. This is why I am constrained by the block size.

My idea is to keep last n blocks in memory and calculate the FFT on the last n blocks to obtain a higher frequency resolution, then do the processing on these frequencies, and after the IFFT, replace only the last block.

Are there any suggestions on whether this is a correct way of implementing an equalizer?

2
Have you considered doing your filtering in the time domain? That's how most audio software does it, and with good reason. The advantages of time domain include (to oversimplify): lower latency, more efficient processing, smoother frequency response (depending on the filter type you choose), pre-echo free time-domain response, and generally mimicking the characteristics of analog audio filters. Here's a great resource: musicdsp.org/en/latest/Filters/197-rbj-audio-eq-cookbook.html and an explanation I wrote: blog.bjornroche.com/2012/08/basic-audio-eqs.htmlBjorn Roche

2 Answers

4
votes

Let me guess (since you left out the relevant information) : you have a decently high sample rate, say 44000 samples/second. That means your blocks are only 6 milliseconds, or in other words your block frequency is 171 Hz. That is perfectly audible.

So, the problem isn't so much that your frequency resolution is too low, you have far too many blocks per second.

The deeper question is why those blocks cause a buzz. There's also a simple answer to that: you're doing a FFT on a time-bound signal. The Fourier Transform in math applies to an infinite signal, which in the practical FFT is approximated by an infinite repetition of your 256 sample block. But the last sample of the block doesn't line up with the first; there will be a jump. That jump therefore occurs 171 timers per second, and that is a buzz sound.

2
votes

At least 3 problems:

First, the way to filter out frequencies in NOT to zero out FFT bins. See this answer for more information: https://dsp.stackexchange.com/questions/6220/why-is-it-a-bad-idea-to-filter-by-zeroing-out-fft-bins/6224#6224

Second, after you compute the length of the impulse response of your desired filter response, you have to zero-pad your FFT by at least that additional length, and then use overlap-add or overlap-save (fast convolution algorithms) to combine your IFFT results, instead of just concatenating them.

Third, 256 samples at a 44.1 kHz sample rate isn't enough to fit even 1 full period of any pitch below 170 Hz. So, yes, low frequency resolution will be limited by your chosen block size. Whether or not this is reasonable depends on your requirements for frequency response.

FFT/IFFT fast convolution is one common way to do DSP equalization if you have an equalization curve with a long impulse response, sufficient compute resource/power/cycles, and do not mind some block size related latency.