home ~ projects ~ socials

Mic Audio Graphic Equalizer

I've started recording blog posts to turn them into mp3s. I want to post them to YouTube too, but I'm not interested in having to make myself presentable every time I want to record. I made this graphic equalizer display so I don't have to. It takes the audio input from a mic and turns it into pretty looking bars.

Click "Start" to request access to the mic and start showing the output full screen. (You can also set title and subtitle text which show when the display is in full screen mode)

JavaScript

let mic
let fft 
let totalBands = 32
let widthOfBands
let baseWidth = 200

function findHeight(fromWidth) {
  return window.screen.height / window.screen.width * fromWidth 
}

function handleFullscreenChange() {
  if (!document.fullscreenElement) {
    resizeCanvas(baseWidth, findHeight(baseWidth))
  } else {
    resizeCanvas(displayWidth, displayHeight)
  }
}

function toggleFullscreen() {
  if (!mic.enabled) {
    mic.start()
  }
  /*
  if (!document.fullscreenElement) {
    document.querySelector('#p5Canvas').requestFullscreen()
  } else {
    document.exitFullscreen()
  }
  */
}

function setup() {
  colorMode(HSB)
  mic = new p5.AudioIn()
  const canvas = createCanvas(baseWidth, findHeight(baseWidth))
  canvas.parent('p5Wrapper')
  canvas.id('p5Canvas')
  canvas.mouseClicked(toggleFullscreen)
  document.querySelector('#p5Canvas').addEventListener(
    'fullscreenchange', handleFullscreenChange
  )
  fft = new p5.FFT(0.9, totalBands)
  fft.setInput(mic)
  describe(`A black canvas that shows a 32 
  bar graphic equalizer display with varying 
  shades of red bars full screen when clicked.`);
}

function draw() {
  background(0)
  stroke(0)
  widthOfBands = width / totalBands
  var spectrum = fft.analyze()
  for (let i = 0; i < spectrum.length; i++) {
    var amp = spectrum[i]
    fill(i, 255, 255)
    var y = map(amp, 0, 256, height, 0)
    rect(i * widthOfBands, y, widthOfBands, height - y)
  }
  if (!mic.enabled) {
    textAlign(CENTER, CENTER)
    textSize(32)
    text("Start", width / 2, height / 2)
  } else if (fullscreen()) {
    textAlign(LEFT, TOP)
    textSize(getInt('#titleSize'))
    text(getValue('#titleText'), 20, 20)
    textSize(getInt('#titleSize') * 0.6)
    text(getValue('#subtitleText'), 20, getInt('#titleSize') + 20)
  }
}

Details

  • I'm using p5.js creative coding javascript library for the heavy lifting. I played around with the WebAudio API directly before and it's way nicer to just have p5 take care of everything
  • Most of the code is straight from the Coding Train and Frequency Spectrum Examples below. The main thing I did was make it full screen with this technique
  • I also added the title and subtitle text so I can show the name of the post I'm recording and the link to it. It's not sophisticated and would break on longer lines. I'll probably address that when I run into it
  • I'm using a few functions (`getValueand `getInt) from my YAGNI JS collection. If you don't recognize them, that's why.
-- end of line --

References