DSP tutorial: Calculating FFT of a live source

This example records audio and periodically prints the dominant frequency of the recorded audio signal.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
public class AudioRecordFFT implements Runnable {
    private final static int SAMPLERATE = 8000;
    private final static int BUFFERSIZE = SAMPLERATE / 2;

    private TargetDataLine tdl;
    private DoubleFFT_1D fft;

    AudioRecordFFT(TargetDataLine tdl) {
        this.tdl = tdl;
    }

    private void calculateFFT(final double[] audioData, final int storedSamples) {
        // we need to initialize a buffer where we store our samples as complex numbers. first value is the real part, second is the imaginary.
        double[] fftData = new double[audioData.length*2];
        for (int i = 0; i < storedSamples; i++) {
            // copying audio data to the fft data buffer, imaginary part is 0
            fftData[2 * i] = audioData[i];
            fftData[2 * i + 1] = 0;
        }

        // calculating the fft of the data, so we will have spectral power of each frequency component
        fft.complexForward(fftData);

        int max_i = -1;
        double max_fftval = -1;
        for (int i = 0; i < fftData.length/2; i += 2) { // we are only looking at the half of the spectrum
            // complex numbers -> vectors, so we compute the length of the vector, which is sqrt(realpart^2+imaginarypart^2)
            double vlen = Math.sqrt(fftData[i] * fftData[i] + fftData[i + 1] * fftData[i + 1]);

            if (max_fftval < vlen && vlen > 0.1) {
                // if this length is bigger than our stored biggest length
                max_fftval = vlen;
                max_i = i;
            }
        }

        if (max_i < 0)
            max_fftval = max_i = 0;
        double dominantFreq = ((max_i) / (double)fftData.length) * SAMPLERATE;
        System.out.println("Dominant frequency: " + dominantFreq + "hz (bin no. " + max_i + ")");
    }

    @Override
    public void run() {
        byte[] abBuffer = new byte[tdl.getBufferSize()];
        double[] abBufferDouble = new double[abBuffer.length/2];

        fft = new DoubleFFT_1D(abBufferDouble.length);

        tdl.start();

        try {
            while (!Thread.interrupted()) {
                // waiting for the buffer to get filled
                while (tdl.available() < tdl.getBufferSize() * 0.5)
                    Thread.sleep(0, 1); // without this, the audio will be choppy
   
                int bytesRead = tdl.read(abBuffer, 0, tdl.available());
   
                // converting frames stored as bytes to double values
                int samplesRead = bytesRead/tdl.getFormat().getFrameSize();
                for (int i = 0; i < samplesRead; i++)
                    abBufferDouble[i] = ((abBuffer[i*2] & 0xFF) | (abBuffer[i*2 + 1] << 8)) / 32768.0;
   
                calculateFFT(abBufferDouble, samplesRead);
            }
        } catch (InterruptedException e) {
        }

        tdl.stop();
        tdl.close();
    }

    public static void main(String[] args) {
        AudioFormat audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, SAMPLERATE, 16, 1, 2, SAMPLERATE, false);
        DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat, BUFFERSIZE);

        TargetDataLine targetDataLine = null;
        try {
            targetDataLine = (TargetDataLine) AudioSystem.getLine(info);
            targetDataLine.open(audioFormat, BUFFERSIZE);
            System.out.println("Buffer size: " + targetDataLine.getBufferSize());
        } catch (LineUnavailableException e1) {
            e1.printStackTrace();
        }

        // creating the recorder thread from this class' instance
        AudioRecordFFT audioRecordFFT = new AudioRecordFFT(targetDataLine);
        Thread audioRecorderThread = new Thread(audioRecordFFT);

        // we use this to read line from the standard input
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        audioRecorderThread.setPriority(Thread.MAX_PRIORITY);
        audioRecorderThread.start();

        System.out.println("Recording... press ENTER to stop recording!");
        try {
            br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }

        audioRecorderThread.interrupt();

        try {
            // waiting for the recorder thread to stop
            audioRecorderThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Recording stopped.");
    }

}

download (849.2 kb)

Name (required)
E-mail (required - never shown publicly)
Webpage URL
Comment:
You may use <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> in your comment.

Trackback responses to this post

About me

Nonoo
I'm Nonoo. This is my blog about music, sounds, filmmaking, amateur radio, computers, programming, electronics and other things I'm obsessed with. ... »

Twitter

Listening now

My favorite artists