我在Raspberry Pi上使用node.js来控制一些乐器。我希望有一个麦克风听一个特定的信号,比如一个500赫兹的音调,并在听到它时触发一个事件。
查看了多个node.js库,node-core-audio(https://www.npmjs.com/package/node-core-audio)是最接近的库,但在编译时失败了。
有人可以推荐一个好方法吗?
答案 0 :(得分:5)
只需将傅里叶变换的某些部分用于您感兴趣的频率。
标量将输入信号乘以两个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周期。
答案 1 :(得分:1)
只是一个单挑,我也遇到过这个问题,但无法找到答案。我继续制作2个NPM模块,1个包装&#34; sndpeek&#34; (一个开源音频分析库)和另一个用该包装模块检测音调的音频; https://www.npmjs.com/package/whistle-detection
太糟糕了,我无法让sndpeek应用程序在我的覆盆子pi上运行,但这些节点应用程序在我的Linux(ubuntu 15.04)和Windows 7机器上运行良好。