OLD | NEW |
| (Empty) |
1 <!doctype html> | |
2 <html> | |
3 <head> | |
4 <title>Test fftSize Changes Resetting AnalyserNode State </title> | |
5 <script src="../resources/testharness.js"></script> | |
6 <script src="../resources/testharnessreport.js"></script> | |
7 <script src="resources/audit-util.js"></script> | |
8 <script src="resources/audio-testing.js"></script> | |
9 </head> | |
10 | |
11 <body> | |
12 <script> | |
13 // Fairly arbitrary sample rate. | |
14 var sampleRate = 24000; | |
15 | |
16 var audit = Audit.createTaskRunner(); | |
17 | |
18 // Verify that setting the fftSize resets the memory for the FFT smoothing | |
19 // operation. Only a few of the possible variations are tested. | |
20 | |
21 audit.defineTask("128->1024", function (taskDone) { | |
22 testFFTSize({ | |
23 initialFFTSize: 128, | |
24 finalFFTSize: 1024, | |
25 errorThreshold: { | |
26 relativeThreshold: 1.9095e-6 | |
27 } | |
28 }).then(taskDone); | |
29 }); | |
30 | |
31 audit.defineTask("512->256", function (taskDone) { | |
32 testFFTSize({ | |
33 initialFFTSize: 512, | |
34 finalFFTSize: 256, | |
35 errorThreshold: { | |
36 relativeThreshold: 1.8166e-6 | |
37 } | |
38 }).then(taskDone); | |
39 }); | |
40 | |
41 function testFFTSize(options) { | |
42 var { | |
43 initialFFTSize, finalFFTSize, errorThreshold | |
44 } = options; | |
45 | |
46 // The duration is fairly arbitrary as long as it's long enough for the | |
47 // FFT test. | |
48 var context = new OfflineAudioContext(1, sampleRate, sampleRate); | |
49 | |
50 // Actual source doesn't matter but a sawtooth is a nice waveform with | |
51 // lots of harmonic content. | |
52 var osc = context.createOscillator(); | |
53 osc.type = "sawtooth"; | |
54 | |
55 // The analyser under test. | |
56 var testAnalyser = context.createAnalyser(); | |
57 testAnalyser.fftSize = initialFFTSize; | |
58 | |
59 // The reference analyser. The fftSize is fixed to the desired value, | |
60 // and we turn off smoothing so that we get the FFT of the current time | |
61 // data. | |
62 var refAnalyser = context.createAnalyser(); | |
63 refAnalyser.fftSize = finalFFTSize; | |
64 refAnalyser.smoothingTimeConstant = 0; | |
65 | |
66 // Setup the graph and start the oscillator. | |
67 osc.connect(testAnalyser) | |
68 .connect(context.destination); | |
69 osc.connect(refAnalyser) | |
70 .connect(context.destination); | |
71 | |
72 osc.start(); | |
73 | |
74 // Let the analyser smooth a few FFTs (rather arbitrary, but should be | |
75 // more than one), then switch the size. | |
76 | |
77 var suspendFrame = 4 * initialFFTSize; | |
78 context.suspend(suspendFrame / context.sampleRate) | |
79 .then(function () { | |
80 testAnalyser.fftSize = finalFFTSize; | |
81 }) | |
82 .then(context.resume.bind(context)); | |
83 | |
84 // Wait some frames and grab the FFT data. This is fairly arbitrary | |
85 // too, and can be independent of the FFT sizes. | |
86 suspendFrame += 1024; | |
87 context.suspend(suspendFrame / context.sampleRate) | |
88 .then(function () { | |
89 var testFFT = new Float32Array(testAnalyser.frequencyBinCount); | |
90 var refFFT = new Float32Array(refAnalyser.frequencyBinCount) | |
91 var testSignal = new Float32Array(testAnalyser.fftSize); | |
92 var refSignal = new Float32Array(refAnalyser.fftSize); | |
93 | |
94 testAnalyser.getFloatTimeDomainData(testSignal); | |
95 refAnalyser.getFloatTimeDomainData(refSignal); | |
96 | |
97 testAnalyser.getFloatFrequencyData(testFFT); | |
98 refAnalyser.getFloatFrequencyData(refFFT); | |
99 | |
100 // Convert the FFT data from dB to linear | |
101 testFFT = testFFT.map(x => Math.pow(10, x / 20)); | |
102 refFFT = refFFT.map(x => Math.pow(10, x / 20)); | |
103 | |
104 // The test data has smoothing applied, but the reference doesn't. | |
105 // Apply the smoothing factor to the reference data. | |
106 var smoothing = 1 - testAnalyser.smoothingTimeConstant; | |
107 refFFT = refFFT.map(x => x * smoothing); | |
108 | |
109 var success = true; | |
110 | |
111 // First a basic sanity check that the time domain signals are | |
112 // exactly the same for both analysers. | |
113 success = Should("Time data", testSignal) | |
114 .beCloseToArray(refSignal, 0) && success; | |
115 | |
116 success = Should("Linear FFT data after setting fftSize = " + testAn
alyser.fftSize, | |
117 testFFT) | |
118 .beCloseToArray(refFFT, errorThreshold) && success; | |
119 | |
120 Should("*** Changing fftSize from " + initialFFTSize + " to " + fina
lFFTSize, success) | |
121 .summarize( | |
122 "correctly reset the smoothing state", | |
123 "did not correctly reset the smoothing state"); | |
124 }) | |
125 .then(context.resume.bind(context)); | |
126 | |
127 return context.startRendering(); | |
128 } | |
129 | |
130 audit.runTasks(); | |
131 </script> | |
132 </body> | |
133 </html> | |
OLD | NEW |