【问题标题】:android getting sound frequencies real time?android实时获取声音频率?
【发布时间】:2013-12-18 22:11:16
【问题描述】:

我一直在尝试使用 fft 实时获取声音频率(数字),但我遇到了运行时错误。有人可以帮忙吗?

package com.example.recordsound;

import edu.emory.mathcs.jtransforms.fft.DoubleFFT_1D;

import ca.uol.aig.fftpack.RealDoubleFFT;

public class MainActivity extends Activity implements OnClickListener{

int audioSource = MediaRecorder.AudioSource.MIC;    // Audio source is the device MIC
int channelConfig = AudioFormat.CHANNEL_IN_MONO;    // Recording in mono
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; // Records in 16bit

private DoubleFFT_1D fft;                           // The fft double array
private RealDoubleFFT transformer;
int blockSize = 256;                               // deal with this many samples at a time
int sampleRate = 8000;                             // Sample rate in Hz
public double frequency = 0.0;                      // the frequency given

RecordAudio recordTask;                             // Creates a Record Audio command
TextView tv;                                        // Creates a text view for the frequency
boolean started = false;
Button startStopButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    tv = (TextView)findViewById(R.id.textView1);  
    startStopButton= (Button)findViewById(R.id.button1);
}

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


private class RecordAudio extends AsyncTask<Void, Double, Void>{
    @Override
    protected Void doInBackground(Void... params){      

        /*Calculates the fft and frequency of the input*/
        //try{
            int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioEncoding);                // Gets the minimum buffer needed
            AudioRecord audioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, audioEncoding, bufferSize);   // The RAW PCM sample recording



            short[] buffer = new short[blockSize];          // Save the raw PCM samples as short bytes

          //  double[] audioDataDoubles = new double[(blockSize*2)]; // Same values as above, as doubles
       //   ----------------------------------------------- 
            double[] re = new double[blockSize];
            double[] im = new double[blockSize];
            double[] magnitude = new double[blockSize];
       //   ----------------------------------------------------
            double[] toTransform = new double[blockSize];

            tv.setText("Hello");
           // fft = new DoubleFFT_1D(blockSize);


            try{
            audioRecord.startRecording();  //Start
            }catch(Throwable t){
                Log.e("AudioRecord", "Recording Failed");
            }

            while(started){
                /* Reads the data from the microphone. it takes in data 
                 * to the size of the window "blockSize". The data is then
                 * given in to audioRecord. The int returned is the number
                 * of bytes that were read*/

                int bufferReadResult = audioRecord.read(buffer, 0, blockSize);

                // Read in the data from the mic to the array
                for(int i = 0; i < blockSize && i < bufferReadResult; i++) {

                    /* dividing the short by 32768.0 gives us the 
                     * result in a range -1.0 to 1.0.
                     * Data for the compextForward is given back 
                     * as two numbers in sequence. Therefore audioDataDoubles
                     * needs to be twice as large*/

                   // audioDataDoubles[2*i] = (double) buffer[i]/32768.0; // signed 16 bit
                    //audioDataDoubles[(2*i)+1] = 0.0;
                    toTransform[i] = (double) buffer[i] / 32768.0; // signed 16 bit

                }

                //audiodataDoubles now holds data to work with
               // fft.complexForward(audioDataDoubles);
                transformer.ft(toTransform);
   //------------------------------------------------------------------------------------------
                // Calculate the Real and imaginary and Magnitude.
                for(int i = 0; i < blockSize; i++){
                    // real is stored in first part of array
                    re[i] = toTransform[i*2];
                    // imaginary is stored in the sequential part
                    im[i] = toTransform[(i*2)+1];
                    // magnitude is calculated by the square root of (imaginary^2 + real^2)
                    magnitude[i] = Math.sqrt((re[i] * re[i]) + (im[i]*im[i]));
                }

                double peak = -1.0;
                // Get the largest magnitude peak
                for(int i = 0; i < blockSize; i++){
                    if(peak < magnitude[i])
                        peak = magnitude[i];
                }
                // calculated the frequency
                frequency = (sampleRate * peak)/blockSize;
//----------------------------------------------------------------------------------------------
                /* calls onProgressUpdate
                 * publishes the frequency
                 */
                publishProgress(frequency);
                try{
                    audioRecord.stop();
                }
                catch(IllegalStateException e){
                    Log.e("Stop failed", e.toString());

                }
            }

    //    } 
        return null;
    }

    protected void onProgressUpdate(Double... frequencies){
        //print the frequency 
        String info = Double.toString(frequencies[0]);
        tv.setText(info);
    }

}

@Override
public void onClick(View v) {
    // TODO Auto-generated method stub
    if(started){
           started = false;
           startStopButton.setText("Start");
           recordTask.cancel(true);
       } else {
           started = true;
           startStopButton.setText("Stop");
           recordTask = new RecordAudio();
           recordTask.execute();
       }

}

}

当我使用 OnClick 运行程序时,它崩溃了 我为 fft 尝试了两个库,但一次运行一个以查看该库是否有效 一旦它到达我将块大小分配给 FFT 对象的行,它就会崩溃 谁能帮忙

【问题讨论】:

  • 我正在尝试获取频率值而不是图表
  • 您能提供崩溃的 logcat 捕获吗?堆栈跟踪会很有帮助。在这种形式中,我可以看到可能的崩溃,因为transformer 从未初始化,所以一旦你到达transformer.ft(toTransform) 行,它就会崩溃NullPointerException

标签: java android audio real-time frequency


【解决方案1】:

试试这个 FFT:

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

它应该解决您的想法。如果您决定重新使用它,请给予作者适当的信任。

来源/作者:EricLarch

【讨论】:

  • 你能解释一下我在哪里使用这个 fft 函数吗?
  • 嗨@Avanz,你能帮我解决一下吗?我必须创建声音频率检测的演示。我已经搜索了这个库android-arsenal.com/details/1/6086,但没有得到正确的..你能指导我上面的解决方案吗
【解决方案2】:

如果您真的想要执行实时音频分析,那么基于 Java 的方法是行不通的。我在 2013 年第四季度为我的公司执行了一项类似的任务,我们决定使用Kiss FFT(可能是具有 BSD 许可证的最简单的 FFT 库),使用 NDK 为 Android 编译。

原生 C/C++ 方法比其 Java 对应方法快很多倍。使用前者,我们几乎可以在所有中高端设备上执行实时音频解码音频特征分析,而后者显然无法做到这一点.

强烈建议您将本机方法视为完成此任务的最佳选择。 Kiss FFT 是一个非常简单的库(字面意思是Keep It Simple FFT),在Android 上编译和使用不会有太多麻烦。您不会对性能结果感到失望。

【讨论】:

  • 同意,不要使用 java 方法,因为它在某些设备上会慢得多。
  • 能否请您介绍一下如何使用该库?
【解决方案3】:

问题解决了吗?由于 ArrayIndexOutOfBoundsException 发生了粉碎。

所以,修改你的代码:

                double[] re = new double[blockSize];
                double[] im = new double[blockSize];
                double[] magnitude = new double[blockSize];

                // Calculate the Real and imaginary and Magnitude.
                for(int i = 0; i < blockSize+1; i++){
                    try {
                        // real is stored in first part of array
                        re[i] = toTransform[i * 2];
                        // imaginary is stored in the sequential part
                        im[i] = toTransform[(i * 2) + 1];
                        // magnitude is calculated by the square root of (imaginary^2 + real^2)
                        magnitude[i] = Math.sqrt((re[i] * re[i]) + (im[i] * im[i]));
                    }catch (ArrayIndexOutOfBoundsException e){
                        Log.e("test", "NULL");
                    }
                }

                double peak = -1.0;
                // Get the largest magnitude peak
                for(int i = 0; i < blockSize; i++){
                    if(peak < magnitude[i])
                        peak = magnitude[i];
                }
                // calculated the frequency
                frequency = Double.toString((sampleRate * peak)/blockSize);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 2013-06-03
    • 2014-12-27
    • 2011-07-11
    相关资源
    最近更新 更多