tor-browser

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

no-dezippering.html (9629B)


      1 <!DOCTYPE html>
      2 <html>
      3  <head>
      4    <title>
      5      Test StereoPannerNode Has No Dezippering
      6    </title>
      7    <script src="/resources/testharness.js"></script>
      8    <script src="/resources/testharnessreport.js"></script>
      9    <script src="../../resources/audit-util.js"></script>
     10    <script src="../../resources/audit.js"></script>
     11  </head>
     12  <body>
     13    <script id="layout-test-code">
     14      // Arbitrary sample rate except that it should be a power of two to
     15      // eliminate any round-off in computing frame boundaries.
     16      let sampleRate = 16384;
     17 
     18      let audit = Audit.createTaskRunner();
     19 
     20      audit.define(
     21          {
     22            label: 'test mono input',
     23            description: 'Test StereoPanner with mono input has no dezippering'
     24          },
     25          (task, should) => {
     26            let context = new OfflineAudioContext(2, sampleRate, sampleRate);
     27            let src = new ConstantSourceNode(context, {offset: 1});
     28            let p = new StereoPannerNode(context, {pan: -1});
     29 
     30            src.connect(p).connect(context.destination);
     31            src.start();
     32 
     33            // Frame at which to change pan value.
     34            let panFrame = 256;
     35            context.suspend(panFrame / context.sampleRate)
     36                .then(() => p.pan.value = 1)
     37                .then(() => context.resume());
     38 
     39            context.startRendering()
     40                .then(renderedBuffer => {
     41                  let c0 = renderedBuffer.getChannelData(0);
     42                  let c1 = renderedBuffer.getChannelData(1);
     43 
     44                  // The first part should be full left.
     45                  should(
     46                      c0.slice(0, panFrame), 'Mono: Left channel, pan = -1: ')
     47                      .beConstantValueOf(1);
     48                  should(
     49                      c1.slice(0, panFrame), 'Mono: Right channel, pan = -1:')
     50                      .beConstantValueOf(0);
     51 
     52                  // The second part should be full right, but due to roundoff,
     53                  // the left channel won't be exactly zero.  Compare the left
     54                  // channel against zero with a threshold instead.
     55                  let tail = c0.slice(panFrame);
     56                  let zero = new Float32Array(tail.length);
     57 
     58                  should(c0.slice(panFrame), 'Mono: Left channel, pan = 1: ')
     59                      .beCloseToArray(zero, {absoluteThreshold: 6.1233e-17});
     60                  should(c1.slice(panFrame), 'Mono: Right channel, pan = 1:')
     61                      .beConstantValueOf(1);
     62                })
     63                .then(() => task.done());
     64          });
     65 
     66      audit.define(
     67          {
     68            label: 'test stereo input',
     69            description:
     70                'Test StereoPanner with stereo input has no dezippering'
     71          },
     72          (task, should) => {
     73            let context = new OfflineAudioContext(2, sampleRate, sampleRate);
     74 
     75            // Create stereo source from two constant source nodes.
     76            let s0 = new ConstantSourceNode(context, {offset: 1});
     77            let s1 = new ConstantSourceNode(context, {offset: 2});
     78            let merger = new ChannelMergerNode(context, {numberOfInputs: 2});
     79 
     80            s0.connect(merger, 0, 0);
     81            s1.connect(merger, 0, 1);
     82 
     83            let p = new StereoPannerNode(context, {pan: -1});
     84 
     85            merger.connect(p).connect(context.destination);
     86            s0.start();
     87            s1.start();
     88 
     89            // Frame at which to change pan value.
     90            let panFrame = 256;
     91            context.suspend(panFrame / context.sampleRate)
     92                .then(() => p.pan.value = 1)
     93                .then(() => context.resume());
     94 
     95            context.startRendering()
     96                .then(renderedBuffer => {
     97                  let c0 = renderedBuffer.getChannelData(0);
     98                  let c1 = renderedBuffer.getChannelData(1);
     99 
    100                  // The first part should be full left.
    101                  should(
    102                      c0.slice(0, panFrame), 'Stereo: Left channel, pan = -1: ')
    103                      .beConstantValueOf(3);
    104                  should(
    105                      c1.slice(0, panFrame), 'Stereo: Right channel, pan = -1:')
    106                      .beConstantValueOf(0);
    107 
    108                  // The second part should be full right, but due to roundoff,
    109                  // the left channel won't be exactly zero.  Compare the left
    110                  // channel against zero with a threshold instead.
    111                  let tail = c0.slice(panFrame);
    112                  let zero = new Float32Array(tail.length);
    113 
    114                  should(c0.slice(panFrame), 'Stereo: Left channel, pan = 1: ')
    115                      .beCloseToArray(zero, {absoluteThreshold: 6.1233e-17});
    116                  should(c1.slice(panFrame), 'Stereo: Right channel, pan = 1:')
    117                      .beConstantValueOf(3);
    118                })
    119                .then(() => task.done());
    120          });
    121 
    122      audit.define(
    123          {
    124            label: 'test mono input setValue',
    125            description: 'Test StereoPanner with mono input value setter ' +
    126                'vs setValueAtTime'
    127          },
    128          (task, should) => {
    129            let context = new OfflineAudioContext(4, sampleRate, sampleRate);
    130 
    131            let src = new OscillatorNode(context);
    132 
    133            src.start();
    134            testWithSetValue(context, src, should, {
    135              prefix: 'Mono'
    136            }).then(() => task.done());
    137          });
    138 
    139      audit.define(
    140          {
    141            label: 'test stereo input setValue',
    142            description: 'Test StereoPanner with mono input value setter ' +
    143                ' vs setValueAtTime'
    144          },
    145          (task, should) => {
    146            let context = new OfflineAudioContext(4, sampleRate, sampleRate);
    147 
    148            let src0 = new OscillatorNode(context, {frequency: 800});
    149            let src1 = new OscillatorNode(context, {frequency: 250});
    150            let merger = new ChannelMergerNode(context, {numberOfChannels: 2});
    151 
    152            src0.connect(merger, 0, 0);
    153            src1.connect(merger, 0, 1);
    154 
    155            src0.start();
    156            src1.start();
    157 
    158            testWithSetValue(context, merger, should, {
    159              prefix: 'Stereo'
    160            }).then(() => task.done());
    161          });
    162 
    163      audit.define(
    164          {
    165            label: 'test mono input automation',
    166            description: 'Test StereoPanner with mono input and automation'
    167          },
    168          (task, should) => {
    169            let context = new OfflineAudioContext(4, sampleRate, sampleRate);
    170 
    171            let src0 = new OscillatorNode(context, {frequency: 800});
    172            let src1 = new OscillatorNode(context, {frequency: 250});
    173            let merger = new ChannelMergerNode(context, {numberOfChannels: 2});
    174 
    175            src0.connect(merger, 0, 0);
    176            src1.connect(merger, 0, 1);
    177 
    178            src0.start();
    179            src1.start();
    180 
    181            let mod = new OscillatorNode(context, {frequency: 100});
    182            mod.start();
    183 
    184            testWithSetValue(context, merger, should, {
    185              prefix: 'Modulated Stereo',
    186              modulator: (testNode, refNode) => {
    187                mod.connect(testNode.pan);
    188                mod.connect(refNode.pan);
    189              }
    190            }).then(() => task.done());
    191          });
    192 
    193 
    194      function testWithSetValue(context, src, should, options) {
    195        let merger = new ChannelMergerNode(
    196            context, {numberOfInputs: context.destination.channelCount});
    197        merger.connect(context.destination);
    198 
    199        let pannerRef = new StereoPannerNode(context, {pan: -0.3});
    200        let pannerTest =
    201            new StereoPannerNode(context, {pan: pannerRef.pan.value});
    202 
    203        let refSplitter =
    204            new ChannelSplitterNode(context, {numberOfOutputs: 2});
    205        let testSplitter =
    206            new ChannelSplitterNode(context, {numberOfOutputs: 2});
    207 
    208        pannerRef.connect(refSplitter);
    209        pannerTest.connect(testSplitter);
    210 
    211        testSplitter.connect(merger, 0, 0);
    212        testSplitter.connect(merger, 1, 1);
    213        refSplitter.connect(merger, 0, 2);
    214        refSplitter.connect(merger, 1, 3);
    215 
    216        src.connect(pannerRef);
    217        src.connect(pannerTest);
    218 
    219        let changeTime = 3 * RENDER_QUANTUM_FRAMES / context.sampleRate;
    220        // An arbitrary position, different from the default pan value.
    221        let newPanPosition = .71;
    222 
    223        pannerRef.pan.setValueAtTime(newPanPosition, changeTime);
    224        context.suspend(changeTime)
    225            .then(() => pannerTest.pan.value = newPanPosition)
    226            .then(() => context.resume());
    227 
    228        if (options.modulator) {
    229          options.modulator(pannerTest, pannerRef);
    230        }
    231        return context.startRendering().then(renderedBuffer => {
    232          let actual = new Array(2);
    233          let expected = new Array(2);
    234 
    235          actual[0] = renderedBuffer.getChannelData(0);
    236          actual[1] = renderedBuffer.getChannelData(1);
    237          expected[0] = renderedBuffer.getChannelData(2);
    238          expected[1] = renderedBuffer.getChannelData(3);
    239 
    240          let label = ['Left', 'Right'];
    241 
    242          for (let k = 0; k < 2; ++k) {
    243            let match =
    244                should(
    245                    actual[k],
    246                    options.prefix + ' ' + label[k] + ' .value setter output')
    247                    .beCloseToArray(expected[k], {absoluteThreshold: 1.192094e-7});
    248            should(
    249                match,
    250                options.prefix + ' ' + label[k] +
    251                    ' .value setter output matches setValueAtTime output')
    252                .beTrue();
    253          }
    254 
    255        });
    256      }
    257 
    258      audit.run();
    259    </script>
    260  </body>
    261 </html>