Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(628)

Side by Side Diff: LayoutTests/webaudio/resources/oscillator-testing.js

Issue 720293002: Replace oscillator tests with more robust tests (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Refactor according to review Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « LayoutTests/webaudio/oscillator-triangle-expected.wav ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Notes about generated waveforms: 1 // Notes about generated waveforms:
2 // 2 //
3 // QUESTION: Why does the wave shape not look like the exact shape (sharp edges) ? 3 // QUESTION: Why does the wave shape not look like the exact shape (sharp edges) ?
4 // ANSWER: Because a shape with sharp edges has infinitely high frequency conten t. 4 // ANSWER: Because a shape with sharp edges has infinitely high frequency conten t.
5 // Since a digital audio signal must be band-limited based on the nyquist freque ncy (half the sample-rate) 5 // Since a digital audio signal must be band-limited based on the nyquist freque ncy (half the sample-rate)
6 // in order to avoid aliasing, this creates more rounded edges and "ringing" in the 6 // in order to avoid aliasing, this creates more rounded edges and "ringing" in the
7 // appearance of the waveform. See Nyquist-Shannon sampling theorem: 7 // appearance of the waveform. See Nyquist-Shannon sampling theorem:
8 // http://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem 8 // http://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem
9 // 9 //
10 // QUESTION: Why does the very end of the generated signal appear to get slightl y weaker? 10 // QUESTION: Why does the very end of the generated signal appear to get slightl y weaker?
11 // ANSWER: This is an artifact of the algorithm to avoid aliasing. 11 // ANSWER: This is an artifact of the algorithm to avoid aliasing.
12 //
13 // QUESTION: Since the tests compare the actual result with an expected referenc e file, how are the
14 // reference files created?
15 // ANSWER: Create an html with the following contents in the webaudio directory. Then run a layout
16 // test on this file. A new file names "<file>-actual.wav" is created that cont ains the new result
17 // that can be used as the new expected reference file. Replace the "sine" belo w with the
18 // oscillator type that you want to use.
19 //
20 // <!doctype html>
21 // <html>
22 // <head>
23 // <script src="resources/compatibility.js"></script>
24 // <script src="resources/buffer-loader.js"></script>
25 // <script src="../resources/js-test.js"></script>
26 // <script src="resources/oscillator-testing.js"></script>
27 // <script src="resources/audio-testing.js"></script>
28 // </head>
29 // <body>
30 // <script>
31 // OscillatorTestingUtils.createNewReference("sine");
32 // </script>
33 // </body>
34 // </html>
35
36 OscillatorTestingUtils = (function () {
12 37
13 var sampleRate = 44100.0; 38 var sampleRate = 44100.0;
14 var nyquist = 0.5 * sampleRate; 39 var nyquist = 0.5 * sampleRate;
15 var lengthInSeconds = 4; 40 var lengthInSeconds = 4;
16 var lowFrequency = 10; 41 var lowFrequency = 10;
17 var highFrequency = nyquist + 2000; // go slightly higher than nyquist to make s ure we generate silence there 42 var highFrequency = nyquist + 2000; // go slightly higher than nyquist to make s ure we generate silence there
18 var context = 0; 43 var context = 0;
19 44
45 // Scaling factor for converting the 16-bit WAV data to float (and vice-versa).
46 var waveScaleFactor = 32768;
47
48 // Thresholds for verifying the test passes. The thresholds are experimentally determined. The
49 // default values here will cause the test to fail, which is useful for determin ing new thresholds,
50 // if needed.
51
52 // SNR must be greater than this to pass the test.
53 // Q: Why is the SNR threshold not infinity?
54 // A: The reference result is a 16-bit WAV file, so it won't compare exactly wit h the
55 // floating point result.
56 var thresholdSNR = 10000;
57
58 // Max diff must be less than this to pass the test.
59 var thresholdDiff = 0;
60
61 // Count the number of differences between the expected and actual result. The t ests passes
62 // if the count is less than this threshold.
63 var thresholdDiffCount = 0;
64
65 // Mostly for debugging
66
67 // An AudioBuffer for the reference (expected) result.
68 var reference = 0;
69
70 // The actual rendered data produced by the test.
71 var renderedData = 0;
72
73 // Signal power of the reference
74 var signalPower = 0;
75
76 // Noise power of the difference between the reference and actual result.
77 var noisePower = 0;
78
20 function generateExponentialOscillatorSweep(context, oscillatorType) { 79 function generateExponentialOscillatorSweep(context, oscillatorType) {
21 var osc = context.createOscillator(); 80 var osc = context.createOscillator();
22 if (oscillatorType == "custom") { 81 if (oscillatorType == "custom") {
23 // Create a simple waveform with three Fourier coefficients. 82 // Create a simple waveform with three Fourier coefficients.
24 // Note the first values are expected to be zero (DC for coeffA and Nyqu ist for coeffB). 83 // Note the first values are expected to be zero (DC for coeffA and Nyqu ist for coeffB).
25 var coeffA = new Float32Array([0, 1, 0.5]); 84 var coeffA = new Float32Array([0, 1, 0.5]);
26 var coeffB = new Float32Array([0, 0, 0]); 85 var coeffB = new Float32Array([0, 0, 0]);
27 var wave = context.createPeriodicWave(coeffA, coeffB); 86 var wave = context.createPeriodicWave(coeffA, coeffB);
28 osc.setPeriodicWave(wave); 87 osc.setPeriodicWave(wave);
29 } else { 88 } else {
30 osc.type = oscillatorType; 89 osc.type = oscillatorType;
31 } 90 }
32 91
33 // Scale by 1/2 to better visualize the waveform and to avoid clipping past full scale. 92 // Scale by 1/2 to better visualize the waveform and to avoid clipping past full scale.
34 var gainNode = context.createGain(); 93 var gainNode = context.createGain();
35 gainNode.gain.value = 0.5; 94 gainNode.gain.value = 0.5;
36 osc.connect(gainNode); 95 osc.connect(gainNode);
37 gainNode.connect(context.destination); 96 gainNode.connect(context.destination);
38 97
39 osc.start(0); 98 osc.start(0);
40 99
41 var nyquist = 0.5 * sampleRate;
42 osc.frequency.setValueAtTime(10, 0); 100 osc.frequency.setValueAtTime(10, 0);
43 osc.frequency.exponentialRampToValueAtTime(highFrequency, lengthInSeconds); 101 osc.frequency.exponentialRampToValueAtTime(highFrequency, lengthInSeconds);
44 } 102 }
103
104 function calculateSNR(sPower, nPower)
105 {
106 if (nPower == 0 && sPower > 0) {
107 return 1000;
108 }
109 return 10 * Math.log10(sPower / nPower);
110 }
111
112 function loadReferenceAndRunTest(oscType) {
113 var bufferLoader = new BufferLoader(
114 context,
115 [ "oscillator-" + oscType + "-expected.wav" ],
116 function (bufferList) {
117 reference = bufferList[0].getChannelData(0);
118 generateExponentialOscillatorSweep(context, oscType);
119 context.oncomplete = checkResult;
120 context.startRendering();
121 });
122
123 bufferLoader.load();
124 }
125
126 function checkResult (event) {
127 renderedData = event.renderedBuffer.getChannelData(0);
128 // Compute signal to noise ratio between the result and the reference. Also keep track
129 // of the max difference (and position).
130
131 var maxError = -1;
132 var errorPosition = -1;
133 var diffCount = 0;
134
135 for (var k = 0; k < renderedData.length; ++k) {
136 var diff = renderedData[k] - reference[k];
137 noisePower += diff * diff;
138 signalPower += reference[k] * reference[k];
139 if (Math.abs(diff) > maxError) {
140 maxError = Math.abs(diff);
141 errorPosition = k;
142 }
143 // The reference file is a 16-bit WAV file, so we will almost never get an exact match
144 // between it and the actual floating-point result.
145 if (diff > 1/waveScaleFactor) {
146 diffCount++;
147 }
148 }
149
150 var snr = calculateSNR(signalPower, noisePower);
151 if (snr >= thresholdSNR) {
152 testPassed("Exceeded SNR threshold of " + thresholdSNR + " dB");
153 } else {
154 testFailed("Expected SNR of " + thresholdSNR + " dB, but actual SNR is " + snr + " dB");
155 }
156
157 if (maxError <= thresholdDiff) {
158 testPassed("Maximum difference below threshold of "
159 + (thresholdDiff * waveScaleFactor) + " ulp (16-bits)");
160 } else {
161 testFailed("Maximum difference of " + (maxError * waveScaleFactor) + " a t "
162 + errorPosition + " exceeded threshold of " + (thresholdDiff * waveScaleFactor)
163 + " ulp (16-bits)");
164 }
165
166 if (diffCount <= thresholdDiffCount) {
167 testPassed("Number of differences between actual and expected result is less than " + thresholdDiffCount);
168 } else {
169 testFailed(diffCount + " differences found but expected no more than " + thresholdDiffCount);
170 }
171
172 finishJSTest();
173 }
174
175 function setThresholds(thresholds) {
176 thresholdSNR = thresholds.snr;
177 thresholdDiff = thresholds.maxDiff / waveScaleFactor;
178 thresholdDiffCount = thresholds.diffCount;
179 }
180
181 function runTest(oscType) {
182 window.jsTestIsAsync = true;
183 context = new OfflineAudioContext(1, sampleRate * lengthInSeconds, sampleRat e);
184 loadReferenceAndRunTest(oscType);
185 }
186
187 function createNewReference(oscType) {
188 if (!window.testRunner)
189 return;
190
191 context = new OfflineAudioContext(1, sampleRate * lengthInSeconds, sampleRa te);
192 generateExponentialOscillatorSweep(context, oscType);
193
194 context.oncomplete = finishAudioTest;
195 context.startRendering();
196
197 testRunner.waitUntilDone();
198 }
199
200 return {
201 sampleRate: sampleRate,
202 lengthInSeconds: lengthInSeconds,
203 thresholdSNR: thresholdSNR,
204 thresholdDiff: thresholdDiff,
205 thresholdDiffCount: thresholdDiffCount,
206 waveScaleFactor: waveScaleFactor,
207 setThresholds: setThresholds,
208 loadReferenceAndRunTest: loadReferenceAndRunTest,
209 runTest: runTest,
210 createNewReference: createNewReference,
211 };
212
213 }());
OLDNEW
« no previous file with comments | « LayoutTests/webaudio/oscillator-triangle-expected.wav ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698