web-dev-qa-db-ja.com

androidサウンド周波数をリアルタイムで取得しますか?

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用に2つのライブラリを試しましたが、ライブラリが機能するかどうかを確認するために一度に1つずつ実行しました。ブロックサイズをFFTオブジェクトに割り当てる行に到達するとすぐにそれはクラッシュします誰も助けることができます

18
Prerak Diwan

この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

12
Avanz

リアルタイムオーディオ分析を本当に実行したい場合、Javaベースのアプローチは実行しません。 2013年第4四半期に私の会社で同様のタスクを実行し、Android用にコンパイルされた Kiss FFT (おそらく、BSDライセンスを持つ最も単純なFFTライブラリ)を使用することにしました。 = NDKを使用します。

ネイティブC/C++アプローチは、そのJava対応するものよりもトン倍高速です。前者では、ほぼすべてのミッドエンドからハイエンドのデバイスでリアルタイムオーディオデコードおよびオーディオ機能分析を実行できます。これは明らかに不可能でした。後者で。

強くは、このタスクを実行するための最良のオプションとしてネイティブアプローチを検討することをお勧めします。 Kiss FFTは非常にシンプルなライブラリ(文字通りKeep It Simple FFTの略)であり、Androidでのコンパイルと使用にそれほど問題はありません。パフォーマンスの結果に失望することはありません。

5
Sebastiano

問題を解決しましたか? 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);
0
송요섭