Skip to main content
Version: 11.8.0

Web Audio on Web

THEOplayer integrates with the Web Audio API, which allows you to do some quite nifty stuff with the player's audio output. If you are unfamiliar with the ideas behind the Web Audio API, Mozilla has an excellent introduction to the basic concepts. This guide helps you set up a demo just like the one in our demo zone.

The Web Audio API is only available on the Web SDK. Make sure your Web SDK includes the webaudio feature.

A very basic Web Audio graph

The first step in working with Web Audio is to create an AudioContext. Once you have one, you can create an AudioNode which contains the player's audio output, and connect it to the context's destination.

const AudioContext = window.AudioContext || window.webkitAudioContext;
const audioCtx = new AudioContext();

const sourceNode = player.audio.createAudioSourceNode(audioCtx);

// Without this connection, the player's audio is piped into the graph but not connected to any output,
// resulting in no sound from your speakers or headphones.
sourceNode.connect(audioCtx.destination);

Playing with the audio gain

A first useful thing we could do is play with the gain, i.e. manipulate the player volume through the Web Audio API.

const AudioContext = window.AudioContext || window.webkitAudioContext;
const audioCtx = new AudioContext();
const sourceNode = player.audio.createAudioSourceNode(audioCtx);
const gainNode = audioCtx.createGain();
sourceNode.connect(gainNode);
gainNode.connect(audioCtx.destination);

This sets up a gain filter on top of the player audio output, which you can manipulate using the gainNode.gain.value property. As an example, you could set up a callback which monitors mouse movement:

document.onmousemove = function (e) {
gainNode.gain.value = (screen.height - e.screenY) / screen.height;
};

The gain is adjusted to the ratio of the distance of the mouse pointer position from the bottom of the screen and the screen height. The farther you move the mouse pointer down, the quieter the output of the video becomes, and the opposite effect when you move the mouse pointer up.

Playing with stereo panning

Similarly, you can play with the stereo panning of the player audio output through the pan.value property of a StereoPanner node.

const AudioContext = window.AudioContext || window.webkitAudioContext;
const audioCtx = new AudioContext();
const sourceNode = player.audio.createAudioSourceNode(audioCtx);
const pannerNode = audioCtx.createStereoPanner();
sourceNode.connect(pannerNode);
pannerNode.connect(audioCtx.destination);

document.onmousemove = function (e) {
pannerNode.pan.value = (2 * e.screenX) / screen.width - 1;
};

Moving the pointer left and right changes the stereo panning of the player audio, with balanced audio at the exact middle of the screen.

Combining both

The Web Audio API allows you to pipe the output of one node as input for another node (in most cases). This way, you can combine the two tricks above: modifying the volume by moving the mouse pointer up and down, and modifying the panning by moving the mouse left and right.

const AudioContext = window.AudioContext || window.webkitAudioContext;
const audioCtx = new AudioContext();
const sourceNode = player.audio.createAudioSourceNode(audioCtx);
const gainNode = audioCtx.createGain();
const pannerNode = audioCtx.createStereoPanner();
sourceNode.connect(pannerNode);
pannerNode.connect(gainNode);
gainNode.connect(audioCtx.destination);

document.onmousemove = function (e) {
gainNode.gain.value = (screen.height - e.screenY) / screen.height;
pannerNode.pan.value = (2 * e.screenX) / screen.width - 1;
};

Manipulating two players at once

Assume that you have two players set up, bound to the variables player1 and player2. You can set up exactly the same audio pipeline for both players, and reroute their audio to a single output.

const sourceNode1 = player1.audio.createAudioSourceNode(audioCtx);
const gainNode1 = audioCtx.createGain();
const pannerNode1 = audioCtx.createStereoPanner();
sourceNode1.connect(pannerNode1);
pannerNode1.connect(gainNode1);
gainNode1.connect(audioCtx.destination);

const sourceNode2 = player2.audio.createAudioSourceNode(audioCtx);
const gainNode2 = audioCtx.createGain();
const pannerNode2 = audioCtx.createStereoPanner();
sourceNode2.connect(pannerNode2);
pannerNode2.connect(gainNode2);
gainNode2.connect(audioCtx.destination);

From there, you can do the inverse for the second player's audio: moving the mouse pointer up decreases the volume for the second player, and the panning is inverted as well.

document.onmousemove = function (e) {
gainNode1.gain.value = (screen.height - e.screenY) / screen.height;
pannerNode1.pan.value = (2 * e.screenX) / screen.width - 1;
gainNode2.gain.value = e.screenY / screen.height;
pannerNode2.pan.value = 1 - (2 * e.screenX) / screen.width;
};

Resources