blob: 270c5f9d4d8c5f79871b224738e5c3e61df25aee [file] [log] [blame]
<!doctype html>
<html>
<head>
<script src="../resources/js-test.js"></script>
<script src="resources/compatibility.js"></script>
<script src="resources/audio-testing.js"></script>
<title>Test Analyser.getByteTimeDomainData()</title>
</head>
<body>
<script>
description("Test AnalyserNode getByteTimeDomainData");
window.jsTestIsAsync = true;
var sampleRate = 48000;
// The size of the analyser frame. Anything larger than 128 is ok, but should be long enough
// to capture the peaks of the oscillator waveform.
var fftSize = 256;
// Number of frames to render. Should be greater than the fftSize, but is otherwise
// arbitrary.
var renderFrames = 2 * fftSize;
var audit = Audit.createTaskRunner();
// Test that getByteTimeDomainData returns the correct values. This test depends on
// getFloatTimeDomainData returning the correct data (for which there is already a test).
audit.defineTask("byte-data", function (done) {
var context = new OfflineAudioContext(1, renderFrames, sampleRate);
// Create a sawtooth as the signal under test. A sine wave or triangle wave would probably
// also work.
var src = context.createOscillator();
src.type = "sawtooth";
// Choose a frequency high enough that we get at least a full period in one analyser fftSize
// frame. Otherwise, the frequency is arbitrary.
src.frequency.value = 440;
// Gain node to make sure the signal goes somewhat above 1, for testing clipping.
var gain = context.createGain();
gain.gain.value = 1.5;
// The analyser node to test
var analyser = context.createAnalyser();
analyser.fftSize = fftSize;
// Connect the graph.
src.connect(gain);
gain.connect(analyser);
analyser.connect(context.destination);
// Stop rendering after one analyser frame so we can grab the data.
context.suspend(fftSize / sampleRate).then(function () {
var floatData = new Float32Array(fftSize);
var byteData = new Uint8Array(fftSize);
analyser.getFloatTimeDomainData(floatData);
analyser.getByteTimeDomainData(byteData);
// Use the float data to compute the expected value for the byte data.
var expected = new Float32Array(fftSize);
for (var k = 0; k < fftSize; ++k) {
// It's important to do Math.fround to match the single-precision float in the
// implementation!
var value = Math.fround(128 * Math.fround(1 + floatData[k]));
// Clip the result to lie in the range [0, 255].
expected[k] = Math.floor(Math.min(255, Math.max(0, value)));
}
// Find the first index of the first sample that exceeds +1 or -1. The test MUST have at
// least one such value.
var indexMax = floatData.findIndex(function (x) { return x > 1; });
var indexMin = floatData.findIndex(function (x) { return x < -1; });
Should("Index of first sample greater than +1", indexMax).beGreaterThanOrEqualTo(0);
Should("Index of first sample less than -1", indexMin).beGreaterThanOrEqualTo(0);
// Verify explicitly that clipping happened correctly at the above indices.
Should("Clip " + floatData[indexMax].toPrecision(6) + ": byteData[" + indexMax + "]",
byteData[indexMax]).beEqualTo(255);
Should("Clip " + floatData[indexMin].toPrecision(6) + ": byteData[" + indexMin + "]",
byteData[indexMin]).beEqualTo(0);
// Verify that all other samples are computed correctly.
Should("Byte data", byteData, {
verbose: true
}).beEqualToArray(expected);
}).then(context.resume.bind(context))
src.start();
context.startRendering().then(done);
});
audit.defineTask("finish", function (done) {
finishJSTest();
done();
});
audit.runTasks();
</script>
</body>
</html>