diff options
Diffstat (limited to 'testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html')
-rw-r--r-- | testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html new file mode 100644 index 0000000000..ed0c15fb9b --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html @@ -0,0 +1,426 @@ +<!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 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 be 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(DOMException, 'NotSupportedError'); + + should( + function() { + g.gain.linearRampToValueAtTime(1, automationTime); + }, + 'linearRampToValueAtTime(1, ' + automationTime + ')') + .throw(DOMException, 'NotSupportedError'); + + should( + function() { + g.gain.exponentialRampToValueAtTime(1, automationTime); + }, + 'exponentialRampToValueAtTime(1, ' + automationTime + ')') + .throw(DOMException, 'NotSupportedError'); + + should( + function() { + g.gain.setTargetAtTime(1, automationTime, 1); + }, + 'setTargetAtTime(1, ' + automationTime + ', 1)') + .throw(DOMException, 'NotSupportedError'); + + should( + function() { + g.gain.setValueAtTime(1, curveStartTime + 1.1 * duration); + }, + 'setValueAtTime(1, ' + (curveStartTime + 1.1 * duration) + ')') + .notThrow(); + + task.done(); + }); + + audit.define('value setter', (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 curveStartTime = 0.; + let duration = 0.2 * testDurationSec; + + // Some time that is known to be during the setValueCurveTime interval. + let automationTime = 0.; + + should( + () => { + g.gain.setValueCurveAtTime(curve, curveStartTime, duration); + }, + 'setValueCurveAtTime(curve, ' + curveStartTime + ', ' + duration + + ')') + .notThrow(); + + should( + function() { + g.gain.value = 0.; + }, + 'value setter') + .throw(DOMException, 'NotSupportedError'); + + 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(DOMException, '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(DOMException, '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 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 overlap', (task, should) => { + let context = + new OfflineAudioContext(1, testDurationFrames, sampleRate); + let g = context.createGain(); + let startTime = 5; + let startTimeLater = 10; + let startTimeEarlier = 2.5; + let curveDuration = 10; + let curveDurationShorter = 5; + let curve = [1, 2, 3]; + + // An initial curve event + should( + () => { + g.gain.setValueCurveAtTime(curve, startTime, curveDuration); + }, + `g.gain.setValueCurveAtTime([${curve}], ${startTime}, ${curveDuration})`) + .notThrow(); + + // Check that an exception is thrown when trying to overlap two curves, + // in various ways + + // Same start time and end time (curve exactly overlapping) + should( + () => { + g.gain.setValueCurveAtTime(curve, startTime, curveDuration); + }, + `second g.gain.setValueCurveAtTime([${curve}], ${startTime}, ${curveDuration})`) + .throw(DOMException, 'NotSupportedError'); + // Same start time, shorter end time + should( + () => { + g.gain.setValueCurveAtTime(curve, startTime, curveDurationShorter); + }, + `g.gain.setValueCurveAtTime([${curve}], ${startTime}, ${curveDurationShorter})`) + .throw(DOMException, 'NotSupportedError'); + // Earlier start time, end time after the start time an another curve + should( + () => { + g.gain.setValueCurveAtTime(curve, startTimeEarlier, curveDuration); + }, + `g.gain.setValueCurveAtTime([${curve}], ${startTimeEarlier}, ${curveDuration})`) + .throw(DOMException, 'NotSupportedError'); + // Start time after the start time of the other curve, but earlier than + // its end. + should( + () => { + g.gain.setValueCurveAtTime(curve, startTimeLater, curveDuration); + }, + `g.gain.setValueCurveAtTime([${curve}], ${startTimeLater}, ${curveDuration})`) + .throw(DOMException, 'NotSupportedError'); + + // New event wholly contained inside existing event + should( + () => { + g.gain.setValueCurveAtTime(curve, startTime + 1, curveDuration - 1); + }, + `g.gain.setValueCurveAtTime([${curve}], ${startTime+1}, ${curveDuration-1})`) + .throw(DOMException, 'NotSupportedError'); + // Old event completely contained inside new event + should( + () => { + g.gain.setValueCurveAtTime(curve, startTime - 1, curveDuration + 1); + }, + `g.gain.setValueCurveAtTime([${curve}], ${startTime-1}, ${curveDuration+1})`) + .throw(DOMException, 'NotSupportedError'); + // Setting an event exactly at the end of the curve should work. + should( + () => { + g.gain.setValueAtTime(1.0, startTime + curveDuration); + }, + `g.gain.setValueAtTime(1.0, ${startTime + curveDuration})`) + .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(DOMException, 'InvalidStateError'); + + should( + () => { + g.gain.setValueCurveAtTime(Float32Array.from([1]), time, 0.01); + }, + 'setValueCurveAtTime([1], ' + time + ', 0.01)') + .throw(DOMException, '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> |