3

電話のマイクを使用してリアルタイムで周波数を記録し、それらを (テキストで) 表示するアプリを開発する必要があります。私は自分のコードをここに投稿しています。FFT および複雑なクラスは、 http://introcs.cs.princeton.edu/java/97data/FFT.java.htmlおよびhttp://introcs.cs.princeton.edu/java/97data/Complex.javaから使用されています。 .html .問題は、エミュレーターでこれを実行すると、頻度がランダムな値から始まり、7996 まで増加し続けることです。その後、プロセス全体が繰り返されます。誰かが私を助けてくれますか?

public class Main extends Activity {

TextView disp;
private static int[] sampleRate = new int[] { 44100, 22050, 11025, 8000 };
short audioData[];
double finalData[];
int bufferSize,srate;
String TAG;
public boolean recording;
AudioRecord recorder;
Complex[] fftArray;
float freq;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    disp = (TextView) findViewById(R.id.display);

    Thread t1 = new Thread(new Runnable(){

        public void run() {

            Log.i(TAG,"Setting up recording");
            for (int rate : sampleRate) {
                try{

                    Log.d(TAG, "Attempting rate " + rate);

            bufferSize=AudioRecord.getMinBufferSize(rate,AudioFormat.CHANNEL_CONFIGURATION_MONO,
            AudioFormat.ENCODING_PCM_16BIT)*3; //get the buffer size to use with this audio record

            if (bufferSize != AudioRecord.ERROR_BAD_VALUE) {

            recorder = new AudioRecord (MediaRecorder.AudioSource.MIC,rate,AudioFormat.CHANNEL_CONFIGURATION_MONO,
            AudioFormat.ENCODING_PCM_16BIT,2048); //instantiate the AudioRecorder
            Log.d(TAG, "BufferSize " +bufferSize);
            srate = rate;

            }

            } catch (Exception e) {
                Log.e(TAG, rate + "Exception, keep trying.",e);
            }
        }
            bufferSize=2048;
            recording=true; //variable to use start or stop recording
            audioData = new short [bufferSize]; //short array that pcm data is put into.
            Log.i(TAG,"Got buffer size =" + bufferSize);                
            while (recording) {  //loop while recording is needed
                   Log.i(TAG,"in while 1");
            if (recorder.getState()==android.media.AudioRecord.STATE_INITIALIZED) // check to see if the recorder has initialized yet.
            if (recorder.getRecordingState()==android.media.AudioRecord.RECORDSTATE_STOPPED)
            recorder.startRecording();  //check to see if the Recorder has stopped or is not recording, and make it record.

            else {
                   Log.i(TAG,"in else");
                  // audiorecord();
                finalData=convert_to_double(audioData);
                Findfft();
                for(int k=0;k<fftArray.length;k++)
                {
                    freq = ((float)srate/(float) fftArray.length) *(float)k;
                    runOnUiThread(new Runnable(){
                     public void run()
                     {
                         disp.setText("The frequency is " + freq);
                         if(freq>=15000)
                             recording = false;
                     }
                 });


                }


             }//else recorder started

    } //while recording

    if (recorder.getState()==android.media.AudioRecord.RECORDSTATE_RECORDING) 
    recorder.stop(); //stop the recorder before ending the thread
    recorder.release(); //release the recorders resources
    recorder=null; //set the recorder to be garbage collected.

         }//run

    });
    t1.start();
}





private void Findfft() {
    // TODO Auto-generated method stub
    Complex[] fftTempArray = new Complex[bufferSize];
    for (int i=0; i<bufferSize; i++)
    {
        fftTempArray[i] = new Complex(finalData[i], 0);
    }
    fftArray = FFT.fft(fftTempArray);
}


private double[] convert_to_double(short data[]) {
    // TODO Auto-generated method stub
    double[] transformed = new double[data.length];

    for (int j=0;j<data.length;j++) {
    transformed[j] = (double)data[j];
    }

    return transformed;

}


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

3 に答える 3

2

あなたの質問には簡潔に答えましたが、あなたの目的をさらに進め、ループを完成させるために...

はい。FFT は、限られた CPU ではピッチ/周波数の識別に最適ではありません。より最適なアプローチは、ここで説明されている YIN です。Tarsosで実装を見つけることができます。直面する問題は、ADK に javax.sound.sampled がないため、AudioRecord の short/bytes を参照される実装に必要な float に変換することです。

于 2014-03-11T21:31:00.517 に答える
1

あなたの問題はここにあります:

Findfft();
for(int k=0;k<fftArray.length;k++) {
    freq = ((float)srate/(float) fftArray.length) *(float)k;
    runOnUiThread(new Runnable() {
        public void run() {
            disp.setText("The frequency is " + freq);
            if(freq>=15000) recording = false;
        }
    });
}

この for ループが行うことは、FFT 値の配列を調べ、配列インデックスを Hz 単位の周波数に変換し、出力することだけです。

記録している周波数を出力したい場合は、少なくとも配列内のデータを確認する必要があります。最も粗い方法は、実数の 2 乗を計算し、最大の周波数ビンを見つけることです。

それに加えて、あなたが使用している FFT アルゴリズムは事前計算を行っていないと思います - モバイル デバイス用に開発しているのを見て、CPU 使用率と電力使用量を計算に入れたいと思うかもしれません。アカウント。

JTransformsは、事前計算を使用して CPU 負荷を軽減するライブラリの 1 つであり、そのドキュメントは非常に完全です。

また、ウィキペディアで FFT から返されたデータを解釈する方法に関する有用な情報を見つけることもできます。悪気はありませんが、自分が何をしているのかよくわかっていないように見えるので、ポインタを示します。

最後に、このアプリを音符に使用しようとしている場合、FFT は最適な方法ではないと多くの人が言っていることを覚えているようですが、それが何であるかは思い出せません。多分他の誰かがそのビットを追加できますか?

于 2013-06-12T13:37:16.153 に答える
0

私は数日後にこの解決策を見つけました-Hrzで周波数を取得するのに最適です:

Jtransformsとこの Jarもダウンロードします - Jtransformsにはこれが必要です。

次に、このタスクを使用します:

public class MyRecorder extends AsyncTask<Void, short[], Void> {

int blockSize = 2048;// = 256;
private static final int RECORDER_SAMPLERATE = 8000;
private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
int BufferElements2Rec = 1024; // want to play 2048 (2K) since 2 bytes we use only 1024
int BytesPerElement = 2;



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

    try {
        final AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
                RECORDER_SAMPLERATE, RECORDER_CHANNELS,
                RECORDER_AUDIO_ENCODING, BufferElements2Rec * BytesPerElement);
        if (audioRecord == null) {
            return null;
        }

        final short[] buffer = new short[blockSize];
        final double[] toTransform = new double[blockSize];
        audioRecord.startRecording();
        while (started) {
            Thread.sleep(100);
            final int bufferReadResult = audioRecord.read(buffer, 0, blockSize);
            publishProgress(buffer);
        }
        audioRecord.stop();
        audioRecord.release();
    } catch (Throwable t) {
        Log.e("AudioRecord", "Recording Failed");
    }
    return null;
}



@Override
protected void onProgressUpdate(short[]... buffer) {
    super.onProgressUpdate(buffer);
    float freq = calculate(RECORDER_SAMPLERATE, buffer[0]);
    }


public static float calculate(int sampleRate, short [] audioData)
{
    int numSamples = audioData.length;
    int numCrossing = 0;
    for (int p = 0; p < numSamples-1; p++)
    {
        if ((audioData[p] > 0 && audioData[p + 1] <= 0) ||
                (audioData[p] < 0 && audioData[p + 1] >= 0))
        {
            numCrossing++;
        }
    }


    float numSecondsRecorded = (float)numSamples/(float)sampleRate;
    float numCycles = numCrossing/2;
    float frequency = numCycles/numSecondsRecorded;


    return frequency;
}
于 2015-07-06T19:06:25.997 に答える