使用 node.js 检测麦克风的音频频率

Posted

技术标签:

【中文标题】使用 node.js 检测麦克风的音频频率【英文标题】:Detect audio frequency from microphone with node.js 【发布时间】:2015-03-23 16:34:45 【问题描述】:

我在 Raspberry Pi 上使用 node.js 来控制一些仪器。我想让一个麦克风监听一个特定的信号,说出一个 500 Hz 的音调,并在听到它时触发一个事件。

查看了多个 node.js 库后,node-core-audio (https://www.npmjs.com/package/node-core-audio) 是最接近的一个,但编译失败。

有人能推荐一个好方法吗?

【问题讨论】:

您的问题是如何访问音频流,或者如何检测流中给定频率的音调?这是两个完全不同的东西。 如何访问流。最坏的情况是我自己实现一个简单的 FFT。但就目前而言,找到合适的音频库简直是一场噩梦。 有a project to add the full Web Audio API to node.js。它看起来还不足以支持您的用例,但也许您可以为它做出贡献。 使用 FFT 来检测单音是多余的 - 只需使用 Goertzel。 【参考方案1】:

只需将傅里叶变换的某些部分用于您感兴趣的频率。

标量将您的输入信号与偏移四分之一波长的两个 500 Hz 音调相乘,总均方根 (RMS) 为 1,这意味着您可以使用 n^-½ 缩放矢量。

var sampleSize = 2000;
var sampleRate = 44100; // Or whatever in use (Hz)
var tone = 500; // tone to detect in Hz
var sin500Hz = Array(sampleSize);
var cos500Hz = Array(sampleSize);
for (var i = 0; i < sampleSize; i++) 
  sin500Hz[i] = Math.sin(2*Math.PI*tone/sampleRate*i)/Math.sqrt(sampleSize); 
  cos500Hz[i] = Math.cos(2*Math.PI*tone/sampleRate*i)/Math.sqrt(sampleSize); 

标量将信号输入与两个向量相乘。

function findTone(inputSamples) 
  var amplitudeSin = 0;
  var amplitudeCos = 0;
  for (var i = 0; i < sampleSize; i++) 
    amplitudeSin += inputSamples[i]*sin500Hz[i]; 
    amplitudeCos += inputSamples[i]*cos500Hz[i]; 
  
  return Math.sqrt(amplitudeSin*amplitudeSin + amplitudeCos*amplitudeCos); 

您可能希望将此值与信号的总幅度进行比较(取区间内所有样本的 RMS),否则也可以使用 findTone() 检测到噪声。

function noiseLevel(inputSamples) 
  var power = 0;
  var average = 0;
  for (var i = 0; i < sampleSize; i++) 
    average += inputSamples[i]; 
  
  average /= sampleSize;
  for (var i = 0; i < sampleSize; i++) 
    power += Math.pow(inputSamples[i] - average, 2); 
  
  return Math.sqrt(power); 

所以您想要的检测可能是配额 findTone(inputSamples)/noiseLevel(inputSamples) 的某个最小值。

如果您使用太多样本,算法将非常精确,并且如果您有一个有偏差或有噪声的 500 Hz 输入信号,可能会比您希望的更精确。那么带通滤波器是一种替代方案。

如果您只需要频谱的一个或几个部分并且 FFT 既不允许任意频率也不允许任意采样集,则使用 FFT 会浪费 CPU 周期。

【讨论】:

【参考方案2】:

请注意,我也遇到过这个问题,但找不到答案。我继续制作了 2 个 NPM 模块,1 个包装了“sndpeek”(一个开源音频分析库),另一个使用该包装的模块检测音调; https://www.npmjs.com/package/whistle-detection

我无法让 sndpeek 应用程序在我的树莓派上运行,这太糟糕了,但这些节点应用程序在我的 Linux (ubuntu 15.04) 和 Windows 7 机器上运行良好。

【讨论】:

以上是关于使用 node.js 检测麦克风的音频频率的主要内容,如果未能解决你的问题,请参考以下文章

VB.net现场频率检测

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

我的应用程序“查找麦克风的音频输入频率”总是崩溃。但为啥?

使用麦克风录制时,SDL 音频捕获未检测到任何音频

使用 C# 程序从 PC 麦克风获取音频

使用套接字 IO 和 Node JS 通过套接字流式传输麦克风