Pre-Fade Metering with Video Element

Sometimes it is useful to display levels for an audio node, even if that level is getting modified somewhere downstream.

Working Example

The web audio API context is loading.

HTML code

<p>The web audio API context is <span id="ctx-status">loading</span>. <button id="ctx-button">Loading</button></p>
<div class="demo-video">
  <video controls id="the-video" crossorigin="anonymous" style="width: 100%;">
    <source src="https://assets.rpy.xyz/testmedia/hoops.mp4" type="video/mp4">
    Sorry, your browser doesn't support embedded videos.
  </video>
  <div>
    <input type="range" id="gain" name="gain" min="0" max="1" value="0" step="0.05">
    <label for="gain">Gain</label>
  </div>
  <div id="peak-meter" style="height: 72px"></div>
</div>

Javascript code

const audioCtx = new AudioContext();

const ctxStatus = document.getElementById('ctx-status');
const buttonElement = document.getElementById('ctx-button');

function updateAudioCtxStatus() {
  ctxStatus.innerText = audioCtx.state;
  if (audioCtx.state === 'suspended') {
    buttonElement.innerText = 'Resume';
  } else {
    buttonElement.innerText = 'Suspend';
  }
}

setInterval(updateAudioCtxStatus, 1000);

buttonElement.addEventListener('click', () => {
  if (audioCtx.state === 'suspended') {
    audioCtx.resume().then(updateAudioCtxStatus);
  } else {
    audioCtx.suspend().then(updateAudioCtxStatus);
  }
});

const videoElement = document.getElementById('the-video');
const meterElement = document.getElementById('peak-meter');
const sourceNode = audioCtx.createMediaElementSource(videoElement);
const gainNode = audioCtx.createGain();
gainNode.gain.setValueAtTime(0, audioCtx.currentTime);

sourceNode.connect(gainNode);
gainNode.connect(audioCtx.destination);

const unused = new webAudioPeakMeter.WebAudioPeakMeter(sourceNode, meterElement);

const gainSlider = document.getElementById('gain');
gainSlider.addEventListener('change', (evt) => {
  gainNode.gain.setValueAtTime(evt.target.value, audioCtx.currentTime);
});