The Ins and Outs

All plugins require inputs and outputs to operate, JSAP is no different. However the channel ordering is different compared to traditional desktop plugins, such as VST or AU. Web Audio operates through connections rather than channels. A connection can carry multiple channels of audio in one of the following configurations: -1.0 (Mono) -2.0 (Stereo) -4.0 (Quadraphonic) -5.1 (Surround Sound)

Each connection must support the possibility of any of these layouts being created. The type of channels actually depends on the output configuration of the device. If 1.0, all nodes will operate as 1.0. If surround sound, all nodes operate as 5.1. This means all up-mixing and down-mixing is done instantly.

The API currently only supports audio input and output objects since other items could be parameterised. You can send non-audio information, such as control signals, as an output however.

Simple use case

...
this.addInput(myInputNode);
this.addOutput(myOutputNode);
...

The above example gives the simplest use, one in and one out. Here, one node is marked as the input, the other the output. The addInput and addOutput functions index serially. This means the first time the function is called, the passed node is set at index [0], the next node at [1].

...
this.addInput(myInputNode);
this.addInput(myOtherInput);
...

In this example, two inputs are defined! The myInputNode is at input index [0] and myOtherInput at [1].

The input and output array can be viewed by accessing the member variable input or output.


\\ Currently this.output = [];

this.addOutput(myNode);
\\ this.output will now equal [myNode];
this.addOutput(anotherNode);
\\ this.output will now equal [myNode, anotherNode];

Sending control information

The Web Audio API allows the routing of Audio Parameters to Audio Nodes and vice versa. Take for instance the following construction for an amplitude modulator:


var carrier = this.context.createOscillator(); // Create an oscillator
var modulator = this.input[0]; // Whatever we've bound to input 0
var mixer = this.context.createGain(); // Create a gain node

carrier.connect(mixer); // Feed carrier into mixer
mixer.connect(this.output[0]); // Feed mixer to whatever node is on output 0

carrier.frequency.value = 440; // Set carrier to 440Hz
carrier.start(); // Start the carrier wave

modulator.connect(mixer.gain); // Control the mixer gain using the modulators' raw value.

In the above example, we can see that an oscillator has been made for the carrier wave and is being fed into the mixer. AM is performed by modulating the amplitude of the carrier. In this case the mixer is the amplitude controller of the oscillator, and its gain value is being controlled by the audio signal from modulator. This shows the Web Audio API's ability to route audio parameters and nodes together. The full specification of the API's connect function can be found here.

The incomming stream is 'summed' with the current parameters' value. For instance, the gain value of mixer is 1.0 by default. The oscillator nodes return a normalised range between [-1.0, 1.0]. Therefore, when summed with gain value the range becomes [0.0, 2.0].

Routing control signals as an input

var DRC = this.context.createDynamicsProcessor();
var nullGain = this.context.createGain();
this.addInput(DRC);
this.addInput(nullGain);
this.addOutput(DRC);

nullGain.connect(DRC.threshold);

In this example, we've create a Dynamics Range Compressor and bound it to input/output 0. A gain node called nullGain is then constructed and bound to input 1. This is then connected to the Dynamics Range Compressors' threshold parameter. Therefore whatever the value of the signal coming in on input 1 will be mapped to the threshold.

Routing control signals as an output

Audio Parameters cannot be used as an output, only Audio Nodes. It is possible to create control signals as an output, but these have to be embedded into the audio stream and not passed as parameters.

Removing Nodes

Nodes can be removed from outputs by calling deleteInput or deleteOutput. This will change the order of all proceding nodes. For instance, if a plugin has three inputs and the 2nd is deleted, the 3rd input moves up one position and input[3] is undefined:


this.addInput(input0);
this.addInput(input1);
this.addInput(input2);
// We have three inputs:
// [input0, input1, input2];

this.deleteInput(input1);

// Our map now looks like this:
// [input0, input2];

this.addInput(input1);
// [input0, input2, input1];