<!DOCTYPE html>
<html>
  <head>
    <title>
      Gain Dezippering Test: Dezippering Removed
    </title>
    <script src="/resources/testharness.js"></script>
    <script src="/resources/testharnessreport.js"></script>
    <script src="/webaudio/resources/audit-util.js"></script>
    <script src="/webaudio/resources/audit.js"></script>
  </head>
  <body>
    <script id="layout-test-code">
      let audit = Audit.createTaskRunner();

      audit.define(
          {label: 'test0', description: 'Dezippering of GainNode removed'},
          (task, should) => {
            // Only need a few frames to verify that dezippering has been
            // removed from the GainNode.  Sample rate is pretty arbitrary.
            let context = new OfflineAudioContext(1, 1024, 16000);

            // Send a unit source to the gain node so we can measure the effect
            // of the gain node.
            let src = new ConstantSourceNode(context, {offset: 1});
            let g = new GainNode(context, {gain: 1});
            src.connect(g).connect(context.destination);

            context.suspend(RENDER_QUANTUM_FRAMES / context.sampleRate)
                .then(() => {
                  g.gain.value = .5;
                })
                .then(() => context.resume());

            src.start();

            context.startRendering()
                .then(audio => {
                  let c = audio.getChannelData(0);

                  // If dezippering has been removed, the gain output should
                  // instantly jump at frame 128 to 0.5.
                  should(c.slice(0, 128), 'output[0:127]').beConstantValueOf(1);
                  should(c.slice(128), 'output[128:]').beConstantValueOf(0.5);
                })
                .then(() => task.done());
          });

      audit.define(
          {
            label: 'test2',
            description: 'Compare value setter and setValueAtTime'
          },
          (task, should) => {
            testWithAutomation(should, {prefix: ''}).then(() => task.done());
          });

      audit.define(
          {label: 'test3', description: 'Automation effects'},
          (task, should) => {
            testWithAutomation(should, {
              prefix: 'With modulation: ',
              modulator: true
            }).then(() => task.done());
          });

      audit.run();

      function testWithAutomation(should, options) {
        // Sample rate must be a power of two to eliminate round-off in
        // computing the time at render quantum boundaries.
        let context = new OfflineAudioContext(2, 1024, 16384);
        let merger = new ChannelMergerNode(context, {numberOfChannels: 2});
        merger.connect(context.destination);

        let src = new OscillatorNode(context);
        let gainTest = new GainNode(context);
        let gainRef = new GainNode(context);

        src.connect(gainTest).connect(merger, 0, 0);
        src.connect(gainRef).connect(merger, 0, 1);

        if (options.modulator) {
          let mod = new OscillatorNode(context, {frequency: 1000});
          let modGain = new GainNode(context);
          mod.connect(modGain);
          modGain.connect(gainTest.gain);
          modGain.connect(gainRef.gain);
          mod.start();
        }

        // Change the gains. Must do the change on a render boundary!
        let changeTime = 3 * RENDER_QUANTUM_FRAMES / context.sampleRate;
        let newGain = .3;

        gainRef.gain.setValueAtTime(newGain, changeTime);
        context.suspend(changeTime)
            .then(() => gainTest.gain.value = newGain)
            .then(() => context.resume());

        src.start();

        return context.startRendering().then(audio => {
          let actual = audio.getChannelData(0);
          let expected = audio.getChannelData(1);

          // The values using the .value setter must be identical to the
          // values using setValueAtTime.
          let match = should(actual, options.prefix + '.value setter output')
                          .beEqualToArray(expected);

          should(
              match,
              options.prefix +
                  '.value setter output matches setValueAtTime output')
              .beTrue();
        });
      }
    </script>
  </body>
</html>
