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