tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

mixing-rules.js (13279B)


      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  {AudioContext} context     Associated AudioContext.
     14 * @param  {Number} numberOfChannels  Number of channels of test buffer.
     15 * @param  {Number} frameLength       Buffer length in frames.
     16 * @return {AudioBuffer}
     17 */
     18 function createShiftedImpulseBuffer(context, numberOfChannels, frameLength) {
     19  let shiftedImpulseBuffer =
     20      context.createBuffer(numberOfChannels, frameLength, context.sampleRate);
     21  for (let channel = 0; channel < numberOfChannels; ++channel) {
     22    let data = shiftedImpulseBuffer.getChannelData(channel);
     23    data[channel] = 1;
     24  }
     25 
     26  return shiftedImpulseBuffer;
     27 }
     28 
     29 /**
     30 * Create a string that displays the content of AudioBuffer.
     31 * @param  {AudioBuffer} audioBuffer  AudioBuffer object to stringify.
     32 * @param  {Number} frameLength       Number of frames to be printed.
     33 * @param  {Number} frameOffset       Starting frame position for printing.
     34 * @return {String}
     35 */
     36 function stringifyBuffer(audioBuffer, frameLength, frameOffset) {
     37  frameOffset = (frameOffset || 0);
     38 
     39  let stringifiedBuffer = '';
     40  for (let channel = 0; channel < audioBuffer.numberOfChannels; ++channel) {
     41    let channelData = audioBuffer.getChannelData(channel);
     42    for (let i = 0; i < frameLength; ++i)
     43      stringifiedBuffer += channelData[i + frameOffset] + ' ';
     44    stringifiedBuffer += '\n';
     45  }
     46 
     47  return stringifiedBuffer;
     48 }
     49 
     50 /**
     51 * Compute number of channels from the connection.
     52 * http://webaudio.github.io/web-audio-api/#dfn-computednumberofchannels
     53 * @param  {String} connections         A string specifies the connection. For
     54 *                                      example, the string "128" means 3
     55 *                                      connections, having 1, 2, and 8 channels
     56 *                                      respectively.
     57 * @param  {Number} channelCount        Channel count.
     58 * @param  {String} channelCountMode    Channel count mode.
     59 * @return {Number}                     Computed number of channels.
     60 */
     61 function computeNumberOfChannels(connections, channelCount, channelCountMode) {
     62  if (channelCountMode == 'explicit')
     63    return channelCount;
     64 
     65  // Must have at least one channel.
     66  let computedNumberOfChannels = 1;
     67 
     68  // Compute "computedNumberOfChannels" based on all the connections.
     69  for (let i = 0; i < connections.length; ++i) {
     70    let connectionNumberOfChannels = parseInt(connections[i]);
     71    computedNumberOfChannels =
     72        Math.max(computedNumberOfChannels, connectionNumberOfChannels);
     73  }
     74 
     75  if (channelCountMode == 'clamped-max')
     76    computedNumberOfChannels = Math.min(computedNumberOfChannels, channelCount);
     77 
     78  return computedNumberOfChannels;
     79 }
     80 
     81 /**
     82 * Apply up/down-mixing (in-place summing) based on 'speaker' interpretation.
     83 * @param  {AudioBuffer} input          Input audio buffer.
     84 * @param  {AudioBuffer} output         Output audio buffer.
     85 */
     86 function speakersSum(input, output) {
     87  if (input.length != output.length) {
     88    throw '[mixing-rules.js] speakerSum(): buffer lengths mismatch (input: ' +
     89        input.length + ', output: ' + output.length + ')';
     90  }
     91 
     92  if (input.numberOfChannels === output.numberOfChannels) {
     93    for (let channel = 0; channel < output.numberOfChannels; ++channel) {
     94      let inputChannel = input.getChannelData(channel);
     95      let outputChannel = output.getChannelData(channel);
     96      for (let i = 0; i < outputChannel.length; i++)
     97        outputChannel[i] += inputChannel[i];
     98    }
     99  } else if (input.numberOfChannels < output.numberOfChannels) {
    100    processUpMix(input, output);
    101  } else {
    102    processDownMix(input, output);
    103  }
    104 }
    105 
    106 /**
    107 * In-place summing to |output| based on 'discrete' channel interpretation.
    108 * @param  {AudioBuffer} input          Input audio buffer.
    109 * @param  {AudioBuffer} output         Output audio buffer.
    110 */
    111 function discreteSum(input, output) {
    112  if (input.length != output.length) {
    113    throw '[mixing-rules.js] speakerSum(): buffer lengths mismatch (input: ' +
    114        input.length + ', output: ' + output.length + ')';
    115  }
    116 
    117  let numberOfChannels =
    118      Math.min(input.numberOfChannels, output.numberOfChannels)
    119 
    120          for (let channel = 0; channel < numberOfChannels; ++channel) {
    121    let inputChannel = input.getChannelData(channel);
    122    let outputChannel = output.getChannelData(channel);
    123    for (let i = 0; i < outputChannel.length; i++)
    124      outputChannel[i] += inputChannel[i];
    125  }
    126 }
    127 
    128 /**
    129 * Perform up-mix by in-place summing to |output| buffer.
    130 * @param  {AudioBuffer} input          Input audio buffer.
    131 * @param  {AudioBuffer} output         Output audio buffer.
    132 */
    133 function processUpMix(input, output) {
    134  let numberOfInputChannels = input.numberOfChannels;
    135  let numberOfOutputChannels = output.numberOfChannels;
    136  let i, length = output.length;
    137 
    138  // Up-mixing: 1 -> 2, 1 -> 4
    139  //   output.L += input
    140  //   output.R += input
    141  //   output.SL += 0 (in the case of 1 -> 4)
    142  //   output.SR += 0 (in the case of 1 -> 4)
    143  if ((numberOfInputChannels === 1 && numberOfOutputChannels === 2) ||
    144      (numberOfInputChannels === 1 && numberOfOutputChannels === 4)) {
    145    let inputChannel = input.getChannelData(0);
    146    let outputChannel0 = output.getChannelData(0);
    147    let outputChannel1 = output.getChannelData(1);
    148    for (i = 0; i < length; i++) {
    149      outputChannel0[i] += inputChannel[i];
    150      outputChannel1[i] += inputChannel[i];
    151    }
    152 
    153    return;
    154  }
    155 
    156  // Up-mixing: 1 -> 5.1
    157  //   output.L += 0
    158  //   output.R += 0
    159  //   output.C += input
    160  //   output.LFE += 0
    161  //   output.SL += 0
    162  //   output.SR += 0
    163  if (numberOfInputChannels == 1 && numberOfOutputChannels == 6) {
    164    let inputChannel = input.getChannelData(0);
    165    let outputChannel2 = output.getChannelData(2);
    166    for (i = 0; i < length; i++)
    167      outputChannel2[i] += inputChannel[i];
    168 
    169    return;
    170  }
    171 
    172  // Up-mixing: 2 -> 4, 2 -> 5.1
    173  //   output.L += input.L
    174  //   output.R += input.R
    175  //   output.C += 0 (in the case of 2 -> 5.1)
    176  //   output.LFE += 0 (in the case of 2 -> 5.1)
    177  //   output.SL += 0
    178  //   output.SR += 0
    179  if ((numberOfInputChannels === 2 && numberOfOutputChannels === 4) ||
    180      (numberOfInputChannels === 2 && numberOfOutputChannels === 6)) {
    181    let inputChannel0 = input.getChannelData(0);
    182    let inputChannel1 = input.getChannelData(1);
    183    let outputChannel0 = output.getChannelData(0);
    184    let outputChannel1 = output.getChannelData(1);
    185    for (i = 0; i < length; i++) {
    186      outputChannel0[i] += inputChannel0[i];
    187      outputChannel1[i] += inputChannel1[i];
    188    }
    189 
    190    return;
    191  }
    192 
    193  // Up-mixing: 4 -> 5.1
    194  //   output.L += input.L
    195  //   output.R += input.R
    196  //   output.C += 0
    197  //   output.LFE += 0
    198  //   output.SL += input.SL
    199  //   output.SR += input.SR
    200  if (numberOfInputChannels === 4 && numberOfOutputChannels === 6) {
    201    let inputChannel0 = input.getChannelData(0);    // input.L
    202    let inputChannel1 = input.getChannelData(1);    // input.R
    203    let inputChannel2 = input.getChannelData(2);    // input.SL
    204    let inputChannel3 = input.getChannelData(3);    // input.SR
    205    let outputChannel0 = output.getChannelData(0);  // output.L
    206    let outputChannel1 = output.getChannelData(1);  // output.R
    207    let outputChannel4 = output.getChannelData(4);  // output.SL
    208    let outputChannel5 = output.getChannelData(5);  // output.SR
    209    for (i = 0; i < length; i++) {
    210      outputChannel0[i] += inputChannel0[i];
    211      outputChannel1[i] += inputChannel1[i];
    212      outputChannel4[i] += inputChannel2[i];
    213      outputChannel5[i] += inputChannel3[i];
    214    }
    215 
    216    return;
    217  }
    218 
    219  // All other cases, fall back to the discrete sum.
    220  discreteSum(input, output);
    221 }
    222 
    223 /**
    224 * Perform down-mix by in-place summing to |output| buffer.
    225 * @param  {AudioBuffer} input          Input audio buffer.
    226 * @param  {AudioBuffer} output         Output audio buffer.
    227 */
    228 function processDownMix(input, output) {
    229  let numberOfInputChannels = input.numberOfChannels;
    230  let numberOfOutputChannels = output.numberOfChannels;
    231  let i, length = output.length;
    232 
    233  // Down-mixing: 2 -> 1
    234  //   output += 0.5 * (input.L + input.R)
    235  if (numberOfInputChannels === 2 && numberOfOutputChannels === 1) {
    236    let inputChannel0 = input.getChannelData(0);  // input.L
    237    let inputChannel1 = input.getChannelData(1);  // input.R
    238    let outputChannel0 = output.getChannelData(0);
    239    for (i = 0; i < length; i++)
    240      outputChannel0[i] += 0.5 * (inputChannel0[i] + inputChannel1[i]);
    241 
    242    return;
    243  }
    244 
    245  // Down-mixing: 4 -> 1
    246  //   output += 0.25 * (input.L + input.R + input.SL + input.SR)
    247  if (numberOfInputChannels === 4 && numberOfOutputChannels === 1) {
    248    let inputChannel0 = input.getChannelData(0);  // input.L
    249    let inputChannel1 = input.getChannelData(1);  // input.R
    250    let inputChannel2 = input.getChannelData(2);  // input.SL
    251    let inputChannel3 = input.getChannelData(3);  // input.SR
    252    let outputChannel0 = output.getChannelData(0);
    253    for (i = 0; i < length; i++) {
    254      outputChannel0[i] += 0.25 *
    255          (inputChannel0[i] + inputChannel1[i] + inputChannel2[i] +
    256           inputChannel3[i]);
    257    }
    258 
    259    return;
    260  }
    261 
    262  // Down-mixing: 5.1 -> 1
    263  //   output += sqrt(1/2) * (input.L + input.R) + input.C
    264  //            + 0.5 * (input.SL + input.SR)
    265  if (numberOfInputChannels === 6 && numberOfOutputChannels === 1) {
    266    let inputChannel0 = input.getChannelData(0);  // input.L
    267    let inputChannel1 = input.getChannelData(1);  // input.R
    268    let inputChannel2 = input.getChannelData(2);  // input.C
    269    let inputChannel4 = input.getChannelData(4);  // input.SL
    270    let inputChannel5 = input.getChannelData(5);  // input.SR
    271    let outputChannel0 = output.getChannelData(0);
    272    let scaleSqrtHalf = Math.sqrt(0.5);
    273    for (i = 0; i < length; i++) {
    274      outputChannel0[i] +=
    275          scaleSqrtHalf * (inputChannel0[i] + inputChannel1[i]) +
    276          inputChannel2[i] + 0.5 * (inputChannel4[i] + inputChannel5[i]);
    277    }
    278 
    279    return;
    280  }
    281 
    282  // Down-mixing: 4 -> 2
    283  //   output.L += 0.5 * (input.L + input.SL)
    284  //   output.R += 0.5 * (input.R + input.SR)
    285  if (numberOfInputChannels == 4 && numberOfOutputChannels == 2) {
    286    let inputChannel0 = input.getChannelData(0);    // input.L
    287    let inputChannel1 = input.getChannelData(1);    // input.R
    288    let inputChannel2 = input.getChannelData(2);    // input.SL
    289    let inputChannel3 = input.getChannelData(3);    // input.SR
    290    let outputChannel0 = output.getChannelData(0);  // output.L
    291    let outputChannel1 = output.getChannelData(1);  // output.R
    292    for (i = 0; i < length; i++) {
    293      outputChannel0[i] += 0.5 * (inputChannel0[i] + inputChannel2[i]);
    294      outputChannel1[i] += 0.5 * (inputChannel1[i] + inputChannel3[i]);
    295    }
    296 
    297    return;
    298  }
    299 
    300  // Down-mixing: 5.1 -> 2
    301  //   output.L += input.L + sqrt(1/2) * (input.C + input.SL)
    302  //   output.R += input.R + sqrt(1/2) * (input.C + input.SR)
    303  if (numberOfInputChannels == 6 && numberOfOutputChannels == 2) {
    304    let inputChannel0 = input.getChannelData(0);    // input.L
    305    let inputChannel1 = input.getChannelData(1);    // input.R
    306    let inputChannel2 = input.getChannelData(2);    // input.C
    307    let inputChannel4 = input.getChannelData(4);    // input.SL
    308    let inputChannel5 = input.getChannelData(5);    // input.SR
    309    let outputChannel0 = output.getChannelData(0);  // output.L
    310    let outputChannel1 = output.getChannelData(1);  // output.R
    311    let scaleSqrtHalf = Math.sqrt(0.5);
    312    for (i = 0; i < length; i++) {
    313      outputChannel0[i] += inputChannel0[i] +
    314          scaleSqrtHalf * (inputChannel2[i] + inputChannel4[i]);
    315      outputChannel1[i] += inputChannel1[i] +
    316          scaleSqrtHalf * (inputChannel2[i] + inputChannel5[i]);
    317    }
    318 
    319    return;
    320  }
    321 
    322  // Down-mixing: 5.1 -> 4
    323  //   output.L += input.L + sqrt(1/2) * input.C
    324  //   output.R += input.R + sqrt(1/2) * input.C
    325  //   output.SL += input.SL
    326  //   output.SR += input.SR
    327  if (numberOfInputChannels === 6 && numberOfOutputChannels === 4) {
    328    let inputChannel0 = input.getChannelData(0);    // input.L
    329    let inputChannel1 = input.getChannelData(1);    // input.R
    330    let inputChannel2 = input.getChannelData(2);    // input.C
    331    let inputChannel4 = input.getChannelData(4);    // input.SL
    332    let inputChannel5 = input.getChannelData(5);    // input.SR
    333    let outputChannel0 = output.getChannelData(0);  // output.L
    334    let outputChannel1 = output.getChannelData(1);  // output.R
    335    let outputChannel2 = output.getChannelData(2);  // output.SL
    336    let outputChannel3 = output.getChannelData(3);  // output.SR
    337    let scaleSqrtHalf = Math.sqrt(0.5);
    338    for (i = 0; i < length; i++) {
    339      outputChannel0[i] += inputChannel0[i] + scaleSqrtHalf * inputChannel2[i];
    340      outputChannel1[i] += inputChannel1[i] + scaleSqrtHalf * inputChannel2[i];
    341      outputChannel2[i] += inputChannel4[i];
    342      outputChannel3[i] += inputChannel5[i];
    343    }
    344 
    345    return;
    346  }
    347 
    348  // All other cases, fall back to the discrete sum.
    349  discreteSum(input, output);
    350 }