Skip to content

Instantly share code, notes, and snippets.

@justinledwards
Created September 2, 2025 14:43
Show Gist options
  • Save justinledwards/0e670970919baf5e2672c79b97af6e50 to your computer and use it in GitHub Desktop.
Save justinledwards/0e670970919baf5e2672c79b97af6e50 to your computer and use it in GitHub Desktop.
easy to follow explanation of audio waveform code
useEffect(() => {
// If we do not have audio data yet or the canvas is not available, stop here.
if (!lastRenderedBuffer || !waveformRef.current) return;
// 1) Get the canvas and its 2D drawing context.
const canvas = waveformRef.current;
const ctx = canvas.getContext("2d");
// Canvas width and height in pixels.
const w = canvas.width;
const h = canvas.height;
// 2) Clear anything drawn before.
ctx.clearRect(0, 0, w, h);
// 3) Set up stroke style for the line we will draw.
ctx.lineWidth = 2;
ctx.strokeStyle = "#3b82f6";
ctx.beginPath();
// 4) Get the audio samples for the first channel.
// Audio samples in Web Audio are floats in the range [-1, 1].
const data = lastRenderedBuffer.getChannelData(0);
// 5) Decide how many audio samples to skip between drawn pixels.
// We only have "w" pixels across the canvas, but "data.length" samples,
// which is usually much larger. We cannot draw every sample to every pixel,
// so we pick a "step" that jumps through the data.
//
// Example: if data.length is 441000 samples and the canvas is 1100 pixels wide,
// step will be 401. That means pixel 0 uses sample 0, pixel 1 uses sample 401,
// pixel 2 uses sample 802, and so on, which fits the whole sound across the width.
const step = Math.max(1, Math.floor(data.length / w));
// 6) Choose an amplitude scale so the line does not hit the very top
// or bottom of the canvas. s = 0.9 means use 90% of the height.
const s = 0.9;
// 7) Draw one vertical position per pixel column.
for (let x = 0; x < w; x++) {
// Pick the sample for this column by jumping ahead "step" samples.
const idx = x * step;
// A single audio sample in [-1, 1].
const v = data[idx];
// 8) Map the sample to a Y position on the canvas.
//
// Audio sample range: [-1, 1]
// First scale the amplitude by "s": v * s is still in [-s, s]
// Shift into [0, 1] by adding 1 and dividing by 2: ((v * s) + 1) / 2
// Canvas has origin at top, so we flip it: 1 - normalized
// Finally scale by canvas height "h" to get pixels.
let y = (1 - ((v * s + 1) / 2)) * h;
// Optional safety: clamp Y so it never goes outside the canvas.
if (y < 0) y = 0;
if (y > h) y = h;
// 9) Move the pen for the first point, then draw lines for the rest.
if (x === 0) ctx.moveTo(x, y);
else ctx.lineTo(x, y);
}
// 10) Put the line on the canvas.
ctx.stroke();
}, [lastRenderedBuffer]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment