Sign in to follow this  
Concentrate

My FFT transformation is wrong?

Recommended Posts

The spectrum graph is definitely wrong. The sound being played is a simple drum sound, one drum bang. [url="http://www.youtube.com/watch?v=bVY7DIgN8G4"]Here is the video[/url]. I don't know why
the movie is speed up in that video.

Anyways here is the rundown of the code:
//sdl calls this function in conjunction to playing it
[code]
void effectProcessFunc(int ch, void *stream, int len, void *udata){
//calculate transformation via FFT
musicAnalyzer.transform(stream,len);
}
[/code]

So now the information is contained in musicAnalyzer class. Here is the rendering:
[code]
glBegin(GL_LINE_LOOP);
const ComplexArray& c = musicAnalyzer.getFFTCalculatedData();
for(size_t i = 0; i < c.size(); ++i){
const float db = 20.0f * std::log(magnitude(c[i][0],c[i][1]));
const float mag = std::max(0.0f,db)/100;
std::cout << mag << "\n";
//glVertex3f(i,0,0);
glVertex3f(i,mag,0.0f);
}
glEnd();
[/code]


Here is the transform function,
[code]
void MusicAnalyzer::transform(const void *sample,const int length){
const char * sampleChunk = reinterpret_cast<const char *>(sample);
_currentSample = TimeDomainArray(length);
const double scaleFactor = 65536;
for(int i = 0; i < length; i += 4){
//sum the channels for now
double leftChannel = to16BitLSB<double>(sampleChunk[i],sampleChunk[i+1]);
double rightChannel = to16BitLSB<double>(sampleChunk[i+2],sampleChunk[i+3]);
double scaledSum = (leftChannel + rightChannel)/(scaleFactor);
//std::cout << i << " : " << sum << endl;
_currentSample[i] = scaledSum;
}
//apply fft on current sample data
_applyFFT();
}
[/code]
and the _applyFFT()
[code]
void MusicAnalyzer::_applyFFT(){
//apply windowing function
_windowFunc->apply(&_currentSample[0] ,&_currentSample[_currentSample.size()]);
//applying 1D real input outputs N/2 + 1, according to the fftw3.2.2 documentation
const int OUTPUT_SIZE = _currentSample.size()/2 + 1;
//setup output data if not created already
if(_frequencyDomainData.isEmpty()) _frequencyDomainData = ComplexArray(OUTPUT_SIZE);
//setup FFT algorithm if not setup already
if(!_fftwPlan) _fftwPlan = fftw_plan_dft_r2c_1d(_currentSample.size(), &_currentSample[0],_frequencyDomainData.getArray(),FFTW_MEASURE);
//check for valid setup
if(!_fftwPlan){ std::cout << "Error: Couldn't create plan\n"; return;}
//execute FFT
fftw_execute(_fftwPlan);

}
[/code]

[code]
const ComplexArray& MusicAnalyzer::getFFTCalculatedData()const{
return _frequencyDomainData;
}
[/code]

can advice? I'm kinda confused right now. Thanks.

EDIT: to get a better view at the video, please download it from [url="http://www.2shared.com/video/4eweCV92/CM_Movie_1.html"]here[/url]

Share this post


Link to post
Share on other sites
Have you set up the coordinate system so that you have a reasonable scale? Looks like the X-axis is way too small, and the Y-axis way large, to map the spectrum to the screen in some reasonable way. Why are you capping the magnitude below 0 dB? Why are you drawing it as a line loop and not a line strip? You probably don't want the first and the last point to connect.

Share this post


Link to post
Share on other sites
Thanks for the tip. After the adjustment this is what I have now. You can download it [url="http://www.2shared.com/video/fyN-bsmG/CM_Movie_1.html"]here[/url] or view it at youtube [url="http://www.youtube.com/watch?v=P3grS2DrzPs"]here[/url]. I don't know why youtube keeps speeding up the video 2x faster. Anyways, here is the render loop,
[code]
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode(GL_MODELVIEW); //Switch to the drawing perspective
glLoadIdentity();
gluLookAt(0,0,20, 0,0,-5, 0,1,0);

//draw graph axis

glColor3f(1.0f,0.0f,0.0f);
glTranslatef(-20,0,0);
glBegin(GL_LINE_STRIP);
const ComplexArray& c = musicAnalyzer.getFFTCalculatedData();
for(size_t i = 0; i < c.size(); ++i){
float mag = magnitude(c[i][0],c[i][1]);
if(mag > 0.0f){
const float db = 20.0f * std::log(mag);
mag = db/100;//std::max(0.0f,db)/100;
}
glVertex3f(i,mag,0.0f);
std::cout <<mag << "\n";
}
glEnd();

SDL_GL_SwapBuffers();
return true;
[/code]

and most of the other things are the same. I don't know exactly if the output is correct?

Share this post


Link to post
Share on other sites
You still haven't commented on whether the coordinate system is properly set up to show the spectrum. I still claim that the Y-axis is too large and the X-axis is too small to see the spectrum properly. A simple orthographic projection with lower and upper limits on both the X- and Y-axis is all you need. You know the limits along the X-axis, and the Y-axis can be determined by the range of the values you commonly expect to get from the magnitude.

Share this post


Link to post
Share on other sites
[b] You know the limits along the X-axis, and the Y-axis can be determined by the range of the values you commonly expect to get from the magnitude.[/b]

I'm not sure how exactly to go about this. Any advice?

Share this post


Link to post
Share on other sites
The X-axis is very trivial; just look at what you pass as the X-coordinate. The Y-axis is also trivial; keep track of the smallest and largest magnitude calculated. I would guess the Y-coordinates should be from -80 to +20 dB. Only you have access to the spectrum values, so only you can determine the approximate range of the magnitude, so just examine the magnitude values, or just make some trial an error by adjusting the coordinate range. A good start should be the range I mentioned.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this