6

サウンド ファイル (.3gp) があり、約 1 分です。このサウンド ファイルの周波数を 1/4 秒ごとに取得したいと考えています。私の考えは、オーディオ ファイルから 1/4 秒ごとにサンプルを受信し、FFT を使用して周波数値を取得することです。これを行う方法はありますか?

実際には、サウンド ファイルを 1/4 秒サンプルのサウンド ファイルに分割し (常に前のファイルを上書きします)、FFT アルゴリズムを使用して、最大の周波数を検出します。しかし、もっと簡単な解決策があるかもしれませんが、これを行う方法もわかりません。

***更新 2 - 新しいコード

私はこれまでこのコードを使用しています:

public class RecordAudio extends AsyncTask<Void, double[], Void> {

    @Override
    protected Void doInBackground(Void... arg0) {

        try {
             int bufferSize = AudioRecord.getMinBufferSize(frequency,
             AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);


            //int bufferSize = AudioRecord.getMinBufferSize(frequency, 
                  //  channelConfiguration, audioEncoding); 

            AudioRecord audioRecord = new AudioRecord( 
                    MediaRecorder.AudioSource.MIC, frequency, 
                    channelConfiguration, audioEncoding, bufferSize); 

            short[] buffer = new short[blockSize];
            //double[] toTransform = new double[blockSize];


            audioRecord.startRecording();


            // started = true; hopes this should true before calling
            // following while loop

            while (started) {
               sampling++;

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

               double[] newArray = new double[blockSize*2];
               double[] magns = new double[blockSize];

               double MaxMagn=0;
               double pitch = 0;

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


               for (int i = 0; i < blockSize && i < bufferReadResult; i++) {
                   re[i] = (double) buffer[i] / 32768.0; // signed   16bit
                   im[i] = 0;
               }    

               newArray = FFTbase.fft(re, im,true);

               for (int i = 0; i < newArray.length; i+=2) {

                   re[i/2]=newArray[i];
                   im[i/2]=newArray[i+1];
                   magns[i/2] = Math.sqrt(re[i/2]*re[i/2]+im[i/2]*im[i/2]);
               }

              // I only need the first half      

              for (int i = 0; i < (magns.length)/2; i++) {
                   if (magns[i]>MaxMagn)
                   {
                       MaxMagn = magns[i];
                       pitch=i;
                   }
               }                                           
                 if (sampling > 50) {
                   Log.i("pitch and magnitude", "" + MaxMagn + "   " + pitch*15.625f);
                   sampling=0;
                   MaxMagn=0;pitch=0;
                   }                   


            }

            audioRecord.stop();

        } catch (Throwable t) {
            t.printStackTrace();
            Log.e("AudioRecord", "Recording Failed");
        }
        return null;
    }

私はこれを使用します: http://www.wikijava.org/wiki/The_Fast_Fourier_Transform_in_Java_%28part_1%29

ギターの弦は正しいように見えますが、私自身のサウンドは次の理由で良くありません。

ここに画像の説明を入力

2 つのピークの大きさはほとんどの場合変化しますが、基本周波数を得るために常に最大のものを見つけます。

4

2 に答える 2

7

FFT を使用したピッチ トラッキングは、スタック オーバーフローでよく聞かれるので、サンプル コードを記載したブログ エントリを書きました。コードは C ですが、説明とリンクがあれば、やりたいことができるはずです。

それを1/4秒単位に分割することに関しては、デフォルト(約1秒だと思います)の代わりに、提案したように1/4秒セグメントのFFTを取ることができます。これで希望する周​​波数分解能が得られない場合は、別のピッチ認識方法を使用する必要がある場合があります。もう 1 つの方法は、1/4 秒よりも長いオーバーラップ セグメントを使用することですが、1/4 秒離れた間隔で開始します。この方法はブログ エントリでほのめかされていますが、設計仕様を満たしていない可能性があります。

于 2012-08-07T22:46:59.190 に答える
1

AsyncTask を試してください:

class GetFrequency extends AsyncTask<String, Void, Void> {
   public Void doInBackground(String... params) {
          while (true) {

             // Apply Logic Here

           try {
                Thread.sleep(250);
               } catch (Exception ie) {
                  // TODO Auto-generated catch block
                e.printStackTrace();
               }
       }
   }  
}

MainActivity でこれを呼び出します。

frequencyButtonListener.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

        new GetFrequency.execute(params);

        }
    });
于 2012-08-07T11:50:00.760 に答える