java - Android FFT后值全为0

标签 java android audio fft

目前我正在尝试对使用 AudioRecord 收集的音频数据执行 FFT。我的问题是 FFT 后每个值都是 0。我不知道为什么。

我正在使用以下代码进行 FFT(来自 FFT library in android Sdk )。样本数量是偶数! (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;
              }
          }
      }
  }
}

这是计算频率的代码:

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");
        }

不幸的是我对FFT不太了解。我可以想象从short[]到double[]的转换是错误的或者完整的FFT本身是错误的。我希望有人能帮助我。

如果您想尝试,您可以在下面找到完整的代码:

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;
    }
}

最佳答案

您的输入均为 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);

关于java - Android FFT后值全为0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21414210/

相关文章:

java - 如何修复 “This web container has not yet been started” + javax.ejb.EJBException

java - 删除非字母数字但保留拉丁字符

android - 关闭应用程序后保存对象并在应用程序再次运行时检索它

java - 适用于 Android 的随机数学问题生成器

google-chrome - 音频下载链接在 Firefox 中有效,但在 Chrome 中流式传输

java - Java 8 Stream 中的 forEach 与 forEachOrdered

java - 复制的文件已损坏

android - 解释顶级 gradle 文件的新格式

javascript - 修改此node.js代码以输出.wav而不是.mp4?

c# - 对象被销毁时 audio.play() 不工作