| <!doctype html> |
| <html> |
| |
| <head> |
| <script src="../resources/js-test.js"></script> |
| <script src="resources/compatibility.js"></script> |
| <script src="resources/audio-testing.js"></script> |
| <script src="resources/audioparam-testing.js"></script> |
| <title>AudioParam Initial Events </title> |
| </head> |
| |
| <body> |
| <script> |
| description("Test Automation Ramps without Initial Event"); |
| window.jsTestIsAsync = true; |
| |
| var sampleRate = 48000; |
| // Number of frames in a rendering quantum. |
| var quantumFrames = 128; |
| // Test doesn't need to run for very long. |
| var renderDuration = 0.2; |
| var renderFrames = renderDuration * sampleRate; |
| var automationEndTime = 0.1; |
| |
| var audit = Audit.createTaskRunner(); |
| |
| // The following tests start a ramp automation without an initial event. This should cause an |
| // initial event to be added implicitly to give a starting point. |
| audit.defineTask("linear-ramp", function (done) { |
| runTest("Linear ramp", { |
| automationFunction: function (node, value, time) { |
| node.gain.linearRampToValueAtTime(value, time); |
| }, |
| referenceFunction: linearRamp, |
| // Experimentally determined threshold |
| threshold: 6.0003e-8, |
| // The starting value of the gain node |
| v0: 0.5, |
| // The target value of the automation |
| v1: 0, |
| }) |
| .then(done); |
| }); |
| |
| audit.defineTask("exponential-ramp", function (done) { |
| runTest("Exponential ramp", { |
| automationFunction: function (node, value, time) { |
| node.gain.exponentialRampToValueAtTime(value, time); |
| }, |
| referenceFunction: exponentialRamp, |
| threshold: 2.3842e-6, |
| v0: 0.5, |
| v1: 2, |
| }) |
| .then(done); |
| }); |
| |
| // Same tests as above, but we delay the call to the automation function. This is to verify that |
| // the we still do the right thing after the context has started. |
| audit.defineTask("delayed-linear-ramp", function (done) { |
| runTest("Delayed linear ramp", { |
| automationFunction: function (node, value, time) { |
| node.gain.linearRampToValueAtTime(value, time); |
| }, |
| referenceFunction: linearRamp, |
| // Experimentally determined threshold |
| threshold: 9.87968e-8, |
| // The starting value of the gain node |
| v0: 0.5, |
| // The target value of the automation |
| v1: 0, |
| delay: quantumFrames / sampleRate |
| }) |
| .then(done); |
| }); |
| |
| audit.defineTask("delayed-exponential-ramp", function (done) { |
| runTest("Delayed exponential ramp", { |
| automationFunction: function (node, value, time) { |
| node.gain.exponentialRampToValueAtTime(value, time); |
| }, |
| referenceFunction: exponentialRamp, |
| // Experimentally determined threshold |
| threshold: 1.3948e-5, |
| // The starting value of the gain node |
| v0: 0.5, |
| // The target value of the automation |
| v1: 2, |
| delay: quantumFrames / sampleRate |
| }) |
| .then(done); |
| }); |
| |
| audit.defineTask("finish", function (done) { |
| finishJSTest(); |
| done(); |
| }); |
| |
| audit.runTasks(); |
| |
| // Generate the expected waveform for a linear ramp starting from the value |v0|, ramping to |
| // |v1| at time |endTime|. The time of |v0| is assumed to be 0. |nFrames| is how many frames |
| // to generate. |
| function linearRamp(v0, v1, startTime, endTime, nFrames) { |
| var expected = createLinearRampArray(startTime, endTime, v0, v1, sampleRate); |
| var preFiller = new Array(Math.floor(startTime * sampleRate)); |
| var postFiller = new Array(nFrames - Math.ceil(endTime * sampleRate)); |
| preFiller.fill(v0); |
| return preFiller.concat(expected.concat(postFiller.fill(v1))); |
| } |
| |
| // Generate the expected waveform for an exponential ramp starting from the value |v0|, |
| // ramping to |v1| at time |endTime|. The time of |v0| is assumed to be 0. |nFrames| is how |
| // many frames to generate. |
| function exponentialRamp(v0, v1, startTime, endTime, nFrames) { |
| var expected = createExponentialRampArray(startTime, endTime, v0, v1, sampleRate); |
| var preFiller = new Array(Math.floor(startTime * sampleRate)); |
| preFiller.fill(v0); |
| var postFiller = new Array(nFrames - Math.ceil(endTime * sampleRate)); |
| return preFiller.concat(expected.concat(postFiller.fill(v1))); |
| } |
| |
| // Run an automation test. |message| is the message to use for printing the results. |options| |
| // is a property bag containing the configuration of the test including the following: |
| // |
| // automationFunction - automation function to use, |
| // referenceFunction - function generating the expected result |
| // threshold - comparison threshold |
| // v0 - starting value |
| // v1 - end value for automation |
| function runTest(message, options) { |
| var automationFunction = options.automationFunction; |
| var referenceFunction = options.referenceFunction; |
| var threshold = options.threshold; |
| var v0 = options.v0; |
| var v1 = options.v1; |
| var delay = options.delay; |
| |
| var context = new OfflineAudioContext(1, renderFrames, sampleRate); |
| |
| // A constant source of amplitude 1. |
| var source = context.createBufferSource(); |
| source.buffer = createConstantBuffer(context, 1, 1); |
| source.loop = true; |
| |
| // Automation is applied to a gain node |
| var gain = context.createGain(); |
| gain.gain.value = v0; |
| |
| // Delay start of automation, if requested |
| if (delay) { |
| context.suspend(options.delay).then(function () { |
| automationFunction(gain, v1, automationEndTime); |
| context.resume(); |
| }); |
| } else { |
| automationFunction(gain, v1, automationEndTime); |
| } |
| |
| source.connect(gain); |
| gain.connect(context.destination); |
| |
| source.start(); |
| |
| return context.startRendering() |
| .then(function (resultBuffer) { |
| var result = resultBuffer.getChannelData(0); |
| var expected = referenceFunction(v0, v1, delay ? delay : 0, automationEndTime, renderFrames); |
| Should(message, result).beCloseToArray(expected, threshold); |
| }); |
| } |
| </script> |
| </body> |
| |
| </html> |