# FFTW audio artifacts when modifying magnitudes in frequency domain

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 :

 //Before FFT, read samples

// Move read cursor by fft_len / hop_factor
sf_seek(infile, passed, SF_SEEK_SET);
passed += fft_len / hop_factor;

• FFT/IFFT
// 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);
fftw_execute(forward);
// process my offt buffer with filtering or something else
// Then copy it in ifft buffer

// IFFT
fftw_execute(backward);
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 !

• 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. – Marcus Müller Sep 12 '20 at 15:57
• 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 ? – Philiste Sep 12 '20 at 16:21
• 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. – Marcus Müller Sep 12 '20 at 16:56
• See the fifth-most-voted-for question on this site: dsp.stackexchange.com/questions/6220/… – Marcus Müller Sep 12 '20 at 16:56
• (FFTw assumes your data is symmetrical, and only uses one half of it.) – Marcus Müller Sep 12 '20 at 17:01