Calculate FFT from audio file

raisa_ picture raisa_ · Jul 10, 2013 · Viewed 21.1k times · Source

Before, I asked question about Get frequency wav audio using FFT and Complex class ,

There, I need to calculate FFT value from AudioRecord input --> from microphone , I somehow managed to get the FFT value...

Now I need to calculate FFT value from *.wav audio file that I saved before, I saved the audio in 'raw' folder inside 'res' folder from my project

I still using the same FFT Class: http://www.cs.princeton.edu/introcs/97data/FFT.java

The complex class to go with it: http://introcs.cs.princeton.edu/java/97data/Complex.java.html

I use this method to read audio file from my raw foldern, then I call method calculateFFT to go with it

private static final int RECORDER_BPP = 16;
  private static final int RECORDER_SAMPLERATE = 44100;
  private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_STEREO;
  private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;


private void asli(){

            int counter = 0;
            int data;
            InputStream inputStream  = getResources().openRawResource(R.raw.b1);
            DataInputStream dataInputStream = new DataInputStream(inputStream);
            List<Integer> content = new ArrayList<Integer>(); 

            try {
                while ((data = dataInputStream.read()) != -1) {
                    content.add(data);
                    counter++; }
            } catch (IOException e) {
                e.printStackTrace();}

                int[] b = new int[content.size()];
                int cont = 0;
                byte[] audio = convertArray(b);
        }

Method to convert to byte

public byte[] convertArray(int[] array) { 

            int minBufferSize = AudioTrack.getMinBufferSize(RECORDER_SAMPLERATE,RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING);
                AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,RECORDER_SAMPLERATE,RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING,minBufferSize, AudioTrack.MODE_STREAM);

        byte[] newarray = new byte[array.length];
        for (int i = 0; i < array.length; i++) {
        newarray[i] = (byte) ((array[i]) & 0xFF);       }

            absNormalizedSignal = calculateFFT(newarray);
            return newarray;
        }

And this is the CalculateFFT method

public double[] calculateFFT(byte[] signal)
        {           
            final int mNumberOfFFTPoints =1024;
            double mMaxFFTSample;
            double temp;
            Complex[] y;
            Complex[] complexSignal = new Complex[mNumberOfFFTPoints];
            double[] absSignal = new double[mNumberOfFFTPoints/2];

            for(int i = 0; i < mNumberOfFFTPoints; i++){
                temp = (double)((signal[2*i] & 0xFF) | (signal[2*i+1] << 8)) / 32768.0F;
                complexSignal[i] = new Complex(temp,0.0);
            }

            y = FFT.fft(complexSignal);

            mMaxFFTSample = 0.0;
            mPeakPos = 0;
            for(int i = 0; i < (mNumberOfFFTPoints/2); i++)
            {
                 absSignal[i] = Math.sqrt(Math.pow(y[i].re(), 2) + Math.pow(y[i].im(), 2));
                 if(absSignal[i] > mMaxFFTSample)
                 {
                     mMaxFFTSample = absSignal[i];
                     mPeakPos = i;
                 } 
            }

            return absSignal;

        }

I used this CalculateFFT method too to process audio from AudioRecorder --> that one with microphone input before... I managed to get value from the AudioRecorder, but I failed to get value from my audio file... I'm not planning to play the audio.. I just need to process it with FFT.

Is there any wrong with my code ?? :o Seems like I fail at getting value from method Asli(); But I dont know which part is wrong..

Any help would be appreciated... :) Thanks

Answer

Nicholas DiPiazza picture Nicholas DiPiazza · Sep 29, 2014

I spent a better part of the morning coding a solution for this using bits and pieces of FFT java snippets I was finding... but then I stumbled upon this amazingly wondeful google code project that has a bunch of util classes for doing signal processing tasks on WAV and MP3 files alike.

https://github.com/Uriopass/audio-analysis Formerly SVN export was on Google code here: https://storage.googleapis.com/google-code-archive-source/v2/code.google.com/audio-analysis/source-archive.zip

It now becomes INSANELY easy:

WaveDecoder decoder = new WaveDecoder(new FileInputStream(wavFile));
FFT fft = new FFT(1024, wavFileObj.getSampleRate());

Now you can use the fft object to do various calculations. They have a bunch of great examples, such as generating a List containing the spectral flux:

    float[] samples = new float[1024];
    float[] spectrum = new float[1024 / 2 + 1];
    float[] lastSpectrum = new float[1024 / 2 + 1];
    List<Float> spectralFlux = new ArrayList<Float>();

    while (decoder.readSamples(samples) > 0) {
        fft.forward(samples);
        System.arraycopy(spectrum, 0, lastSpectrum, 0, spectrum.length);
        System.arraycopy(fft.getSpectrum(), 0, spectrum, 0, spectrum.length);

        float flux = 0;
        for (int i = 0; i < spectrum.length; i++)
            flux += (spectrum[i] - lastSpectrum[i]);
        spectralFlux.add(flux);
    }

My company needed a way for me to analyze some audio to see if some expected hold music had happened. So first I generated a WAV file for an example that did have the hold music. Then I captured some audio of one of thee examples that did not have the hold music. Now all that is left is to average up the spectral flux of the wav and I'm set.

Note: I could not have simply taken amplitudes... but the fourier transformation has frequencies that I could correctly use to make my comparison.

I love math.