| <!DOCTYPE html> |
| <html> |
| <head> |
| <title> |
| Test Processing Of AudioParams of Disconnected AudioNodes |
| </title> |
| <script src="../../imported/w3c/web-platform-tests/resources/testharness.js"></script> |
| <script src="../../resources/testharnessreport.js"></script> |
| <script src="../resources/audit.js"></script> |
| </head> |
| <body> |
| <script id="layout-test-code"> |
| // Arbitrary sample rate. |
| let sampleRate = 8000; |
| |
| // Arbitrary number of frames for the test, except it must be greater than |
| // |automationEndFrame|. |
| let renderFrames = 1024; |
| |
| // The linear ramp automation ends at this frame. Arbitrary, except it |
| // must be strictly less than the render length. |
| let automationEndFrame = 128; |
| |
| let audit = Audit.createTaskRunner(); |
| |
| // There should be a test for every single node which has an AudioParam. |
| // Source nodes are not included in this because the AudioParams for the |
| // source nodes only process when the node has been started. |
| |
| audit.define('BiquadFilterNode', async (task, should) => { |
| let nodeName = 'BiquadFilterNode' |
| await testParamAutomation(should, { |
| nodeName: nodeName, |
| paramName: 'Q', |
| initialValue: 2, |
| rampFinalValue: 5 |
| }); |
| await testParamAutomation(should, { |
| nodeName: nodeName, |
| paramName: 'detune', |
| initialValue: 1, |
| rampFinalValue: 0.5 |
| }); |
| await testParamAutomation(should, { |
| nodeName: nodeName, |
| paramName: 'frequency', |
| initialValue: 1000, |
| rampFinalValue: 100 |
| }); |
| await testParamAutomation(should, { |
| nodeName: nodeName, |
| paramName: 'gain', |
| initialValue: -3, |
| rampFinalValue: 3 |
| }); |
| task.done(); |
| }); |
| |
| audit.define('DelayNode', (task, should) => { |
| testParamAutomation(should, { |
| nodeName: 'DelayNode', |
| paramName: 'delayTime', |
| initialValue: 0.25, |
| rampFinalValue: 0.5 |
| }).then(() => task.done()); |
| }); |
| |
| audit.define('DynamicsCompressorNode', async (task, should) => { |
| let nodeName = 'DynamicsCompressorNode'; |
| await testParamAutomation(should, { |
| nodeName: nodeName, |
| paramName: 'attack', |
| initialValue: 0.1, |
| rampFinalValue: 0.5 |
| }); |
| await testParamAutomation(should, { |
| nodeName: nodeName, |
| paramName: 'knee', |
| initialValue: 0, |
| rampFinalValue: 25 |
| }); |
| await testParamAutomation(should, { |
| nodeName: nodeName, |
| paramName: 'ratio', |
| initialValue: 1, |
| rampFinalValue: 15 |
| }); |
| await testParamAutomation(should, { |
| nodeName: nodeName, |
| paramName: 'release', |
| initialValue: 0, |
| rampFinalValue: 0.75 |
| }); |
| await testParamAutomation(should, { |
| nodeName: nodeName, |
| paramName: 'threshold', |
| initialValue: -50, |
| rampFinalValue: -10 |
| }); |
| task.done(); |
| }); |
| |
| audit.define('GainNode', (task, should) => { |
| testParamAutomation(should, { |
| nodeName: 'GainNode', |
| paramName: 'gain', |
| initialValue: 1, |
| rampFinalValue: 0.5 |
| }).then(() => task.done()); |
| }); |
| |
| audit.define('PannerNode', async (task, should) => { |
| let nodeName = 'PannerNode'; |
| await testParamAutomation(should, { |
| nodeName: nodeName, |
| paramName: 'positionX', |
| initialValue: 0.1, |
| rampFinalValue: 0.5 |
| }); |
| await testParamAutomation(should, { |
| nodeName: nodeName, |
| paramName: 'positionY', |
| initialValue: 2, |
| rampFinalValue: 30 |
| }); |
| await testParamAutomation(should, { |
| nodeName: nodeName, |
| paramName: 'positionZ', |
| initialValue: 1, |
| rampFinalValue: 15 |
| }); |
| await testParamAutomation(should, { |
| nodeName: nodeName, |
| paramName: 'orientationX', |
| initialValue: 0.1, |
| rampFinalValue: 0.5 |
| }); |
| await testParamAutomation(should, { |
| nodeName: nodeName, |
| paramName: 'orientationY', |
| initialValue: 2, |
| rampFinalValue: 30 |
| }); |
| await testParamAutomation(should, { |
| nodeName: nodeName, |
| paramName: 'orientationZ', |
| initialValue: 1, |
| rampFinalValue: 15 |
| }); |
| task.done(); |
| }); |
| |
| audit.define('StereoPannerNode', (task, should) => { |
| testParamAutomation(should, { |
| nodeName: 'StereoPannerNode', |
| paramName: 'pan', |
| initialValue: 1, |
| rampFinalValue: 0.5 |
| }).then(() => task.done()); |
| }); |
| |
| audit.define('AudioListener', async (task, should) => { |
| await testAudioListener(should, { |
| paramName: 'positionX', |
| initialValue: 1, |
| rampFinalValue: 100 |
| }); |
| await testAudioListener(should, { |
| paramName: 'positionY', |
| initialValue: 1, |
| rampFinalValue: 200 |
| }); |
| await testAudioListener(should, { |
| paramName: 'positionZ', |
| initialValue: 1, |
| rampFinalValue: 300 |
| }); |
| await testAudioListener(should, { |
| paramName: 'forwardX', |
| initialValue: 1, |
| rampFinalValue: -100 |
| }); |
| await testAudioListener(should, { |
| paramName: 'forwardY', |
| initialValue: 1, |
| rampFinalValue: -200 |
| }); |
| await testAudioListener(should, { |
| paramName: 'forwardZ', |
| initialValue: 1, |
| rampFinalValue: -300 |
| }); |
| await testAudioListener(should, { |
| paramName: 'upX', |
| initialValue: 1, |
| rampFinalValue: 99 |
| }); |
| await testAudioListener(should, { |
| paramName: 'upY', |
| initialValue: 1, |
| rampFinalValue: 42 |
| }); |
| await testAudioListener(should, { |
| paramName: 'upZ', |
| initialValue: 1, |
| rampFinalValue: 137 |
| }); |
| task.done(); |
| }); |
| |
| // Run test of automation processing. |options| is a dictionary that |
| // describes the node to test, the AudioParams to be tested and the values |
| // for the AudioParam. The members of the dictionary are: |
| // |
| // nodeName - name of the node (constructor name) |
| // paramName - name of the AudioParam to be tested |
| // initialValue - starting value for linear ramp |
| // rampFinalValue - finale value for linear ramp |
| // |
| // The test is considered to have succeeded if the |.value| of the |
| // AudioParam is the final value. |
| // |
| // A simple graph is created containing the node to be tested, connected |
| // to the destination. A linear ramp automation is scheduled for the |
| // specified AudioParam, starting and ending at the values given. |
| // |
| // Processing is started and after some number of frames, the |.value| of |
| // the AudioParam is obtained and compared against the final value. These |
| // should match exactly. |
| function testParamAutomation(should, options) { |
| let context = new OfflineAudioContext(1, renderFrames, sampleRate); |
| |
| // Create the node to be tested |
| let node = new window[options.nodeName](context); |
| node.connect(context.destination); |
| |
| // A linear ramp starting at frame 0 to frame |automationEndFrame| is |
| // used for the test. This value is fairly arbitrary, but it should be |
| // less than the total render frames. |
| |
| node[options.paramName].setValueAtTime(options.initialValue, 0); |
| node[options.paramName].linearRampToValueAtTime( |
| options.rampFinalValue, automationEndFrame / context.sampleRate); |
| |
| return context.startRendering().then(function(resultBuffer) { |
| // Sanity check: the given ramp final value must not be the default |
| // value, otherwise we can't easily tell if the automation was |
| // actually run. |
| should( |
| options.rampFinalValue, |
| options.nodeName + '.' + options.paramName + ' ramp final value') |
| .notBeEqualTo(node[options.paramName].defaultValue); |
| |
| // The actual AudioParam value should be the rampe final value. |
| should( |
| node[options.paramName].value, |
| options.nodeName + '.' + options.paramName + '.value') |
| .beEqualTo(options.rampFinalValue); |
| }); |
| } |
| |
| function testAudioListener(should, options) { |
| let context = new OfflineAudioContext(1, renderFrames, sampleRate); |
| |
| // Create the node to be tested |
| let node = new PannerNode(context); |
| node.connect(context.destination); |
| |
| // A linear ramp starting at frame 0 to frame |automationEndFrame| is |
| // used for the test. This value is fairly arbitrary, but it should be |
| // less than the total render frames. |
| |
| context.listener[options.paramName].setValueAtTime( |
| options.initialValue, 0); |
| context.listener[options.paramName].linearRampToValueAtTime( |
| options.rampFinalValue, automationEndFrame / context.sampleRate); |
| |
| return context.startRendering().then(function(resultBuffer) { |
| // Sanity check: the given ramp final value must not be the default |
| // value, otherwise we can't easily tell if the automation was |
| // actually run. |
| should( |
| options.rampFinalValue, |
| 'AudioListener.' + options.paramName + ' ramp final value') |
| .notBeEqualTo(context.listener[options.paramName].defaultValue); |
| |
| // The actual AudioParam value should be the rampe final value. |
| should( |
| context.listener[options.paramName].value, |
| 'AudioListener.' + options.paramName + '.value') |
| .beEqualTo(options.rampFinalValue); |
| }); |
| } |
| |
| audit.run(); |
| </script> |
| </body> |
| </html> |