1 <!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN">
4 <script src=
"../resources/js-test.js"></script>
5 <script src=
"resources/compatibility.js"></script>
6 <script src=
"resources/audio-testing.js"></script>
10 <div id=
"description"></div>
11 <div id=
"console"></div>
14 description("Test scaling of FFT data for AnalyserNode");
16 // The number of analysers. We have analysers from size for each of the possible sizes of 32,
17 // 64, 128, 256, 512, 1024 and 2048 for a total of 7.
18 var numberOfAnalysers
= 7;
19 var sampleRate
= 44100;
20 var nyquistFrequency
= sampleRate
/ 2;
22 // Frequency of the sine wave test signal. Should be high enough so that we get at least one
23 // full cycle for the 32-point FFT. This should also be such that the frequency should be
24 // exactly in one of the FFT bins for each of the possible FFT sizes.
25 var oscFrequency
= nyquistFrequency
/16;
27 // The actual peak values from each analyser. Useful for examining the results in Chrome.
28 var peakValue
= new Array(numberOfAnalysers
);
30 // For a 0dBFS sine wave, we would expect the FFT magnitude to be 0dB as well, but the
31 // analyzer node applies a Blackman window (to smooth the estimate). This reduces the energy
32 // of the signal so the FFT peak is less than 0dB. The threshold value given here was
33 // determined experimentally.
35 // See https://code.google.com/p/chromium/issues/detail?id=341596.
36 var peakThreshold
= [-14.43, -13.56, -13.56, -13.56, -13.56, -13.56, -13.56];
38 var allTestsPassed
= true;
40 function checkResult(order
, analyser
) {
42 var index
= order
- 5;
43 var fftSize
= 1 << order
;
44 var fftData
= new Float32Array(fftSize
);
45 analyser
.getFloatFrequencyData(fftData
);
47 // Compute the frequency bin that should contain the peak.
48 var expectedBin
= analyser
.frequencyBinCount
* (oscFrequency
/ nyquistFrequency
);
50 // Find the actual bin by finding the bin containing the peak.
52 peakValue
[index
] = -1000;
53 for (k
= 0; k
< analyser
.frequencyBinCount
; ++k
) {
54 if (fftData
[k
] > peakValue
[index
]) {
56 peakValue
[index
] = fftData
[k
];
62 if (actualBin
== expectedBin
) {
63 testPassed("Actual FFT peak in the expected position (" + expectedBin
+ ").");
66 testFailed("Actual FFT peak (" + actualBin
+ ") differs from expected (" + expectedBin
+ ").");
69 if (peakValue
[index
] >= peakThreshold
[index
]) {
70 testPassed("Peak value is near " + peakThreshold
[index
] + " dBFS as expected.");
73 testFailed("Peak value of " + peakValue
[index
]
74 + " is incorrect. (Expected approximately "
75 + peakThreshold
[index
] + ").");
79 testPassed("Analyser correctly scaled FFT data of size " + fftSize
);
81 testFailed("Analyser incorrectly scaled FFT data of size " + fftSize
);
83 allTestsPassed
= allTestsPassed
&& success
;
85 if (fftSize
== 2048) {
87 testPassed("All Analyser tests passed.");
89 testFailed("At least one Analyser test failed.");
98 if (window
.testRunner
) {
99 testRunner
.dumpAsText();
100 testRunner
.waitUntilDone();
103 window
.jsTestIsAsync
= true;
105 // Test each analyser size from order 5 (size 32) to 11 (size 2048).
106 for (order
= 5; order
< 12; ++order
) {
107 // Create a new offline context for each analyser test with the number of samples
108 // exactly equal to the fft size. This ensures that the analyser node gets the
109 // expected data from the oscillator.
110 var context
= new OfflineAudioContext(1, 1 << order
, sampleRate
);
111 // Use a sine wave oscillator as the reference source signal.
112 var osc
= context
.createOscillator();
114 osc
.frequency
.value
= oscFrequency
;
115 osc
.connect(context
.destination
);
117 var analyser
= context
.createAnalyser();
118 // No smoothing to simplify the analysis of the result.
119 analyser
.smoothingTimeConstant
= 0;
120 analyser
.fftSize
= 1 << order
;
121 osc
.connect(analyser
);
124 context
.oncomplete
= checkResult(order
, analyser
);
125 context
.startRendering();
130 successfullyParsed
= true;