tor-browser

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

realtimeanalyser-fft-scaling.html (3637B)


      1 <!DOCTYPE html>
      2 <html>
      3  <head>
      4    <title>
      5      realtimeanalyser-fft-scaling.html
      6    </title>
      7    <script src="/resources/testharness.js"></script>
      8    <script src="/resources/testharnessreport.js"></script>
      9  </head>
     10  <body>
     11    <div id="description"></div>
     12    <div id="console"></div>
     13    <script>
     14      // The number of analysers. We have analysers from size for each of the
     15      // possible sizes of 2^5 to 2^15 for a total of 11.
     16      const numberOfAnalysers = 11;
     17      const sampleRate = 44100;
     18      const nyquistFrequency = sampleRate / 2;
     19 
     20      // Frequency of the sine wave test signal.  Should be high enough so that
     21      // we get at least one full cycle for the 32-point FFT.  This should also
     22      // be such that the frequency should be exactly in one of the FFT bins for
     23      // each of the possible FFT sizes.
     24      const oscFrequency = nyquistFrequency / 16;
     25 
     26      // The actual peak values from each analyser.  Useful for examining the
     27      // actual peak values.
     28      const peakValue = new Array(numberOfAnalysers);
     29 
     30      // For a 0dBFS sine wave, we would expect the FFT magnitude to be 0dB as
     31      // well, but the analyzer node applies a Blackman window (to smooth the
     32      // estimate).  This reduces the energy of the signal so the FFT peak is
     33      // less than 0dB.  The threshold value given here was determined
     34      // experimentally.
     35      //
     36      // See https://code.google.com/p/chromium/issues/detail?id=341596.
     37      const peakThreshold = [
     38        -14.43, -13.56, -13.56, -13.56, -13.56, -13.56, -13.56, -13.56, -13.56,
     39        -13.56, -13.56,
     40      ];
     41 
     42      function checkResult(order, analyser) {
     43        const index = order - 5;
     44        const fftSize = 1 << order;
     45 
     46        // We only need frequencyBinCount bins.
     47        const fftData = new Float32Array(fftSize);
     48        analyser.getFloatFrequencyData(fftData);
     49 
     50        // Compute the frequency bin that should contain the peak.
     51        const expectedBin =
     52            analyser.frequencyBinCount * (oscFrequency / nyquistFrequency);
     53 
     54        // Find the actual bin by finding the bin containing the peak.
     55        let actualBin = 0;
     56        peakValue[index] = -1000;
     57        for (let k = 0; k < analyser.frequencyBinCount; ++k) {
     58          if (fftData[k] > peakValue[index]) {
     59            actualBin = k;
     60            peakValue[index] = fftData[k];
     61          }
     62        }
     63 
     64        assert_equals(
     65            actualBin, expectedBin,
     66            `${(fftSize)}-point FFT peak position`);
     67        assert_greater_than_equal(
     68            peakValue[index], peakThreshold[index],
     69            `${fftSize}-point FFT peak value in dBFS`);
     70      }
     71 
     72      // Run the tests for FFT sizes 2^5 through 2^15.
     73      function runTest(order) {
     74        const context = new OfflineAudioContext(1, 1 << order, sampleRate);
     75        const fftSize = 1 << order;
     76 
     77        // Use a sine wave oscillator as the reference source signal.
     78        const osc = new OscillatorNode(
     79            context, {type: 'sine', frequency: oscFrequency});
     80 
     81        // No smoothing to simplify the analysis of the result.
     82        const analyser = new AnalyserNode(context, {
     83          fftSize: fftSize,
     84          smoothingTimeConstant: 0,
     85        });
     86 
     87        osc.connect(context.destination);
     88 
     89        osc.connect(analyser);
     90 
     91        osc.start();
     92 
     93        return context.startRendering().then(() => {
     94          checkResult(order, analyser);
     95        });
     96      }
     97 
     98      promise_test(async t => {
     99        for (let k = 5; k <= 15; ++k) {
    100          await runTest(k);
    101        }
    102      }, 'FFT scaling tests — Test Scaling of FFT in AnalyserNode');
    103    </script>
    104  </body>
    105 </html>