blob: 7ed2702a0079d85117663cf24592af7e8d850f37 [file] [log] [blame]
<!doctype html>
<html>
<head>
<title>Test PeriodicWave Normalization</title>
<script src="../resources/js-test.js"></script>
<script src="resources/compatibility.js"></script>
<script src="resources/audio-testing.js"></script>
</head>
<body>
<script>
description("Test PeriodicWave Normalization");
window.jsTestIsAsync = true;
var sampleRate = 48000;
var renderFrames = sampleRate;
var context;
var audit = Audit.createTaskRunner();
var testSet = [
// Test the default case where the two-arg createPeriodicWave is called. The waveform
// should be normalized.
{
name: "option-default/normalized",
// This option is treated specially; it means that the two-arg function is called.
option: "NONE",
// Somewhat arbitrary except that resulting waveform should have amplitude greater than
// 1. And we don't want a simple sine wave because that always has max amplitude of 1.
realCoef: [0, -1, 1],
threshold: 1e-5,
expectedMax: 1
},
{
name: "option-null/normalized",
option: null,
// Somewhat arbitrary except that resulting waveform should have amplitude greater than
// 1. And we don't want a simple sine wave because that always has max amplitude of 1.
realCoef: [0, -1, 1],
threshold: 1e-5,
expectedMax: 1
},
// Explicitly set to false. Waveform should be normalized.
{
name: "false/normalized",
option: {
disableNormalization: false
},
realCoef: [0, -1, 1],
threshold: 1e-5,
expectedMax: 1
},
// Explicitly disable normalization. Waveform is not normalized.
{
name: "true/unnormalized",
option: {
disableNormalization: true
},
// Somewhat arbitrary except that resulting waveform should have amplitude very clearly
// greater than 1.
realCoef: [0, 10],
threshold: 1e-5,
expectedMax: 10
},
// Explicitly set to some value that is not false. Waveform should NOT be normalized.
{
name: "foo/unnormalized",
option: {
disableNormalization: "foo"
},
realCoef: [0, 10],
threshold: 1e-5,
expectedMax: 10
},
// Explicitly set to null, which is the same as false. Waveform is normalized.
{
name: "null/unnormalized",
option: {
disableNormalization: null
},
realCoef: [0, 1, -1],
threshold: 1e-5,
expectedMax: 1
},
// Pass in a random dictionary not using our key. Waveform should be normalized.
{
name: "random-key-value/normalized",
option: {
randomKey: true
},
realCoef: [0, -1, 1],
threshold: 1e-5,
expectedMax: 1
},
// Set options to several random keys. Waveform must be normalized.
{
name: "more-random-keys/normalized",
option: {
key1: "value1",
key2: 42
},
realCoef: [0, 1, -1],
threshold: 1e-5,
expectedMax: 1
},
// Set option to include our key (set to true) amongst a bunch of others. Waveform is NOT normalized.
{
name: "true-with-random-keys/unnormalized",
option: {
key1: "value1",
disableNormalization: true
},
realCoef: [0, 10],
threshold: 1e-5,
expectedMax: 10
},
// Set option to include our key (set to false) amongst a bunch of others. Waveform is normalized.
{
name: "false-with-random-keys/normalized",
option: {
key1: "value1",
disableNormalization: false
},
realCoef: [0, 10],
threshold: 1e-5,
expectedMax: 1
},
// Set option to a non-dictionary. Waveform is normalized.
{
name: "non-dict/normalized",
option : [1, 2, 3],
realCoef: [0, 1, -1],
threshold: 1e-5,
expectedMax: 1
},
];
function arrayMax(array) {
return array.reduce(function (reducedValue, currentValue) {
return Math.max(reducedValue, Math.abs(currentValue));
}, -1);
}
function createAndRunAudioGraph(options, realCoef, imagCoef, verify) {
context = new OfflineAudioContext(1, renderFrames, sampleRate);
var osc = context.createOscillator();
var r = new Float32Array(realCoef);
var i = new Float32Array(imagCoef);
var wave;
// If options is "NONE", we want to be sure to call the two-arg createPeriodicWave to make
// sure the default method works as expected.
if (options === "NONE") {
//console.log("2-arg: " + options);
wave = context.createPeriodicWave(r, i);
} else {
//console.log("3-arg: " + options);
wave = context.createPeriodicWave(r, i, options);
}
osc.setPeriodicWave(wave);
osc.connect(context.destination);
osc.start();
return context.startRendering().then(verify);
}
// Define a test function from the given test parameter. This is used as the Audit.defineTask
// task function.
function defineTest(test) {
return function (done) {
var imagCoef = new Float32Array(test.realCoef.length);
createAndRunAudioGraph(test.option, test.realCoef, imagCoef, function (result) {
var prefix;
// Try to print out the test.option in a reasonably nice but explicit way.
if (test.option === "NONE") {
prefix = "";
} else if (Array.isArray(test.option)) {
prefix = "[" + test.option + "]: ";
} else {
prefix = JSON.stringify(test.option) + ": ";
}
Should(prefix + "amplitude", arrayMax(result.getChannelData(0)))
.beCloseTo(test.expectedMax, test.threshold);
}).then(done);
};
}
// Ensure the actual Audit test name is unique by prepending an index to the provided test
// name.
function actualTestName(name, index) {
return index + ":" + name;
}
function defineTasks() {
for (var k = 0; k < testSet.length; ++k) {
var test = testSet[k];
audit.defineTask(actualTestName(test.name, k), defineTest(test));
}
// Explicitly define the last test to finish up everything.
audit.defineTask(actualTestName("finish-tests", testSet.length), function (done) {
finishJSTest();
done();
});
}
// Run all of the tests defined in testSet.
function runAuditTests() {
var tests = testSet.map(function (value, index) {
return actualTestName(value.name, index);
}).concat(actualTestName("finish-tests", testSet.length));
audit.runTasks.apply(audit, tests);
};
defineTasks();
runAuditTests();
successfullyParsed = true;
</script>
</body>
</html>