2

我希望能够使用 java 检测预定频率的音调。我正在做的是播放音调(音调的频率因用户输入而异),我试图检测音调是否具有特定频率。如果是,我执行某个方法。根据我的阅读,我需要 FFT,但我不确定如何在 java 中实现它。似乎有很多关于如何做到这一点的文档,但是有哪些文档涉及查看音频文件而不是实时分析。我不需要将音频保存到文件中,只需确定是否以及何时录制了频率为 x 的音调。

理想情况下,我想以 44KHz 的采样率进行记录,并在确定是否检测到音调后,确定何时以 +-3ms 的精度检测到音调。但是,只要不荒谬(即+100ms),低于此的精度是可以接受的。从我查到的资料中,我大致知道我需要做什么,但我需要帮助将它们联系在一起。使用伪代码它看起来大致像这样(我认为)

请注意,我大致知道在 +-1 秒内可以检测到满足频率的音调

for(i = 0, i < 440000 * 2, i++){//*2 because of expected appearance interval;may change
    record sound sample
    fft(sound sample)
    if(frequencySoundSample > x){
        do something
        return
    }
}

播放音调时会有相当大的背景噪音。但是音调会有一个非常高的频率,比如 15-22KHz,所以我相信通过简单地寻找录音机何时检测到一个非常高的频率,我可以确定它是我的音调(音调也将以高幅度可能为 0.5 秒或 1 秒)。我知道不会有其他高频声音作为背景噪音(我预计背景频率可能高达 5KHz)。

那我有两个问题。我提供的伪代码是否足以满足我的需求?如果不是,或者如果有更好的方法可以做到这一点,我完全赞成。其次,我将如何在java中实现它?我知道我需要做什么,但我无法将所有这些联系在一起。我对 java 很熟悉,但我不熟悉与音频有关的语法,而且我对 fft 没有任何经验。请明确并给出带有注释的代码。我一直在试图解决这个问题,我只需要看到它都捆绑在一起。谢谢你。

编辑

我知道使用像我这样的 for 循环不会产生我想要的频率。更多的是粗略地展示我想要的东西。也就是说,随着时间的推移,同时记录、执行 fft 和测试频率。

4

2 回答 2

4

如果您只是在寻找一个特定的频率,那么基于 FFT 的方法对于您的特定应用来说可能是一个糟糕的选择,原因有两个:

  1. 这是矫枉过正 - 你正在计算整个频谱只是为了检测一个点的幅度

  2. 要为您的起始检测获得 3 ms 分辨率,您需要在连续 FFT 之间有较大的重叠,这将需要比仅处理连续样本块更多的 CPU 带宽

检测单音是否存在的更好选择是Goertzel 算法(又名 Goertzel 滤波器)。它实际上是在单个频域 bin 上评估的 DFT,并广泛用于音调检测。它的计算成本比 FFT 低得多,实现起来非常简单,您可以在每个样本上测试它的输出,因此没有分辨率问题(除了物理定律规定的问题)。您需要对输出的幅度进行低通滤波,然后使用某种阈值检测来确定音调的开始时间。

请注意,关于音调检测和使用 Goertzel 算法(例如精确音调开始/持续时间测量?),SO 已经有许多有用的问题和答案 - 我建议将这些与 Wikipedia 条目一起作为一个好的起点阅读。

于 2013-09-06T07:36:03.800 回答
2

我实际上也在用 Java 进行音高检测的类似项目。如果你想使用 FFT,你可以通过这些步骤来完成。Java 有很多库可以让你轻松完成这个过程。

首先,您需要读入声音文件。这可以使用 Java Sound 来完成。它是一个内置库,具有可以轻松录制声音的功能。可以在此处找到示例。默认采样率为 44,100 KHz(CD 质量)。这些示例可以让您从播放实际音调到表示音调的双字节数组。

其次,您应该使用 JTransforms 进行 FFT。这是对一组样本进行 FFT 的示例

FFT 为您提供的数组长度是您传递的样本数组长度的两倍。您需要通过两个 FFT 数组,因为该数组的每个部分都表示为一个虚构的和一个真实的部分。用 sqrt(im^2 + re^2) 计算这个数组每个部分的大小。然后,找出哪个幅度最大。该幅度的索引对应于您正在寻找的频率。

请记住,您不会对整个声音部分进行 FFT。您将声音分成块,然后对每个块进行 FFT。块可以重叠以获得更高的准确性,但这应该不是问题,因为您只是在寻找预定的音符。如果您想提高性能,您还可以在执行此操作之前对每个块进行窗口化。

一旦你有了所有的 FFT,他们应该确认一个特定的频率,你可以根据你想要的笔记来检查它。

如果您想尝试将其可视化,我建议您使用 JFreeChart。这是另一个可以轻松绘制图形的库。

于 2013-09-06T19:35:46.200 回答