| OLD | NEW |
| 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/testharness.js"></script> |
| 6 <script src="../../resources/testharnessreport.js"></script> |
| 6 <script src="../resources/audit-util.js"></script> | 7 <script src="../resources/audit-util.js"></script> |
| 7 <script src="../resources/audio-testing.js"></script> | 8 <script src="../resources/audit.js"></script> |
| 8 <script src="../resources/mixing-rules.js"></script> | 9 <script src="../resources/mixing-rules.js"></script> |
| 9 </head> | 10 </head> |
| 10 | 11 |
| 11 <body> | 12 <body> |
| 12 | 13 |
| 13 <script> | 14 <script> |
| 14 description("Channel mixing rules for AudioNodes."); | 15 let audit = Audit.createTaskRunner(); |
| 15 | 16 let context = 0; |
| 16 var context = 0; | 17 let sampleRate = 44100; |
| 17 var sampleRate = 44100; | 18 let renderNumberOfChannels = 8; |
| 18 var renderNumberOfChannels = 8; | 19 let singleTestFrameLength = 8; |
| 19 var singleTestFrameLength = 8; | 20 let testBuffers; |
| 20 var testBuffers; | 21 |
| 21 | 22 // A list of connections to an AudioNode input, each of which is to be used in |
| 22 // A list of connections to an AudioNode input, each of which is to be used in o
ne or more specific test cases. | 23 // one or more specific test cases. Each element in the list is a string, with |
| 23 // Each element in the list is a string, with the number of connections correspo
nding to the length of the string, | 24 // the number of connections corresponding to the length of the string, and each |
| 24 // and each character in the string is from '1' to '8' representing a 1 to 8 cha
nnel connection (from an AudioNode output). | 25 // character in the string is from '1' to '8' representing a 1 to 8 channel |
| 25 // For example, the string "128" means 3 connections, having 1, 2, and 8 channel
s respectively. | 26 // connection (from an AudioNode output). |
| 26 var connectionsList = ["1", "2", "3", "4", "5", "6", "7", "8", "11", "12", "14",
"18", "111", "122", "123", "124", "128"]; | 27 |
| 27 | 28 // For example, the string "128" means 3 connections, having 1, 2, and 8 |
| 28 // A list of mixing rules, each of which will be tested against all of the conne
ctions in connectionsList. | 29 // channels respectively. |
| 29 var mixingRulesList = [ | 30 |
| 30 {channelCount: 2, channelCountMode: "max", channelInterpretation: "speakers"
}, | 31 let connectionsList = [ |
| 31 {channelCount: 4, channelCountMode: "clamped-max", channelInterpretation: "s
peakers"}, | 32 '1', '2', '3', '4', '5', '6', '7', '8', '11', '12', '14', '18', '111', '122', |
| 32 | 33 '123', '124', '128' |
| 33 // Test up-down-mix to some explicit speaker layouts. | |
| 34 {channelCount: 1, channelCountMode: "explicit", channelInterpretation: "spea
kers"}, | |
| 35 {channelCount: 2, channelCountMode: "explicit", channelInterpretation: "spea
kers"}, | |
| 36 {channelCount: 4, channelCountMode: "explicit", channelInterpretation: "spea
kers"}, | |
| 37 {channelCount: 6, channelCountMode: "explicit", channelInterpretation: "spea
kers"}, | |
| 38 | |
| 39 {channelCount: 2, channelCountMode: "max", channelInterpretation: "discrete"
}, | |
| 40 {channelCount: 4, channelCountMode: "clamped-max", channelInterpretation: "d
iscrete"}, | |
| 41 {channelCount: 4, channelCountMode: "explicit", channelInterpretation: "disc
rete"}, | |
| 42 {channelCount: 8, channelCountMode: "explicit", channelInterpretation: "disc
rete"}, | |
| 43 ]; | 34 ]; |
| 44 | 35 |
| 45 var numberOfTests = mixingRulesList.length * connectionsList.length; | 36 // A list of mixing rules, each of which will be tested against all of the |
| 37 // connections in connectionsList. |
| 38 let mixingRulesList = [ |
| 39 {channelCount: 2, channelCountMode: 'max', channelInterpretation: 'speakers'}, |
| 40 { |
| 41 channelCount: 4, |
| 42 channelCountMode: 'clamped-max', |
| 43 channelInterpretation: 'speakers' |
| 44 }, |
| 45 |
| 46 // Test up-down-mix to some explicit speaker layouts. |
| 47 { |
| 48 channelCount: 1, |
| 49 channelCountMode: 'explicit', |
| 50 channelInterpretation: 'speakers' |
| 51 }, |
| 52 { |
| 53 channelCount: 2, |
| 54 channelCountMode: 'explicit', |
| 55 channelInterpretation: 'speakers' |
| 56 }, |
| 57 { |
| 58 channelCount: 4, |
| 59 channelCountMode: 'explicit', |
| 60 channelInterpretation: 'speakers' |
| 61 }, |
| 62 { |
| 63 channelCount: 6, |
| 64 channelCountMode: 'explicit', |
| 65 channelInterpretation: 'speakers' |
| 66 }, |
| 67 |
| 68 {channelCount: 2, channelCountMode: 'max', channelInterpretation: 'discrete'}, |
| 69 { |
| 70 channelCount: 4, |
| 71 channelCountMode: 'clamped-max', |
| 72 channelInterpretation: 'discrete' |
| 73 }, |
| 74 { |
| 75 channelCount: 4, |
| 76 channelCountMode: 'explicit', |
| 77 channelInterpretation: 'discrete' |
| 78 }, |
| 79 { |
| 80 channelCount: 8, |
| 81 channelCountMode: 'explicit', |
| 82 channelInterpretation: 'discrete' |
| 83 }, |
| 84 ]; |
| 85 |
| 86 let numberOfTests = mixingRulesList.length * connectionsList.length; |
| 46 | 87 |
| 47 // Print out the information for an individual test case. | 88 // Print out the information for an individual test case. |
| 48 function printTestInformation(testNumber, actualBuffer, expectedBuffer, frameLen
gth, frameOffset) { | 89 function printTestInformation( |
| 49 var actual = stringifyBuffer(actualBuffer, frameLength); | 90 testNumber, actualBuffer, expectedBuffer, frameLength, frameOffset) { |
| 50 var expected = stringifyBuffer(expectedBuffer, frameLength, frameOffset); | 91 let actual = stringifyBuffer(actualBuffer, frameLength); |
| 92 let expected = stringifyBuffer(expectedBuffer, frameLength, frameOffset); |
| 51 debug('TEST CASE #' + testNumber + '\n'); | 93 debug('TEST CASE #' + testNumber + '\n'); |
| 52 debug('actual channels:\n' + actual); | 94 debug('actual channels:\n' + actual); |
| 53 debug('expected channels:\n' + expected); | 95 debug('expected channels:\n' + expected); |
| 54 } | 96 } |
| 55 | 97 |
| 56 function scheduleTest(testNumber, connections, channelCount, channelCountMode, c
hannelInterpretation) { | 98 function scheduleTest( |
| 57 var mixNode = context.createGain(); | 99 testNumber, connections, channelCount, channelCountMode, |
| 58 mixNode.channelCount = channelCount; | 100 channelInterpretation) { |
| 59 mixNode.channelCountMode = channelCountMode; | 101 let mixNode = context.createGain(); |
| 60 mixNode.channelInterpretation = channelInterpretation; | 102 mixNode.channelCount = channelCount; |
| 61 mixNode.connect(context.destination); | 103 mixNode.channelCountMode = channelCountMode; |
| 62 | 104 mixNode.channelInterpretation = channelInterpretation; |
| 63 for (var i = 0; i < connections.length; ++i) { | 105 mixNode.connect(context.destination); |
| 64 var connectionNumberOfChannels = connections.charCodeAt(i) - "0".charCod
eAt(0); | 106 |
| 65 | 107 for (let i = 0; i < connections.length; ++i) { |
| 66 var source = context.createBufferSource(); | 108 let connectionNumberOfChannels = |
| 67 // Get a buffer with the right number of channels, converting from 1-bas
ed to 0-based index. | 109 connections.charCodeAt(i) - '0'.charCodeAt(0); |
| 68 var buffer = testBuffers[connectionNumberOfChannels - 1]; | 110 |
| 69 source.buffer = buffer; | 111 let source = context.createBufferSource(); |
| 70 source.connect(mixNode); | 112 // Get a buffer with the right number of channels, converting from 1-based |
| 71 | 113 // to 0-based index. |
| 72 // Start at the right offset. | 114 let buffer = testBuffers[connectionNumberOfChannels - 1]; |
| 73 var sampleFrameOffset = testNumber * singleTestFrameLength; | 115 source.buffer = buffer; |
| 74 var time = sampleFrameOffset / sampleRate; | 116 source.connect(mixNode); |
| 75 source.start(time); | 117 |
| 76 } | 118 // Start at the right offset. |
| 77 } | 119 let sampleFrameOffset = testNumber * singleTestFrameLength; |
| 78 | 120 let time = sampleFrameOffset / sampleRate; |
| 79 function checkTestResult(renderedBuffer, testNumber, connections, channelCount,
channelCountMode, channelInterpretation) { | 121 source.start(time); |
| 80 var s = "connections: " + connections + ", " + channelCountMode; | 122 } |
| 81 | 123 } |
| 82 // channelCount is ignored in "max" mode. | 124 |
| 83 if (channelCountMode == "clamped-max" || channelCountMode == "explicit") { | 125 function checkTestResult( |
| 84 s += "(" + channelCount + ")"; | 126 renderedBuffer, testNumber, connections, channelCount, channelCountMode, |
| 85 } | 127 channelInterpretation, should) { |
| 86 | 128 let s = 'connections: ' + connections + ', ' + channelCountMode; |
| 87 s += ", " + channelInterpretation; | 129 |
| 88 | 130 // channelCount is ignored in "max" mode. |
| 89 var computedNumberOfChannels = computeNumberOfChannels(connections, channelC
ount, channelCountMode); | 131 if (channelCountMode == 'clamped-max' || channelCountMode == 'explicit') { |
| 90 | 132 s += '(' + channelCount + ')'; |
| 91 // Create a zero-initialized silent AudioBuffer with computedNumberOfChannel
s. | 133 } |
| 92 var destBuffer = context.createBuffer(computedNumberOfChannels, singleTestFr
ameLength, context.sampleRate); | 134 |
| 93 | 135 s += ', ' + channelInterpretation; |
| 94 // Mix all of the connections into the destination buffer. | 136 |
| 95 for (var i = 0; i < connections.length; ++i) { | 137 let computedNumberOfChannels = |
| 96 var connectionNumberOfChannels = connections.charCodeAt(i) - "0".charCod
eAt(0); | 138 computeNumberOfChannels(connections, channelCount, channelCountMode); |
| 97 var sourceBuffer = testBuffers[connectionNumberOfChannels - 1]; // conve
rt from 1-based to 0-based index | 139 |
| 98 | 140 // Create a zero-initialized silent AudioBuffer with computedNumberOfChannels. |
| 99 if (channelInterpretation == "speakers") { | 141 let destBuffer = context.createBuffer( |
| 100 speakersSum(sourceBuffer, destBuffer); | 142 computedNumberOfChannels, singleTestFrameLength, context.sampleRate); |
| 101 } else if (channelInterpretation == "discrete") { | 143 |
| 102 discreteSum(sourceBuffer, destBuffer); | 144 // Mix all of the connections into the destination buffer. |
| 103 } else { | 145 for (let i = 0; i < connections.length; ++i) { |
| 104 alert("Invalid channel interpretation!"); | 146 let connectionNumberOfChannels = |
| 105 } | 147 connections.charCodeAt(i) - '0'.charCodeAt(0); |
| 106 } | 148 let sourceBuffer = |
| 107 | 149 testBuffers[connectionNumberOfChannels - 1]; // convert from 1-based to |
| 108 // Use this when debugging mixing rules. | 150 // 0-based index |
| 109 // printTestInformation(testNumber, renderedBuffer, destBuffer, singleTestFr
ameLength, sampleFrameOffset); | 151 |
| 110 | 152 if (channelInterpretation == 'speakers') { |
| 111 // Validate that destBuffer matches the rendered output. | 153 speakersSum(sourceBuffer, destBuffer); |
| 112 // We need to check the rendered output at a specific sample-frame-offset co
rresponding | 154 } else if (channelInterpretation == 'discrete') { |
| 113 // to the specific test case we're checking for based on testNumber. | 155 discreteSum(sourceBuffer, destBuffer); |
| 114 | 156 } else { |
| 115 var sampleFrameOffset = testNumber * singleTestFrameLength; | 157 alert('Invalid channel interpretation!'); |
| 116 for (var c = 0; c < renderNumberOfChannels; ++c) { | 158 } |
| 117 var renderedData = renderedBuffer.getChannelData(c); | 159 } |
| 118 for (var frame = 0; frame < singleTestFrameLength; ++frame) { | 160 |
| 119 var renderedValue = renderedData[frame + sampleFrameOffset]; | 161 // Use this when debugging mixing rules. |
| 120 | 162 // printTestInformation(testNumber, renderedBuffer, destBuffer, |
| 121 var expectedValue = 0; | 163 // singleTestFrameLength, sampleFrameOffset); |
| 122 if (c < destBuffer.numberOfChannels) { | 164 |
| 123 var expectedData = destBuffer.getChannelData(c); | 165 // Validate that destBuffer matches the rendered output. We need to check |
| 124 expectedValue = expectedData[frame]; | 166 // the rendered output at a specific sample-frame-offset corresponding to |
| 125 } | 167 // the specific test case we're checking for based on testNumber. |
| 126 | 168 |
| 127 // We may need to add an epsilon in the comparison if we add more te
st vectors. | 169 let sampleFrameOffset = testNumber * singleTestFrameLength; |
| 128 if (renderedValue != expectedValue) { | 170 for (let c = 0; c < renderNumberOfChannels; ++c) { |
| 129 var message = s + "rendered: " + renderedValue + " expected: " +
expectedValue + " channel: " + c + " frame: " + frame; | 171 let renderedData = renderedBuffer.getChannelData(c); |
| 130 testFailed(s); | 172 for (let frame = 0; frame < singleTestFrameLength; ++frame) { |
| 131 return; | 173 let renderedValue = renderedData[frame + sampleFrameOffset]; |
| 132 } | 174 |
| 133 } | 175 let expectedValue = 0; |
| 134 } | 176 if (c < destBuffer.numberOfChannels) { |
| 135 | 177 let expectedData = destBuffer.getChannelData(c); |
| 136 testPassed(s); | 178 expectedValue = expectedData[frame]; |
| 137 } | 179 } |
| 138 | 180 |
| 139 function checkResult(event) { | 181 // We may need to add an epsilon in the comparison if we add more |
| 140 var buffer = event.renderedBuffer; | 182 // test vectors. |
| 141 | 183 if (renderedValue != expectedValue) { |
| 142 // Sanity check result. | 184 let message = s + 'rendered: ' + renderedValue + ' expected: ' + |
| 143 if (buffer.length != numberOfTests * singleTestFrameLength || buffer.numberO
fChannels != renderNumberOfChannels) { | 185 expectedValue + ' channel: ' + c + ' frame: ' + frame; |
| 144 testFailed("OfflineAudioContext result not of expected size!"); | 186 // testFailed(s); |
| 145 finishJSTest(); | 187 should(renderedValue, s).beEqualTo(expectedValue); |
| 146 return; | 188 return; |
| 147 } | 189 } |
| 148 | 190 } |
| 149 // Check all the tests. | 191 } |
| 150 var testNumber = 0; | 192 |
| 151 for (var m = 0; m < mixingRulesList.length; ++m) { | 193 should(true, s).beTrue(); |
| 152 var mixingRules = mixingRulesList[m]; | 194 } |
| 153 for (var i = 0; i < connectionsList.length; ++i, ++testNumber) { | 195 |
| 154 checkTestResult(buffer, testNumber, connectionsList[i], mixingRules.
channelCount, mixingRules.channelCountMode, mixingRules.channelInterpretation); | 196 function checkResult(buffer, should) { |
| 155 } | 197 // Sanity check result. |
| 156 } | 198 should(buffer.length, 'Rendered number of frames') |
| 157 | 199 .beEqualTo(numberOfTests * singleTestFrameLength); |
| 158 finishJSTest(); | 200 should(buffer.numberOfChannels, 'Rendered number of channels') |
| 159 } | 201 .beEqualTo(renderNumberOfChannels); |
| 160 | 202 |
| 161 function runTest() { | 203 // Check all the tests. |
| 162 if (window.testRunner) { | 204 let testNumber = 0; |
| 163 testRunner.dumpAsText(); | 205 for (let m = 0; m < mixingRulesList.length; ++m) { |
| 164 testRunner.waitUntilDone(); | 206 let mixingRules = mixingRulesList[m]; |
| 165 } | 207 for (let i = 0; i < connectionsList.length; ++i, ++testNumber) { |
| 166 | 208 checkTestResult( |
| 167 window.jsTestIsAsync = true; | 209 buffer, testNumber, connectionsList[i], mixingRules.channelCount, |
| 168 | 210 mixingRules.channelCountMode, mixingRules.channelInterpretation, |
| 169 // Create 8-channel offline audio context. | 211 should); |
| 170 // Each test will render 8 sample-frames starting at sample-frame position t
estNumber * 8. | 212 } |
| 171 var totalFrameLength = numberOfTests * singleTestFrameLength; | 213 } |
| 172 context = new OfflineAudioContext(renderNumberOfChannels, totalFrameLength,
sampleRate); | 214 } |
| 173 | 215 |
| 174 // Set destination to discrete mixing. | 216 audit.define('test', function(task, should) { |
| 175 context.destination.channelCount = renderNumberOfChannels; | 217 task.describe('Channel mixing rules for AudioNodes'); |
| 176 context.destination.channelCountMode = "explicit"; | 218 |
| 177 context.destination.channelInterpretation = "discrete"; | 219 // Create 8-channel offline audio context. Each test will render 8 |
| 178 | 220 // sample-frames starting at sample-frame position testNumber * 8. |
| 179 // Create test buffers from 1 to 8 channels. | 221 let totalFrameLength = numberOfTests * singleTestFrameLength; |
| 180 testBuffers = new Array(); | 222 context = new OfflineAudioContext( |
| 181 for (var i = 0; i < renderNumberOfChannels; ++i) { | 223 renderNumberOfChannels, totalFrameLength, sampleRate); |
| 182 testBuffers[i] = createShiftedImpulseBuffer(context, i + 1, singleTestFr
ameLength); | 224 |
| 183 } | 225 // Set destination to discrete mixing. |
| 184 | 226 context.destination.channelCount = renderNumberOfChannels; |
| 185 // Schedule all the tests. | 227 context.destination.channelCountMode = 'explicit'; |
| 186 var testNumber = 0; | 228 context.destination.channelInterpretation = 'discrete'; |
| 187 for (var m = 0; m < mixingRulesList.length; ++m) { | 229 |
| 188 var mixingRules = mixingRulesList[m]; | 230 // Create test buffers from 1 to 8 channels. |
| 189 for (var i = 0; i < connectionsList.length; ++i, ++testNumber) { | 231 testBuffers = new Array(); |
| 190 scheduleTest(testNumber, connectionsList[i], mixingRules.channelCoun
t, mixingRules.channelCountMode, mixingRules.channelInterpretation); | 232 for (let i = 0; i < renderNumberOfChannels; ++i) { |
| 191 } | 233 testBuffers[i] = |
| 192 } | 234 createShiftedImpulseBuffer(context, i + 1, singleTestFrameLength); |
| 193 | 235 } |
| 194 // Render then check results. | 236 |
| 195 context.oncomplete = checkResult; | 237 // Schedule all the tests. |
| 196 context.startRendering(); | 238 let testNumber = 0; |
| 197 } | 239 for (let m = 0; m < mixingRulesList.length; ++m) { |
| 198 | 240 let mixingRules = mixingRulesList[m]; |
| 199 runTest(); | 241 for (let i = 0; i < connectionsList.length; ++i, ++testNumber) { |
| 242 scheduleTest( |
| 243 testNumber, connectionsList[i], mixingRules.channelCount, |
| 244 mixingRules.channelCountMode, mixingRules.channelInterpretation); |
| 245 } |
| 246 } |
| 247 |
| 248 // Render then check results. |
| 249 // context.oncomplete = checkResult; |
| 250 context.startRendering().then(buffer => { |
| 251 checkResult(buffer, should); |
| 252 task.done(); |
| 253 }); |
| 254 ; |
| 255 }); |
| 256 |
| 257 audit.run(); |
| 200 | 258 |
| 201 </script> | 259 </script> |
| 202 | 260 |
| 203 </body> | 261 </body> |
| 204 </html> | 262 </html> |
| OLD | NEW |