| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
| <html> |
| <head> |
| <script src="../resources/js-test.js"></script> |
| <script src="resources/compatibility.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 for a total of 7. |
| var numberOfAnalysers = 7; |
| var sampleRate = 44100; |
| var nyquistFrequency = sampleRate / 2; |
| |
| // Frequency of the sine wave test signal. Should be high enough so that we get at least one |
| // full cycle for the 32-point FFT. This should also be such that the frequency should be |
| // exactly in one of the FFT bins for each of the possible FFT sizes. |
| var oscFrequency = nyquistFrequency/16; |
| |
| // The actual peak values from each analyser. Useful for examining the results in Chrome. |
| var peakValue = new Array(numberOfAnalysers); |
| |
| // 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 = [-14.43, -13.56, -13.56, -13.56, -13.56, -13.56, -13.56]; |
| |
| var allTestsPassed = true; |
| |
| function checkResult(order, analyser) { |
| return function () { |
| var index = order - 5; |
| var fftSize = 1 << order; |
| var fftData = new Float32Array(fftSize); |
| analyser.getFloatFrequencyData(fftData); |
| |
| // Compute the frequency bin that should contain the peak. |
| var expectedBin = analyser.frequencyBinCount * (oscFrequency / nyquistFrequency); |
| |
| // Find the actual bin by finding the bin containing the peak. |
| var actualBin = 0; |
| peakValue[index] = -1000; |
| for (k = 0; k < analyser.frequencyBinCount; ++k) { |
| if (fftData[k] > peakValue[index]) { |
| actualBin = k; |
| peakValue[index] = 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[index] >= peakThreshold[index]) { |
| testPassed("Peak value is near " + peakThreshold[index] + " dBFS as expected."); |
| } else { |
| success = false; |
| testFailed("Peak value of " + peakValue[index] |
| + " is incorrect. (Expected approximately " |
| + peakThreshold[index] + ")."); |
| } |
| |
| 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 (fftSize == 2048) { |
| if (allTestsPassed) { |
| testPassed("All Analyser tests passed."); |
| } else { |
| testFailed("At least one Analyser test failed."); |
| } |
| |
| finishJSTest(); |
| } |
| } |
| } |
| |
| function runTests() { |
| if (window.testRunner) { |
| testRunner.dumpAsText(); |
| testRunner.waitUntilDone(); |
| } |
| |
| window.jsTestIsAsync = true; |
| |
| // Test each analyser size from order 5 (size 32) to 11 (size 2048). |
| for (order = 5; order < 12; ++order) { |
| // Create a new offline context for each analyser test with the number of samples |
| // exactly equal to the fft size. This ensures that the analyser node gets the |
| // expected data from the oscillator. |
| var context = new OfflineAudioContext(1, 1 << order, sampleRate); |
| // Use a sine wave oscillator as the reference source signal. |
| var osc = context.createOscillator(); |
| osc.type = "sine"; |
| osc.frequency.value = oscFrequency; |
| osc.connect(context.destination); |
| |
| var analyser = context.createAnalyser(); |
| // No smoothing to simplify the analysis of the result. |
| analyser.smoothingTimeConstant = 0; |
| analyser.fftSize = 1 << order; |
| osc.connect(analyser); |
| |
| osc.start(); |
| context.oncomplete = checkResult(order, analyser); |
| context.startRendering(); |
| } |
| } |
| |
| runTests(); |
| successfullyParsed = true; |
| </script> |
| </body> |
| </html> |