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

Side by Side Diff: LayoutTests/webaudio/stereopannernode-panning.html

Issue 691143007: Implement StereoPannerNode for robust stereo panning (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
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
OLDNEW
(Empty)
1 <!DOCTYPE html>
2 <html>
3
4 <head>
5 <script src="resources/compatibility.js"></script>
6 <script src="resources/audio-testing.js"></script>
7 <script src="../resources/js-test.js"></script>
8 </head>
9
10 <body>
11 <div id="description"></div>
12 <div id="console"></div>
13 <script>
14 description("Test panning model of StereoPannerNode.");
15
16 window.jsTestIsAsync = true;
17
18 var sampleRate = 44100;
19
20 // Number of nodes to create for testing.
21 var nodesToCreate = 100;
22
23 // Interval between the onset of each impulse.
24 var timeStep = 0.001;
25
26 // Total render length. Should be long enough for all panner nodes.
27 var renderLength = timeStep * (nodesToCreate + 1);
28
29 var impulse;
30 var impulseLength = Math.round(timeStep * sampleRate);
31
32 // Pan step unit for each test trial.
33 var panStep = 2 / (nodesToCreate - 1);
34
35 var sources = [];
36 var panners = [];
37 var panPositions = [];
38 var onsets = [];
39
40 var ctx = new OfflineAudioContext(2, sampleRate * renderLength, sampleRate);
Raymond Toy 2014/11/12 18:06:52 Probably better to use "context" instead of "ctx".
hongchan 2014/11/12 22:01:42 Done.
41
42 // Calculates channel gains based on equal power panning model.
43 function getChannelGains (pan) {
44 var normalized = 0.5 * Math.PI * (pan * 0.5 + 0.5);
45 return {
46 gainL: Math.cos(normalized),
47 gainR: Math.sin(normalized)
48 };
49 }
50
51 function prepareTest() {
52 impulse = createImpulseBuffer(ctx, impulseLength);
53
54 // Create multiple buffur source nodes and panner nodes for test trials.
Raymond Toy 2014/11/12 18:06:52 Typos: "buffur" -> buffer Maybe instead of "for t
hongchan 2014/11/12 22:01:42 Done.
55 // Each source node plays the same impulse buffer and goes through a
56 // panner node. Each trial is performed sequentially with the interval of
57 // 'timeStep' and a different pan position.
58 for (var i = 0; i < nodesToCreate; i++) {
59 sources[i] = ctx.createBufferSource();
60 panners[i] = ctx.createStereoPanner();
61 sources[i].connect(panners[i]);
62 panners[i].connect(ctx.destination);
63
64 sources[i].buffer = impulse;
65
66 // Moves the pan value for each panner by pan step unit.
67 panners[i].pan.value = panPositions[i] = panStep * i - 1;
68
69 onsets[i] = timeStep * i;
70 sources[i].start(onsets[i]);
71 }
72 }
73
74 // To verify the result, check if each source is an impulse turning at a
Raymond Toy 2014/11/12 18:06:52 Typo? "turning" -> "starting"?
hongchan 2014/11/12 22:01:42 Done.
75 // different time and the rendered impulse has the expected gain.
76 function verifyResult(event) {
77
78 var success = true;
79
80 // The max error we allow between the rendered impulse and the
81 // expected value. This value is experimentally determined. Set
82 // to 0 to make the test fail to see what the actual error is.
83 var maxAllowedError = 1.3e-6;
84
85 var chanL = event.renderedBuffer.getChannelData(0),
86 chanR = event.renderedBuffer.getChannelData(1);
87
88 // Number of impulses found in the rendered result.
89 var impulseIndex = 0;
90
91 // Max (relative) error and the index of the maxima for the left
92 // and right channels.
93 var maxErrorL = 0,
94 maxErrorR = 0,
95 maxErrorIndexL = 0,
96 maxErrorIndexR = 0;
97
98 // Locations of where the impulses aren't at the expected locations.
99 var errors = [];
100
101 for (var i = 0; i < chanL.length; i++) {
102
103 // We assume that the left and right channels start at the same instant.
104 if (chanL[i] !== 0 || chanR[i] !== 0) {
105
106 // Get amount of error between actual and expected gain.
107 var expected = getChannelGains(panPositions[impulseIndex]),
108 errorL = Math.abs(chanL[i] - expected.gainL),
109 errorR = Math.abs(chanR[i] - expected.gainR);
110
111 if (errorL > maxErrorL) {
112 maxErrorL = errorL;
113 maxErrorIndexL = impulseIndex;
114 }
115
116 if (errorR > maxErrorR) {
117 maxErrorR = errorR;
118 maxErrorIndexR = impulseIndex;
119 }
120
121 // Keep track of the impulses that didn't show up where we expected
122 // them to be.
123 var expectedOffset = timeToSampleFrame(onsets[impulseIndex], sampleRat e);
124 if (i != expectedOffset) {
125 errors.push({
126 actual: i,
127 expected: expectedOffset
128 });
129 }
130
131 impulseIndex++;
132 }
133 }
134
135 if (impulseIndex === nodesToCreate) {
136 testPassed('Number of impulses matches the number of panner nodes.');
137 } else {
138 testFailed('Number of impulses is incorrect. (Found ' + impulseIndex + ' but expected ' + nodesToCreate + ')');
139 sucess = false;
140 }
141
142 if (errors.length === 0) {
143 testPassed("All impulses at expected offsets.");
144 } else {
145 testFailed(errors.length + " timing errors found in " + nodesToCreate + " panner nodes.");
146 for (var i = 0; i < errors.length; i++) {
147 testFailed("Impulse at sample " + errors[i].actual + " but expected " + errors[i].expected);
148 }
149 success = false;
150 }
151
152 if (maxErrorL <= maxAllowedError) {
153 testPassed("Left channel gain values are correct.");
154 } else {
155 testFailed("Left channel gain values are incorrect. Max error = " + max ErrorL + " at time " + onsets[maxErrorIndexL] + " (threshold = " + maxAllowedErr or + ")");
156 success = false;
157 }
158
159 if (maxErrorR <= maxAllowedError) {
160 testPassed("Right channel gain values are correct.");
161 } else {
162 testFailed("Right channel gain values are incorrect. Max error = " + ma xErrorR + " at time " + onsets[maxErrorIndexR] + " (threshold = " + maxAllowedEr ror + ")");
163 success = false;
164 }
165
166 if (success)
167 testPassed("StereoPannerNode test passed.");
168 else
169 testFailed("StereoPannerNode test failed.");
170
171 finishJSTest();
172 }
173
174 prepareTest();
175 ctx.oncomplete = verifyResult;
176 ctx.startRendering();
177
178 successfullyParsed = true;
179 </script>
180 </body>
181
182 </html>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698