111 lines
3.9 KiB
HTML
111 lines
3.9 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>
|
|
realtimeanalyser-fft-scaling.html
|
|
</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>
|
|
<div id="description"></div>
|
|
<div id="console"></div>
|
|
<script id="layout-test-code">
|
|
let audit = Audit.createTaskRunner();
|
|
|
|
// The number of analysers. We have analysers from size for each of the
|
|
// possible sizes of 2^5 to 2^15 for a total of 11.
|
|
let numberOfAnalysers = 11;
|
|
let sampleRate = 44100;
|
|
let nyquistFrequency = sampleRate / 2;
|
|
|
|
// Frequency of the sine wave test signal. Should be high enough so that
|
|
// we get at least one full cycle for the 32-point FFT. This should also
|
|
// be such that the frequency should be exactly in one of the FFT bins for
|
|
// each of the possible FFT sizes.
|
|
let oscFrequency = nyquistFrequency / 16;
|
|
|
|
// The actual peak values from each analyser. Useful for examining the
|
|
// actual peak values.
|
|
let peakValue = new Array(numberOfAnalysers);
|
|
|
|
// For a 0dBFS sine wave, we would expect the FFT magnitude to be 0dB as
|
|
// well, but the analyzer node applies a Blackman window (to smooth the
|
|
// estimate). This reduces the energy of the signal so the FFT peak is
|
|
// less than 0dB. The threshold value given here was determined
|
|
// experimentally.
|
|
//
|
|
// See https://code.google.com/p/chromium/issues/detail?id=341596.
|
|
let peakThreshold = [
|
|
-14.43, -13.56, -13.56, -13.56, -13.56, -13.56, -13.56, -13.56, -13.56,
|
|
-13.56, -13.56
|
|
];
|
|
|
|
function checkResult(order, analyser, should) {
|
|
return function() {
|
|
let index = order - 5;
|
|
let fftSize = 1 << order;
|
|
let fftData = new Float32Array(fftSize);
|
|
analyser.getFloatFrequencyData(fftData);
|
|
|
|
// Compute the frequency bin that should contain the peak.
|
|
let expectedBin =
|
|
analyser.frequencyBinCount * (oscFrequency / nyquistFrequency);
|
|
|
|
// Find the actual bin by finding the bin containing the peak.
|
|
let actualBin = 0;
|
|
peakValue[index] = -1000;
|
|
for (k = 0; k < analyser.frequencyBinCount; ++k) {
|
|
if (fftData[k] > peakValue[index]) {
|
|
actualBin = k;
|
|
peakValue[index] = fftData[k];
|
|
}
|
|
}
|
|
|
|
should(actualBin, (1 << order) + '-point FFT peak position')
|
|
.beEqualTo(expectedBin);
|
|
|
|
should(
|
|
peakValue[index], (1 << order) + '-point FFT peak value in dBFS')
|
|
.beGreaterThanOrEqualTo(peakThreshold[index]);
|
|
}
|
|
}
|
|
|
|
audit.define(
|
|
{
|
|
label: 'FFT scaling tests',
|
|
description: 'Test Scaling of FFT in AnalyserNode'
|
|
},
|
|
async function(task, should) {
|
|
let tests = [];
|
|
for (let k = 5; k <= 15; ++k)
|
|
await runTest(k, should);
|
|
task.done();
|
|
});
|
|
|
|
function runTest(order, should) {
|
|
let context = new OfflineAudioContext(1, 1 << order, sampleRate);
|
|
// Use a sine wave oscillator as the reference source signal.
|
|
let osc = context.createOscillator();
|
|
osc.type = 'sine';
|
|
osc.frequency.value = oscFrequency;
|
|
osc.connect(context.destination);
|
|
|
|
let analyser = context.createAnalyser();
|
|
// No smoothing to simplify the analysis of the result.
|
|
analyser.smoothingTimeConstant = 0;
|
|
analyser.fftSize = 1 << order;
|
|
osc.connect(analyser);
|
|
|
|
osc.start();
|
|
return context.startRendering().then(() => {
|
|
checkResult(order, analyser, should)();
|
|
});
|
|
}
|
|
|
|
audit.run();
|
|
</script>
|
|
</body>
|
|
</html>
|