简体   繁体   中英

Using gdx Library and FFT to Calculate Frequency (Java)

I am currently using the gdx library com.badlogic.gdx.audio.analysis.FFT and the method:

private float[] fft(int N, int fs, float[] array) {
    float[] fft_cpx, tmpr, tmpi;
    float[] res = new float[N / 2];
    // float[] mod_spec =new float[array.length/2];
    float[] real_mod = new float[N];
    float[] imag_mod = new float[N];
    double[] real = new double[N];
    double[] imag = new double[N];
    double[] mag = new double[N];
    double[] phase = new double[N];
    float[] new_array = new float[N];
    // Zero Pad signal
    for (int i = 0; i < N; i++) {
        if (i < array.length) {
            new_array[i] = array[i];
        } 
        else {
            new_array[i] = 0;
        }
    }

    FFT fft = new FFT(N, 8000);

    fft.forward(new_array);
    fft_cpx = fft.getSpectrum();
    tmpi = fft.getImaginaryPart();
    tmpr = fft.getRealPart();
    for (int i = 0; i < new_array.length; i++) {
        real[i] = (double) tmpr[i];
        imag[i] = (double) tmpi[i];

        mag[i] = Math.sqrt((real[i] * real[i]) + (imag[i] * imag[i]));
        phase[i] = Math.atan2(imag[i], real[i]);

        /**** Reconstruction ****/
        real_mod[i] = (float) (mag[i] * Math.cos(phase[i]));
        imag_mod[i] = (float) (mag[i] * Math.sin(phase[i]));

    }
    fft.inverse(real_mod, imag_mod, res);
    return res;

}

How then do I use this method to find the frequency (and then note) of sound recorded from the microphone?

Your goal is to take all magnitudes of individual frequencies in mag[i] and to find the largest one. For start, you can just loop over them and find the maximum mag[i]. Then you have to recalculate it's corresponding frequency from i index.

Frequency is determined by this equation:

freq = i * Fs / N;

Where Fs is sampling frequency of your time domain data (input wave data), N - number of samples you did compute FFT from. i is the index of your frequency domain data (computed magnitudes and phases)

In your case you can add line like into your for cycle to debug it:

double freq = (double)i*(double)fs/(double)N;
System.out.println("Frequency: "+ Double.toString(freq) + "Magnitude: "+ Double.toString(mag[i]));

Check this link for more information: How to get frequency from fft result?

Nyquist theorem

... states that you can perfectly reconstruct frequencies only if you have twice the samples.... for reconstructing 1000Hz, you have to have at least 2000 samples per second. (Still this wave will be very distorted.).

If you have samplerate of 22000Hz, you would be able to somehow measure frequencies up to 11000Hz. Your data in mag and phase will be meaningful to the first half of array 0..N/2 , then, you'll see just a mirror image of previous data (see the link to wikipedia page for a picture.)

If you want to determine your N check this answer or google more. Try to start with arbitrary numbers like one tenth of samplerate fs. The larger N, the slower will be your algorithm.

Table of note frequencies

Simplest way is to make a table of all frequencies you will detect and then just compare your frequency with maximum magnitude to all frequencie values in table. With a small tolerance, for example +-2% of the value in table. Be sure those tolerances do not overlap for two consecutive notes.

Microphone input

Google up keywords like java microphone input library tutorial, or check this answer .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM