blob: 04746dbc1afdfa6a7ee636af1b751fb83c07c5fd [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<script src="../resources/js-test.js"></script>
<script src="resources/compatibility.js"></script>
<script src="resources/audio-testing.js"></script>
</head>
<body>
<script>
description('Test disconnect() method on AudioParam destination.');
window.jsTestIsAsync = true;
var renderQuantum = 128;
var sampleRate = 44100;
var renderDuration = 0.5;
var disconnectTime = 0.5 * renderDuration;
var audit = Audit.createTaskRunner();
// Calculate the index for disconnection.
function getDisconnectIndex(disconnectTime) {
var disconnectIndex = disconnectTime * sampleRate;
return disconnectIndex -= (disconnectIndex) % renderQuantum;
}
// Get the index of value change.
function getValueChangeIndex(array, targetValue) {
return array.findIndex(function (element, index) {
if (element === targetValue)
return true;
});
}
// Task 1: test disconnect(AudioParam) method.
audit.defineTask('disconnect(AudioParam)', function (done) {
// Creates a buffer source with value [1] and then connect it to two gain
// nodes in series. The output of the buffer source is lowered by half
// (* 0.5) and then connected to two |.gain| AudioParams in each gain node.
//
// (1) bufferSource => gain1 => gain2
// (2) bufferSource => half => gain1.gain
// (3) half => gain2.gain
//
// This graph should produce the output of 2.25 (= 1 * 1.5 * 1.5). After
// disconnecting (3), it should produce 1.5.
var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
var source = context.createBufferSource();
var buffer1ch = createConstantBuffer(context, 1, 1);
var half = context.createGain();
var gain1 = context.createGain();
var gain2 = context.createGain();
source.buffer = buffer1ch;
source.loop = true;
half.gain.value = 0.5;
source.connect(gain1);
gain1.connect(gain2);
gain2.connect(context.destination);
source.connect(half);
// Connecting |half| to both |gain1.gain| and |gain2.gain| amplifies the
// signal by 2.25 (= 1.5 * 1.5) because each gain node amplifies the signal
// by 1.5 (= 1.0 + 0.5).
half.connect(gain1.gain);
half.connect(gain2.gain);
source.start();
// Schedule the disconnection at the half of render duration.
context.suspend(disconnectTime).then(function () {
half.disconnect(gain2.gain);
context.resume();
});
context.startRendering().then(function (buffer) {
var channelData = buffer.getChannelData(0);
var disconnectIndex = getDisconnectIndex(disconnectTime);
var valueChangeIndex = getValueChangeIndex(channelData, 1.5);
// Expected values are: 1 * 1.5 * 1.5 -> 1 * 1.5 = [2.25, 1.5]
Should('Channel #0', channelData).containValues([2.25, 1.5]);
Should('The index of value change', valueChangeIndex)
.beEqualTo(disconnectIndex);
}).then(done);
});
// Task 2: test disconnect(AudioParam, output) method.
audit.defineTask('disconnect(AudioParam, output)', function (done) {
// Create a 2-channel buffer source with [1, 2] in each channel and
// make a serial connection through gain1 and gain 2. The make the buffer
// source half with a gain node and connect it to a 2-output splitter.
// Connect each output to 2 gain AudioParams respectively.
//
// (1) bufferSource => gain1 => gain2
// (2) bufferSource => half => splitter(2)
// (3) splitter#0 => gain1.gain
// (4) splitter#1 => gain2.gain
//
// This graph should produce 3 (= 1 * 1.5 * 2) and 6 (= 2 * 1.5 * 2) for
// each channel. After disconnecting (4), it should output 1.5 and 3.
var context = new OfflineAudioContext(2, renderDuration * sampleRate, sampleRate);
var source = context.createBufferSource();
var buffer2ch = createConstantBuffer(context, 1, [1, 2]);
var splitter = context.createChannelSplitter(2);
var half = context.createGain();
var gain1 = context.createGain();
var gain2 = context.createGain();
source.buffer = buffer2ch;
source.loop = true;
half.gain.value = 0.5;
source.connect(gain1);
gain1.connect(gain2);
gain2.connect(context.destination);
// |source| originally is [1, 2] but it becomes [0.5, 1] after 0.5 gain.
// Each splitter's output will be applied to |gain1.gain| and |gain2.gain|
// respectively in an additive fashion.
source.connect(half);
half.connect(splitter);
// This amplifies the signal by 1.5. (= 1.0 + 0.5)
splitter.connect(gain1.gain, 0);
// This amplifies the signal by 2. (= 1.0 + 1.0)
splitter.connect(gain2.gain, 1);
source.start();
// Schedule the disconnection at the half of render duration.
context.suspend(disconnectTime).then(function () {
splitter.disconnect(gain2.gain, 1);
context.resume();
});
context.startRendering().then(function (buffer) {
var channelData0 = buffer.getChannelData(0);
var channelData1 = buffer.getChannelData(1);
var disconnectIndex = getDisconnectIndex(disconnectTime);
var valueChangeIndexCh0 = getValueChangeIndex(channelData0, 1.5);
var valueChangeIndexCh1 = getValueChangeIndex(channelData1, 3);
// Expected values are: 1 * 1.5 * 2 -> 1 * 1.5 = [3, 1.5]
Should('Channel #0', channelData0).containValues([3, 1.5]);
Should('The index of value change in channel #0', valueChangeIndexCh0)
.beEqualTo(disconnectIndex);
// Expected values are: 2 * 1.5 * 2 -> 2 * 1.5 = [6, 3]
Should('Channel #1', channelData1).containValues([6, 3]);
Should('The index of value change in channel #1', valueChangeIndexCh1)
.beEqualTo(disconnectIndex);
}).then(done);
});
// Task 3: exception checks.
audit.defineTask('exceptions', function (done) {
var context = new AudioContext();
var gain1 = context.createGain();
var splitter = context.createChannelSplitter(2);
var gain2 = context.createGain();
var gain3 = context.createGain();
// Connect a splitter to gain nodes and merger so we can test the possible
// ways of disconnecting the nodes to verify that appropriate exceptions
// are thrown.
gain1.connect(splitter);
splitter.connect(gain2.gain, 0);
splitter.connect(gain3.gain, 1);
gain2.connect(gain3);
gain3.connect(context.destination);
// gain1 is not connected to gain3.gain. Exception should be thrown.
Should('gain1.disconnect(gain3.gain)', function () {
gain1.disconnect(gain3.gain);
}).throw('InvalidAccessError');
// When the output index is good but the destination is invalid.
Should('splitter.disconnect(gain1.gain, 1)', function () {
splitter.disconnect(gain1.gain, 1);
}).throw('InvalidAccessError');
// When both arguments are wrong, throw IndexSizeError first.
Should('splitter.disconnect(gain1.gain, 2)', function () {
splitter.disconnect(gain1.gain, 2);
}).throw('IndexSizeError');
done();
});
audit.defineTask('finish', function (done) {
finishJSTest();
done();
});
audit.runTasks(
'disconnect(AudioParam)',
'disconnect(AudioParam, output)',
'exceptions',
'finish'
);
successfullyParsed = true;
</script>
</body>
</html>