我有一个声音文件(.3gp),大概约1分钟.我想每1/4秒获得一次这个声音文件的频率.我的想法是每隔1/4秒从音频文件接收采样并使用FFT我可能得到频率值.有没有办法做到这一点?
实际上我会将声音文件分成1 / 4sec样本声音文件(alwyas覆盖这些声音文件),然后使用FFT算法并检测magintude最大的频率.但是可能有更简单的解决方案,但我也不知道如何做到这一点.
***更新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,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
吉他弦似乎是正确的,但我自己的声音并不好,因为:
两个峰值的大小在大部分时间都会发生变化,我总能找到最大值来获得基频.