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

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: 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
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 type="text/javascript" src="resources/audio-testing.js"></script>
24 // <script type="text/javascript" src="resources/oscillator-testing.js"></script >
25 // </head>
26 // <body>
27 // <script>
28 // window.onload = init;
29 //
30 // function init() {
31 // if (!window.testRunner)
32 // return;
33 //
34 // context = new OfflineAudioContext(1, sampleRate * lengthInSeconds, sample Rate);
35 // generateExponentialOscillatorSweep(context, "sine");
36 //
37 // context.oncomplete = finishAudioTest;
38 // context.startRendering();
39 //
40 // testRunner.waitUntilDone();
41 // }
42 //
43 // </script>
44 // </body>
45 // </html>
12 46
13 var sampleRate = 44100.0; 47 var sampleRate = 44100.0;
14 var nyquist = 0.5 * sampleRate; 48 var nyquist = 0.5 * sampleRate;
15 var lengthInSeconds = 4; 49 var lengthInSeconds = 4;
16 var lowFrequency = 10; 50 var lowFrequency = 10;
17 var highFrequency = nyquist + 2000; // go slightly higher than nyquist to make s ure we generate silence there 51 var highFrequency = nyquist + 2000; // go slightly higher than nyquist to make s ure we generate silence there
18 var context = 0; 52 var context = 0;
19 53
54 // Mostly for debugging
55
56 // An AudioBuffer for the reference (expected) result.
57 var reference = 0;
58
59 // The actual rendered data produced by the test.
60 var renderedData = 0;
61
62 // Signal power of the reference
63 var signalPower = 0;
64
65 // Noise power of the difference between the reference and actual result.
66 var noisePower = 0;
67
20 function generateExponentialOscillatorSweep(context, oscillatorType) { 68 function generateExponentialOscillatorSweep(context, oscillatorType) {
21 var osc = context.createOscillator(); 69 var osc = context.createOscillator();
22 if (oscillatorType == "custom") { 70 if (oscillatorType == "custom") {
23 // Create a simple waveform with three Fourier coefficients. 71 // 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). 72 // 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]); 73 var coeffA = new Float32Array([0, 1, 0.5]);
26 var coeffB = new Float32Array([0, 0, 0]); 74 var coeffB = new Float32Array([0, 0, 0]);
27 var wave = context.createPeriodicWave(coeffA, coeffB); 75 var wave = context.createPeriodicWave(coeffA, coeffB);
28 osc.setPeriodicWave(wave); 76 osc.setPeriodicWave(wave);
29 } else { 77 } else {
30 osc.type = oscillatorType; 78 osc.type = oscillatorType;
31 } 79 }
32 80
33 // Scale by 1/2 to better visualize the waveform and to avoid clipping past full scale. 81 // Scale by 1/2 to better visualize the waveform and to avoid clipping past full scale.
34 var gainNode = context.createGain(); 82 var gainNode = context.createGain();
35 gainNode.gain.value = 0.5; 83 gainNode.gain.value = 0.5;
36 osc.connect(gainNode); 84 osc.connect(gainNode);
37 gainNode.connect(context.destination); 85 gainNode.connect(context.destination);
38 86
39 osc.start(0); 87 osc.start(0);
40 88
41 var nyquist = 0.5 * sampleRate; 89 var nyquist = 0.5 * sampleRate;
42 osc.frequency.setValueAtTime(10, 0); 90 osc.frequency.setValueAtTime(10, 0);
43 osc.frequency.exponentialRampToValueAtTime(highFrequency, lengthInSeconds); 91 osc.frequency.exponentialRampToValueAtTime(highFrequency, lengthInSeconds);
44 } 92 }
93
94 function calculateSNR(sPower, nPower)
95 {
96 if (nPower == 0 && sPower > 0) {
97 return 1000;
98 }
99 return 10 * Math.log10(sPower / nPower);
100 }
101
102 function loadReferenceAndRunTest(oscType) {
103 var bufferLoader = new BufferLoader(
104 context,
105 [ "oscillator-" + oscType + "-expected.wav" ],
106 function (bufferList) {
107 reference = bufferList[0].getChannelData(0);
108 generateExponentialOscillatorSweep(context, oscType);
109 context.oncomplete = checkResult;
110 context.startRendering();
111 });
112
113 bufferLoader.load();
114 }
115
116 function checkResult (event) {
117 renderedData = event.renderedBuffer.getChannelData(0);
118 // Compute signal to noise ratio between the result and the reference. Also keep track
119 // of the max difference (and position).
120
121 var maxError = -1;
122 var errorPosition = -1;
123 var diffCount = 0;
124
125 for (var k = 0; k < renderedData.length; ++k) {
126 var diff = renderedData[k] - reference[k];
127 noisePower += diff * diff;
128 signalPower += reference[k] * reference[k];
129 if (Math.abs(diff) > maxError) {
130 maxError = Math.abs(diff);
131 errorPosition = k;
132 }
133 // The reference file is a 16-bit WAV file, so we will never get an exac t match
134 // between it and the actual floating-point result.
135 if (diff > 1/waveScaleFactor) {
136 diffCount++;
137 }
138 }
139
140 var snr = calculateSNR(signalPower, noisePower);
141 if (snr < thresholdSNR) {
142 testFailed("Expected SNR of " + thresholdSNR + " dB, but actual SNR is " + snr + " dB");
143 } else {
144 testPassed("Exceeded SNR threshold of " + thresholdSNR + " dB");
145 }
146
147 if (maxError > thresholdDiff) {
148 testFailed("Maximum difference of " + (maxError * waveScaleFactor) + " a t "
149 + errorPosition + " exceeded threshold of " + (thresholdDiff * waveScaleFactor)
150 + " ulp (16-bits)");
151 } else {
152 testPassed("Maximum difference below threshold of "
153 + (thresholdDiff * waveScaleFactor) + " ulp (16-bits)");
154 }
155 if (diffCount > thresholdDiffCount) {
156 testFailed(diffCount + " differences found but expected no more than " + thresholdDiffCount);
157 } else {
158 testPassed("Number of differences between actual and expected result is less than " + thresholdDiffCount);
159 }
160
161 finishJSTest();
162 }
163
164
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698