PDA

View Full Version : More help with FFT


metalhobo
04-17-2010, 10:41 PM
Sorry for being such a noob, but I really need some help with WDL fft.

From what I have gathered, if you do a complex DFT with N samples on a function with a defined real part in the time domain and with the time imaginary part zero, in the frequency domain you get the spectrum data in bins 0 through N/2 of both the real and imaginary parts (they are equal, I think) with the frequency of the bins from 0 to N/2 equal to the sample rate times the bin number divided by the FFT size. The bins N/2+1 to N-1 represent the negative frequency spectrum, and for the real part N/2+1 is equal to N/2-1, all the way to N-1 being equal to bin 1.

Using this info which I'm not positively sure of, I tried doing some processing but get no output.

WDL_fft_init();
WDL_fft(fftbuffer, fftbuffersize, false);
//---------------------------------------


//--
for(int p = 0; p < fftbuffersize; p++) //make quieter
{
fftbuffer[p].re /= (fftbuffersize);
fftbuffer[p].im /= (fftbuffersize);
}
//--



for(int x = 0; x <= fftbuffersize/2; x++)
{
double F = (GetSampleRate() * (x)) / (fftbuffersize);
fftbuffer[x].re *= (10.46 + 20 * log10(.00008885*F + 12.601/F - (.04292)*sqrt(F) + (.05472)*(log (F))*(log (F)) - .8933));
fftbuffer[x].im *= (10.46 + 20 * log10(.00008885*F + 12.601/F - (.04292)*sqrt(F) + (.05472)*(log (F))*(log (F)) - .8933));
}

for(int x = fftbuffersize/2 + 1; x < fftbuffersize; x++)
{
double F = (GetSampleRate() * (fftbuffersize-x)) / (fftbuffersize);
fftbuffer[x].re *= (10.46 + 20 * log10(.00008885*F + 12.601/F - (.04292)*sqrt(F) + (.05472)*(log (F))*(log (F)) - .8933));
fftbuffer[x].im *= (10.46 + 20 * log10(.00008885*F + 12.601/F - (.04292)*sqrt(F) + (.05472)*(log (F))*(log (F)) - .8933));
}

//---------------------------------------
WDL_fft(fftbuffer, fftbuffersize, true);

The long function of F is just a equalization curve I'm trying to implement.

metalhobo
04-22-2010, 08:32 PM
Nobody, huh?

cc_
04-23-2010, 12:53 AM
I haven't used the wdl fft, I guess what I'd check is: does it work just doing an fft then ifft? Is the scaling step needed? Does it work with a much simpler frequency curve (eg a straight line)?

metalhobo
04-23-2010, 03:08 PM
I haven't used the wdl fft, I guess what I'd check is: does it work just doing an fft then ifft? Is the scaling step needed? Does it work with a much simpler frequency curve (eg a straight line)?

Yes, straight up doing the fft then inverse works perfectly, but it adds about 30 dB gain. Using the scaling statement subsequently works perfectly in attaining unity gain. It's only the curve that causes it to not work.

I think trying it with a simpler curve might be a good idea, thanks.

metalhobo
04-23-2010, 10:47 PM
Update:

I think I figured out that I need to permute the FFT'd buffer before I apply the EQ function and then I need to un-permute it before I do the inverse FFT, something like this (I think, but I'm really taking a pretty wild guess here):


WDL_fft_init();
WDL_fft(fftbuffer, fftbuffersize, false);

for (int i = 0; i < fftbuffersize; i++)
{
int j = WDL_fft_permute(fftbuffersize, i);
sortedbuffer[i].re = fftbuffer[j].re;
sortedbuffer[i].im = fftbuffer[j].im;
}

//do processing on sortedbuffer here


for (int i = 0; i < fftbuffersize; i++)
{
int j = WDL_fft_permute(fftbuffersize, i);
unsortedbuffer[j].re = sortedbuffer[i].re;
unsortedbuffer[j].im = sortedbuffer[i].im;
}

WDL_fft(unsortedbuffer, fftbuffersize, true);



That seems to get me good output, but the simple eq curves I try and apply don't work exactly I would hope, although I do get intact output unlike before.

The question I want to ask to those who are knowledgeable on specifically the WDL FFT program is how the frequencies are sorted after permuting. Like are the positive freqs from bins 0 to fftsize/2 - 1, then the negative freqs mirrored after that? Or are the negative freqs completely disregarded? Moreover, how come the frequencies aren't in the right order to begin with? The whole permutation thing is kind of confusing for me, I'm sorry.

metalhobo
04-23-2010, 11:10 PM
Alright, I think I actually got it. From what I have gathered, the pos freqs go from 0 to N/2 where N = fftsize. That means that the pos freqs have 2 more bins than the neg freqs, which go from N/2 + 1 to N - 1.

Here's an example I did of a hard high-pass, which is located where the "//do processing on sortedbuffer here" is in the previous code segment:

for(int x = 0; x <= fftbuffersize/2; x++)
{
double F = (GetSampleRate() * (x)) / (fftbuffersize);
if(F < 1000){
sortedbuffer[x].re = 0;
sortedbuffer[x].im = 0;
}
}


for(int x = fftbuffersize/2 + 1; x < fftbuffersize; x++) //Neg freqs
{
sortedbuffer[x].re = sortedbuffer[fftbuffersize - x].re;
sortedbuffer[x].im = -1 * sortedbuffer[fftbuffersize - x].im;
}


This seems to work!

Kind of.

The filter works great and the signal sounds intact except for some strange clicking going on intermittently. It's not what I would call loud clicking, but it is quite annoying. Anyone know what's up?

Perhaps the clicking is just due to the incredibly primitive way of filtering, but one can never be too sure, lol

One more thing: is it okay to just copy the positive freqs to the negative side of the buffer like I did, or should I actually do the processing on the negative side?



edit: Working with my complicated EQ function I was initially trying to implement, I am an idiot. Initially I was multiplying the FT'd signal by the gain in DB when I should have been multiplying by the amplitude ratio :facepalm: Moreover, with the log for certain values I was trying to take the log of a negative value which is why it wasn't getting any output. Stupid mistakes. Got that squared away now, though.

The new curve does work great but I still get that annoying clicking. It has me really confused.

Xenakios
04-25-2010, 09:58 AM
I still get that annoying clicking. It has me really confused.

I just started playing with FFT processing myself today. Your posts above helped me a bit in understanding how the WDL FFT routines must be used, thanks!

Your clicking problem is likely because you are not doing pre FFT and post inverse FFT window enveloping. I got the filtering working without clicks by implementing that in my code. Unfortunately the enveloping makes the code much more complex, because you must for example have 2 streams of FFT processing happening. (Because the FFT buffer windowing makes the sound change in volume periodically, 2 signal streams must be done in appropriate sync and mixed together so that the end result is a continuous non-"tremolo" sound.)

My code currently does the processing quite naively, as I was just testing, and isn't suitable for use in a "realtime" environment. I can post the code I did if you'd like, but you would probably have to rewrite all the logic to work inside a VST plugin environment. Hopefully the tip about gain enveloping the FFT buffers helps you a bit.

edit : there's by the way a JesuSonic plugin included in Reaper called fft-filter, perhaps studying it's source code will be useful.