Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Utilities for mixing rule testing. | |
| 2 // http://webaudio.github.io/web-audio-api/#channel-up-mixing-and-down-mixing | |
| 3 | |
| 4 | |
| 5 /** | |
| 6 * Create an n-channel buffer, with all sample data zero except for a shifted | |
| 7 * impulse. The impulse position depends on the channel index. For example, for | |
| 8 * a 4-channel buffer: | |
| 9 * channel 0: 1 0 0 0 0 0 0 0 | |
| 10 * channel 1: 0 1 0 0 0 0 0 0 | |
| 11 * channel 2: 0 0 1 0 0 0 0 0 | |
| 12 * channel 3: 0 0 0 1 0 0 0 0 | |
| 13 * @param {Number} numberOfChannels Number of channels of test buffer. | |
|
Raymond Toy
2016/03/08 18:04:06
If you're going to document the code this way, don
hongchan
2016/03/08 23:53:34
Done.
| |
| 14 * @return {AudioBuffer} | |
| 15 */ | |
| 16 function createShiftedImpulseBuffer(context, numberOfChannels, frameLength) { | |
| 17 var shiftedImpulseBuffer = context.createBuffer(numberOfChannels, frameLengt h, context.sampleRate); | |
| 18 for (var channel = 0; channel < numberOfChannels; ++channel) { | |
| 19 var data = shiftedImpulseBuffer.getChannelData(channel); | |
| 20 data[channel] = 1; | |
| 21 } | |
| 22 | |
| 23 return shiftedImpulseBuffer; | |
| 24 } | |
| 25 | |
| 26 /** | |
| 27 * Stringify AudioBuffer content with options. | |
|
Raymond Toy
2016/03/08 18:04:07
Not obvious how you want to stringify the AudioBuf
hongchan
2016/03/08 23:53:35
Done.
| |
| 28 * @param {AudioBuffer} audioBuffer AudioBuffer object to stringify. | |
|
Raymond Toy
2016/03/08 18:04:07
The other parameters/outputs have the description
hongchan
2016/03/08 23:53:34
Done.
| |
| 29 * @param {Number} frameLength Length to print. | |
| 30 * @param {Number} frameOffset Offset frames to print. | |
|
Raymond Toy
2016/03/08 18:04:07
This description of frameOffset doesn't really say
hongchan
2016/03/08 23:53:34
Done.
| |
| 31 * @return {String} Assembled string for printing. | |
| 32 */ | |
| 33 function stringifyBuffer(audioBuffer, frameLength, frameOffset) { | |
| 34 frameOffset = (frameOffset || 0); | |
| 35 | |
| 36 var stringifiedBuffer = ''; | |
| 37 for (var channel = 0; channel < audioBuffer.numberOfChannels; ++channel) { | |
| 38 var channelData = audioBuffer.getChannelData(channel); | |
| 39 for (var i = 0; i < frameLength; ++i) | |
| 40 stringifiedBuffer += channelData[i + frameOffset] + ' '; | |
| 41 stringifiedBuffer += '\n'; | |
| 42 } | |
| 43 | |
| 44 return stringifiedBuffer; | |
| 45 } | |
| 46 | |
| 47 /** | |
| 48 * Computer number of channels from the connection. | |
|
Raymond Toy
2016/03/08 18:04:06
Typo: "Computer" -> "Compute"
hongchan
2016/03/08 23:53:35
Done.
| |
| 49 * @param {String} connections A string specifies the connection. The | |
| 50 * string "128" means 3 connections, having | |
|
Raymond Toy
2016/03/08 18:04:06
Description doesn't line up with the rest of the d
hongchan
2016/03/08 23:53:34
Done.
| |
| 51 * 1, 2, and 8 channels respectively. | |
| 52 * @param {Number} channelCount Channel count. | |
| 53 * @param {String} channelCountMode Channel count mode. | |
| 54 * @return {Number} A computed number of channels. | |
|
Raymond Toy
2016/03/08 18:04:06
A link to the spec would be nice. I can never reme
hongchan
2016/03/08 23:53:35
URL is at the top of this file, and I don't think
Raymond Toy
2016/03/08 23:56:54
That link is for the mixing rules. This function
hongchan
2016/03/09 19:34:24
It does not have a separate section, but a definit
| |
| 55 */ | |
| 56 function computeNumberOfChannels(connections, channelCount, channelCountMode) { | |
| 57 if (channelCountMode == "explicit") | |
| 58 return channelCount; | |
| 59 | |
| 60 // Must have at least one channel. | |
| 61 var computedNumberOfChannels = 1; | |
| 62 | |
| 63 // Compute "computedNumberOfChannels" based on all the connections. | |
| 64 for (var i = 0; i < connections.length; ++i) { | |
| 65 var connectionNumberOfChannels = parseInt(connections[i]); | |
| 66 computedNumberOfChannels = Math.max(computedNumberOfChannels, connectionNumb erOfChannels); | |
| 67 } | |
| 68 | |
| 69 if (channelCountMode == "clamped-max") | |
| 70 computedNumberOfChannels = Math.min(computedNumberOfChannels, channelCount); | |
| 71 | |
| 72 return computedNumberOfChannels; | |
| 73 } | |
| 74 | |
| 75 /** | |
| 76 * Apply up/down-mixing rules based on 'speaker' interpretation. | |
| 77 * @param {AudioBuffer} source Source audio buffer. | |
| 78 * @param {AudioBuffer} destination Destination audio buffer. | |
| 79 */ | |
| 80 function speakersSum(source, destination) { | |
| 81 if (source.length != destination.length) | |
| 82 throw "[mixing-rules.js] speakerSum(): buffer lengths mismatch"; | |
|
Raymond Toy
2016/03/08 18:04:06
Since you know the lengths, print them out in the
hongchan
2016/03/08 23:53:35
Done.
| |
| 83 | |
| 84 if (source.numberOfChannels === destination.numberOfChannels) { | |
| 85 for (var channel = 0; channel < destination.numberOfChannels; ++channel) { | |
| 86 var sourceChannel = source.getChannelData(channel); | |
| 87 var destinationChannel = destination.getChannelData(channel); | |
| 88 for (var i = 0; i < destinationChannel.length; i++) | |
| 89 destinationChannel[i] += sourceChannel[i]; | |
| 90 } | |
| 91 | |
| 92 return; | |
| 93 } | |
| 94 | |
| 95 if (source.numberOfChannels < destination.numberOfChannels) | |
|
Raymond Toy
2016/03/08 18:04:07
I find this style confusing. I think it's clearer
hongchan
2016/03/08 23:53:34
Done.
| |
| 96 processUpMix(source, destination); | |
| 97 else | |
| 98 processDownMix(source, destination); | |
| 99 } | |
| 100 | |
| 101 /** | |
| 102 * Discrete channel interpretation mixing. | |
| 103 * @param {AudioBuffer} source Source audio buffer. | |
| 104 * @param {AudioBuffer} destination Destination audio buffer. | |
|
Raymond Toy
2016/03/08 18:04:07
Since nothing is returned, I suggest saying that t
hongchan
2016/03/08 23:53:34
Done.
| |
| 105 */ | |
| 106 function discreteSum(source, destination) { | |
| 107 if (source.length != destination.length) | |
| 108 throw "[mixing-rules.js] discreteSum(): buffer lengths mismatch"; | |
|
Raymond Toy
2016/03/08 18:04:06
Give lengths in message.
hongchan
2016/03/08 23:53:35
Done.
| |
| 109 | |
| 110 var numberOfChannels = source.numberOfChannels < destination.numberOfChannels | |
| 111 ? source.numberOfChannels | |
| 112 : destination.numberOfChannels; | |
|
Raymond Toy
2016/03/08 18:04:07
numberOfChannels = Math.min(source.numberOfChannel
hongchan
2016/03/08 23:53:34
Done. I was following the original test code - but
| |
| 113 | |
| 114 for (var channel = 0; channel < numberOfChannels; ++channel) { | |
| 115 var sourceChannel = source.getChannelData(channel); | |
| 116 var destinationChannel = destination.getChannelData(channel); | |
| 117 for (var i = 0; i < destinationChannel.length; i++) | |
| 118 destinationChannel[i] += sourceChannel[i]; | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 /** | |
| 123 * Process up-mix. | |
| 124 * @param {AudioBuffer} source Source audio buffer. | |
| 125 * @param {AudioBuffer} destination Destination audio buffer. | |
|
Raymond Toy
2016/03/08 18:04:07
Say that the destination is modified.
hongchan
2016/03/08 23:53:35
Done.
| |
| 126 */ | |
| 127 function processUpMix(source, destination) { | |
| 128 var numberOfSourceChannels = source.numberOfChannels; | |
| 129 var numberOfDestinationChannels = destination.numberOfChannels; | |
| 130 var i, length = destination.length; | |
| 131 | |
| 132 // Up-mixing: 1 -> 2, 1 -> 4 | |
| 133 // output.L = input | |
| 134 // output.R = input | |
| 135 // output.SL = 0 (in the case of 1 -> 4) | |
| 136 // output.SR = 0 (in the case of 1 -> 4) | |
|
Raymond Toy
2016/03/08 18:04:06
Make comment notation match code notation more clo
hongchan
2016/03/08 23:53:35
Done.
| |
| 137 if ((numberOfSourceChannels === 1 && numberOfDestinationChannels === 2) || | |
| 138 (numberOfSourceChannels === 1 && numberOfDestinationChannels === 4)) { | |
| 139 var sourceChannel = source.getChannelData(0); | |
| 140 var destinationChannel0 = destination.getChannelData(0); | |
| 141 var destinationChannel1 = destination.getChannelData(1); | |
| 142 for (i = 0; i < length; i++) { | |
| 143 destinationChannel0[i] += sourceChannel[i]; | |
|
Raymond Toy
2016/03/08 18:04:06
This doesn't match the comment. You're summing the
hongchan
2016/03/08 23:53:34
Done.
| |
| 144 destinationChannel1[i] += sourceChannel[i]; | |
| 145 } | |
| 146 | |
| 147 return; | |
| 148 } | |
| 149 | |
| 150 // Up-mixing: 1 -> 5.1 | |
| 151 // output.L = 0 | |
| 152 // output.R = 0 | |
| 153 // output.C = input | |
| 154 // output.LFE = 0 | |
| 155 // output.SL = 0 | |
| 156 // output.SR = 0 | |
| 157 if (numberOfSourceChannels == 1 && numberOfDestinationChannels == 6) { | |
| 158 var sourceChannel = source.getChannelData(0); | |
| 159 var destinationChannel2 = destination.getChannelData(2); | |
| 160 for (i = 0; i < length; i++) | |
| 161 destinationChannel2[i] += sourceChannel[i]; | |
|
Raymond Toy
2016/03/08 18:04:06
Again, this doesn't match the comment. Update com
hongchan
2016/03/08 23:53:34
Done.
| |
| 162 | |
| 163 return; | |
| 164 } | |
| 165 | |
| 166 // Up-mixing: 2 -> 4, 2 -> 5.1 | |
| 167 // output.L = input.L | |
| 168 // output.R = input.R | |
| 169 // output.C = 0 (in the case of 2 -> 5.1) | |
| 170 // output.LFE = 0 (in the case of 2 -> 5.1) | |
| 171 // output.SL = 0 | |
| 172 // output.SR = 0 | |
| 173 if ((numberOfSourceChannels === 2 && numberOfDestinationChannels === 4) || | |
| 174 (numberOfSourceChannels === 2 && numberOfDestinationChannels === 6)) { | |
| 175 var sourceChannel0 = source.getChannelData(0); | |
| 176 var sourceChannel1 = source.getChannelData(1); | |
| 177 var destinationChannel0 = destination.getChannelData(0); | |
| 178 var destinationChannel1 = destination.getChannelData(1); | |
| 179 for (i = 0; i < length; i++) { | |
| 180 destinationChannel0[i] += sourceChannel0[i]; | |
| 181 destinationChannel1[i] += sourceChannel1[i]; | |
|
Raymond Toy
2016/03/08 18:04:07
Again, this doesn't match the comment. Update com
hongchan
2016/03/08 23:53:35
Done.
| |
| 182 } | |
| 183 | |
| 184 return; | |
| 185 } | |
| 186 | |
| 187 // Up-mixing: 4 -> 5.1 | |
| 188 // output.L = input.L | |
| 189 // output.R = input.R | |
| 190 // output.C = 0 | |
| 191 // output.LFE = 0 | |
| 192 // output.SL = input.SL | |
| 193 // output.SR = input.SR | |
| 194 if (numberOfSourceChannels === 4 && numberOfDestinationChannels === 6) { | |
| 195 var sourceChannel0 = source.getChannelData(0); | |
| 196 var sourceChannel1 = source.getChannelData(1); | |
| 197 var sourceChannel2 = source.getChannelData(2); | |
| 198 var sourceChannel3 = source.getChannelData(3); | |
| 199 var destinationChannel0 = destination.getChannelData(0); | |
| 200 var destinationChannel1 = destination.getChannelData(1); | |
| 201 var destinationChannel4 = destination.getChannelData(4); | |
| 202 var destinationChannel5 = destination.getChannelData(5); | |
| 203 for (i = 0; i < length; i++) { | |
| 204 destinationChannel0[i] += sourceChannel0[i]; | |
| 205 destinationChannel1[i] += sourceChannel1[i]; | |
| 206 destinationChannel4[i] += sourceChannel2[i]; | |
| 207 destinationChannel5[i] += sourceChannel3[i]; | |
| 208 } | |
| 209 | |
| 210 return; | |
| 211 } | |
| 212 | |
| 213 // All other cases, fall back to the discrete sum. | |
| 214 discreteSum(source, destination); | |
| 215 } | |
| 216 | |
| 217 /** | |
| 218 * Process down-mix from source to destination by summing into the existing data . | |
| 219 * @param {AudioBuffer} source Source audio buffer. | |
| 220 * @param {AudioBuffer} destination Destination audio buffer. | |
| 221 */ | |
| 222 function processDownMix(source, destination) { | |
| 223 var numberOfSourceChannels = source.numberOfChannels; | |
| 224 var numberOfDestinationChannels = destination.numberOfChannels; | |
| 225 var i, length = destination.length; | |
| 226 | |
| 227 // Down-mixing: 2 -> 1 | |
| 228 // output = 0.5 * (input.L + input.R) | |
| 229 if (numberOfSourceChannels === 2 && numberOfDestinationChannels === 1) { | |
| 230 var sourceChannel0 = source.getChannelData(0); | |
| 231 var sourceChannel1 = source.getChannelData(1); | |
| 232 var destinationChannel0 = destination.getChannelData(0); | |
| 233 for (i = 0; i < length; i++) | |
| 234 destinationChannel0[i] += 0.5 * (sourceChannel0[i] + sourceChannel1[i]); | |
|
Raymond Toy
2016/03/08 18:04:07
Again, this doesn't match the comment. Update com
hongchan
2016/03/08 23:53:35
Done.
| |
| 235 | |
| 236 return; | |
| 237 } | |
| 238 | |
| 239 // Down-mixing: 4 -> 1 | |
| 240 // output = 0.25 * (input.L + input.R + input.SL + input.SR) | |
| 241 if (numberOfSourceChannels === 4 && numberOfDestinationChannels === 1) { | |
| 242 var sourceChannel0 = source.getChannelData(0); | |
| 243 var sourceChannel1 = source.getChannelData(1); | |
| 244 var sourceChannel2 = source.getChannelData(2); | |
| 245 var sourceChannel3 = source.getChannelData(3); | |
| 246 var destinationChannel0 = destination.getChannelData(0); | |
| 247 for (i = 0; i < length; i++) { | |
| 248 destinationChannel0[i] += 0.25 * (sourceChannel0[i] + sourceChannel1[i] | |
|
Raymond Toy
2016/03/08 18:04:07
Again, this doesn't match the comment. Update com
hongchan
2016/03/08 23:53:35
Done.
| |
| 249 + sourceChannel2[i] + sourceChannel3[i]); | |
| 250 } | |
| 251 | |
| 252 return; | |
| 253 } | |
| 254 | |
| 255 // Down-mixing: 5.1 -> 1 | |
| 256 // output = sqrt(1/2) * (input.L + input.R) + input.C | |
| 257 // + 0.5 * (input.SL + input.SR) | |
| 258 if (numberOfSourceChannels === 6 && numberOfDestinationChannels === 1) { | |
| 259 var sourceChannel0 = source.getChannelData(0); | |
| 260 var sourceChannel1 = source.getChannelData(1); | |
| 261 var sourceChannel2 = source.getChannelData(2); | |
| 262 var sourceChannel4 = source.getChannelData(4); | |
| 263 var sourceChannel5 = source.getChannelData(5); | |
| 264 var destinationChannel0 = destination.getChannelData(0); | |
| 265 var scaleSqrtHalf = Math.sqrt(0.5); | |
| 266 for (i = 0; i < length; i++) { | |
| 267 destinationChannel0[i] += | |
|
Raymond Toy
2016/03/08 18:04:07
This doesn't match the comment. Update comment or
hongchan
2016/03/08 23:53:34
Done.
| |
| 268 scaleSqrtHalf * (sourceChannel0[i] + sourceChannel1[i]) | |
| 269 + sourceChannel2[i] + 0.5 * (sourceChannel4[i] + sourceChannel5[i]); | |
| 270 } | |
| 271 | |
| 272 return; | |
| 273 } | |
| 274 | |
| 275 // Down-mixing: 4 -> 2 | |
| 276 // output.L = 0.5 * (input.L + input.SL) | |
| 277 // output.R = 0.5 * (input.R + input.SR) | |
| 278 if (numberOfSourceChannels == 4 && numberOfDestinationChannels == 2) { | |
| 279 var sourceChannel0 = source.getChannelData(0); | |
|
Raymond Toy
2016/03/08 18:04:07
Probably want to say how sourceChannel<n> is assig
hongchan
2016/03/08 23:53:34
Done.
| |
| 280 var sourceChannel1 = source.getChannelData(1); | |
| 281 var sourceChannel2 = source.getChannelData(2); | |
| 282 var sourceChannel3 = source.getChannelData(3); | |
| 283 var destinationChannel0 = destination.getChannelData(0); | |
| 284 var destinationChannel1 = destination.getChannelData(1); | |
| 285 for (i = 0; i < length; i++) { | |
| 286 destinationChannel0[i] += 0.5 * (sourceChannel0[i] + sourceChannel2[i]); | |
| 287 destinationChannel1[i] += 0.5 * (sourceChannel1[i] + sourceChannel3[i]); | |
|
Raymond Toy
2016/03/08 18:04:07
This doesn't match the comment. Update comment or
hongchan
2016/03/08 23:53:35
Done.
| |
| 288 } | |
| 289 | |
| 290 return; | |
| 291 } | |
| 292 | |
| 293 // Down-mixing: 5.1 -> 2 | |
| 294 // output.L = input.L + sqrt(1/2) * (input.C + input.SL) | |
| 295 // output.R = input.R + sqrt(1/2) * (input.C + input.SR) | |
| 296 if (numberOfSourceChannels == 6 && numberOfDestinationChannels == 2) { | |
| 297 var sourceChannel0 = source.getChannelData(0); | |
| 298 var sourceChannel1 = source.getChannelData(1); | |
| 299 var sourceChannel2 = source.getChannelData(2); | |
| 300 var sourceChannel4 = source.getChannelData(4); | |
| 301 var sourceChannel5 = source.getChannelData(5); | |
| 302 var destinationChannel0 = destination.getChannelData(0); | |
| 303 var destinationChannel1 = destination.getChannelData(1); | |
| 304 var scaleSqrtHalf = Math.sqrt(0.5); | |
| 305 for (i = 0; i < length; i++) { | |
| 306 destinationChannel0[i] += sourceChannel0[i] | |
| 307 + scaleSqrtHalf * (sourceChannel2[i] + sourceChannel4[i]); | |
| 308 destinationChannel1[i] += sourceChannel1[i] | |
| 309 + scaleSqrtHalf * (sourceChannel2[i] + sourceChannel5[i]); | |
| 310 } | |
| 311 | |
| 312 return; | |
| 313 } | |
| 314 | |
| 315 // Down-mixing: 5.1 -> 4 | |
| 316 // output.L = input.L + sqrt(1/2) * input.C | |
| 317 // output.R = input.R + sqrt(1/2) * input.C | |
| 318 // output.SL = input.SL | |
| 319 // output.SR = input.SR | |
| 320 if (numberOfSourceChannels === 6 && numberOfDestinationChannels === 4) { | |
| 321 var sourceChannel0 = source.getChannelData(0); | |
| 322 var sourceChannel1 = source.getChannelData(1); | |
| 323 var sourceChannel2 = source.getChannelData(2); | |
| 324 var sourceChannel4 = source.getChannelData(4); | |
| 325 var sourceChannel5 = source.getChannelData(5); | |
| 326 var destinationChannel0 = destination.getChannelData(0); | |
| 327 var destinationChannel1 = destination.getChannelData(1); | |
| 328 var destinationChannel2 = destination.getChannelData(2); | |
| 329 var destinationChannel3 = destination.getChannelData(3); | |
| 330 var scaleSqrtHalf = Math.sqrt(0.5); | |
| 331 for (i = 0; i < length; i++) { | |
| 332 destinationChannel0[i] += sourceChannel0[i] + scaleSqrtHalf * sourceChanne l2[i]; | |
| 333 destinationChannel1[i] += sourceChannel1[i] + scaleSqrtHalf * sourceChanne l2[i]; | |
| 334 destinationChannel2[i] += sourceChannel4[i]; | |
| 335 destinationChannel3[i] += sourceChannel5[i]; | |
| 336 } | |
| 337 | |
| 338 return; | |
| 339 } | |
| 340 | |
| 341 // All other cases, fall back to the discrete sum. | |
| 342 discreteSum(source, destination); | |
| 343 } | |
| OLD | NEW |