JavaScript Audio
Useful page if you want to just generate some audio and see and hear the output. Works best if you have a dev server that reloads on file change.
It plays a sound for 1 second at 44100 samples/second, and displays the corresponding wave.
Code below!
<!DOCTYPE html>
<title>Interactive audio</title>
<svg width="44100" height="200">
<path d="M0 2 L 44100,2" stroke="red" fill="none" stroke-width="2" />
<path d="M0 100 L 44100,100" stroke="blue" fill="none" stroke-width="2" stroke-dasharray="8" />
<path id="graph" d="" stroke="black" fill="none" stroke-width="2" />
<path d="M0 198 L 44100,198" stroke="red" fill="none" stroke-width="2" />
</svg>
<audio id="sound" controls autoplay></audio>
<script>
// antialiased saw wave
const saw =sample, rate, freq =>
const partial = sample * freq / rate;
const phase = partial - Math.trunc;
const saw = phase * 2 - 1;
// polyblep
if < freq /
const t = phase / freq;
return saw -2 * t - * - 1;
else if >1 - freq /
const t = - 1 / /;
return saw - * + 2 * t + 1;
else
return saw;
;
// filter settings
const falloff = 800;
const resonance = 3.5;
// filter states
let f1 = 0;
let f2 = 0;
let f3 = 0;
let f4 = 0;
// generate audio
const soundfun =sample, rate =>
// saw wave
const wave = saw, rate, 120;
// ladder lowpass filter
// https://www.native-instruments.com/fileadmin/ni_media/downloads/pdf/VAFilterDesign_2.1.0.pdf
const a = Math.exp- / * 6.28;
const inp = -f4 * resonance + wave;
f1 +=1 - * -;
f2 +=1 - * -;
f3 +=1 - * -;
f4 +=1 - * -;
return f2;
;
const plot =rate, fn =>
let path = "M 0 100";
forlet i = 0; i < rate; i++
const sample = fn, * 100 + 100;
path += ` L ${i},${sample}`;
console.log;
return path;
;
// generate sound
const gen =rate, fn =>
// buffer
const buf =;
// header
buf.push'R'.charCodeAt0, 'I'.charCodeAt0, 'F'.charCodeAt0, 'F'.charCodeAt0;
// file size
const size = 36 + rate * 2;
buf.push & 255, >> 8 & 255, >> 16 & 255, >> 24 & 255;
// header
buf.push'W'.charCodeAt0, 'A'.charCodeAt0, 'V'.charCodeAt0, 'E'.charCodeAt0;
// format
buf.push'f'.charCodeAt0, 'm'.charCodeAt0, 't'.charCodeAt0, ' '.charCodeAt0;
// sub chunk size
buf.push16, 0, 0, 0;
// format, pcm
buf.push1, 0;
// channels
buf.push1, 0;
// rate
buf.push
rate & 255, >> 8 & 255, >> 16 & 255, >> 24 & 255
;
// byte rate
buf.push * 2 & 255, * 2 >> 8 & 255, * 2 >> 16 & 255, * 2 >> 24 & 255;
// block align
buf.push2, 0;
// bits per samble
buf.push16, 0;
// data
buf.push'd'.charCodeAt0, 'a'.charCodeAt0, 't'.charCodeAt0, 'a'.charCodeAt0;
// section size
const sector = rate * 2;
buf.push & 255, >> 8 & 255, >> 16 & 255, >> 24 & 255;
// add audio
forlet i = 0; i < rate; i++
const sample = fn, * 32768;
const low = sample & 255;
const high = >> 8 & 255;
buf.push,;
;
// convert to blob
const blob = new Blobnew Uint8Array,: "audio/wav";
// make url
return URL.createObjectURL;
;
const audio = document.getElementById"sound";
const graph = document.getElementById"graph";
// set the source
audio.src = gen44100,;
graph.setAttribute"d", plot44100,;
</script>