<!DOCTYPE html>
<html>
  <head>
    <title>
      Test Custom 440 Hz Oscillator
    </title>
    <script src="../../imported/w3c/web-platform-tests/resources/testharness.js"></script>
    <script src="../../resources/testharnessreport.js"></script>
    <script src="../resources/audit-util.js"></script>
    <script src="../resources/audit.js"></script>
  </head>
  <body>
      <script id = 'layout-test-code'>let sampleRate = 48000;

      // Minimum allowed SNR between the actual oscillator and the expected
      // result.  Experimentally determined.
      let snrThreshold = 59.280;
      // Max absolute difference between actual and expected oscillator
      // outputs.  Experimentally determined.
      let maxDiffThreshold = 1.5640e-3;

      let audit = Audit.createTaskRunner();

      // Test that two ways of creating a 440-Hz sine wave produce the same
      // results, within some tolerance.

      audit.define('440 Hz Osc', (task, should) => {
        // 3-channel context: channel 0 = actual output; channel 1 = expected
        // output, channel 2 = difference between channels 0 and 1.
        let context = new OfflineAudioContext(3, sampleRate, sampleRate);
        let merger = new ChannelMergerNode(
            context, {numberOfInputs: context.destination.channelCount});
        merger.connect(context.destination);

        // Create a 440 Hz oscillator in following way.  Use a PeriodicWave with
        // a single harmonic value of 440 and use that in an oscillator with
        // fundamental frequeqncy of 1 Hz.  This should produce a 440 Hz sine
        // wave.  This is the test signal.
        let imag = new Float32Array(512);
        imag[440] = 1;
        let wave440 =
            new PeriodicWave(context, {imag: imag, disableNormaliztion: true});

        let oscTest =
            new OscillatorNode(context, {frequency: 1, periodicWave: wave440});

        // Create a 440 Hz oscillator by specifying a frequency of 440 Hz.  We
        // use a periodicWave for this so we can disable normalization.
        let oscRef = new OscillatorNode(context, {
          frequency: 440,
          periodocWave: new PeriodicWave(
              context, {imag: [0, 1], disableNormaliztion: true})
        });

        oscTest.connect(merger, 0, 0);
        oscRef.connect(merger, 0, 1);

        // Compute the difference of the two signals
        let neg = new GainNode(context, {gain: -1});
        neg.connect(merger, 0, 2);

        oscTest.connect(merger, 0, 2);
        oscRef.connect(neg);

        oscTest.start();
        oscRef.start();

        context.startRendering()
            .then(result => {
              // Extract the actual output, the reference output and the
              // difference signal from the rendered data.
              actual = result.getChannelData(0);
              ref = result.getChannelData(1);
              diff = result.getChannelData(2);

              // The actual and reference signals should be close, and the SNR
              // should be high.
              should(actual, 'Test oscillator output').beCloseToArray(
                  ref, {absoluteThreshold: maxDiffThreshold});

              let snr = 10 * Math.log10(computeSNR(actual, ref));
              should(snr, 'SNR').beGreaterThanOrEqualTo(snrThreshold);

            })
            .then(() => task.done());
      });

      audit.run();
    </script>
  </body>
</html>
