chromium/third_party/blink/web_tests/webaudio/Analyser/realtimeanalyser-freq-data-smoothing.html

<!DOCTYPE html>
<html>
  <head>
    <title>
      Test Analyser getFloatFrequencyData and getByteFrequencyData, Smoothing
    </title>
    <script src="../../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/realtimeanalyser-testing.js"></script>
    <script src="../resources/fft.js"></script>
  </head>
  <body>
    <script id="layout-test-code">
      // Use a power of two to eliminate any round-off in the computation of the
      // times for context.suspend().
      let sampleRate = 32768;

      // The largest FFT size for the analyser node is 32768.  We want to render
      // longer than this so that we have at least one complete buffer of data
      // of 32768 samples.
      let renderFrames = 2 * 32768;
      let renderDuration = renderFrames / sampleRate;

      let audit = Audit.createTaskRunner();

      // Do one basic test of smoothing of the FFT data.
      audit.define('smoothing test', (task, should) => {
        // Test only 512-point FFT.  The size isn't too important as long as
        // it's greater than 128 (a rendering quantum).
        let options = {order: 9, smoothing: 0.5, floatRelError: 5.9207e-6};

        let success = true;

        let graph = createGraph(options);

        context = graph.context;
        analyser = graph.analyser;

        let smoothedFloatResult = new Float32Array(analyser.frequencyBinCount);
        smoothedFloatResult.fill(0);

        // Stop after one analyser frame to get the initial FFT
        let suspendFrame = analyser.fftSize;
        context.suspend(suspendFrame / sampleRate)
            .then(function() {
              let timeData = new Float32Array(analyser.fftSize);
              let freqData = new Float32Array(analyser.frequencyBinCount);
              analyser.getFloatTimeDomainData(timeData);
              analyser.getFloatFrequencyData(freqData);

              let expectedFreq = computeFFTMagnitude(timeData, options.order);
              smoothFFT(smoothedFloatResult, expectedFreq, options.smoothing);

              let message = 'First ' + analyser.fftSize +
                  '-point FFT at frame ' + (context.currentTime * sampleRate);
              let comparison = compareFloatFreq(
                  message, freqData, smoothedFloatResult.map(linearToDb),
                  should, options);
              success = success && comparison.success;

              // Test the byte frequency data.
              let byteFreqData = new Uint8Array(analyser.frequencyBinCount);
              analyser.getByteFrequencyData(byteFreqData);

              // Convert the expected float frequency data to byte data.
              let expectedByteData = convertFloatToByte(
                  smoothedFloatResult.map(linearToDb), analyser.minDecibels,
                  analyser.maxDecibels);

              should(byteFreqData, analyser.fftSize + '-point byte FFT')
                  .beCloseToArray(expectedByteData, 0);

            })
            .then(context.resume.bind(context));

        // Skip an analyser frame and grab another to verify that the smoothing
        // is done correctly.
        suspendFrame += 2 * analyser.fftSize;
        context.suspend(suspendFrame / sampleRate)
            .then(function() {
              let timeData = new Float32Array(analyser.fftSize);
              let freqDataInDb = new Float32Array(analyser.frequencyBinCount);

              // Grab the time domain and frequency domain data
              analyser.getFloatTimeDomainData(timeData);
              analyser.getFloatFrequencyData(freqDataInDb);

              let newFreqData = computeFFTMagnitude(timeData, options.order);
              // Smooth the data together

              smoothFFT(smoothedFloatResult, newFreqData, options.smoothing);
              let message = 'Smoothed ' + analyser.fftSize +
                  '-point FFT at frame ' + (context.currentTime * sampleRate);
              let comparison = compareFloatFreq(
                  message, freqDataInDb, smoothedFloatResult.map(linearToDb),
                  should, {
                    order: options.order,
                    smoothing: options.smoothing,
                    floatRelError: 2.5332e-5
                  });
              success = success && comparison.success;

              // Test the byte frequency data.
              let byteFreqData = new Uint8Array(analyser.frequencyBinCount);
              analyser.getByteFrequencyData(byteFreqData);

              // Convert the expected float frequency data to byte data.
              let expectedByteData = convertFloatToByte(
                  smoothedFloatResult.map(linearToDb), analyser.minDecibels,
                  analyser.maxDecibels);

              should(byteFreqData, analyser.fftSize + '-point byte FFT')
                  .beCloseToArray(expectedByteData, 0);

            })
            .then(context.resume.bind(context));

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

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