| Index: LayoutTests/webaudio/realtimeanalyser-fft-scaling.html
|
| diff --git a/LayoutTests/webaudio/realtimeanalyser-fft-scaling.html b/LayoutTests/webaudio/realtimeanalyser-fft-scaling.html
|
| index aed53e72e97e34af83fbf21efdeed6fc165ecf79..73dd517f07d2e5db6ee28d99ad74cff7b3737a9b 100644
|
| --- a/LayoutTests/webaudio/realtimeanalyser-fft-scaling.html
|
| +++ b/LayoutTests/webaudio/realtimeanalyser-fft-scaling.html
|
| @@ -14,14 +14,18 @@
|
| 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.
|
| + // 64, 128, 256, 512, 1024 and 2048 for a total of 7.
|
| var numberOfAnalysers = 7;
|
| var sampleRate = 44100;
|
| - var context;
|
| - var osc;
|
| - var oscFrequency = sampleRate/32;
|
| - var analysers = new Array(7);
|
| - var peakValue = new Array(7);
|
| + 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
|
| @@ -31,63 +35,65 @@
|
| // 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];
|
|
|
| - function checkResult() {
|
| - var allTestsPassed = true;
|
| -
|
| - for (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]
|
| + 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[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();
|
| + + 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();
|
| @@ -96,26 +102,28 @@
|
|
|
| window.jsTestIsAsync = true;
|
|
|
| - context = new OfflineAudioContext(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.
|
| + // Test each analyser size from order 5 (size 32) to 11 (size 2048).
|
| for (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]);
|
| + // 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();
|
| }
|
| -
|
| - osc.start();
|
| - context.oncomplete = checkResult;
|
| - context.startRendering();
|
| }
|
|
|
| runTests();
|
|
|