Question

My goal is to be able to process a single note from a guitar (or other instrument), and convert it into a frequency value.

This does not have to be in real time- I figured it would be much easier to record a one-second sound and analyse the data afterwards.

I understand that to do this I need to use a Fourier transform (and have a class that will perform a FFT). However, I don't really understand the input / output of a FFT algorithm- the class I am using seems to use a complex vector input and give a complex vector output. What do these represent?

Also, could anyone recommend any Java classes that can detect and record an input (and if possible, give frequency or values that can be plugged into FFT?)?

Thanks in advance.

Was it helpful?

Solution

Input to your FFT will be a time-domain signal representing the audio. If you record some sound for a second from the mic, this will really contain a wave that is made up of various frequencies at different amounts - hopefully mostly the frequency/frequencies corresponding to the note which you are playing, plus some outside noise and noise introduced by the microphone and electronics. If in that 1 second you happen to have, say, 512 time points (so the mic can sample at 512 times a second), then each of those time points represents the intensity picked up by the mic. These sound intensity values can be turned from their time-domain representation to a frequency-domain representation using the FFT.

If you now give this to the FFT, as it is a real-valued input, you will get a symmetric complex output (symmetric around the central value) and can ignore the second half of the complex vector output and use only the first half - i.e. the second half will be symmetric (and thus "identical") to the first half. The output represents the contributions of each frequency to the input waveform - in essence, each "bin" or array index contains information about that frequency's amplitude. To extract the amplitude you want to do:

magnitudeFFTData[i] = Math.sqrt((real * real) + (imaginary * imaginary));

where real and imaginary are the real and imaginary parts of the complex number at that frequency bin. To get the frequency corresponding to a given bin, you need the following:

frequency = i * Fs / N;

where i is bin or array index number, Fs the sampling frequency and N the number of data points. From a project of mine wherein I recently used the FFT:

for (int i = (curPersonFFTData.length / 64); i < (curPersonFFTData.length / 40); i++) {
            double rr = (curPersonFFTData[i].getReal());
            double ri = (curPersonFFTData[i].getImaginary());

            magnitudeCurPersonFFTData[i] = Math.sqrt((rr * rr) + (ri * ri));
            ds.addValue(magnitudeCurPersonFFTData[i]);
        }

The divisions by 64 and 40 are arbitrary and useful for my case only, to only get certain frequency components, as opposed to all frequencies, which you might want. You can easily do all this in real time.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top