1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
<!DOCTYPE html>
<html>
<head>
<title>
audioparam-method-chaining.html
</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>
<script src="/webaudio/resources/audioparam-testing.js"></script>
</head>
<body>
<script id="layout-test-code">
let sampleRate = 8000;
// Create a dummy array for setValueCurveAtTime method.
let curveArray = new Float32Array([5.0, 6.0]);
// AudioNode dictionary with associated dummy arguments.
let methodDictionary = [
{name: 'setValueAtTime', args: [1.0, 0.0]},
{name: 'linearRampToValueAtTime', args: [2.0, 1.0]},
{name: 'exponentialRampToValueAtTime', args: [3.0, 2.0]},
{name: 'setTargetAtTime', args: [4.0, 2.0, 0.5]},
{name: 'setValueCurveAtTime', args: [curveArray, 5.0, 1.0]},
{name: 'cancelScheduledValues', args: [6.0]}
];
let audit = Audit.createTaskRunner();
// Task: testing entries from the dictionary.
audit.define('from-dictionary', (task, should) => {
let context = new AudioContext();
methodDictionary.forEach(function(method) {
let sourceParam = context.createGain().gain;
should(
sourceParam === sourceParam[method.name](...method.args),
'The return value of ' + sourceParam.constructor.name + '.' +
method.name + '()' +
' matches the source AudioParam')
.beEqualTo(true);
});
task.done();
});
// Task: test method chaining with invalid operation.
audit.define('invalid-operation', (task, should) => {
let context = new OfflineAudioContext(1, sampleRate, sampleRate);
let osc = context.createOscillator();
let amp1 = context.createGain();
let amp2 = context.createGain();
osc.connect(amp1);
osc.connect(amp2);
amp1.connect(context.destination);
amp2.connect(context.destination);
// The first operation fails with an exception, thus the second one
// should not have effect on the parameter value. Instead, it should
// maintain the default value of 1.0.
should(
function() {
amp1.gain.setValueAtTime(0.25, -1.0)
.linearRampToValueAtTime(2.0, 1.0);
},
'Calling setValueAtTime() with a negative end time')
.throw(RangeError);
// The first operation succeeds but the second fails due to zero target
// value for the exponential ramp. Thus only the first should have
// effect on the parameter value, setting the value to 0.5.
should(
function() {
amp2.gain.setValueAtTime(0.5, 0.0).exponentialRampToValueAtTime(
0.0, 1.0);
},
'Calling exponentialRampToValueAtTime() with a zero target value')
.throw(RangeError);
osc.start();
osc.stop(1.0);
context.startRendering()
.then(function(buffer) {
should(amp1.gain.value, 'The gain value of the first gain node')
.beEqualTo(1.0);
should(amp2.gain.value, 'The gain value of the second gain node')
.beEqualTo(0.5);
})
.then(() => task.done());
});
// Task: verify if the method chaining actually works. Create an arbitrary
// envelope and compare the result with the expected one created by JS
// code.
audit.define('verification', (task, should) => {
let context = new OfflineAudioContext(1, sampleRate * 4, sampleRate);
let constantBuffer = createConstantBuffer(context, 1, 1.0);
let source = context.createBufferSource();
source.buffer = constantBuffer;
source.loop = true;
let envelope = context.createGain();
source.connect(envelope);
envelope.connect(context.destination);
envelope.gain.setValueAtTime(0.0, 0.0)
.linearRampToValueAtTime(1.0, 1.0)
.exponentialRampToValueAtTime(0.5, 2.0)
.setTargetAtTime(0.001, 2.0, 0.5);
source.start();
context.startRendering()
.then(function(buffer) {
let expectedEnvelope =
createLinearRampArray(0.0, 1.0, 0.0, 1.0, sampleRate);
expectedEnvelope.push(...createExponentialRampArray(
1.0, 2.0, 1.0, 0.5, sampleRate));
expectedEnvelope.push(...createExponentialApproachArray(
2.0, 4.0, 0.5, 0.001, sampleRate, 0.5));
// There are slight differences between JS implementation of
// AudioParam envelope and the internal implementation. (i.e.
// double/float and rounding up) The error threshold is adjusted
// empirically through the local testing.
should(buffer.getChannelData(0), 'The rendered envelope')
.beCloseToArray(
expectedEnvelope, {absoluteThreshold: 4.0532e-6});
})
.then(() => task.done());
});
audit.run();
</script>
</body>
</html>
|