4 <title>Test Different PeriodicWave Lengths at Different Sample Rates
</title>
5 <script src=
"../resources/js-test.js"></script>
6 <script src=
"resources/compatibility.js"></script>
7 <script src=
"resources/audio-testing.js"></script>
12 description("Test Different PeriodicWave Lengths at Different Sample Rates");
13 window
.jsTestIsAsync
= true;
15 // Test PeriodicWave objects with varying number of coefficients at different sample rates.
16 // Basically, verify that the coefficients are used at the appropriate sample rates. This is
17 // done by comparing the outputs of two periodic waves used in oscillators. The output should
18 // either be exactly zero or not depending on whether the coefficients were used.
23 var audit
= Audit
.createTaskRunner();
25 // The set of Audit tests to be run to verify that PeriodicWave is using the correct number of
26 // coefficients. The name does not have to be unique; the index of the entry is appended to
27 // the test. Every entry (except the last) needs sampleRate, bigWave, smallWave, and
31 // Tests for contexts at 192 kHz.
33 // Test that we use more than 2048 Fourier coefficients at 192 kHz sample rate. Basically
34 // verifies that 8192 is acceptable.
36 name
: "192khz-test-1",
40 verifier
: resultShouldBeNonZero
43 // Test that we use at least 2049 Fourier coefficients at 192 kHz sample rate.
45 name
: "192khz-test-2",
49 verifier
: resultShouldBeNonZero
52 // Test that we use all 8192 Fourier coefficients at 192 kHz sample rate. Ideally, we'd
53 // like to compare 8191 coefficients vs 8192 coefficients. However, due to single-precision
54 // arithmetic, the wave forms are identical in this case. Thus, use a somewhat smaller
55 // value where the wave forms are actually different.
57 name
: "192khz-test-3",
60 smallWave
: (8 - 1 / 256) * 1024,
61 verifier
: resultShouldBeNonZero
64 // Tests for contexts at 48 kHz.
66 // Test that we do not use more than 2048 Fourier coefficients at 48 kHz. This depends on
67 // the internal implementation where, for backward compatibility and speed, we only use 2048
68 // coefficients at 48 kHz. (This is also true for rates below 88.2 kHz.) Also tests that
69 // 8192 coefficients are allowed (but not all coefficients are used, of course).
75 verifier
: resultShouldBeZero
78 // Test that we do not use more than 2048 Fourier coefficients.
84 verifier
: resultShouldBeZero
87 // It's not immediately clear with single-preicison arithmetic that we can distinguish
88 // between 2049 and 2048 coefficients, so do one more test with slightly more coefficients.
92 bigWave
: (2 + 1 / 64) * 1024,
94 verifier
: resultShouldBeZero
97 // Test that we use at least 2048 Fourier coefficients at 48 kHz. Ideally we want to
98 // compare 2047 and 2048 coefficients, but single-precision arithmetic makes the resulting
99 // waveforms the same. Hence use a smaller value that produces different waveforms.
101 name
: "48khz-test-4",
105 verifier
: resultShouldBeNonZero
108 // Tests for contexts at 24 kHz.
110 // Test that we do not use more than 1024 Fourier coefficients at 24 kHz.
112 name
: "24khz-test-1",
116 verifier
: resultShouldBeZero
119 // Test that we do not use more than 1024 Fourier coefficients at 24 kHz.
121 name
: "24khz-test-2",
125 verifier
: resultShouldBeZero
128 // Test that we use at least 1024 Fourier coefficients at 24 kHz. Again, 1023 and 1024
129 // produce the same waveforms in single-precisiion so use a smaller wave table size.
131 name
: "24khz-test-3",
135 verifier
: resultShouldBeNonZero
139 function generatePrefix (sampleRate
, bigLength
, smallLength
) {
140 return "At " + (sampleRate
/ 1000) + " kHz, PeriodicWave with "
141 + bigLength
+ " coefficients vs "
142 + smallLength
+ ": ";
145 // Returns a function the verifies that the result is zero. The parameters control what is
146 // printed in the messages.
147 function resultShouldBeZero(sampleRate
, bigLength
, smallLength
) {
148 return function (buffer
) {
149 var prefix
= generatePrefix(sampleRate
, bigLength
, smallLength
);
150 if (isBufferZero(buffer
))
151 testPassed(prefix
+ "identical as expected.");
153 testFailed(prefix
+ "unexpectedly differ.");
157 // Returns a function the verifies that the result is non-zero. The parameters control what is
158 // printed in the messages.
159 function resultShouldBeNonZero(sampleRate
, bigLength
, smallLength
) {
160 return function (buffer
) {
161 var prefix
= generatePrefix(sampleRate
, bigLength
, smallLength
);
162 if (!isBufferZero(buffer
))
163 testPassed(prefix
+ "differ as expected.");
165 testFailed(prefix
+ "unexpectedly are identical.");
169 // Creates a function that is used to run an Audit test for a given sample rate, periodic wave
170 // sizes, and verifier.
171 function createAuditTestFunction(sampleRate
, bigLength
, smallLength
, verifier
) {
172 return function (done
) {
173 // Create the audio graph, render it, and then verify that the output is the expected
175 createAudioGraph(sampleRate
, bigLength
, smallLength
);
177 context
.startRendering()
178 .then(verifier(sampleRate
, bigLength
, smallLength
))
183 // Create the audio graph for the test.
184 function createAudioGraph(sampleRate
, bigPeriodicWaveLength
, smallPeriodicWaveLength
) {
185 context
= new OfflineAudioContext(1, renderLength
* sampleRate
, sampleRate
);
187 // Two PeriodicWave objects are created with different sizes (small and big). The contents
188 // are the same except that the samll sized PeriodicWave has fewer coefficients.
189 var smallWaveRealCoef
= new Float32Array(smallPeriodicWaveLength
);
190 var smallWaveImagCoef
= new Float32Array(smallPeriodicWaveLength
);
191 var bigWaveRealCoef
= new Float32Array(bigPeriodicWaveLength
);
192 var bigWaveImagCoef
= new Float32Array(bigPeriodicWaveLength
);
194 // Set up the Fourier coefficients for a square wave.
195 for (var k
= 0; k
< bigPeriodicWaveLength
; k
+= 2) {
196 bigWaveImagCoef
[k
] = 4 / Math
.PI
/ k
;
197 if (k
< smallPeriodicWaveLength
)
198 smallWaveImagCoef
[k
] = bigWaveImagCoef
[k
];
201 var smallPeriodicWave
= context
.createPeriodicWave(smallWaveRealCoef
, smallWaveImagCoef
);
202 var bigPeriodicWave
= context
.createPeriodicWave(bigWaveRealCoef
, bigWaveImagCoef
);
204 // Create oscillators using these PeriodicWave's.
205 var smallOscillator
= context
.createOscillator();
206 var bigOscillator
= context
.createOscillator();
208 smallOscillator
.setPeriodicWave(smallPeriodicWave
);
209 bigOscillator
.setPeriodicWave(bigPeriodicWave
);
211 // Use a frequency of 1 Hz to make the distinction easier. Can't tell from this test, but
212 // if you plot the signals from these oscillators, it's very clear that they are different.
213 smallOscillator
.frequency
.value
= 1;
214 bigOscillator
.frequency
.value
= 1;
216 // The desired output is the difference between these oscillators.
217 var gain
= context
.createGain();
218 gain
.gain
.value
= -1;
219 smallOscillator
.connect(gain
);
221 gain
.connect(context
.destination
);
222 bigOscillator
.connect(context
.destination
);
224 // Start the oscillators.
225 smallOscillator
.start();
226 bigOscillator
.start();
229 // Return true if the buffer is exactly zero.
230 function isBufferZero(buffer
) {
231 if (buffer
.getChannelData(0).find(function (x
) { return x
!= 0; }))
236 // Ensure the actual Audit test name is unique by prepending an index to the provided test
238 function actualTestName(name
, index
) {
239 return index
+ ":" + name
;
242 // Define the tasks based on the entries in testSet.
243 function defineAuditTests () {
244 for (var k
= 0; k
< testSet
.length
; ++k
) {
245 var test
= testSet
[k
];
246 var actualName
= actualTestName(test
.name
, k
);
247 audit
.defineTask(actualName
,
248 createAuditTestFunction(test
.sampleRate
, test
.bigWave
, test
.smallWave
, test
.verifier
));
250 // Define the finish test last.
251 audit
.defineTask(actualTestName("finish-tests", testSet
.length
), function (done
) {
260 successfullyParsed
= true;