tor-browser

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

gain.html (5030B)


      1 <!DOCTYPE html>
      2 <html>
      3  <head>
      4    <title>
      5      Basic GainNode Functionality
      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  </head>
     11  <body>
     12    <script id="layout-test-code">
     13      // Tests that GainNode is properly scaling the gain.  We'll render 11
     14      // notes, starting at a gain of 1.0, decreasing in gain by 0.1.  The 11th
     15      // note will be of gain 0.0, so it should be silent (at the end in the
     16      // rendered output).
     17      // Use a power of two to eliminate any round-off when converting frame to
     18      // time.
     19      const sampleRate = 32768;
     20      // Make sure the buffer duration and spacing are all exact frame lengths
     21      // so that the note spacing is also on frame boundaries to eliminate
     22      // sub-sample accurate start of a ABSN.
     23      const bufferDurationSeconds = Math.floor(0.125 * sampleRate) / sampleRate;
     24      const numberOfNotes = 11;
     25      // Leave about 20ms of silence, being sure this is an exact frame
     26      // duration.
     27      const noteSilence = Math.floor(0.020 * sampleRate) / sampleRate;
     28      const noteSpacing = bufferDurationSeconds + noteSilence;
     29      const lengthInSeconds = numberOfNotes * noteSpacing;
     30 
     31      // Create a stereo AudioBuffer of duration |lengthInSeconds| consisting of
     32      // a pure sine wave with the given |frequency|.  Both channels contain the
     33      // same data.
     34      function createSinWaveBuffer(context, lengthInSeconds, frequency) {
     35        let audioBuffer =
     36            context.createBuffer(2, lengthInSeconds * sampleRate, sampleRate);
     37 
     38        let n = audioBuffer.length;
     39        let channelL = audioBuffer.getChannelData(0);
     40        let channelR = audioBuffer.getChannelData(1);
     41 
     42        for (let i = 0; i < n; ++i) {
     43          channelL[i] = Math.sin(frequency * 2.0 * Math.PI * i / sampleRate);
     44          channelR[i] = channelL[i];
     45        }
     46 
     47        return audioBuffer;
     48      }
     49 
     50      function playNote(context, time, gain, buffer, merger) {
     51        let source = context.createBufferSource();
     52        source.buffer = buffer;
     53 
     54        let gainNode = context.createGain();
     55        gainNode.gain.value = gain;
     56 
     57        let sourceSplitter = context.createChannelSplitter(2);
     58        let gainSplitter = context.createChannelSplitter(2);
     59 
     60        // Split the stereo channels from the source output and the gain output
     61        // and merge them into the desired channels of the merger.
     62        source.connect(gainNode).connect(gainSplitter);
     63        source.connect(sourceSplitter);
     64 
     65        gainSplitter.connect(merger, 0, 0);
     66        gainSplitter.connect(merger, 1, 1);
     67        sourceSplitter.connect(merger, 0, 2);
     68        sourceSplitter.connect(merger, 1, 3);
     69 
     70        source.start(time);
     71      }
     72 
     73      promise_test(async t => {
     74        let context = new OfflineAudioContext(
     75            4, sampleRate * lengthInSeconds, sampleRate);
     76 
     77        let merger = new ChannelMergerNode(
     78            context, {numberOfInputs: context.destination.channelCount});
     79        merger.connect(context.destination);
     80 
     81        let sinWaveBuffer = createSinWaveBuffer(
     82            context, bufferDurationSeconds, 880.0);
     83 
     84        let startTimes = [];
     85        let gainValues = [];
     86 
     87        for (let i = 0; i < numberOfNotes; ++i) {
     88          let time = i * noteSpacing;
     89          let gain = 1.0 - i / (numberOfNotes - 1);
     90          startTimes.push(time);
     91          gainValues.push(gain);
     92          playNote(context, time, gain, sinWaveBuffer, merger);
     93        }
     94 
     95        let buffer = await context.startRendering();
     96 
     97        let actual0 = buffer.getChannelData(0);
     98        let actual1 = buffer.getChannelData(1);
     99        let reference0 = buffer.getChannelData(2);
    100        let reference1 = buffer.getChannelData(3);
    101 
    102        let bufferDurationFrames =
    103            Math.ceil(bufferDurationSeconds * context.sampleRate);
    104 
    105        for (let k = 0; k < startTimes.length; ++k) {
    106          let startFrame = Math.floor(startTimes[k] * context.sampleRate);
    107          let gain = gainValues[k];
    108          for (let n = 0; n < bufferDurationFrames; ++n) {
    109            reference0[startFrame + n] *= gain;
    110            reference1[startFrame + n] *= gain;
    111          }
    112        }
    113 
    114        const tolerance = 1.1877e-7;
    115        assert_array_approx_equals(actual0, reference0, tolerance,
    116            'Left output from gain node should match scaled reference');
    117        assert_array_approx_equals(actual1, reference1, tolerance,
    118            'Right output from gain node should match scaled reference');
    119 
    120        let snr0 = 10 * Math.log10(computeSNR(actual0, reference0));
    121        let snr1 = 10 * Math.log10(computeSNR(actual1, reference1));
    122 
    123        assert_greater_than_equal(
    124            snr0, 148.71, 'Left SNR (in dB) must be ≥ 148.71');
    125        assert_greater_than_equal(
    126            snr1, 148.71, 'Right SNR (in dB) must be ≥ 148.71');
    127      }, 'GainNode should scale gains properly across notes');
    128    </script>
    129  </body>
    130 </html>