| <!DOCTYPE html> |
| <html> |
| <head> |
| <title> |
| Test Exceptions from setValueCurveAtTime |
| </title> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="/webaudio/resources/audit-util.js"></script> |
| <script src="/webaudio/resources/audit.js"></script> |
| </head> |
| <body> |
| <script id="layout-test-code"> |
| let sampleRate = 48000; |
| // Some short duration because we don't need to run the test for very |
| // long. |
| let testDurationSec = 0.125; |
| let testDurationFrames = testDurationSec * sampleRate; |
| |
| let audit = Audit.createTaskRunner(); |
| |
| audit.define('setValueCurve', (task, should) => { |
| let success = true; |
| let context = |
| new OfflineAudioContext(1, testDurationFrames, sampleRate); |
| let g = context.createGain(); |
| let curve = new Float32Array(2); |
| |
| // Start time and duration for setValueCurveAtTime |
| let curveStartTime = 0.1 * testDurationSec; |
| let duration = 0.1 * testDurationSec; |
| |
| // Some time that is known to during the setValueCurveTime interval. |
| let automationTime = curveStartTime + duration / 2; |
| |
| should( |
| () => { |
| g.gain.setValueCurveAtTime(curve, curveStartTime, duration); |
| }, |
| 'setValueCurveAtTime(curve, ' + curveStartTime + ', ' + duration + |
| ')') |
| .notThrow(); |
| |
| should( |
| function() { |
| g.gain.setValueAtTime(1, automationTime); |
| }, |
| 'setValueAtTime(1, ' + automationTime + ')') |
| .throw('NotSupportedError'); |
| |
| should( |
| function() { |
| g.gain.linearRampToValueAtTime(1, automationTime); |
| }, |
| 'linearRampToValueAtTime(1, ' + automationTime + ')') |
| .throw('NotSupportedError'); |
| |
| should( |
| function() { |
| g.gain.exponentialRampToValueAtTime(1, automationTime); |
| }, |
| 'exponentialRampToValueAtTime(1, ' + automationTime + ')') |
| .throw('NotSupportedError'); |
| |
| should( |
| function() { |
| g.gain.setTargetAtTime(1, automationTime, 1); |
| }, |
| 'setTargetAtTime(1, ' + automationTime + ', 1)') |
| .throw('NotSupportedError'); |
| |
| should( |
| function() { |
| g.gain.setValueAtTime(1, curveStartTime + 1.1 * duration); |
| }, |
| 'setValueAtTime(1, ' + (curveStartTime + 1.1 * duration) + ')') |
| .notThrow(); |
| |
| task.done(); |
| }); |
| |
| audit.define('automations', (task, should) => { |
| let context = |
| new OfflineAudioContext(1, testDurationFrames, sampleRate); |
| let g = context.createGain(); |
| |
| let curve = new Float32Array(2); |
| // Start time and duration for setValueCurveAtTime |
| let startTime = 0; |
| let timeInterval = testDurationSec / 10; |
| let time; |
| |
| startTime += timeInterval; |
| should(() => { |
| g.gain.linearRampToValueAtTime(1, startTime); |
| }, 'linearRampToValueAtTime(1, ' + startTime + ')').notThrow(); |
| |
| startTime += timeInterval; |
| should(() => { |
| g.gain.exponentialRampToValueAtTime(1, startTime); |
| }, 'exponentialRampToValueAtTime(1, ' + startTime + ')').notThrow(); |
| |
| startTime += timeInterval; |
| should(() => { |
| g.gain.setTargetAtTime(1, startTime, 0.1); |
| }, 'setTargetAtTime(1, ' + startTime + ', 0.1)').notThrow(); |
| |
| startTime += timeInterval; |
| should(() => { |
| g.gain.setValueCurveAtTime(curve, startTime, 0.1); |
| }, 'setValueCurveAtTime(curve, ' + startTime + ', 0.1)').notThrow(); |
| |
| // Now try to setValueCurve that overlaps each of the above automations |
| startTime = timeInterval / 2; |
| |
| for (let k = 0; k < 4; ++k) { |
| time = startTime + timeInterval * k; |
| should( |
| () => { |
| g.gain.setValueCurveAtTime(curve, time, 0.01); |
| }, |
| 'setValueCurveAtTime(curve, ' + time + ', 0.01)') |
| .throw('NotSupportedError'); |
| } |
| |
| // Elements of setValueCurve should be finite. |
| should( |
| () => { |
| g.gain.setValueCurveAtTime( |
| Float32Array.from([NaN, NaN]), time, 0.01); |
| }, |
| 'setValueCurveAtTime([NaN, NaN], ' + time + ', 0.01)') |
| .throw('TypeError'); |
| |
| should( |
| () => { |
| g.gain.setValueCurveAtTime( |
| Float32Array.from([1, Infinity]), time, 0.01); |
| }, |
| 'setValueCurveAtTime([1, Infinity], ' + time + ', 0.01)') |
| .throw('TypeError'); |
| |
| let d = context.createDelay(); |
| // Check that we get warnings for out-of-range values and also throw for |
| // non-finite values. |
| should( |
| () => { |
| d.delayTime.setValueCurveAtTime( |
| Float32Array.from([1, 5]), time, 0.01); |
| }, |
| 'delayTime.setValueCurveAtTime([1, 5], ' + time + ', 0.01)') |
| .notThrow(); |
| |
| should( |
| () => { |
| d.delayTime.setValueCurveAtTime( |
| Float32Array.from([1, 5, Infinity]), time, 0.01); |
| }, |
| 'delayTime.setValueCurveAtTime([1, 5, Infinity], ' + time + |
| ', 0.01)') |
| .throw('TypeError'); |
| |
| // One last test that prints out lots of digits for the time. |
| time = Math.PI / 100; |
| should( |
| () => { |
| g.gain.setValueCurveAtTime(curve, time, 0.01); |
| }, |
| 'setValueCurveAtTime(curve, ' + time + ', 0.01)') |
| .throw('NotSupportedError'); |
| |
| task.done(); |
| }); |
| |
| audit.define('catch-exception', (task, should) => { |
| // Verify that the curve isn't inserted into the time line even if we |
| // catch the exception. |
| let success = true; |
| let context = |
| new OfflineAudioContext(1, testDurationFrames, sampleRate); |
| let gain = context.createGain(); |
| let source = context.createBufferSource(); |
| let buffer = context.createBuffer(1, 1, context.sampleRate); |
| buffer.getChannelData(0)[0] = 1; |
| source.buffer = buffer; |
| source.loop = true; |
| |
| source.connect(gain); |
| gain.connect(context.destination); |
| |
| gain.gain.setValueAtTime(1, 0); |
| try { |
| // The value curve has an invalid element. This automation shouldn't |
| // be inserted into the timeline at all. |
| gain.gain.setValueCurveAtTime( |
| Float32Array.from([0, NaN]), 128 / context.sampleRate, .5); |
| } catch (e) { |
| }; |
| source.start(); |
| |
| context.startRendering() |
| .then(function(resultBuffer) { |
| // Since the setValueCurve wasn't inserted, the output should be |
| // exactly 1 for the entire duration. |
| should( |
| resultBuffer.getChannelData(0), |
| 'Handled setValueCurve exception so output') |
| .beConstantValueOf(1); |
| |
| }) |
| .then(() => task.done()); |
| }); |
| |
| audit.define('start-end', (task, should) => { |
| let context = |
| new OfflineAudioContext(1, testDurationFrames, sampleRate); |
| let g = context.createGain(); |
| let curve = new Float32Array(2); |
| |
| // Verify that a setValueCurve can start at the end of an automation. |
| let time = 0; |
| let timeInterval = testDurationSec / 50; |
| should(() => { |
| g.gain.setValueAtTime(1, time); |
| }, 'setValueAtTime(1, ' + time + ')').notThrow(); |
| |
| time += timeInterval; |
| should(() => { |
| g.gain.linearRampToValueAtTime(0, time); |
| }, 'linearRampToValueAtTime(0, ' + time + ')').notThrow(); |
| |
| // setValueCurve starts at the end of the linear ramp. This should be |
| // fine. |
| should( |
| () => { |
| g.gain.setValueCurveAtTime(curve, time, timeInterval); |
| }, |
| 'setValueCurveAtTime(..., ' + time + ', ' + timeInterval + ')') |
| .notThrow(); |
| |
| // exponentialRamp ending one interval past the setValueCurve should be |
| // fine. |
| time += 2 * timeInterval; |
| should(() => { |
| g.gain.exponentialRampToValueAtTime(1, time); |
| }, 'exponentialRampToValueAtTime(1, ' + time + ')').notThrow(); |
| |
| // setValueCurve starts at the end of the exponential ramp. This should |
| // be fine. |
| should( |
| () => { |
| g.gain.setValueCurveAtTime(curve, time, timeInterval); |
| }, |
| 'setValueCurveAtTime(..., ' + time + ', ' + timeInterval + ')') |
| .notThrow(); |
| |
| // setValueCurve at the end of the setValueCurve should be fine. |
| time += timeInterval; |
| should( |
| () => { |
| g.gain.setValueCurveAtTime(curve, time, timeInterval); |
| }, |
| 'setValueCurveAtTime(..., ' + time + ', ' + timeInterval + ')') |
| .notThrow(); |
| |
| // setValueAtTime at the end of setValueCurve should be fine. |
| time += timeInterval; |
| should(() => { |
| g.gain.setValueAtTime(0, time); |
| }, 'setValueAtTime(0, ' + time + ')').notThrow(); |
| |
| // setValueCurve at the end of setValueAtTime should be fine. |
| should( |
| () => { |
| g.gain.setValueCurveAtTime(curve, time, timeInterval); |
| }, |
| 'setValueCurveAtTime(..., ' + time + ', ' + timeInterval + ')') |
| .notThrow(); |
| |
| // setTarget starting at the end of setValueCurve should be fine. |
| time += timeInterval; |
| should(() => { |
| g.gain.setTargetAtTime(1, time, 1); |
| }, 'setTargetAtTime(1, ' + time + ', 1)').notThrow(); |
| |
| task.done(); |
| }); |
| |
| audit.define('curve lengths', (task, should) => { |
| let context = |
| new OfflineAudioContext(1, testDurationFrames, sampleRate); |
| let g = context.createGain(); |
| let time = 0; |
| |
| // Check for invalid curve lengths |
| should( |
| () => { |
| g.gain.setValueCurveAtTime(Float32Array.from([]), time, 0.01); |
| }, |
| 'setValueCurveAtTime([], ' + time + ', 0.01)') |
| .throw('InvalidStateError'); |
| |
| should( |
| () => { |
| g.gain.setValueCurveAtTime(Float32Array.from([1]), time, 0.01); |
| }, |
| 'setValueCurveAtTime([1], ' + time + ', 0.01)') |
| .throw('InvalidStateError'); |
| |
| should(() => { |
| g.gain.setValueCurveAtTime(Float32Array.from([1, 2]), time, 0.01); |
| }, 'setValueCurveAtTime([1,2], ' + time + ', 0.01)').notThrow(); |
| |
| task.done(); |
| }); |
| |
| audit.run(); |
| </script> |
| </body> |
| </html> |