<!DOCTYPE html>

<!--
Tests that multiple audio-rate signals (AudioNode outputs) can be connected to an AudioParam
and that these signals are summed, along with the AudioParams intrinsic value.
-->

<html>
<head>
<script src="resources/audio-testing.js"></script>
<script src="resources/mix-testing.js"></script>
<script src="../resources/js-test.js"></script>

</head>
<body>

<script>

var sampleRate = 44100.0;
var lengthInSeconds = 1;

var context = 0;

// Buffers used by the two gain controlling sources.
var linearRampBuffer;
var toneBuffer;
var toneFrequency = 440;

// Arbitrary non-zero value.
var baselineGain = 5;

// Allow for a small round-off error.
var maxAllowedError = 1e-6;

function checkResult(event) {
    var renderedBuffer = event.renderedBuffer;
    var renderedData = renderedBuffer.getChannelData(0);

    // Get buffer data from the two sources used to control gain.
    var linearRampData = linearRampBuffer.getChannelData(0);
    var toneData = toneBuffer.getChannelData(0);

    var n = renderedBuffer.length;

    if (n == linearRampBuffer.length) {
        testPassed("Rendered signal is of correct length.");
    } else {
        testFailed("Rendered signal is not of correct length.");
    }

    // Check that the rendered result exactly matches the sum of the intrinsic gain plus the two sources used to control gain.
    // This is because we're changing the gain of a signal having constant value 1.
    var success = true;
    for (var i = 0; i < n; ++i) {
        var expectedValue = baselineGain + linearRampData[i] + toneData[i];
        var error = Math.abs(expectedValue - renderedData[i]);

        if (error > maxAllowedError) {
            success = false;
            break;
        }
    }

    if (success) {
        testPassed("Rendered signal matches sum of two audio-rate gain changing signals plus baseline gain.");
    } else {
        testFailed("Rendered signal differs from the sum of two audio-rate gain changing signals plus baseline gain.");
    }

    finishJSTest();
}

function runTest() {
    window.jsTestIsAsync = true;

    var sampleFrameLength = sampleRate * lengthInSeconds;

    // Create offline audio context.
    context = new OfflineAudioContext(1, sampleFrameLength, sampleRate);

    // Create buffer used by the source which will have its gain controlled.
    var constantOneBuffer = createConstantBuffer(context, sampleFrameLength, 1);
    var constantSource = context.createBufferSource();
    constantSource.buffer = constantOneBuffer;

    // Create 1st buffer used to control gain (a linear ramp).
    linearRampBuffer = createLinearRampBuffer(context, sampleFrameLength);
    var gainSource1 = context.createBufferSource();
    gainSource1.buffer = linearRampBuffer;

    // Create 2st buffer used to control gain (a simple sine wave tone).
    toneBuffer = createToneBuffer(context, toneFrequency, lengthInSeconds, 1);
    var gainSource2 = context.createBufferSource();
    gainSource2.buffer = toneBuffer;

    // Create a gain node controlling the gain of constantSource and make the connections.
    var gainNode = context.createGain();

    // Intrinsic baseline gain.
    // This gain value should be summed with gainSource1 and gainSource2.
    gainNode.gain.value = baselineGain;

    constantSource.connect(gainNode);
    gainNode.connect(context.destination);

    // Connect two audio-rate signals to control the .gain AudioParam.
    gainSource1.connect(gainNode.gain);
    gainSource2.connect(gainNode.gain);

    // Start all sources at time 0.
    constantSource.start(0);
    gainSource1.start(0);
    gainSource2.start(0);

    context.oncomplete = checkResult;
    context.startRendering();
}

runTest();

</script>
</body>
</html>
