<!DOCTYPE html>
<html>
<head>
<title>
Test Multiple Calls to getFloatFrequencyData
</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>
</head>
<body>
<script id="layout-test-code">
let sampleRate = 48000;
// Render enough data to run the test.
let renderFrames = 2 * 1024;
let renderDuration = renderFrames / sampleRate;
let audit = Audit.createTaskRunner();
audit.define('test', (task, should) => {
let context = new OfflineAudioContext(1, renderFrames, sampleRate);
// Use sawtooth oscillator as the source because it has quite a bit of
// harmonic content. Otherwise, the type doesn't really matter.
let osc = context.createOscillator();
osc.type = 'sawtooth';
// Create an analyser with 256-point FFT. The FFT size doesn't really
// matter much.
let analyser = context.createAnalyser();
analyser.fftSize = 256;
osc.connect(analyser);
analyser.connect(context.destination);
let success = true;
// Suspend after getting a full analyser frame. (Not really necessary,
// but it's nice that the frame doesn't include any initial zeroes.
let suspendFrame = analyser.fftSize;
context.suspend(suspendFrame / sampleRate)
.then(function() {
// Test successive calls to getFloatFrequencyData in the same
// rendering quantum.
let f1 = new Float32Array(analyser.frequencyBinCount);
let f2 = new Float32Array(analyser.frequencyBinCount);
analyser.getFloatFrequencyData(f1);
analyser.getFloatFrequencyData(f2);
should(f2, 'Second call to getFloatFrequencyData')
.beEqualToArray(f1);
})
.then(context.resume.bind(context));
suspendFrame += 128;
context.suspend(suspendFrame / sampleRate)
.then(function() {
// Test successive calls to getByteFrequencyData in the same
// rendering quantum.
let f1 = new Uint8Array(analyser.frequencyBinCount);
let f2 = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(f1);
analyser.getByteFrequencyData(f2);
should(f2, 'Second call to getByteFrequencyData')
.beEqualToArray(f1);
})
.then(context.resume.bind(context));
suspendFrame += 128;
context.suspend(suspendFrame / sampleRate)
.then(function() {
// Test calls to getFloatFrequencyData followed by
// getByteFrequencyData. The float data, when converted to byte
// values should be identical to the result from
// getByteFrequencyData.
let f1 = new Float32Array(analyser.frequencyBinCount);
let f2 = new Uint8Array(analyser.frequencyBinCount);
analyser.getFloatFrequencyData(f1);
analyser.getByteFrequencyData(f2);
let byteValuesFromFloat = convertFloatToByte(
f1, analyser.minDecibels, analyser.maxDecibels);
should(
byteValuesFromFloat,
'Output of getByteFrequencyData after getFloatFrequencyData')
.beEqualToArray(f2);
})
.then(context.resume.bind(context));
suspendFrame += 128;
context.suspend(suspendFrame / sampleRate)
.then(function() {
// Test calls to getByteFrequencyData followed by
// getFloatFrequencyData. The float data, when converted to byte
// values should be identical to the result from
// getByteFrequencyData.
let f1 = new Uint8Array(analyser.frequencyBinCount);
let f2 = new Float32Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(f1);
analyser.getFloatFrequencyData(f2);
let byteValuesFromFloat = convertFloatToByte(
f2, analyser.minDecibels, analyser.maxDecibels);
should(
f1,
'Output of getFloatFrequenycData (converted to byte) after getByteFrequencyData')
.beEqualToArray(byteValuesFromFloat);
})
.then(context.resume.bind(context));
osc.start();
context.startRendering().then(() => task.done());
});
audit.run();
// Convert the float frequency data (in dB), |floatFreqData|, to byte
// values using the dB limits |minDecibels| and |maxDecibels|. The new
// byte array is returned.
function convertFloatToByte(floatFreqData, minDecibels, maxDecibels) {
let scale = 255 / (maxDecibels - minDecibels);
return floatFreqData.map(function(x) {
let value = Math.floor(scale * (x - minDecibels));
return Math.min(255, Math.max(0, value));
});
}
</script>
</body>
</html>