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

Side by Side Diff: third_party/WebKit/LayoutTests/webaudio/audionode-channel-rules.html

Issue 1773973002: Complete the implementation of up/down-mixing rules for AudioNode (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Clean up and addressing feedback Created 4 years, 9 months 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
1 <!DOCTYPE html> 1 <!DOCTYPE html>
2 2
3 <html> 3 <html>
4 <head> 4 <head>
5 <script src="../resources/js-test.js"></script> 5 <script src="../resources/js-test.js"></script>
6 <script src="resources/compatibility.js"></script> 6 <script src="resources/compatibility.js"></script>
7 <script type="text/javascript" src="resources/audio-testing.js"></script> 7 <script src="resources/audio-testing.js"></script>
8 <script src="resources/mixing-rules.js"></script>
8 </head> 9 </head>
9 10
10 <body> 11 <body>
11 <div id="description"></div>
12 <div id="console"></div>
13 12
14 <script> 13 <script>
15 description("Channel mixing rules for AudioNodes."); 14 description("Channel mixing rules for AudioNodes.");
16 15
17 var context = 0; 16 var context = 0;
18 var sampleRate = 44100; 17 var sampleRate = 44100;
19 var renderNumberOfChannels = 8; 18 var renderNumberOfChannels = 8;
20 var singleTestFrameLength = 8; 19 var singleTestFrameLength = 8;
21 var testBuffers; 20 var testBuffers;
22 21
(...skipping 15 matching lines...) Expand all
38 {channelCount: 6, channelCountMode: "explicit", channelInterpretation: "spea kers"}, 37 {channelCount: 6, channelCountMode: "explicit", channelInterpretation: "spea kers"},
39 38
40 {channelCount: 2, channelCountMode: "max", channelInterpretation: "discrete" }, 39 {channelCount: 2, channelCountMode: "max", channelInterpretation: "discrete" },
41 {channelCount: 4, channelCountMode: "clamped-max", channelInterpretation: "d iscrete"}, 40 {channelCount: 4, channelCountMode: "clamped-max", channelInterpretation: "d iscrete"},
42 {channelCount: 4, channelCountMode: "explicit", channelInterpretation: "disc rete"}, 41 {channelCount: 4, channelCountMode: "explicit", channelInterpretation: "disc rete"},
43 {channelCount: 8, channelCountMode: "explicit", channelInterpretation: "disc rete"}, 42 {channelCount: 8, channelCountMode: "explicit", channelInterpretation: "disc rete"},
44 ]; 43 ];
45 44
46 var numberOfTests = mixingRulesList.length * connectionsList.length; 45 var numberOfTests = mixingRulesList.length * connectionsList.length;
47 46
48 // Create an n-channel buffer, with all sample data zero except for a shifted im pulse. 47 // Print out the information for an individual test case.
49 // The impulse position depends on the channel index. 48 function printTestInformation(testNumber, actualBuffer, expectedBuffer, frameLen gth, frameOffset) {
50 // For example, for a 4-channel buffer: 49 var actual = stringifyBuffer(actualBuffer, frameLength);
51 // channel0: 1 0 0 0 0 0 0 0 50 var expected = stringifyBuffer(expectedBuffer, frameLength, frameOffset);
52 // channel1: 0 1 0 0 0 0 0 0 51 debug('TEST CASE #' + testNumber + '\n');
53 // channel2: 0 0 1 0 0 0 0 0 52 debug('actual channels:\n' + actual);
54 // channel3: 0 0 0 1 0 0 0 0 53 debug('expected channels:\n' + expected);
55 function createTestBuffer(numberOfChannels) {
56 var buffer = context.createBuffer(numberOfChannels, singleTestFrameLength, c ontext.sampleRate);
57 for (var i = 0; i < numberOfChannels; ++i) {
58 var data = buffer.getChannelData(i);
59 data[i] = 1;
60 }
61 return buffer;
62 }
63
64 // Discrete channel interpretation mixing:
65 // https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#UpMix
66 // up-mix by filling channels until they run out then ignore remaining dest chan nels.
67 // down-mix by filling as many channels as possible, then dropping remaining sou rce channels.
68 function discreteSum(sourceBuffer, destBuffer) {
69 if (sourceBuffer.length != destBuffer.length) {
70 alert("discreteSum(): invalid AudioBuffer!");
71 return;
72 }
73
74 var numberOfChannels = sourceBuffer.numberOfChannels < destBuffer.numberOfCh annels ? sourceBuffer.numberOfChannels : destBuffer.numberOfChannels;
75 var length = numberOfChannels;
76
77 for (var c = 0; c < numberOfChannels; ++c) {
78 var source = sourceBuffer.getChannelData(c);
79 var dest = destBuffer.getChannelData(c);
80 for (var i = 0; i < length; ++i) {
81 dest[i] += source[i];
82 }
83 }
84 }
85
86 // Speaker channel interpretation mixing:
87 // https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#UpMix
88 function speakersSum(sourceBuffer, destBuffer)
89 {
90 var numberOfSourceChannels = sourceBuffer.numberOfChannels;
91 var numberOfDestinationChannels = destBuffer.numberOfChannels;
92 var length = destBuffer.length;
93
94 if (numberOfDestinationChannels == 2 && numberOfSourceChannels == 1) {
95 // Handle mono -> stereo case (summing mono channel into both left and r ight).
96 var source = sourceBuffer.getChannelData(0);
97 var destL = destBuffer.getChannelData(0);
98 var destR = destBuffer.getChannelData(1);
99
100 for (var i = 0; i < length; ++i) {
101 destL[i] += source[i];
102 destR[i] += source[i];
103 }
104 } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 2) {
105 // Handle stereo -> mono case. output += 0.5 * (input.L + input.R).
106 var sourceL = sourceBuffer.getChannelData(0);
107 var sourceR = sourceBuffer.getChannelData(1);
108 var dest = destBuffer.getChannelData(0);
109
110 for (var i = 0; i < length; ++i) {
111 dest[i] += 0.5 * (sourceL[i] + sourceR[i]);
112 }
113 } else if (numberOfDestinationChannels == 6 && numberOfSourceChannels == 1) {
114 // Handle mono -> 5.1 case, sum mono channel into center.
115 var source = sourceBuffer.getChannelData(0);
116 var dest = destBuffer.getChannelData(2);
117
118 for (var i = 0; i < length; ++i) {
119 dest[i] += source[i];
120 }
121 } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 6) {
122 // Handle 5.1 -> mono.
123 var sourceL = sourceBuffer.getChannelData(0);
124 var sourceR = sourceBuffer.getChannelData(1);
125 var sourceC = sourceBuffer.getChannelData(2);
126 // skip LFE for now, according to current spec.
127 var sourceSL = sourceBuffer.getChannelData(4);
128 var sourceSR = sourceBuffer.getChannelData(5);
129 var dest = destBuffer.getChannelData(0);
130
131 for (var i = 0; i < length; ++i) {
132 dest[i] += 0.7071 * (sourceL[i] + sourceR[i]) + sourceC[i] + 0.5 * ( sourceSL[i] + sourceSR[i]);
133 }
134 } else {
135 // Fallback for unknown combinations.
136 discreteSum(sourceBuffer, destBuffer);
137 }
138 } 54 }
139 55
140 function scheduleTest(testNumber, connections, channelCount, channelCountMode, c hannelInterpretation) { 56 function scheduleTest(testNumber, connections, channelCount, channelCountMode, c hannelInterpretation) {
141 var mixNode = context.createGain(); 57 var mixNode = context.createGain();
142 mixNode.channelCount = channelCount; 58 mixNode.channelCount = channelCount;
143 mixNode.channelCountMode = channelCountMode; 59 mixNode.channelCountMode = channelCountMode;
144 mixNode.channelInterpretation = channelInterpretation; 60 mixNode.channelInterpretation = channelInterpretation;
145 mixNode.connect(context.destination); 61 mixNode.connect(context.destination);
146 62
147 for (var i = 0; i < connections.length; ++i) { 63 for (var i = 0; i < connections.length; ++i) {
148 var connectionNumberOfChannels = connections.charCodeAt(i) - "0".charCod eAt(0); 64 var connectionNumberOfChannels = connections.charCodeAt(i) - "0".charCod eAt(0);
149 65
150 var source = context.createBufferSource(); 66 var source = context.createBufferSource();
151 // Get a buffer with the right number of channels, converting from 1-bas ed to 0-based index. 67 // Get a buffer with the right number of channels, converting from 1-bas ed to 0-based index.
152 var buffer = testBuffers[connectionNumberOfChannels - 1]; 68 var buffer = testBuffers[connectionNumberOfChannels - 1];
153 source.buffer = buffer; 69 source.buffer = buffer;
154 source.connect(mixNode); 70 source.connect(mixNode);
155 71
156 // Start at the right offset. 72 // Start at the right offset.
157 var sampleFrameOffset = testNumber * singleTestFrameLength; 73 var sampleFrameOffset = testNumber * singleTestFrameLength;
158 var time = sampleFrameOffset / sampleRate; 74 var time = sampleFrameOffset / sampleRate;
159 source.start(time); 75 source.start(time);
160 } 76 }
161 } 77 }
162 78
163 function computeNumberOfChannels(connections, channelCount, channelCountMode) {
164 if (channelCountMode == "explicit")
165 return channelCount;
166
167 var computedNumberOfChannels = 1; // Must have at least one channel.
168
169 // Compute "computedNumberOfChannels" based on all the connections.
170 for (var i = 0; i < connections.length; ++i) {
171 var connectionNumberOfChannels = connections.charCodeAt(i) - "0".charCod eAt(0);
172 computedNumberOfChannels = Math.max(computedNumberOfChannels, connection NumberOfChannels);
173 }
174
175 if (channelCountMode == "clamped-max")
176 computedNumberOfChannels = Math.min(computedNumberOfChannels, channelCou nt);
177
178 return computedNumberOfChannels;
179 }
180
181 function checkTestResult(renderedBuffer, testNumber, connections, channelCount, channelCountMode, channelInterpretation) { 79 function checkTestResult(renderedBuffer, testNumber, connections, channelCount, channelCountMode, channelInterpretation) {
182 var s = "connections: " + connections + ", " + channelCountMode; 80 var s = "connections: " + connections + ", " + channelCountMode;
183 81
184 // channelCount is ignored in "max" mode. 82 // channelCount is ignored in "max" mode.
185 if (channelCountMode == "clamped-max" || channelCountMode == "explicit") { 83 if (channelCountMode == "clamped-max" || channelCountMode == "explicit") {
186 s += "(" + channelCount + ")"; 84 s += "(" + channelCount + ")";
187 } 85 }
188 86
189 s += ", " + channelInterpretation; 87 s += ", " + channelInterpretation;
190 88
191 var computedNumberOfChannels = computeNumberOfChannels(connections, channelC ount, channelCountMode); 89 var computedNumberOfChannels = computeNumberOfChannels(connections, channelC ount, channelCountMode);
192 90
193 // Show rendered output for this test:
194 //
195 // console.log(s);
196 // var sampleFrameOffset = testNumber * singleTestFrameLength;
197 // for (var c = 0; c < renderNumberOfChannels; ++c) {
198 // var data = renderedBuffer.getChannelData(c);
199 // var s = "";
200 // for (var sampleFrame = 0; sampleFrame < singleTestFrameLength; ++samp leFrame) {
201 // s += data[sampleFrame + sampleFrameOffset] + " ";
202 // }
203 // s += "\n";
204 // console.log(s);
205 // }
206 // return;
207
208 // Create a zero-initialized silent AudioBuffer with computedNumberOfChannel s. 91 // Create a zero-initialized silent AudioBuffer with computedNumberOfChannel s.
209 var destBuffer = context.createBuffer(computedNumberOfChannels, singleTestFr ameLength, context.sampleRate); 92 var destBuffer = context.createBuffer(computedNumberOfChannels, singleTestFr ameLength, context.sampleRate);
210 93
211 // Mix all of the connections into the destination buffer. 94 // Mix all of the connections into the destination buffer.
212 for (var i = 0; i < connections.length; ++i) { 95 for (var i = 0; i < connections.length; ++i) {
213 var connectionNumberOfChannels = connections.charCodeAt(i) - "0".charCod eAt(0); 96 var connectionNumberOfChannels = connections.charCodeAt(i) - "0".charCod eAt(0);
214 var sourceBuffer = testBuffers[connectionNumberOfChannels - 1]; // conve rt from 1-based to 0-based index 97 var sourceBuffer = testBuffers[connectionNumberOfChannels - 1]; // conve rt from 1-based to 0-based index
215 98
216 if (channelInterpretation == "speakers") { 99 if (channelInterpretation == "speakers") {
217 speakersSum(sourceBuffer, destBuffer); 100 speakersSum(sourceBuffer, destBuffer);
218 } else if (channelInterpretation == "discrete") { 101 } else if (channelInterpretation == "discrete") {
219 discreteSum(sourceBuffer, destBuffer); 102 discreteSum(sourceBuffer, destBuffer);
220 } else { 103 } else {
221 alert("Invalid channel interpretation!"); 104 alert("Invalid channel interpretation!");
222 } 105 }
223 } 106 }
224 107
108 // Use this when debugging mixing rules.
109 // printTestInformation(testNumber, renderedBuffer, destBuffer, singleTestFr ameLength, sampleFrameOffset);
110
225 // Validate that destBuffer matches the rendered output. 111 // Validate that destBuffer matches the rendered output.
226 // We need to check the rendered output at a specific sample-frame-offset co rresponding 112 // We need to check the rendered output at a specific sample-frame-offset co rresponding
227 // to the specific test case we're checking for based on testNumber. 113 // to the specific test case we're checking for based on testNumber.
228 114
229 var sampleFrameOffset = testNumber * singleTestFrameLength; 115 var sampleFrameOffset = testNumber * singleTestFrameLength;
230 for (var c = 0; c < renderNumberOfChannels; ++c) { 116 for (var c = 0; c < renderNumberOfChannels; ++c) {
231 var renderedData = renderedBuffer.getChannelData(c); 117 var renderedData = renderedBuffer.getChannelData(c);
232 for (var frame = 0; frame < singleTestFrameLength; ++frame) { 118 for (var frame = 0; frame < singleTestFrameLength; ++frame) {
233 var renderedValue = renderedData[frame + sampleFrameOffset]; 119 var renderedValue = renderedData[frame + sampleFrameOffset];
234 120
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
286 context = new OfflineAudioContext(renderNumberOfChannels, totalFrameLength, sampleRate); 172 context = new OfflineAudioContext(renderNumberOfChannels, totalFrameLength, sampleRate);
287 173
288 // Set destination to discrete mixing. 174 // Set destination to discrete mixing.
289 context.destination.channelCount = renderNumberOfChannels; 175 context.destination.channelCount = renderNumberOfChannels;
290 context.destination.channelCountMode = "explicit"; 176 context.destination.channelCountMode = "explicit";
291 context.destination.channelInterpretation = "discrete"; 177 context.destination.channelInterpretation = "discrete";
292 178
293 // Create test buffers from 1 to 8 channels. 179 // Create test buffers from 1 to 8 channels.
294 testBuffers = new Array(); 180 testBuffers = new Array();
295 for (var i = 0; i < renderNumberOfChannels; ++i) { 181 for (var i = 0; i < renderNumberOfChannels; ++i) {
296 testBuffers[i] = createTestBuffer(i + 1); 182 testBuffers[i] = createShiftedImpulseBuffer(context, i + 1, singleTestFr ameLength);
297 } 183 }
298 184
299 // Schedule all the tests. 185 // Schedule all the tests.
300 var testNumber = 0; 186 var testNumber = 0;
301 for (var m = 0; m < mixingRulesList.length; ++m) { 187 for (var m = 0; m < mixingRulesList.length; ++m) {
302 var mixingRules = mixingRulesList[m]; 188 var mixingRules = mixingRulesList[m];
303 for (var i = 0; i < connectionsList.length; ++i, ++testNumber) { 189 for (var i = 0; i < connectionsList.length; ++i, ++testNumber) {
304 scheduleTest(testNumber, connectionsList[i], mixingRules.channelCoun t, mixingRules.channelCountMode, mixingRules.channelInterpretation); 190 scheduleTest(testNumber, connectionsList[i], mixingRules.channelCoun t, mixingRules.channelCountMode, mixingRules.channelInterpretation);
305 } 191 }
306 } 192 }
307 193
308 // Render then check results. 194 // Render then check results.
309 context.oncomplete = checkResult; 195 context.oncomplete = checkResult;
310 context.startRendering(); 196 context.startRendering();
311 } 197 }
312 198
313 runTest(); 199 runTest();
314 200
315 </script> 201 </script>
316 202
317 </body> 203 </body>
318 </html> 204 </html>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698