FFT - Frequency detection doesn't seem to work correctly

Viewed 17

I finally have a working FFT implemented, but the frequency doesn't seem to work correctly. For example, while playing a musical instrument, the notes give (somewhat) consistent but random frequency values (a "C" on my alto sax gives a 602Hz and an "E" gives a 387hz, should be ~312 and ~397 respectively, at least according to an app I have) Here's the code:

public static void main(final String[] args) throws Exception {
    final AudioFormat format = new AudioFormat(
            AudioFormat.Encoding.PCM_SIGNED,
            44100,
            16,
            1,
            2,
            44100,
            false
    );

    final DataLine.Info info = new DataLine.Info(
            TargetDataLine.class,
            format
    );

    final TargetDataLine targetLine = (TargetDataLine) AudioSystem.getLine(info);
    targetLine.open();
    targetLine.start();

    final AudioInputStream audioInputStream = new AudioInputStream(targetLine);

    final byte[] buf = new byte[1024];
    final int numberOfSamples = buf.length / format.getFrameSize();
    final JavaFFT fft = new JavaFFT(numberOfSamples);

    while (true) {
        audioInputStream.read(buf);

        final float[] samples = decode(buf, format);
        final float[][] transformed = fft.transform(samples);
        final float[] real = transformed[0];
        final float[] imaginary = transformed[1];
        final double[] magnitudes = toMagnitudes(real, imaginary);

        // do something with magnitudes

        printDetectedIndex(magnitudes);
    }
}


private static void printDetectedIndex(double[] magnitudes) {
    int index = maxIndex(magnitudes);
    float frequency = (float) index * 44100 / 1024;
    int fInt = (int) frequency; // remove decimal part
    System.out.println("Frequency: " + frequency + "Hz (" + fInt + "Hz)");
}

// function to return index of the largest element in array
public static int maxIndex(double[] array) {
    int maxIndex = 9;
    for (int i = 9; i < array.length; i++) {
        if (array[i] > array[maxIndex]) {
            maxIndex = i;
        }
    }
    return maxIndex;
}

Any help would be much appreciated!

0 Answers
Related