mirror of
https://github.com/servo/servo.git
synced 2025-07-16 11:53:39 +01:00
397 lines
14 KiB
HTML
397 lines
14 KiB
HTML
<!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 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('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 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 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>
|