在android中,每1/4秒获取一个音频文件的频率

在android中,每1/4秒获取一个音频文件的频率,android,audio,fft,frequency,Android,Audio,Fft,Frequency,我有一个声音文件(.3gp),大约1分钟。我想每1/4秒获取一次这个声音文件的频率。我的想法是每1/4秒从音频文件接收一次样本,使用FFT我可能会得到频率值。有没有办法做到这一点 实际上,我会将声音文件分割成1/4秒的采样声音文件(总是覆盖上一个),然后使用FFT算法检测magintude最大的频率。但是可能会有更简单的解决办法,但是我也不知道怎么做 ***更新2-新代码 到目前为止,我使用了以下代码: public class RecordAudio extends AsyncTask<

我有一个声音文件(.3gp),大约1分钟。我想每1/4秒获取一次这个声音文件的频率。我的想法是每1/4秒从音频文件接收一次样本,使用FFT我可能会得到频率值。有没有办法做到这一点

实际上,我会将声音文件分割成1/4秒的采样声音文件(总是覆盖上一个),然后使用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, 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;
    }
公共类RecordAudio扩展异步任务{
@凌驾
受保护的Void doInBackground(Void…arg0){
试一试{
int bufferSize=AudioRecord.getMinBufferSize(频率,
AudioFormat.CHANNEL(单声道,AudioFormat.ENCODING(PCM)(16位);
//int bufferSize=AudioRecord.getMinBufferSize(频率,
//信道配置、音频编码);
音频记录=新的音频记录(
MediaRecorder.AudioSource.MIC,频率,
信道配置、音频编码、缓冲区大小);
short[]buffer=新的short[blockSize];
//double[]toTransform=新的double[blockSize];
录音。开始录制();
//started=true;希望在调用之前这应该是true
//跟随while循环
while(启动){
采样++;
double[]re=新的double[blockSize];
double[]im=新的double[blockSize];
double[]newArray=newdouble[blockSize*2];
double[]magns=新的double[blockSize];
双MaxMagn=0;
双节距=0;
int bufferReadResult=audioRecord.read(缓冲区,0,
块大小);
对于(int i=0;iMaxMagn)
{
MaxMagn=magns[i];
螺距=i;
}
}                                           
如果(采样>50){
对数i(“螺距和幅值”,“最大磁振”,“螺距+15.625f”);
抽样=0;
MaxMagn=0;节距=0;
}                   
}
录音。停止();
}捕获(可丢弃的t){
t、 printStackTrace();
Log.e(“录音”,“录音失败”);
}
返回null;
}
我用这个:

吉他弦似乎正确,但我自己的声音不好,因为:

两个峰值的大小在大部分时间都会发生变化,我总是找到最大的峰值来获得基频。

尝试异步任务

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();
               }
       }
   }  
}

在堆栈溢出问题上,FFT的基音跟踪经常被问到。我写了一个。代码是用C编写的,但是有了解释和链接,你应该能够做你想做的事情


至于将其划分为1/4秒的增量,您可以按照您的建议简单地采用1/4秒段的FFT,而不是默认值(我认为大约是1秒)。如果这不能提供您想要的频率分辨率,您可能必须使用不同的基音识别方法。您可以做的另一件事是使用长度超过1/4秒的重叠段,但间隔为1/4秒。此方法是指博客条目,但可能不符合您的设计规范。

Hi,thanks的答案。我有一些无法修复的错误。onPostExecute、onPreExecute和onProgress update会给我sytax错误。如果你不想要它们,就删除它们吧!!我删除了它们。坦白说,我不明白它应该如何工作。我在/sdcard/music.3gp中有一个.3gp文件,我想分析一下。所以我用新的GetFrequency制作了一个按钮。执行(参数);但它给了我一个错误GetFrequency.execute无法解析为一个类型。我的另一个问题是,我会对需要应用的逻辑表示怀疑。@JaniBela请尝试编辑的代码…很抱歉,我无法帮助你了解逻辑,因为我在Android中没有使用频率!谢谢你的回答,用我的代码更新了我的问题。我解决了1/4秒的问题nds启动一个采样计数器,当它达到一个给定值时,它会再次启动。但是在更高的频率下,基音检测不是很好。如果我发出一个很大的高声,高次谐波会使整个事情出错,如果是3khz,我会得到13khz左右。然而,例如,我得到的是600hz,而不是1kz,所以我不知道问题出在哪里问题是,如果你有一个声音有谐波(即任何乐器,或任何不是纯正弦波的噪音)然后简单地找到FFT的峰值并不能告诉你基音。对应于基音的频率可能比谐波的振幅低。你需要仔细阅读一下_mandrill说的是真的,但很明显你还有其他问题,因为你得到的频率不是倍数,因此不是谐波。如果我有稍后,我将更仔细地查看您的代码,但在第一次浏览时,您似乎犯了一些错误:1.查看整个转换的数据,而不是下半部分;2.不打开数据窗口。所有这些以及
frequencyButtonListener.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

        new GetFrequency.execute(params);

        }
    });