Benedikt Bock
Benedikt Bock

Reputation: 1027

Android Values are all 0 after FFT

currently i am trying to perform an FFT on AudioData collected with AudioRecord. My Problem is that every Value is 0 after the FFT. I have no idea why.

I am using the Following code for the FFT (from FFT library in android Sdk). The number of samples is even! (8192)

public class FFT {

  int n, m;

  // Lookup tables. Only need to recompute when size of FFT changes.
  double[] cos;
  double[] sin;

  public FFT(int n) {
      this.n = n;
      this.m = (int) (Math.log(n) / Math.log(2));

      // Make sure n is a power of 2
      if (n != (1 << m))
          throw new RuntimeException("FFT length must be power of 2");

      // precompute tables
      cos = new double[n / 2];
      sin = new double[n / 2];

      for (int i = 0; i < n / 2; i++) {
          cos[i] = Math.cos(-2 * Math.PI * i / n);
          sin[i] = Math.sin(-2 * Math.PI * i / n);
      }

  }

  public void fft(double[] x, double[] y) {
      int i, j, k, n1, n2, a;
      double c, s, t1, t2;

      // Bit-reverse
      j = 0;
      n2 = n / 2;
      for (i = 1; i < n - 1; i++) {
          n1 = n2;
          while (j >= n1) {
              j = j - n1;
              n1 = n1 / 2;
          }
          j = j + n1;

          if (i < j) {
              t1 = x[i];
              x[i] = x[j];
              x[j] = t1;
              t1 = y[i];
              y[i] = y[j];
              y[j] = t1;
          }
      }

      // FFT
      n1 = 0;
      n2 = 1;

      for (i = 0; i < m; i++) {
          n1 = n2;
          n2 = n2 + n2;
          a = 0;

          for (j = 0; j < n1; j++) {
              c = cos[a];
              s = sin[a];
              a += 1 << (m - i - 1);

              for (k = j; k < n; k = k + n2) {
                  t1 = c * x[k + n1] - s * y[k + n1];
                  t2 = s * x[k + n1] + c * y[k + n1];
                  x[k + n1] = x[k] - t1;
                  y[k + n1] = y[k] - t2;
                  x[k] = x[k] + t1;
                  y[k] = y[k] + t2;
              }
          }
      }
  }
}

This is the code to calculate the Frequency:

private void writeToScreen()
        {
            while(isRecording)
            {
                double[] y = new double[bufferSize];

                for (int i = 0; i < y.length; i++) {
                    y[i]=0;
                }

                double[] x = new double[bufferSize];
                //short[] to double[]
                for (int i = 0; i < x.length; i++) 
                {
                    x[i]= audioBuffer[i]/32768;
                }

                //perform fft
                fft meinfft = new fft(bufferSize);
                meinfft.FFT(x, y);


                        System.out.println("Alle Werte x und y nach FFT:");
                        for (int i = 0; i < x.length; i++) { //Every Value is 0.0
                            if(x[i] != 0 || y[i] != 0)
                            System.out.println("x["+i+"]: "+ x[i] +" y["+i+"]: "+y[i]);
                        }
                        System.out.println("Ende Aller Werte");

                // calculate index of max Value
                int maxIndex =0;
                for (int i = 1; i < x.length; i++) {
                    if(Math.sqrt(x[i]*x[i]+y[i]*y[i]) > Math.sqrt(x[maxIndex]*x[maxIndex]+y[maxIndex]*y[maxIndex]) )
                    {
                        maxIndex = i;
                    }
                }
                System.out.println("Index des Maximums: "+maxIndex);

                double freq = ((1.0 * sampleRate) / (1.0 * bufferSize)) * maxIndex; //Frequency is always 0
                System.out.println("wahrscheinliche Frequenz: "+freq);

                try
                {
                    Thread.sleep(1000);
                }
                catch (InterruptedException e)
                {}
            }
            System.out.println("Writethread beendet");
        }

Unfortunately i dosn't know very much about FFT. I could imagine that the Transformation from short[] to double[] is wrong or the complete FFT itself. I hope someone can help me.

If you want to try you'll find the complete code below:

import java.io.IOException;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.LinearLayout;
import android.widget.TextView;
//import android.os.Bundle;
import android.os.Environment;
import android.view.ViewGroup;
import android.widget.Button;
import android.view.View;
import android.view.View.OnClickListener;
import android.content.Context;
import android.util.Log;
import android.media.MediaRecorder;
import android.media.MediaPlayer;
import de.benediktbock.fft.fft;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder.AudioSource;
import java.io.IOException;


public class MainActivity extends Activity {
    private static final String LOG_TAG = "FFTTEST";
    private PlayButton   mPlayButton = null;
    private TextView    realTeil = null;
    private TextView    imgTeil = null;
    private fft         mFFT = null; 

    private int channel_config = AudioFormat.CHANNEL_IN_MONO;
    private int format = AudioFormat.ENCODING_PCM_16BIT;
    private int sampleRate = 8000;
    private int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channel_config, format);
    private AudioRecord audioInput = null; //new AudioRecord(AudioSource.MIC, sampleSize, channel_config, format, bufferSize);
    private short[] audioBuffer = new short[bufferSize];
    private Thread readingThread = null,writingThread=null;
    private boolean isRecording = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        LinearLayout ll = new LinearLayout(this);
        mPlayButton = new PlayButton(this);

        ll.addView(mPlayButton,new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT,
                0));

        realTeil = new TextView(this);
        ll.addView(realTeil,new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT,
                0));

        imgTeil = new TextView(this);
        ll.addView(imgTeil,new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT,
                0));
        setContentView(ll);

        realTeil.setText("Realteil");
        imgTeil.setText("Imaginärteil");


    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    class PlayButton extends Button {
        boolean mStartPlaying = true;

        OnClickListener clicker = new OnClickListener() {
            public void onClick(View v) {
                onPlay(mStartPlaying);
                if (mStartPlaying) {
                    setText("Stop");
                } else {
                    setText("Start");
                }
                mStartPlaying = !mStartPlaying;
            }
        };

        public PlayButton(Context ctx) {
            super(ctx);
            setText("Start");
            setOnClickListener(clicker);
        }
    }

    private void onPlay(boolean start) {
        if (start) {
            startRecording();
        } else {
            stopRecording();
        }

    }

    private void startRecording()
    {
        audioInput = new AudioRecord(AudioSource.MIC, sampleRate, channel_config, format, bufferSize);


        audioInput.startRecording();
        isRecording = true;
        readingThread = new Thread(new Runnable() 
            {
                @Override
                public void run() 
                {
                    readAudioToBuffer();
                }
            },"readAudio Thread");

        readingThread.start();

        writingThread = new Thread(new Runnable() 
        {
            @Override
            public void run() 
            {
                writeToScreen();
            }
        },"write Thread");

        writingThread.start();
    }
    private void writeToScreen()
    {
        while(isRecording)
        {
            double[] y = new double[bufferSize];

            for (int i = 0; i < y.length; i++) {
                y[i]=0;
            }

            double[] x = new double[bufferSize];
            //short[] to double[]
            for (int i = 0; i < x.length; i++) 
            {
                x[i]= audioBuffer[i]/32768;
            }

            //perform fft
            fft meinfft = new fft(bufferSize);
            meinfft.FFT(x, y);


                    System.out.println("Alle Werte x und y nach FFT:");
                    for (int i = 0; i < x.length; i++) { //Every Value is 0.0
                        if(x[i] != 0 || y[i] != 0)
                        System.out.println("x["+i+"]: "+ x[i] +" y["+i+"]: "+y[i]);
                    }
                    System.out.println("Ende Aller Werte");

            // calculate index of max Value
            int maxIndex =0;
            for (int i = 1; i < x.length; i++) {
                if(Math.sqrt(x[i]*x[i]+y[i]*y[i]) > Math.sqrt(x[maxIndex]*x[maxIndex]+y[maxIndex]*y[maxIndex]) )
                {
                    maxIndex = i;
                }
            }
            System.out.println("Index des Maximums: "+maxIndex);

            double freq = ((1.0 * sampleRate) / (1.0 * bufferSize)) * maxIndex; //Frequency is always 0
            System.out.println("wahrscheinliche Frequenz: "+freq);

            try
            {
                Thread.sleep(1000);
            }
            catch (InterruptedException e)
            {}
        }
        System.out.println("Writethread beendet");
    }

    private void readAudioToBuffer()
    {
        while(isRecording)
        {
            audioInput.read(audioBuffer, 0,bufferSize);
        }

        System.out.println("Thread wurde beendet");

    }

    private void stopRecording()
    {
        isRecording = false;
        audioInput.stop();
        audioInput.release();
        audioInput= null;
        readingThread = null;
    }
}

Upvotes: 0

Views: 281

Answers (1)

Chris Stratton
Chris Stratton

Reputation: 40407

Your inputs are all 0.

short s = 32767;
double d = s/32768;
System.out.println("dividing a short yields a truncated result " + d);
d = (double) s / 32768;
System.out.println("casting to a double and then dividing yields " + d);

Upvotes: 1

Related Questions