Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can web audio gain nodes control other gain nodes?

I'd like to create hierarchical "channels" where the parents gain will limit the child's gain.

So for example, I'd like sounds played on the child to have 0.1 volume.

var child = context.createGain();
var parent = context.createGain();
parent.gain.value = 0.1;
child.gain.value = 1.0;
child.connect(parent);
like image 922
Tom Kerr Avatar asked Oct 31 '25 05:10

Tom Kerr


2 Answers

Yes, audio gain is chained hierarchically as described.

It multiplies the input audio signal by the (possibly time-varying) gain attribute, copying the result to the output. By default, it will take the input and pass it through to the output unchanged, which represents a constant gain change of 1.

As with other AudioParams, the gain parameter represents a mapping from time (in the coordinate system of AudioContext.currentTime) to floating-point value. Every PCM audio sample in the input is multiplied by the gain parameter's value for the specific time corresponding to that audio sample. This multiplied value represents the PCM audio sample for the output.

from http://www.w3.org/TR/webaudio/#GainNode

Here is a complete example.

<html>
<body>
<script type="text/javascript">

var AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();

var parentGain = context.createGain();
var childGain = context.createGain();

parentGain.gain.value = 0.1;
childGain.gain.value = 1.0;

childGain.connect(parentGain);
parentGain.connect(context.destination);

var bufferSize = 4096;
var pinkNoise = (function() {
    var b0, b1, b2, b3, b4, b5, b6;
    b0 = b1 = b2 = b3 = b4 = b5 = b6 = 0.0;
    var node = context.createScriptProcessor(bufferSize, 1, 1);
    node.onaudioprocess = function(e) {
        var output = e.outputBuffer.getChannelData(0);
        for (var i = 0; i < bufferSize; i++) {
            var white = Math.random() * 2 - 1;
            b0 = 0.99886 * b0 + white * 0.0555179;
            b1 = 0.99332 * b1 + white * 0.0750759;
            b2 = 0.96900 * b2 + white * 0.1538520;
            b3 = 0.86650 * b3 + white * 0.3104856;
            b4 = 0.55000 * b4 + white * 0.5329522;
            b5 = -0.7616 * b5 - white * 0.0168980;
            output[i] = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362;
            output[i] *= 0.11; // (roughly) compensate for gain
            b6 = white * 0.115926;
        }
    }
    return node;
})();

pinkNoise.connect(childGain);

</script>
</body>
</html>
like image 158
Tom Kerr Avatar answered Nov 02 '25 20:11

Tom Kerr


Yes, you can chain gain nodes serially, as you describe. Note that this isn't a "limiting" effect in your example - it's multiplicative. (If parent.gain.value were 2, the end result would be a .2x gain.)

like image 39
cwilso Avatar answered Nov 02 '25 20:11

cwilso