Android音频FFT使用audiorecord检索特定频率幅度

use*_*060 38 java android fft frequency audiorecord

我目前正在尝试使用Android实现一些代码,以检测何时通过手机的麦克风播放多个特定的音频范围.我已经使用AudioRecord类设置了类:

int channel_config = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int format = AudioFormat.ENCODING_PCM_16BIT;
int sampleSize = 8000;
int bufferSize = AudioRecord.getMinBufferSize(sampleSize, channel_config, format);
AudioRecord audioInput = new AudioRecord(AudioSource.MIC, sampleSize, channel_config, format, bufferSize);
Run Code Online (Sandbox Code Playgroud)

然后读入音频:

short[] audioBuffer = new short[bufferSize];
audioInput.startRecording();
audioInput.read(audioBuffer, 0, bufferSize);
Run Code Online (Sandbox Code Playgroud)

执行FFT是我陷入困境的地方,因为我在这方面的经验很少.我一直在尝试使用这个类:

在JavaComplex类中使用FFT 来实现它

然后我发送以下值:

Complex[] fftTempArray = new Complex[bufferSize];
for (int i=0; i<bufferSize; i++)
{
    fftTempArray[i] = new Complex(audio[i], 0);
}
Complex[] fftArray = fft(fftTempArray);
Run Code Online (Sandbox Code Playgroud)

这可能很容易让我误解了这个课程是如何工作的,但是返回的值跳到了整个地方,即使在沉默中也不代表一致的频率.是否有人知道执行此任务的方法,或者我是否过于复杂化以尝试仅抓取少量频率范围而不是将其绘制为图形表示?

sha*_*ams 33

首先,您需要确保将获得的结果正确转换为float/double.我不确定short []版本是如何工作的,但byte []版本只返回原始字节版本.然后需要将此字节数组正确转换为浮点数.转换的代码应如下所示:

    double[] micBufferData = new double[<insert-proper-size>];
    final int bytesPerSample = 2; // As it is 16bit PCM
    final double amplification = 100.0; // choose a number as you like
    for (int index = 0, floatIndex = 0; index < bytesRecorded - bytesPerSample + 1; index += bytesPerSample, floatIndex++) {
        double sample = 0;
        for (int b = 0; b < bytesPerSample; b++) {
            int v = bufferData[index + b];
            if (b < bytesPerSample - 1 || bytesPerSample == 1) {
                v &= 0xFF;
            }
            sample += v << (b * 8);
        }
        double sample32 = amplification * (sample / 32768.0);
        micBufferData[floatIndex] = sample32;
    }
Run Code Online (Sandbox Code Playgroud)

然后使用micBufferData []创建输入复杂数组.

获得结果后,使用结果中复数的大小.除了具有实际值的频率之外,大多数幅度应接近零.

您需要采样频率将数组索引转换为这样的幅度到频率:

private double ComputeFrequency(int arrayIndex) {
    return ((1.0 * sampleRate) / (1.0 * fftOutWindowSize)) * arrayIndex;
}
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢您的回复,但我还有一些问题.在运行'ComputeFrequency'方法之前,我是否仍然可以从返回的复杂数组中提取值?同样的问题似乎仍然允许零星的数字出现在10到3000左右,而房间很不幸 (2认同)