android实时获取声音频率?

  发布于 2023-02-13 12:31

我一直试图使用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{
    @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对象的行崩溃可以帮助任何人

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

    原生C/C++方法比Java对应方法很多.对于前者,我们已经能够在几乎每个中高端设备上执行实时音频解码音频特征分析,这对后者来说显然是不可能的.

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

    2023-02-13 12:34 回答
  • 试试这个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

    2023-02-13 12:35 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有