| <!DOCTYPE html> |
| <html> |
| <head> |
| <title> |
| AudioParam Initial Events |
| </title> |
| <script src="../../imported/w3c/web-platform-tests/resources/testharness.js"></script> |
| <script src="../../resources/testharnessreport.js"></script> |
| <script src="../resources/audit-util.js"></script> |
| <script src="../resources/audit.js"></script> |
| <script src="../resources/audioparam-testing.js"></script> |
| </head> |
| <body> |
| <script id="layout-test-code"> |
| let sampleRate = 48000; |
| // Number of frames in a rendering quantum. |
| let quantumFrames = 128; |
| // Test doesn't need to run for very long. |
| let renderDuration = 0.2; |
| let renderFrames = renderDuration * sampleRate; |
| let automationEndTime = 0.1; |
| |
| let 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.define('linear-ramp', (task, should) => { |
| runTest('Linear ramp', should, { |
| automationFunction: function(node, value, time) { |
| node.gain.linearRampToValueAtTime(value, time); |
| }, |
| referenceFunction: linearRamp, |
| // Experimentally determined threshold |
| threshold: {absoluteThreshold: 6.0003e-8}, |
| // The starting value of the gain node |
| v0: 0.5, |
| // The target value of the automation |
| v1: 0, |
| }).then(() => task.done()); |
| }); |
| |
| audit.define('exponential-ramp', (task, should) => { |
| runTest('Exponential ramp', should, { |
| automationFunction: function(node, value, time) { |
| node.gain.exponentialRampToValueAtTime(value, time); |
| }, |
| referenceFunction: exponentialRamp, |
| threshold: {absoluteThreshold: 2.3842e-6}, |
| v0: 0.5, |
| v1: 2, |
| }).then(() => task.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.define('delayed-linear-ramp', (task, should) => { |
| runTest('Delayed linear ramp', should, { |
| automationFunction: function(node, value, time) { |
| node.gain.linearRampToValueAtTime(value, time); |
| }, |
| referenceFunction: linearRamp, |
| // Experimentally determined threshold |
| threshold: {absoluteThreshold: 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(() => task.done()); |
| }); |
| |
| audit.define('delayed-exponential-ramp', (task, should) => { |
| runTest('Delayed exponential ramp', should, { |
| automationFunction: function(node, value, time) { |
| node.gain.exponentialRampToValueAtTime(value, time); |
| }, |
| referenceFunction: exponentialRamp, |
| // Experimentally determined threshold |
| threshold: {absoluteThreshold: 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(() => task.done()); |
| }); |
| |
| audit.run(); |
| |
| // 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) { |
| let expected = |
| createLinearRampArray(startTime, endTime, v0, v1, sampleRate); |
| let preFiller = new Array(Math.floor(startTime * sampleRate)); |
| let 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) { |
| let expected = |
| createExponentialRampArray(startTime, endTime, v0, v1, sampleRate); |
| let preFiller = new Array(Math.floor(startTime * sampleRate)); |
| preFiller.fill(v0); |
| let 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, should, options) { |
| let automationFunction = options.automationFunction; |
| let referenceFunction = options.referenceFunction; |
| let threshold = options.threshold; |
| let v0 = options.v0; |
| let v1 = options.v1; |
| let delay = options.delay; |
| |
| let context = new OfflineAudioContext(1, renderFrames, sampleRate); |
| |
| // A constant source of amplitude 1. |
| let source = context.createBufferSource(); |
| source.buffer = createConstantBuffer(context, 1, 1); |
| source.loop = true; |
| |
| // Automation is applied to a gain node. Set the initial value of the |
| // gain in the constructor; using the value setter does an implicit |
| // setValueAtTime which sets an initial event. This defeats the purpose |
| // of the test. |
| let gain = new GainNode(context, {gain: 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) { |
| let result = resultBuffer.getChannelData(0); |
| let expected = referenceFunction( |
| v0, v1, delay ? delay : 0, automationEndTime, renderFrames); |
| should(result, message).beCloseToArray(expected, threshold); |
| }); |
| } |
| </script> |
| </body> |
| </html> |