在java中录制音频,并实时确定是否播放了x频率的音调,如果是,请采取措施

在java中录制音频,并实时确定是否播放了x频率的音调,如果是,请采取措施,java,audio,real-time,fft,audio-recording,Java,Audio,Real Time,Fft,Audio Recording,我希望能够使用java检测预定频率的音调。我所做的是播放一个音调(音调的频率随用户输入而变化),并尝试检测音调是否具有特定的频率。如果是,我执行某个方法。从我所读到的内容来看,我需要使用FFT,但我不确定如何在java中实现它。似乎有很多关于如何做的文档,但是文档涉及的是查看音频文件,而不是实时分析。我不需要将音频保存到文件中,只需确定是否以及何时录制了频率为x的音调 理想情况下,我希望以44KHz的采样率记录,并在确定是否检测到音调后,以+-3ms的精度确定何时检测到音调。但是,如果精度低于此

我希望能够使用java检测预定频率的音调。我所做的是播放一个音调(音调的频率随用户输入而变化),并尝试检测音调是否具有特定的频率。如果是,我执行某个方法。从我所读到的内容来看,我需要使用FFT,但我不确定如何在java中实现它。似乎有很多关于如何做的文档,但是文档涉及的是查看音频文件,而不是实时分析。我不需要将音频保存到文件中,只需确定是否以及何时录制了频率为x的音调

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

请注意,我大致知道在+-1s内可能检测到令人满意的频率

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
    }
}
for(i=0,i<440000*2,i++){//*2,因为预期的出现间隔;可能会更改
录音样本
fft(声音采样)
如果(频率SoundSample>x){
做点什么
返回
}
}
播放音调时会有相当大的背景噪音。但是,音调的频率会非常高,比如15-22KHz,因此我相信,只要在录音机检测到非常高的频率时查找,我就可以确定这是我的音调(同时,音调可能会以高振幅播放0.5秒或1秒)。我知道不会有其他高频声音作为背景噪音(我预计背景频率可能高达5KHz)

那么我有两个问题。我提供的伪代码是否足以满足我的要求?如果不是,或者有更好的方法,我完全赞成。第二,我将如何在java中实现这一点?我知道我需要做什么,但我很难把它们联系在一起。我对java相当熟练,但我不熟悉音频的语法,也没有fft方面的经验。请明确,并给出带有注释的代码。我想弄明白这一点已经有一段时间了,我只想看看这一切是如何联系在一起的。多谢各位

编辑


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

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

  • 这太过分了——你计算整个光谱只是为了检测某一点的幅度

  • 要获得3毫秒的起始检测分辨率,您需要在连续FFT之间有一个较大的重叠,这将需要比仅处理连续采样块多得多的CPU带宽

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


    请注意,关于音调检测和使用Goertzel算法(例如),已经有很多有用的问题和答案了-我建议将这些问题和Wikipedia条目一起阅读,作为一个很好的起点。

    我实际上也在用Java进行类似的音调检测项目。如果您想使用FFT,可以通过以下步骤来实现。Java有很多库,可以使这个过程变得简单

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

    其次,您应该使用jt变换进行FFT。下面是对一组样本进行FFT的示例

    FFT给出的数组长度是传递给它的样本数组长度的两倍。您需要按两个的顺序遍历FFT数组,因为该数组的每个部分都表示为一个虚块和一个实块。使用sqrt(im^2+re^2)计算此数组每个部分的大小。然后,找出哪个震级最大。这个数量级的指数对应于你要寻找的频率

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

    一旦你有了所有的FFT,他们应该确认一个特定的频率,你可以对照你想要的音符来检查

    如果您想尝试将其可视化,我建议使用JFreeChart。这是另一个使图形化变得容易的库