【发布时间】:2017-08-10 05:31:56
【问题描述】:
我正在使用 Web Audio API,可能在 AnalyserNode 中发现了一个错误。假设我有两个正弦振荡器以不同的频率播放,分别为 200 Hz 和 8000 Hz。使用两个不同的 AnalyserNode(s) 我从两个振荡器中提取非零频率数据,它们如下(来自 chrome 控制台):
OSC1 (200 Hz)
Bin 0 value 1
Bin 1 value 3
Bin 2 value 9
Bin 3 value 18
Bin 4 value 30
Bin 5 value 43
Bin 6 value 36
Bin 7 value 159
Bin 8 value 236
Bin 9 value 255
Bin 10 value 255
Bin 11 value 212
Bin 12 value 86
Bin 13 value 46
Bin 14 value 36
Bin 15 value 21
Bin 16 value 8
OSC2 (8000 Hz)
Bin 364 value 6
Bin 365 value 18
Bin 366 value 32
Bin 367 value 46
Bin 368 value 52
Bin 369 value 126
Bin 370 value 224
Bin 371 value 255
Bin 372 value 255
Bin 373 value 226
Bin 374 value 132
Bin 375 value 51
Bin 376 value 47
Bin 377 value 33
Bin 378 value 19
Bin 379 value 7
现在,如果我将第一个振荡器的频率值更改为 8000 Hz(与第二个振荡器相同)并再次提取非零频率数据,我希望在第二个振荡器的相同 Bins 中大致获得非零值(比如在 300-400 范围内),但奇怪的是在 0-50 范围内的 Bins 中也有非零值(当我们使用 200 Hz 频率提取频率数据时)。
OSC1 (8000 Hz)
Bin 2 value 2
Bin 3 value 11
Bin 4 value 23
Bin 5 value 36
Bin 6 value 29
Bin 7 value 152
Bin 8 value 229
Bin 9 value 255
Bin 10 value 248
Bin 11 value 205
Bin 12 value 79
Bin 13 value 38
Bin 14 value 29
Bin 15 value 14
Bin 16 value 1
Bin 364 value 7
Bin 365 value 19
Bin 366 value 33
Bin 367 value 47
Bin 368 value 50
Bin 369 value 137
Bin 370 value 228
Bin 371 value 255
Bin 372 value 255
Bin 373 value 222
Bin 374 value 121
Bin 375 value 52
Bin 376 value 45
Bin 377 value 31
Bin 378 value 18
Bin 379 value 5
这是预期的行为还是错误?这对我来说似乎不正确。我也不确定在使用例如 requestAnimationFrame 循环分析标准音频文件时这是否也会传播。 在完整示例的代码下方。
注意:在分析仪完成快速傅里叶变换算法并且频率数据可用之前,要提取频率数据需要稍等片刻,因此我使用了 2 个 timeOut 函数,一个用于第一次提取频率数据从 osc1 和 osc2 以及第二个在振荡器频率变为 8000 Hz 后再次从 osc1 中提取频率数据。
var AudioContext = window.AudioContext || window.webkitAudioContext;
var ctx = new AudioContext();
// first oscillator (200 Hz)
var osc1 = ctx.createOscillator();
osc1.frequency.value = 200;
var analyser1 = ctx.createAnalyser();
var gain1 = ctx.createGain();
gain1.gain.value = 0;
osc1.connect(analyser1);
analyser1.connect(gain1);
gain1.connect(ctx.destination);
// second oscillator (8000 Hz)
var osc2 = ctx.createOscillator();
osc2.frequency.value = 8000;
var analyser2 = ctx.createAnalyser();
var gain2 = ctx.createGain();
gain2.gain.value = 0;
osc2.connect(analyser2);
analyser2.connect(gain2);
gain2.connect(ctx.destination);
// start oscillators
osc1.start();
osc2.start();
// get frequency data
var freqData1 = new Uint8Array(analyser1.frequencyBinCount);
var freqData2 = new Uint8Array(analyser2.frequencyBinCount);
setTimeout(function() {
analyser1.getByteFrequencyData(freqData1);
analyser2.getByteFrequencyData(freqData2);
console.log("OSC1 (200 Hz)");
printNonZeroFreqData(freqData1);
console.log("OSC2 (8000 Hz)");
printNonZeroFreqData(freqData2);
// change frequency of osc1 to 8000 Hz
osc1.frequency.value = 8000;
// wait a bit, then extract again frequency data from osc1
setTimeout(function() {
freqData1 = new Uint8Array(analyser1.frequencyBinCount);
analyser1.getByteFrequencyData(freqData1);
console.log("OSC1 (8000 Hz)");
printNonZeroFreqData(freqData1);
}, 500);
}, 500);
// print non zero frequency values
function printNonZeroFreqData(arr) {
for (var i = 0; i < arr.length; ++i) {
if (arr[i] != 0) {
console.log("Bin " + i, "\tvalue " + arr[i]);
}
}
console.log("");
}
【问题讨论】:
标签: javascript fft frequency web-audio-api