| <!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> |