I'm currently working with FFT (FFTW3) that I'm using to apply treatments on audio files frequencies.

The Forward/Backward test is passed, since I can get the exact same soundfile when processing IFFT. So I assume my implementation is clean.

The thing for which I'm not an expert is to treat data then. For example, I have tried to implement a really naive filter to remove some of the frequencies in the sound. It is simply written like this :

int fft_buf_size = fft_len / 2 + 1
for(int i = 0; i < fft_buf_size; i++) 
  int freq = i * (sample_rate / fft_len);
  if(freq > 50 && freq < 400) {
    fft_buf[i][0] = 0.0;
    fft_buf[i][1] = 0.0;

This seems to process successfully the treatment, buf it does generate artifacts after IFFT. I have tried windowing samples before FFT and unwindowing after FFT (which seems pretty useless) with Hamming method.

Last thing I tried is to overlap my windows (with hop factor of 2 or 3), which seemed to me to be the best way not to produce those artifacts. But, it only changes the artifacts periods, as those artifacts are correlated to the fft length (window size) too.

The overlap/windowing system is done like this :

  • First reading
 //Before FFT, read samples

 // Move read cursor by fft_len / hop_factor
 sf_seek(infile, passed, SF_SEEK_SET);
 sf_readf_double(infile, buffer, fft_len);
 passed += fft_len / hop_factor;
// initialisation of the fftw plans
 fftw_plan forward = fftw_plan_dft_r2c_1d(fft_len, inbuf, offt, FFTW_ESTIMATE);
 fftw_plan backward = fftw_plan_dft_c2r_1d(fft_len, ifft, obuf, FFTW_ESTIMATE);

// After each read with sndfile, I process buffers by channels
for(int ch = 0; ch < number_of_channels; ch++) {
  for(int i = 0; i < fft_len; i++) 
     inbuf[i] = buffer[i * number_of_channels + ch] * hamming(i, fft_len);
  // process my offt buffer with filtering or something else
  // Then copy it in ifft buffer

  // IFFT
  for(int i = 0; i < fft_len; i++) 
   buffer[i * number_of_channels + ch] = outbuf[i] / hamming(i, fft_len);
  • Then writing
 //After IFFT, write samples
 int overlap_size = (fft_len * number_of_channels) / hop_factor;
 int overlap_index = (fft_len * number_of_channels) - overlap_size;

  // sum with overlap buffer
 for(int i = 0; i < overlap_size; i++) {
  buffer[i] += overlap_buffer[overlap_index + i];
 // then copy buffer for next overlapping
 std::copy(buffer.begin(), buffer.end(), overlap_buffer.data());

  // Move write cursor to read_cursor position
 sf_seek(outfile, passed, SF_SEEK_SET);
 sf_write_double(outfile, buffer, fft_len * number_of_channels);

Am I doing something wrong, or didn't I figure the way to avoid those artefacts ?

I'm still not an FFT expert, so some of the common uses may be missing. Thanks !

  • $\begingroup$ so, you don't tell us about the most important part: what is the processing you do in frequency domain? Does it preserve the symmetry of the frequency-domain signal? Otherwise, the inverse transform isn't real. $\endgroup$ Sep 12 '20 at 15:57
  • $\begingroup$ The only thing I do in frequency domain is setting some values to 0 as described in the first code block. And since r2c dft outputs in an array or complexe of size fft_len/2 +1 I assumed the symetry was managed by fftw. Is that the point I'm wrong about ? $\endgroup$
    – Philiste
    Sep 12 '20 at 16:21
  • $\begingroup$ but which values? Again, you break symmetry, your time-domain signal can't be real-valued anymore. Also, regarding setting values in the frequency domain to zero: Usually a bad idea. $\endgroup$ Sep 12 '20 at 16:56
  • $\begingroup$ See the fifth-most-voted-for question on this site: dsp.stackexchange.com/questions/6220/… $\endgroup$ Sep 12 '20 at 16:56
  • $\begingroup$ (FFTw assumes your data is symmetrical, and only uses one half of it.) $\endgroup$ Sep 12 '20 at 17:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.