<!DOCTYPE html>
<!--
Tests that AudioBufferSourceNode supports loop-points with .loopStart and .loopEnd.
-->
<html>
  <head>
    <title>
      audiobuffersource-loop-points.html
    </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>
    <script src="../resources/audio-file-utils.js"></script>
  </head>
  <body>
    <script id="layout-test-code">
      let audit = Audit.createTaskRunner();

      // Use power of two to eliminate round-off in computing frames from time
      // and vice versa. 
      let sampleRate = 32768;
      let numberOfNotes = 60;  // play over a 5 octave range
      // Make sure noteDuration, noteSilence, and noteSpacing are exactly whole
      // frames.
      let noteDuration = Math.floor(0.025 * sampleRate) / sampleRate;
      // Leave about 5ms of silence between each "note"
      let noteSilence = Math.floor(0.005 * sampleRate) / sampleRate;
      let noteSpacing = noteDuration + noteSilence;
      let lengthInSeconds = numberOfNotes * noteSpacing;

      let context = 0;
      let expectedAudio;

      function createTestBuffer(frequency, sampleRate) {
        // Create a buffer containing two periods at this frequency.
        // The 1st half is a pure sine wave period scaled by a linear ramp from
        // 0 -> 1. The 2nd half of the buffer corresponds exactly to one pure
        // sine wave period.
        let onePeriodDuration = 1 / frequency;
        let sampleFrameLength = 2 * onePeriodDuration * sampleRate;

        let audioBuffer =
            context.createBuffer(1, sampleFrameLength, sampleRate);

        let n = audioBuffer.length;
        let channelData = audioBuffer.getChannelData(0);

        for (let i = 0; i < n; ++i) {
          let sample = Math.sin(frequency * 2.0 * Math.PI * i / sampleRate);

          // Linear ramp from 0 -> 1 for the first period.
          // Stay at 1 for the 2nd period.
          let scale = i < n / 2 ? i / (n / 2) : 1;
          sample *= scale;

          channelData[i] = sample;
        }

        return audioBuffer;
      }

      function playNote(buffer, time, duration, playbackRate) {
        let source = context.createBufferSource();
        source.buffer = buffer;
        source.playbackRate.value = playbackRate;

        let gainNode = context.createGain();
        source.connect(gainNode);
        gainNode.connect(context.destination);

        // Loop the 2nd half of the buffer.
        // We should be able to hear any problems as glitches if the looping
        // incorrectly indexes to anywhere outside of the desired loop-points,
        // since only the 2nd half is a perfect sine-wave cycle, while the 1st
        // half of the buffer contains a linear ramp of a sine-wave cycle.
        source.loop = true;
        source.loopStart = 0.5 * buffer.duration;
        source.loopEnd = buffer.duration;

        // Play for the given duration.
        source.start(time);
        source.stop(time + duration);

        // Apply a quick linear fade-out to avoid a click at the end of the
        // note.
        gainNode.gain.value = 1;
        gainNode.gain.setValueAtTime(1, time + duration - 0.005);
        gainNode.gain.linearRampToValueAtTime(0, time + duration);
      }

      audit.define(
          {
            label: 'initialize',
            description: 'Set up context and expected results'
          },
          async (task, should) => {
            // Create offline audio context.
            should(
                () => {context = new OfflineAudioContext(
                           2, sampleRate * lengthInSeconds, sampleRate)},
                'Creating context for testing')
                .notThrow();

            const arrayBuffer = await Audit.loadFileFromUrl(
              'resources/audiobuffersource-loop-points-expected.wav');
            expectedAudio = await context.decodeAudioData(arrayBuffer);
            task.done();
         });

      audit.define(
          {
            label: 'test',
            description: 'Test loop points and compare with expected results'
          },
          (task, should) => {
            // Create the test buffer.
            // We'll loop this with the loop-points set for the 2nd half of this
            // buffer.
            let buffer = createTestBuffer(440.0, sampleRate);

            // Play all the notes as a chromatic scale.
            for (let i = 0; i < numberOfNotes; ++i) {
              let time = i * noteSpacing;
              // start three octaves down
              let semitone = i - numberOfNotes / 2;

              // Convert from semitone to rate.
              let playbackRate = Math.pow(2, semitone / 12);

              playNote(buffer, time, noteDuration, playbackRate);
            }

            context.startRendering()
                .then(renderedAudio => {
                  // Compute a threshold based on the maximum error, |maxUlp|,
                  // in ULP. This is experimentally determined. Assuming that
                  // the reference file is a 16-bit wav file, the max values in
                  // the wave file are +/- 32768.
                  let maxUlp = 1.9532e-3;
                  let threshold = maxUlp / 32768;

                  for (let k = 0; k < renderedAudio.numberOfChannels; ++k) {
                    should(
                        renderedAudio.getChannelData(k),
                        'Rendered audio for channel ' + k)
                        .beCloseToArray(
                            expectedAudio.getChannelData(k),
                            {absoluteThreshold: threshold});
                  }

                  const filename = 'audiobuffersource-loop-points-actual.wav';
                  if (downloadAudioBuffer(renderedAudio, filename, true)) {
                    should(true, 'Saved reference file').message(filename, '');
                  }
                })
                .then(() => task.done());
          });

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