| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
| <html> |
| <head> |
| <script src="../resources/js-test.js"></script> |
| <script src="resources/audio-testing.js"></script> |
| </head> |
| |
| <body> |
| <div id="description"></div> |
| <div id="console"></div> |
| |
| <script> |
| description("Test scaling of FFT data for AnalyserNode"); |
| |
| // The number of analysers. We have analysers from size for each of the possible sizes of 32, |
| // 64, 128, 256, 512, 1024 and 2048. |
| var numberOfAnalysers = 7; |
| var sampleRate = 44100; |
| var context; |
| var osc; |
| var oscFrequency = sampleRate/32; |
| var analysers = new Array(7); |
| var peakValue = new Array(7); |
| |
| // For a 0dBFS sine wave, we would expect the FFT magnitude to be 0dB as well, but the |
| // analyzer node applies a Blackman window (to smooth the estimate). This reduces the energy |
| // of the signal so the FFT peak is less than 0dB. The threshold value given here was |
| // determined experimentally. |
| // |
| // See https://code.google.com/p/chromium/issues/detail?id=341596. |
| var peakThreshold = [-8.41, -7.54, -7.54, -7.54, -7.54, -7.54, -7.54]; |
| |
| function checkResult() { |
| var allTestsPassed = true; |
| |
| for (var n = 0; n < analysers.length; ++n) { |
| // Grab the FFT data from each analyser. |
| var fftSize = analysers[n].fftSize; |
| var fftData = new Float32Array(fftSize); |
| analysers[n].getFloatFrequencyData(fftData); |
| |
| // Compute the frequency bin that should contain the peak. |
| var expectedBin = fftSize * (oscFrequency / sampleRate); |
| |
| // Find the actual bin by finding the bin containing the peak. |
| var actualBin = 0; |
| peakValue[n] = -1000; |
| for (k = 0; k < analysers[n].frequencyBinCount; ++k) { |
| if (fftData[k] > peakValue[n]) { |
| actualBin = k; |
| peakValue[n] = fftData[k]; |
| } |
| } |
| |
| var success = true; |
| |
| if (actualBin == expectedBin) { |
| testPassed("Actual FFT peak in the expected position (" + expectedBin + ")"); |
| } else { |
| success = false; |
| testFailed("Actual FFT peak (" + actualBin + ") differs from expected (" + expectedBin + ")"); |
| } |
| |
| if (peakValue[n] >= peakThreshold[n]) { |
| testPassed("Peak value is near 0 dBFS as expected"); |
| } else { |
| success = false; |
| testFailed("Peak value of " + peakValue[n] |
| + " is incorrect. (Expected approximately " |
| + peakThreshold[n] + ")"); |
| } |
| |
| if (success) { |
| testPassed("Analyser correctly scaled FFT data of size " + fftSize); |
| } else { |
| testFailed("Analyser incorrectly scaled FFT data of size " + fftSize); |
| } |
| allTestsPassed = allTestsPassed && success; |
| } |
| |
| if (allTestsPassed) { |
| testPassed("All Analyser tests passed."); |
| } else { |
| testFailed("At least one Analyser test failed."); |
| } |
| |
| finishJSTest(); |
| } |
| |
| function runTests() { |
| window.jsTestIsAsync = true; |
| |
| context = new webkitOfflineAudioContext(1, 2048, sampleRate); |
| |
| // Use a sine wave oscillator as the reference source signal. |
| osc = context.createOscillator(); |
| osc.type = "sine"; |
| osc.frequency.value = oscFrequency; |
| osc.connect(context.destination); |
| |
| // Create an analyser node for each of the possible valid sizes. |
| for (var order = 5; order < 12; ++order) { |
| analysers[order - 5] = context.createAnalyser(); |
| // No smoothing so between frames to simplify testing. |
| analysers[order - 5].smoothingTimeConstant = 0; |
| analysers[order - 5].fftSize = 1 << order; |
| osc.connect(analysers[order - 5]); |
| } |
| |
| osc.start(0); |
| context.oncomplete = checkResult; |
| context.startRendering(); |
| } |
| |
| runTests(); |
| </script> |
| </body> |
| </html> |