Android:查找音频输入的基本频率 [英] Android: Finding fundamental frequency of audio input

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

问题描述

因此,我一直在努力寻找最佳解决方案,以实时计算使用AudioRecord捕获的样本的基频. 我在这里围绕SO的一些示例进行了研究: 这个和这个是对我帮助最大的问题,但我仍然不完全了解他们将如何寻找基本频率.因此,我要寻找的是一个更详细的说明,该操作说明我需要执行什么操作才能找到具有样本的基本频率.

So, I've been trying for some time now to find the best solution to calculate the fundamental frequency of a sample captured using AudioRecord in real-time. I have looked around some examples around here on SO: This one, and this one are the questions that helped me the most, but I still did not understand fully how they would work for finding the fundamental frequency. So what I am looking for is a more detailed explanation of what do I need to do to find the fundamental frequency having a sample.

因此,我创建了一个AudioRecord:

So, I create an AudioRecord:

micData = new AudioRecord(audioSource, sampleRate, channel, encoding, bufferSize);
data = new short[bufferSize];

然后开始收听:

micData.startRecording();    
sample = micData.read(data,0,bufferSize);

而且我了解如何创建复杂数组,但是我不完全了解 FFT.java 我可以使用的值来创建这些复数,而其中一个是返回峰值频率的方法.

And I understand how to create a Complex array, but I don't know exactly wich methods out of FFT.java I can use the values of to create these complex numbers and the wich one would be the method that returns the peak frequency.

推荐答案

在阅读您的问题时,我不确定您是否要使用FFT.很好,因为我不建议仅使用FFT.留在时域中,使用自相关或AMDF,如果要获得更准确的结果,则不使用FFT作为附加组件.

Reading your question I see you are not sure yet that you want to use FFT. That's good because I don't recommend using just FFT. Stay in time domain, use Autocorrelation or AMDF and if you want more accurate results, than use FFT as a additional component.

这是我的Java代码,用于计算基本频率.我写评论是因为您说您仍然不了解该过程.

Here is my Java code for calculating fundamental frequency. I wrote comments because you say you still don't understand the process.

public double getPitchInSampleRange(AudioSamples as, int start, int end) throws Exception {
    //If your sound is musical note/voice you need to limit the results because it wouldn't be above 4500Hz or bellow 20Hz
    int nLowPeriodInSamples = (int) as.getSamplingRate() / 4500;
    int nHiPeriodInSamples = (int) as.getSamplingRate() / 20;

    //I get my sample values from my AudioSamples class. You can get them from wherever you want
    double[] samples = Arrays.copyOfRange((as.getSamplesChannelSegregated()[0]), start, end);
    if(samples.length < nHiPeriodInSamples) throw new Exception("Not enough samples");

    //Since we're looking the periodicity in samples, in our case it won't be more than the difference in sample numbers
    double[] results = new double[nHiPeriodInSamples - nLowPeriodInSamples];

    //Now you iterate the time lag
    for(int period = nLowPeriodInSamples; period < nHiPeriodInSamples; period++) {
        double sum = 0;
        //Autocorrelation is multiplication of the original and time lagged signal values
        for(int i = 0; i < samples.length - period; i++) {
            sum += samples[i]*samples[i + period];
        }
        //find the average value of the sum
        double mean = sum / (double)samples.length;
        //and put it into results as a value for some time lag. 
        //You subtract the nLowPeriodInSamples for the index to start from 0.
        results[period - nLowPeriodInSamples] = mean;
    }
    //Now, it is obvious that the mean will be highest for time lag equal to the periodicity of the signal because in that case
    //most of the positive values will be multiplied with other positive and most of the negative values will be multiplied with other
    //negative resulting again as positive numbers and the sum will be high positive number. For example, in the other case, for let's say half period
    //autocorrelation will multiply negative with positive values resulting as negatives and you will get low value for the sum.        
    double fBestValue = Double.MIN_VALUE;
    int nBestIndex = -1; //the index is the time lag
    //So
    //The autocorrelation is highest at the periodicity of the signal
    //The periodicity of the signal can be transformed to frequency
    for(int i = 0; i < results.length; i++) {
        if(results[i] > fBestValue) {
            nBestIndex = i; 
            fBestValue = results[i]; 
        }
    }
    //Convert the period in samples to frequency and you got yourself a fundamental frequency of a sound
    double res = as.getSamplingRate() / (nBestIndex + nLowPeriodInSamples)

    return res;
}

您还需要知道的是,自相关方法中存在常见的八度音阶错误,尤其是在信号中存在噪声的情况下.根据我的经验,钢琴音或吉他没问题.错误很少见.但是人的声音可能是...

What else you need to know is that there are common octave mistakes in the autocorrelation method especially if you have noise in the signal. From my experience, piano sound or guitar isn't problem. The mistakes are rare. But human voice could be...

这篇关于Android:查找音频输入的基本频率的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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