Web Audio API AnalyserNode中可能存在的错误

时间:2017-03-18 18:22:53

标签: javascript fft frequency web-audio-api

我正在玩Web Audio API,可能在AnalyserNode中发现了一个错误。假设我有两个正弦振荡器分别以200 Hz和8000 Hz的频率播放。使用两个不同的AnalyserNode,我从两个振荡器中提取非零频率数据,这些数据如下(来自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("");
}

1 个答案:

答案 0 :(得分:0)

这是预期的。根据{{​​3}},连续调用提取频率数据将来自当前调用的数据与来自先前调用的数据的历史相结合。如果我们只想查看当前时间的频率数据,请将smoothingTimeConstant设置为0。

spec