Android的音频FFT显示基频 [英] Android audio FFT to display fundamental frequency

查看:310
本文介绍了Android的音频FFT显示基频的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经工作了一段时间的Andr​​oid项目,显示输入信号的基频(作为一个调谐器)。我已经成功地实现了AudioRecord类和我从中获取数据。然而,我有该数据执行FFT,以获得输入信号的基本频率之苦。我一直在寻找的职位<一href="http://stackoverflow.com/questions/5774104/android-audio-fft-to-retrieve-specific-frequency-magnitude-using-audiorecord">here,而现在用 FFT在Java中和的复合类去用它。

I have been working on an Android project for awhile that displays the fundamental frequency of an input signal (to act as a tuner). I have successfully implemented the AudioRecord class and am getting data from it. However, I am having a hard time performing an FFT on this data to get the fundamental frequency of the input signal. I have been looking at the post here, and am using FFT in Java and Complex class to go with it.

我已经成功地使用发现,FFT在Java中的FFT功能,但我不知道如果我得到正确的结果。对于FFT的大小(开方[重*重+ IM * IM])我得到了启动高值,围绕15000赫兹,然后再慢慢减少至约300赫兹。好像没有吧。

I have successfully used the FFT function found in FFT in Java, but I am not sure if I am obtaining the correct results. For the magnitude of the FFT (sqrt[re*re+im*im]) I am getting values that start high, around 15000 Hz, and then slowly diminish to about 300 Hz. Doesn't seem right.

此外,尽可能远离麦克风的原始数据云,数据看起来不错,但第一个50值或使总人数3,除非我又打了调整按钮,同时仍然在应用程序,然后我只能获得约15。那是正常的吗?

Also, as far as the raw data from the mic goes, the data seems fine, except that the first 50 values or so are always the number 3, unless I hit the tuning button again while still in the application and then I only get about 15. Is that normal?

下面是一个有点我的code。

Here is a bit of my code.

首先,我转换短数据(从麦克风获得)为双用下列code这是从<一个href="http://stackoverflow.com/questions/5774104/android-audio-fft-to-retrieve-specific-frequency-magnitude-using-audiorecord">post我一直在寻找。的code这个片段,我不完全理解,但我认为它的工作原理。

First of all, I convert the short data (obtained from the microphone) to a double using the following code which is from the post I have been looking at. This snippet of code I do not completely understand, but I think it works.

//Conversion from short to double
double[] micBufferData = new double[bufferSizeInBytes];//size may need to change
    final int bytesPerSample = 2; // As it is 16bit PCM
    final double amplification = 1.0; // choose a number as you like
    for (int index = 0, floatIndex = 0; index < bufferSizeInBytes - bytesPerSample + 1; index += bytesPerSample, floatIndex++) {
        double sample = 0;
        for (int b = 0; b < bytesPerSample; b++) {
            int v = audioData[index + b];
            if (b < bytesPerSample - 1 || bytesPerSample == 1) {
                v &= 0xFF;
            }
            sample += v << (b * 8);
        }
        double sample32 = amplification * (sample / 32768.0);
        micBufferData[floatIndex] = sample32;
    }

在code,则继续如下:

The code then continues as follows:

 //Create Complex array for use in FFT
    Complex[] fftTempArray = new Complex[bufferSizeInBytes];
    for (int i=0; i<bufferSizeInBytes; i++)
    {
        fftTempArray[i] = new Complex(micBufferData[i], 0);
    }

    //Obtain array of FFT data
    final Complex[] fftArray = FFT.fft(fftTempArray);
    final Complex[] fftInverse = FFT.ifft(fftTempArray);

    //Create an array of magnitude of fftArray
    double[] magnitude = new double[fftArray.length];
    for (int i=0; i<fftArray.length; i++){
        magnitude[i]= fftArray[i].abs();
    }


    fft.setTextColor(Color.GREEN);
    fft.setText("fftArray is "+ fftArray[500] +" and fftTempArray is "+fftTempArray[500] + " and fftInverse is "+fftInverse[500]+" and audioData is "+audioData[500]+ " and magnitude is "+ magnitude[1] + ", "+magnitude[500]+", "+magnitude[1000]+" Good job!");
    for(int i = 2; i < samples; i++){
        fft.append(" " + magnitude[i] + " Hz");
    }

这最后一点就是要检查什么样的价值观,我得到(和我保持理智!)。在上面提到的帖子,它谈论需要采样频率并给出了code:

That last bit is just to check what values I am getting (and to keep me sane!). In the post referred to above, it talks about needing the sampling frequency and gives this code:

private double ComputeFrequency(int arrayIndex) {
return ((1.0 * sampleRate) / (1.0 * fftOutWindowSize)) * arrayIndex;
}

我如何实现这个code?我并不真的明白的地方fftOutWindowSize和arrayIndex从何而来?

How do I implement this code? I don't realy understand where fftOutWindowSize and arrayIndex comes from?

任何帮助是极大AP preciated!

Any help is greatly appreciated!

达斯汀

推荐答案

最近我工作的要求几乎是相同的项目。也许你并不需要任何帮助了,但我会给我的想法呢。也许有人需要这样的未来。

Recently I'm working on a project which requires almost the same. Probably you don't need any help anymore but I will give my thoughts anyway. Maybe someone need this in the future.

  1. 在我不知道是否短期翻番功能的工作,我不明白的code既没有片断。它写的字节双转换。
  2. 在code:双[] micBufferData =新的双[bufferSizeInBytes];我觉得大小 micBufferData 应该是 bufferSizeInBytes / 2 ,因为每个样本需要两个字节, micBufferData 应该是样本号。
  3. FFT算法确实需要一个FFT窗口大小,并且它必须是一个数是2。然而,许多算法的功率可以接收数字作为输入的任意它将做休息。在这些算法的文件应该具有输入的要求。你的情况,复杂数组的大小可以是FFT算法的输入。我真的不知道FFT算法的细节,但我认为逆一个是没有必要的。
  4. 要使用你给在去年的code,你应该首先找到样本数组中的峰值指数。我用的复合双数组作为输入,而不是,所以在我的情况是这样的:双MAXVAL = -1; INT maxIndex = -1;

  1. I'm not sure whether the short to double function works, I don't understand that snippet of code neither. It is wrote for byte to double conversion.
  2. In the code: "double[] micBufferData = new double[bufferSizeInBytes];" I think the size of micBufferData should be "bufferSizeInBytes / 2", since every sample takes two bytes and the size of micBufferData should be the sample number.
  3. FFT algorithms do require a FFT window size, and it has to be a number which is the power of 2. However many algorithms can receive an arbitrary of number as input and it will do the rest. In the document of those algorithms should have the requirements of input. In your case, the size of the Complex array can be the input of FFT algorithms. And I don't really know the detail of the FFT algorithm but I think the inverse one is not needed.
  4. To use the code you gave at last, you should firstly find the peak index in the sample array. I used double array as input instead of Complex, so in my case it is something like: double maxVal = -1;int maxIndex = -1;

for( int j=0; j < mFftSize / 2; ++j ) {
    double v = fftResult[2*j] * fftResult[2*j] + fftResult[2*j+1] * fftResult[2*j+1];
    if( v > maxVal ) {
        maxVal = v;
        maxIndex = j;
    }
}

2 * j是的实部和2 * J + 1是虚部。 maxIndex 是你想要的峰值幅度(更多细节<一个索引href="http://stackoverflow.com/questions/7649003/jtransforms-fft-in-android-from-pcm-data">here),并用它作为输入 ComputeFrequency 函数的返回值是你想要的样品阵列的频率。

2*j is the real part and 2*j+1 is the imaginary part. maxIndex is the index of the peak magnitude you want (More detail here), and use it as input to the ComputeFrequency function. The return value is the frequency of the sample array you want.

希望它可以帮助别人。

这篇关于Android的音频FFT显示基频的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆