我希望能够使用Java检测预定频率的音调。我正在做的是播放一个音调(该音调的频率可以通过用户输入来更改),并且我试图检测该音调是否具有特定的频率。如果是,我执行某种方法。从我阅读的内容中,我将需要FFT,但是我不确定如何在Java中实现它。似乎有很多有关如何执行此操作的文档,但是所提供的文档涉及查看音频文件,而不是实时分析。我不需要将音频保存到文件中,只需确定是否以及何时录制了频率为x的音调即可。

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

请注意,大约在何时可以检测到令人满意的频率音调时,我知道在-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中实现呢?我知道我需要做什么,但是我很难将所有内容 bundle 在一起。我对Java相当体面,但是我对音频所涉及的语法不熟悉,而且我对fft没有任何经验。请明确,并提供带有注释的代码。我一直试图弄清楚这一点,我只需要看到所有这些都绑在一起即可。谢谢。

编辑

我知道使用像我一样的for循环不会产生我想要的频率。更多地显示了我想要的。也就是说,随着时间的流逝,一次记录,执行fft并测试频率。

最佳答案

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

  • 太过分了-您正在计算整个频谱只是为了检测某一点的幅度
  • 为获得3 ms的开始检测分辨率,您将需要在连续的FFT之间有很大的重叠,这比处理连续的采样块需要更多的CPU带宽

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

    请注意,SO上已经有许多关于音调检测和使用Goertzel算法(例如Precise tone onset/duration measurement?)的有用问题和答案-我建议将它们与Wikipedia条目一起阅读,作为一个很好的起点。

    10-07 22:09