tor-browser

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

osc-basic-waveform.html (7415B)


      1 <!doctype html>
      2 <html>
      3  <head>
      4    <title>
      5      Test Basic Oscillator Sine Wave Test
      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 
     13  <body>
     14    <script>
     15      // Don't change the sample rate.  The tests below depend on this sample
     16      // rate to cover all the cases in Chrome's implementation.  But the tests
     17      // are general and apply to any browser.
     18      const sampleRate = 44100;
     19 
     20      // Only need a few samples for testing, so just use two renders.
     21      const durationFrames = 2 * RENDER_QUANTUM_FRAMES;
     22 
     23      let audit = Audit.createTaskRunner();
     24 
     25      // The following tests verify that the oscillator produces the same
     26      // results as the mathematical oscillators.  We choose sine wave and a
     27      // custom wave because we know they're bandlimited and won't change with
     28      // the frequency.
     29      //
     30      // The tests for 1 and 2 Hz are intended to test Chrome's interpolation
     31      // algorithm, but are still generally applicable to any browser.
     32 
     33      audit.define(
     34          {label: 'Test 0', description: 'Sine wave: 100 Hz'},
     35          async (task, should) => {
     36            let context = new OfflineAudioContext(
     37                {length: durationFrames, sampleRate: sampleRate});
     38 
     39            const freqHz = 100;
     40 
     41            let src =
     42                new OscillatorNode(context, {type: 'sine', frequency: freqHz});
     43            src.connect(context.destination);
     44 
     45            src.start();
     46 
     47            let renderedBuffer = await context.startRendering();
     48            checkResult(should, renderedBuffer, context, {
     49              freqHz: freqHz,
     50              a1: 0,
     51              b1: 1,
     52              prefix: 'Sine',
     53              threshold: 1.8045e-5,
     54              snrThreshold: 112.5
     55            });
     56            task.done();
     57          });
     58 
     59      audit.define(
     60          {label: 'Test 1', description: 'Sine wave: -100 Hz'},
     61          async (task, should) => {
     62            let context = new OfflineAudioContext(
     63                {length: durationFrames, sampleRate: sampleRate});
     64 
     65            const freqHz = -100;
     66 
     67            let src =
     68                new OscillatorNode(context, {type: 'sine', frequency: freqHz});
     69            src.connect(context.destination);
     70 
     71            src.start();
     72 
     73            let renderedBuffer = await context.startRendering();
     74            checkResult(should, renderedBuffer, context, {
     75              freqHz: freqHz,
     76              a1: 0,
     77              b1: 1,
     78              prefix: 'Sine',
     79              threshold: 1.8045e-5,
     80              snrThreshold: 112.67
     81            });
     82            task.done();
     83          });
     84 
     85      audit.define(
     86          {label: 'Test 2', description: 'Sine wave: 2 Hz'},
     87          async (task, should) => {
     88            let context = new OfflineAudioContext(
     89                {length: durationFrames, sampleRate: sampleRate});
     90 
     91            const freqHz = 2;
     92 
     93            let src =
     94                new OscillatorNode(context, {type: 'sine', frequency: freqHz});
     95            src.connect(context.destination);
     96 
     97            src.start();
     98 
     99            let renderedBuffer = await context.startRendering();
    100            checkResult(should, renderedBuffer, context, {
    101              freqHz: freqHz,
    102              a1: 0,
    103              b1: 1,
    104              prefix: 'Sine',
    105              threshold: 1.4516e-7,
    106              snrThreshold: 119.93
    107            });
    108            task.done();
    109          });
    110 
    111      audit.define(
    112          {label: 'Test 3', description: 'Sine wave: 1 Hz'},
    113          async (task, should) => {
    114            let context = new OfflineAudioContext(
    115                {length: durationFrames, sampleRate: sampleRate});
    116 
    117            const freqHz = 1;
    118 
    119            let src =
    120                new OscillatorNode(context, {type: 'sine', frequency: freqHz});
    121            src.connect(context.destination);
    122 
    123            src.start();
    124 
    125            let renderedBuffer = await context.startRendering();
    126            checkResult(should, renderedBuffer, context, {
    127              freqHz: freqHz,
    128              a1: 0,
    129              b1: 1,
    130              prefix: 'Sine',
    131              threshold: 1.4157e-7,
    132              snrThreshold: 112.22
    133            });
    134            task.done();
    135          });
    136 
    137      audit.define(
    138          {label: 'Test 4', description: 'Custom wave: 100 Hz'},
    139          async (task, should) => {
    140            let context = new OfflineAudioContext(
    141                {length: durationFrames, sampleRate: sampleRate});
    142 
    143            const freqHz = 100;
    144 
    145            let wave = new PeriodicWave(
    146                context,
    147                {real: [0, 1], imag: [0, 1], disableNormalization: true});
    148            let src = new OscillatorNode(
    149                context,
    150                {type: 'custom', frequency: freqHz, periodicWave: wave});
    151            src.connect(context.destination);
    152 
    153            src.start();
    154 
    155            let renderedBuffer = await context.startRendering();
    156            checkResult(should, renderedBuffer, context, {
    157              freqHz: freqHz,
    158              a1: 1,
    159              b1: 1,
    160              prefix: 'Custom',
    161              threshold: 5.1e-5,
    162              snrThreshold: 112.6
    163            });
    164            task.done();
    165          });
    166 
    167      audit.define(
    168          {label: 'Test 5', description: 'Custom wave: 1 Hz'},
    169          async (task, should) => {
    170            let context = new OfflineAudioContext(
    171                {length: durationFrames, sampleRate: sampleRate});
    172 
    173            const freqHz = 1;
    174 
    175            let wave = new PeriodicWave(
    176                context,
    177                {real: [0, 1], imag: [0, 1], disableNormalization: true});
    178            let src = new OscillatorNode(
    179                context,
    180                {type: 'custom', frequency: freqHz, periodicWave: wave});
    181            src.connect(context.destination);
    182 
    183            src.start();
    184 
    185            let renderedBuffer = await context.startRendering();
    186            checkResult(should, renderedBuffer, context, {
    187              freqHz: freqHz,
    188              a1: 1,
    189              b1: 1,
    190              prefix: 'Custom',
    191              threshold: 4.7684e-7,
    192              snrThreshold: 133.0
    193            });
    194            task.done();
    195          });
    196 
    197      audit.run();
    198 
    199      function waveForm(context, freqHz, a1, b1, nsamples) {
    200        let buffer =
    201            new AudioBuffer({length: nsamples, sampleRate: context.sampleRate});
    202        let signal = buffer.getChannelData(0);
    203        const omega = 2 * Math.PI * freqHz / context.sampleRate;
    204        for (let k = 0; k < nsamples; ++k) {
    205          signal[k] = a1 * Math.cos(omega * k) + b1 * Math.sin(omega * k);
    206        }
    207 
    208        return buffer;
    209      }
    210 
    211      function checkResult(should, renderedBuffer, context, options) {
    212        let {freqHz, a1, b1, prefix, threshold, snrThreshold} = options;
    213 
    214        let actual = renderedBuffer.getChannelData(0);
    215 
    216        let expected =
    217            waveForm(context, freqHz, a1, b1, actual.length).getChannelData(0);
    218 
    219        should(actual, `${prefix}: ${freqHz} Hz`).beCloseToArray(expected, {
    220          absoluteThreshold: threshold
    221        });
    222 
    223        let snr = 10 * Math.log10(computeSNR(actual, expected));
    224 
    225        should(snr, `${prefix}: SNR (db)`).beGreaterThanOrEqualTo(snrThreshold);
    226      }
    227    </script>
    228  </body>
    229 </html>