OLD | NEW |
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> | 1 <!DOCTYPE html> |
2 <html> | 2 <html> |
3 <head> | 3 <head> |
| 4 <title> |
| 5 realtimeanalyser-fft-scaling.html |
| 6 </title> |
4 <script src="../../resources/testharness.js"></script> | 7 <script src="../../resources/testharness.js"></script> |
5 <script src="../../resources/testharnessreport.js"></script> | 8 <script src="../../resources/testharnessreport.js"></script> |
6 <script src="../resources/audit-util.js"></script> | 9 <script src="../resources/audit-util.js"></script> |
7 <script src="../resources/audit.js"></script> | 10 <script src="../resources/audit.js"></script> |
8 </head> | 11 </head> |
9 | |
10 <body> | 12 <body> |
11 <div id="description"></div> | 13 <div id="description"></div> |
12 <div id="console"></div> | 14 <div id="console"></div> |
13 | 15 <script id="layout-test-code"> |
14 <script> | |
15 let audit = Audit.createTaskRunner(); | 16 let audit = Audit.createTaskRunner(); |
16 | 17 |
17 // The number of analysers. We have analysers from size for each of the | 18 // The number of analysers. We have analysers from size for each of the |
18 // possible sizes of 2^5 to 2^15 for a total of 11. | 19 // possible sizes of 2^5 to 2^15 for a total of 11. |
19 let numberOfAnalysers = 11; | 20 let numberOfAnalysers = 11; |
20 let sampleRate = 44100; | 21 let sampleRate = 44100; |
21 let nyquistFrequency = sampleRate / 2; | 22 let nyquistFrequency = sampleRate / 2; |
22 | 23 |
23 // Frequency of the sine wave test signal. Should be high enough so that
we get at least one | 24 // Frequency of the sine wave test signal. Should be high enough so that |
24 // full cycle for the 32-point FFT. This should also be such that the fre
quency should be | 25 // we get at least one full cycle for the 32-point FFT. This should also |
25 // exactly in one of the FFT bins for each of the possible FFT sizes. | 26 // be such that the frequency should be exactly in one of the FFT bins for |
26 let oscFrequency = nyquistFrequency/16; | 27 // each of the possible FFT sizes. |
| 28 let oscFrequency = nyquistFrequency / 16; |
27 | 29 |
28 // The actual peak values from each analyser. Useful for examining the re
sults in Chrome. | 30 // The actual peak values from each analyser. Useful for examining the |
| 31 // results in Chrome. |
29 let peakValue = new Array(numberOfAnalysers); | 32 let peakValue = new Array(numberOfAnalysers); |
30 | 33 |
31 // For a 0dBFS sine wave, we would expect the FFT magnitude to be 0dB as w
ell, but the | 34 // For a 0dBFS sine wave, we would expect the FFT magnitude to be 0dB as |
32 // analyzer node applies a Blackman window (to smooth the estimate). This
reduces the energy | 35 // well, but the analyzer node applies a Blackman window (to smooth the |
33 // of the signal so the FFT peak is less than 0dB. The threshold value gi
ven here was | 36 // estimate). This reduces the energy of the signal so the FFT peak is |
34 // determined experimentally. | 37 // less than 0dB. The threshold value given here was determined |
| 38 // experimentally. |
35 // | 39 // |
36 // See https://code.google.com/p/chromium/issues/detail?id=341596. | 40 // See https://code.google.com/p/chromium/issues/detail?id=341596. |
37 let peakThreshold = [-14.43, -13.56, -13.56, -13.56, -13.56, -13.56, | 41 let peakThreshold = [ |
38 -13.56, -13.56, -13.56, -13.56, -13.56 | 42 -14.43, -13.56, -13.56, -13.56, -13.56, -13.56, -13.56, -13.56, -13.56, |
| 43 -13.56, -13.56 |
39 ]; | 44 ]; |
40 | 45 |
41 function checkResult(order, analyser, should) { | 46 function checkResult(order, analyser, should) { |
42 return function () { | 47 return function() { |
43 let index = order - 5; | 48 let index = order - 5; |
44 let fftSize = 1 << order; | 49 let fftSize = 1 << order; |
45 let fftData = new Float32Array(fftSize); | 50 let fftData = new Float32Array(fftSize); |
46 analyser.getFloatFrequencyData(fftData); | 51 analyser.getFloatFrequencyData(fftData); |
47 | 52 |
48 // Compute the frequency bin that should contain the peak. | 53 // Compute the frequency bin that should contain the peak. |
49 let expectedBin = analyser.frequencyBinCount * (oscFrequency / nyq
uistFrequency); | 54 let expectedBin = |
| 55 analyser.frequencyBinCount * (oscFrequency / nyquistFrequency); |
50 | 56 |
51 // Find the actual bin by finding the bin containing the peak. | 57 // Find the actual bin by finding the bin containing the peak. |
52 let actualBin = 0; | 58 let actualBin = 0; |
53 peakValue[index] = -1000; | 59 peakValue[index] = -1000; |
54 for (k = 0; k < analyser.frequencyBinCount; ++k) { | 60 for (k = 0; k < analyser.frequencyBinCount; ++k) { |
55 if (fftData[k] > peakValue[index]) { | 61 if (fftData[k] > peakValue[index]) { |
56 actualBin = k; | 62 actualBin = k; |
57 peakValue[index] = fftData[k]; | 63 peakValue[index] = fftData[k]; |
58 } | 64 } |
59 } | 65 } |
60 | 66 |
61 should(actualBin, (1 << order) + "-point FFT peak position") | 67 should(actualBin, (1 << order) + '-point FFT peak position') |
62 .beEqualTo(expectedBin); | 68 .beEqualTo(expectedBin); |
63 | 69 |
64 should(peakValue[index], (1 << order) + | 70 should( |
65 "-point FFT peak value in dBFS") | 71 peakValue[index], (1 << order) + '-point FFT peak value in dBFS') |
66 .beGreaterThanOrEqualTo(peakThreshold[index]); | 72 .beGreaterThanOrEqualTo(peakThreshold[index]); |
67 } | 73 } |
68 } | 74 } |
69 | 75 |
70 audit.define({ | 76 audit.define( |
71 label: "FFT scaling tests", | 77 { |
72 description: "Test Scaling of FFT in AnalyserNode" | 78 label: 'FFT scaling tests', |
73 }, function (task, should) { | 79 description: 'Test Scaling of FFT in AnalyserNode' |
74 let tests = []; | 80 }, |
75 for (let k = 5; k <= 15; ++k) | 81 function(task, should) { |
76 tests.push(runTest(k, should)); | 82 let tests = []; |
| 83 for (let k = 5; k <= 15; ++k) |
| 84 tests.push(runTest(k, should)); |
77 | 85 |
78 // The order in which the tests finish is not important. | 86 // The order in which the tests finish is not important. |
79 Promise.all(tests) | 87 Promise.all(tests).then(task.done.bind(task)); |
80 .then(task.done.bind(task)); | 88 }); |
81 }); | |
82 | 89 |
83 function runTest(order, should) { | 90 function runTest(order, should) { |
84 let context = new OfflineAudioContext(1, 1 << order, sampleRate); | 91 let context = new OfflineAudioContext(1, 1 << order, sampleRate); |
85 // Use a sine wave oscillator as the reference source signal. | 92 // Use a sine wave oscillator as the reference source signal. |
86 let osc = context.createOscillator(); | 93 let osc = context.createOscillator(); |
87 osc.type = "sine"; | 94 osc.type = 'sine'; |
88 osc.frequency.value = oscFrequency; | 95 osc.frequency.value = oscFrequency; |
89 osc.connect(context.destination); | 96 osc.connect(context.destination); |
90 | 97 |
91 let analyser = context.createAnalyser(); | 98 let analyser = context.createAnalyser(); |
92 // No smoothing to simplify the analysis of the result. | 99 // No smoothing to simplify the analysis of the result. |
93 analyser.smoothingTimeConstant = 0; | 100 analyser.smoothingTimeConstant = 0; |
94 analyser.fftSize = 1 << order; | 101 analyser.fftSize = 1 << order; |
95 osc.connect(analyser); | 102 osc.connect(analyser); |
96 | 103 |
97 osc.start(); | 104 osc.start(); |
98 context.oncomplete = checkResult(order, analyser, should); | 105 context.oncomplete = checkResult(order, analyser, should); |
99 return context.startRendering() | 106 return context.startRendering().then(function(audioBuffer) { |
100 .then(function (audioBuffer) { | 107 checkResult(audioBuffer, order, analyser); |
101 checkResult(audioBuffer, order, analyser); | 108 }); |
102 }); | |
103 } | 109 } |
104 | 110 |
105 audit.run(); | 111 audit.run(); |
106 </script> | 112 </script> |
107 </body> | 113 </body> |
108 </html> | 114 </html> |
OLD | NEW |