tor-browser

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

no-dezippering.html (7401B)


      1 <!DOCTYPE html>
      2 <html>
      3  <head>
      4    <title>
      5      Test DelayNode Has No Dezippering
      6    </title>
      7    <script src="/resources/testharness.js"></script>
      8    <script src="/resources/testharnessreport.js"></script>
      9    <script src="/webaudio/resources/audit-util.js"></script>
     10    <script src="/webaudio/resources/audit.js"></script>
     11  </head>
     12  <body>
     13    <script id="layout-test-code">
     14      // The sample rate must be a power of two to avoid any round-off errors in
     15      // computing when to suspend a context on a rendering quantum boundary.
     16      // Otherwise this is pretty arbitrary.
     17      let sampleRate = 16384;
     18 
     19      let audit = Audit.createTaskRunner();
     20 
     21      audit.define(
     22          {label: 'test0', description: 'Test DelayNode has no dezippering'},
     23          (task, should) => {
     24            let context = new OfflineAudioContext(1, sampleRate, sampleRate);
     25 
     26            // Simple integer ramp for testing delay node
     27            let buffer = new AudioBuffer(
     28                {length: context.length, sampleRate: context.sampleRate});
     29            let rampData = buffer.getChannelData(0);
     30            for (let k = 0; k < rampData.length; ++k) {
     31              rampData[k] = k + 1;
     32            }
     33 
     34            // |delay0Frame| is the initial delay in frames. |delay1Frame| is
     35            // the new delay in frames.  These must be integers.
     36            let delay0Frame = 64;
     37            let delay1Frame = 16;
     38 
     39            let src = new AudioBufferSourceNode(context, {buffer: buffer});
     40            let delay = new DelayNode(
     41                context, {delayTime: delay0Frame / context.sampleRate});
     42 
     43            src.connect(delay).connect(context.destination);
     44 
     45            // After a render quantum, change the delay to |delay1Frame|.
     46            context.suspend(RENDER_QUANTUM_FRAMES / context.sampleRate)
     47                .then(() => {
     48                  delay.delayTime.value = delay1Frame / context.sampleRate;
     49                })
     50                .then(() => context.resume());
     51 
     52            src.start();
     53            context.startRendering()
     54                .then(renderedBuffer => {
     55                  let renderedData = renderedBuffer.getChannelData(0);
     56 
     57                  // The first |delay0Frame| frames should be zero.
     58                  should(
     59                      renderedData.slice(0, delay0Frame),
     60                      'output[0:' + (delay0Frame - 1) + ']')
     61                      .beConstantValueOf(0);
     62 
     63                  // Now we have the ramp should show up from the delay.
     64                  let ramp0 =
     65                      new Float32Array(RENDER_QUANTUM_FRAMES - delay0Frame);
     66                  for (let k = 0; k < ramp0.length; ++k) {
     67                    ramp0[k] = rampData[k];
     68                  }
     69 
     70                  should(
     71                      renderedData.slice(delay0Frame, RENDER_QUANTUM_FRAMES),
     72                      'output[' + delay0Frame + ':' +
     73                          (RENDER_QUANTUM_FRAMES - 1) + ']')
     74                      .beEqualToArray(ramp0);
     75 
     76                  // After one rendering quantum, the delay is changed to
     77                  // |delay1Frame|.
     78                  let ramp1 =
     79                      new Float32Array(context.length - RENDER_QUANTUM_FRAMES);
     80                  for (let k = 0; k < ramp1.length; ++k) {
     81                    // ramp1[k] = 1 + k + RENDER_QUANTUM_FRAMES - delay1Frame;
     82                    ramp1[k] =
     83                        rampData[k + RENDER_QUANTUM_FRAMES - delay1Frame];
     84                  }
     85                  should(
     86                      renderedData.slice(RENDER_QUANTUM_FRAMES),
     87                      'output[' + RENDER_QUANTUM_FRAMES + ':]')
     88                      .beEqualToArray(ramp1);
     89                })
     90                .then(() => task.done());
     91          });
     92 
     93      audit.define(
     94          {label: 'test1', description: 'Test value setter and setValueAtTime'},
     95          (task, should) => {
     96            testWithAutomation(should, {prefix: '', threshold: 6.5819e-5})
     97                .then(() => task.done());
     98          });
     99 
    100      audit.define(
    101          {label: 'test2', description: 'Test value setter and modulation'},
    102          (task, should) => {
    103            testWithAutomation(should, {
    104              prefix: 'With modulation: ',
    105              modulator: true
    106            }).then(() => task.done());
    107          });
    108 
    109      // Compare .value setter with setValueAtTime, Optionally allow modulation
    110      // of |delayTime|.
    111      function testWithAutomation(should, options) {
    112        let prefix = options.prefix;
    113        // Channel 0 is the output of delay node using the setter and channel 1
    114        // is the output using setValueAtTime.
    115        let context = new OfflineAudioContext(2, sampleRate, sampleRate);
    116 
    117        let merger = new ChannelMergerNode(
    118            context, {numberOfInputs: context.destination.channelCount});
    119        merger.connect(context.destination);
    120 
    121        let src = new OscillatorNode(context);
    122 
    123        // |delay0Frame| is the initial delay value in frames. |delay1Frame| is
    124        // the new delay in frames. The values here are constrained only by the
    125        // constraints for a DelayNode.  These are pretty arbitrary except we
    126        // wanted them to be fractional so as not be on a frame boundary to
    127        // test interpolation compared with |setValueAtTime()|..
    128        let delay0Frame = 3.1;
    129        let delay1Frame = 47.2;
    130 
    131        let delayTest = new DelayNode(
    132            context, {delayTime: delay0Frame / context.sampleRate});
    133        let delayRef = new DelayNode(
    134            context, {delayTime: delay0Frame / context.sampleRate});
    135 
    136        src.connect(delayTest).connect(merger, 0, 0);
    137        src.connect(delayRef).connect(merger, 0, 1);
    138 
    139        if (options.modulator) {
    140          // Fairly arbitrary modulation of the delay time, with a peak
    141          // variation of 10 ms.
    142          let mod = new OscillatorNode(context, {frequency: 1000});
    143          let modGain = new GainNode(context, {gain: .01});
    144          mod.connect(modGain);
    145          modGain.connect(delayTest.delayTime);
    146          modGain.connect(delayRef.delayTime);
    147          mod.start();
    148        }
    149 
    150        // The time at which the delay time of |delayTest| node will be
    151        // changed.  This MUST be on a render quantum boundary, but is
    152        // otherwise arbitrary.
    153        let changeTime = 3 * RENDER_QUANTUM_FRAMES / context.sampleRate;
    154 
    155        // Schedule the delay change on |delayRef| and also apply the value
    156        // setter for |delayTest| at |changeTime|.
    157        delayRef.delayTime.setValueAtTime(
    158            delay1Frame / context.sampleRate, changeTime);
    159        context.suspend(changeTime)
    160            .then(() => {
    161              delayTest.delayTime.value = delay1Frame / context.sampleRate;
    162            })
    163            .then(() => context.resume());
    164 
    165        src.start();
    166 
    167        return context.startRendering().then(renderedBuffer => {
    168          let actual = renderedBuffer.getChannelData(0);
    169          let expected = renderedBuffer.getChannelData(1);
    170 
    171          let match = should(actual, prefix + '.value setter output')
    172                          .beCloseToArray(
    173                              expected, {absoluteThreshold: options.threshold});
    174          should(
    175              match,
    176              prefix + '.value setter output matches setValueAtTime output')
    177              .beTrue();
    178        });
    179      }
    180 
    181      audit.run();
    182    </script>
    183  </body>
    184 </html>