Skip to content

Instantly share code, notes, and snippets.

@ppalone
Created April 16, 2023 06:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ppalone/4470de209f5218bb28846393aa83b304 to your computer and use it in GitHub Desktop.
Save ppalone/4470de209f5218bb28846393aa83b304 to your computer and use it in GitHub Desktop.
Simple Audio Visualizer
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Audio Visualizer 🎵</title>
<style>
* {
box-sizing: border-box;
font-family: monospace;
}
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
canvas {
position: absolute;
z-index: -1;
top: 0;
left: 0;
/* width: 100%; */
/* height: 100%; */
display: block;
}
#root {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
</style>
</head>
<body>
<audio src="/audio/audio.mp3"></audio>
<canvas id="canvas"></canvas>
<div id="root">
<button id="play">PLAY</button>
</div>
<!-- Scripts -->
<script>
class Rectangle {
constructor(x, y, w, h) {
// x: x co-ordinate
// y: y co-ordinate
// w: width
// h: height
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
update(ctx, h) {
this.h = h;
this.draw(ctx)
}
// draw
draw(ctx) {
ctx.fillStyle = "rgb(255, 130, 160)"
ctx.fillRect(this.x, this.y, this.w, this.h)
}
}
</script>
<script>
// canvas
const canvas = document.getElementById("canvas")
// context
const ctx = canvas.getContext("2d")
const MAX_WIDTH = window.innerWidth;
const MAX_HEIGHT = window.innerHeight;
console.log(MAX_WIDTH, MAX_HEIGHT)
canvas.width = MAX_WIDTH;
canvas.height = MAX_HEIGHT;
const BARS = MAX_WIDTH > 600 ? 64 : 32;
const GAP = 2;
const SAFE = 10;
const BAR_WIDTH = Math.ceil(((MAX_WIDTH - 2 * SAFE) - BARS * GAP) / BARS);
const rectangles = []
for (let i = 0; i < BARS; i++) {
const rect = new Rectangle(
SAFE + i * (BAR_WIDTH + GAP),
Math.ceil(MAX_HEIGHT / 2),
BAR_WIDTH,
-1 * 0
);
rectangles.push(rect)
}
const play = document.querySelector("#play")
const animate = () => {
ctx.fillStyle = "beige";
ctx.fillRect(0, 0, MAX_WIDTH, MAX_HEIGHT)
analyser.getByteFrequencyData(data)
// rectangles.forEach(rect => {
// rect.update(ctx, -1 * (Math.random() * 200 + 50))
// })
// const copy = [...data].reverse()
data.forEach((d, idx) => {
rectangles[idx].update(ctx, -1 * (d + 1))
})
// data.forEach((d, idx) => {
// rectangles[idx].update(ctx, 1 * (d + 1))
// })
requestAnimationFrame(animate)
}
// audio element
const audio = document.querySelector("audio")
// audio context
const context = new AudioContext();
const source = context.createMediaElementSource(audio)
const analyser = context.createAnalyser()
source.connect(analyser)
analyser.connect(context.destination)
let data
audio.addEventListener("play", () => {
// console.log(analyser.getByteTimeDomainData)
analyser.fftSize = BARS * 2
const n = analyser.frequencyBinCount
data = new Uint8Array(n)
requestAnimationFrame(animate)
})
play.onclick = () => {
play.textContent = "PAUSE";
audio.play().catch(console.error)
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment