To start off, we create the WebAudioApi context and analyser objects. These will handle the audio processing.
let context = new (window.AudioContext || window.webkitAudioContext)();
let analyser = context.createAnalyser();
let soundDataArray;
const MAX_SOUND_VALUE = 256; //The largest value that can be stored in soundDataArray.When the user clicks on the audio input and selects a file, this function loads and plays the music.
audioInput.onchange = function() { 
  let sound = document.getElementById("soundElement");
  let reader = new FileReader(); //Make a file reader
  reader.onload = function(e) { 
    sound.src = this.result; //give the audio element the sound file
    sound.controls = true; //yeah we want to pause, play and also change volume. Do you?
    sound.play();
  };
  reader.readAsDataURL(this.files[0]); //read that file.
  createAudioObjects();
};createAudioObjects(); handles all the WebAudioApi connections, and creates the soundDataArray at a suitable size.
function createAudioObjects() {
  source = context.createMediaElementSource(document.getElementById("soundElement"));
  source.connect(analyser);
  analyser.connect(context.destination); 
  analyser.fftSize = 1024; //128, 256, 512, 1024 and 2048 are valid values.
  let bufferLength = analyser.frequencyBinCount;
  soundDataArray = new Uint8Array(bufferLength);
}loadAudio() also calls createAudioObjects(). It loads a default audio file to be played if the user doesn't want to search for their own music.
function loadAudio() {
  var mediaUrl = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/ivan-ibarra_-_cultos-personales.ogg"; 
  let sound = document.getElementById("soundElement");
  sound.crossOrigin = 'anonymous'; 
  sound.src = mediaUrl;
  sound.controls = true;
  sound.play();
  createAudioObjects();
}Please note that the music link above was stolen from another codepen pen. I have no idea how to host music files online and then access them appropriately. I spent a couple of hours trying different things to no avail.
Here is the helper function I use to for when I want to iterate through the heights of the sound bars displayed in the music visualisation. Note how the result is normalised between 0 and 1, 0 is no volume, 1 is maximum.
//Returns the average of a small sample of the array, normalised between 0-1. Index declares which sample you want, ideal for iteration.
//How to use this function is best described through example - see how I use it in the p5js code below.
function getSampleOfSoundData(index, noSampleSections, soundDataArray){
  let sampleSize = Math.floor((soundDataArray.length/2) / noSampleSections); 
  
  let minBound = index * sampleSize; 
  let maxBound = (index + 1) * sampleSize;
  let sum = 0;
  
  for (let i = minBound; i < maxBound; i++){
    sum += soundDataArray[i];
  }
  let average = sum / sampleSize;
  
  return average / MAX_SOUND_VALUE;
}Here is an example of a basic p5js visualiser, using the above functions.
function setup(){
  createCanvas(windowWidth, windowHeight);
  colorMode(HSB, 360, 100, 100, 1); 
  fill(0,100,100,1);
  noStroke();
}
function draw(){
  background(0);
  if((soundDataArray === undefined) == false){ //Be careful with trying to access an undefined array before music starts playing.
    analyser.getByteFrequencyData(soundDataArray);
  }
  displayVisualiser();
}
function displayVisualiser() {
  let numOfBars = 20;
  let soundLevel = 0;
  
  for (let i = 0; i < numOfBars; i++){
    if((soundDataArray === undefined) == false){
      soundLevel = getSampleOfSoundData(i, numOfBars, soundDataArray);
    }
    rect(300 + i*10, 200, 10,-soundLevel*200);
  }
}You can view the result live here.