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

Posted

技术标签:

【中文标题】Android音频FFT使用audiorecord检索特定频率幅度【英文标题】:Android audio FFT to retrieve specific frequency magnitude using audiorecord 【发布时间】:2011-08-12 01:25:38 【问题描述】:

我目前正在尝试使用 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);

然后读入音频:

short[] audioBuffer = new short[bufferSize];
audioInput.startRecording();
audioInput.read(audioBuffer, 0, bufferSize);

执行 FFT 是我卡住的地方,因为我在这方面的经验很少。我一直在尝试使用这个类:

FFT in Java 和 Complex class to go with it

然后我发送以下值:

Complex[] fftTempArray = new Complex[bufferSize];
for (int i=0; i<bufferSize; i++)

    fftTempArray[i] = new Complex(audio[i], 0);

Complex[] fftArray = fft(fftTempArray);

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

【问题讨论】:

嘿,如果你想通了,能否请你发布代码的最终版本?谢谢 【参考方案1】:

首先,您需要确保您获得的结果正确转换为浮点数/双精度数。我不确定 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;
    

然后你使用 micBufferData[] 创建你的输入复数数组。

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

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

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

【讨论】:

非常感谢您的回复,但我仍有一些问题。在运行“ComputeFrequency”方法之前,我是否仍然能够从返回的复数数组中提取值?同样的问题似乎仍然允许出现零星的数字,从 10 到大约 3000 不等,而不幸的是房间里一片寂静 是的,您仍然应该能够从复数数组中提取值,您希望使用复数的大小(即 sqrt(rere + im我是))。即使房间完全安静,麦克风也可能会引入背景噪音,这些噪音会出现在 FFT 上。将数组索引转换为频率以查看显示的确切频率。这些频率的值可能有助于了解它们是否是背景噪声。 我很好奇我是否正确地调用了关于虚数的复数数组。我现在实现它的方式与我在原始示例中的实现方式非常相似,但是现在循环遍历新的 micBufferData 数组并将每个值分配给一个复数数组作为实数,虚数不断为0. 这可能是我出错的地方,但我读过的前面的例子似乎表明这是正确的方法。知道是否还有其他东西要进去吗?再次感谢! 你的复数没问题。您只需要设置实部并将虚部设置为零。 我有类似的问题请检查我的问题任何帮助appriciated pls。 ***.com/questions/10908582/…

以上是关于Android音频FFT使用audiorecord检索特定频率幅度的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin Android 音频 DSP

如何延迟音频播放以与 FFT 同步

JTransforms 在 Android 音频中的使用

通过Android录音进行简单音频分析

Android音频记录和处理

C# 应用程序:来自音频输出的示例音频 -> FFT 算法 -> 可视化