Normalize FFT magnitude to imitate WMP
Here's some Octave code that shows what I think should happen. I hope the syntax is self-explanatory:
%# First generate some test data
%# make a time domain waveform of sin + low level noise
N = 1024;
x = sin(2*pi*200.5*((0:1:(N-1))')/N) + 0.01*randn(N,1);
%# Now do the processing the way the visualizer should
%# first apply Hann window = 0.5*(1+cos)
xw = x.*hann(N, 'periodic');
%# Calculate FFT. Octave returns double sided spectrum
Sw = fft(xw);
%# Calculate the magnitude of the first half of the spectrum
Sw = abs(Sw(1:(1+N/2))); %# abs is sqrt(real^2 + imag^2)
%# For comparison, also calculate the unwindowed spectrum
Sx = fft(x)
Sx = abs(Sx(1:(1+N/2)));
subplot(2,1,1);
plot([Sx Sw]); %# linear axes, blue is unwindowed version
subplot(2,1,2);
loglog([Sx Sw]); %# both axes logarithmic
which results in the following graph: top: regular spectral plot, bottom: loglog spectral plot (blue is unwindowed) http://img710.imageshack.us/img710/3994/spectralplots.png
I'm letting Octave handle the scaling from linear to log x and y axes. Do you get something similar for a simple waveform like a sine wave?
OLD ANSWER
I'm not familiar with the visualizer you mention, but in general:
- Spectra are often displayed using a log y-axis (or colormap for spectrograms).
- Your FFT might be returning a double-sided spectrum, but you probably want to use only the first half (looks like you're doing already).
- Applying a window function to your time data makes the spectral peaks narrower by reducing leakage (looks like you're doing this too).
- You might need to divide by the transform blocksize if you're concerned with absolute magnitudes (I guess not important in your case).
- It looks like the Ocean Mist visualizer is using a log x-axis too. It might also be smoothing adjacent frequency bins in sets or something.
Normally for this kind of thing you want to convert your FFT output to a power spectrum, usually with a log (dB) amplitude scale, e.g. for a given output bin:
p = 10.0 * log10 (re * re + im * im);