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;
- 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 !