How I made any keyboard play a little tune, with no audio files
I wanted typing to feel nice. Not a click track, but something closer to playing an instrument. So I built a typing sounds page where your keyboard can sound like a typewriter, rain, bubbles, an 8-bit game or a piano. T
I wanted typing to feel nice. Not a click track, but something closer to playing an instrument. So I built a typing sounds page where your keyboard can sound like a typewriter, rain, bubbles, an 8-bit game or a piano.
The fun part: there isn't a single audio file. Every sound is made live with the Web Audio API, and the piano is tuned so that whatever you type sounds musical.
Try it first (type your name on the Piano): https://prakashcollective.com/typing-sounds/
1. One shared audio context
Browsers only allow sound after the person interacts, so the context is created on the first key press and reused after that:
let ctx, master;
function audio() {
if (ctx) return ctx;
ctx = new AudioContext();
master = ctx.createGain();
master.connect(ctx.destination);
return ctx;
}
Everything else connects to master, so one volume slider controls all the sounds.
2. A tiny tone helper
Most sounds are built from one small function: an oscillator with a quick fade in and a longer fade out.
function tone({ wave = "sine", f0 = 440, dur = 0.1, gain = 0.3, at = 0 }) {
const t = ctx.currentTime + at;
const o = ctx.createOscillator(), g = ctx.createGain();
o.type = wave;
o.frequency.setValueAtTime(f0, t);
g.gain.setValueAtTime(0.0001, t);
g.gain.exponentialRampToValueAtTime(gain, t + 0.004);
g.gain.exponentialRampToValueAtTime(0.0001, t + dur);
o.connect(g).connect(master);
o.start(t);
o.stop(t + dur + 0.05);
}
exponentialRampToValueAtTime can't reach zero, so it ramps to 0.0001 instead. That tiny detail removes the clicks you'd otherwise hear at the start and end of each note.
3. Why the piano always sounds nice
If every key played a random note, typing would sound like a cat walking on a piano. The trick is the pentatonic scale: five notes (C, D, E, G, A) that never clash with each other, which is why it's used in so much folk and children's music.
const PENT = [0, 2, 4, 7, 9]; // semitones above C
const noteFreq = i =>
261.63 * Math.pow(2, (PENT[i % 5] + 12 * Math.floor(i / 5)) / 12);
Each key gets a number from its position on the keyboard, and that number is spread over three octaves:
const scaleIndex = code => (order[code] * 7) % 15;
Multiplying by 7 before the modulo shuffles neighbouring keys apart, so typing along a row jumps around the scale instead of walking straight up it. It sounds more like a melody that way.
4. Making a sine wave sound like a piano
A single sine wave sounds like a test tone. A piano note has overtones that fade faster than the main note, so each key plays three sines at once:
function play(f, g = 0.22) {
tone({ f0: f, dur: 1.4, gain: g });
tone({ f0: f * 2, dur: 0.9, gain: g * 0.3 });
tone({ f0: f * 3, dur: 0.5, gain: g * 0.1 });
}
Space plays a soft chord, and Enter plays a little rising arpeggio, so a full sentence ends on something that sounds finished.
5. The other sounds
- Typewriter: a short burst of white noise through a high-pass filter, plus a tiny high triangle wave for the metal.
- Rain: sine waves that drop quickly in pitch, like drops hitting a surface.
- Bubbles: the opposite, sine waves that slide up.
- 8-bit: the same pentatonic notes as the piano, but on a square wave.
Try it
It's free, there's no sign up and it works in any browser: https://prakashcollective.com/typing-sounds/
If you have an idea for another sound pack, I'd love to hear it in the comments.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes ā full credit and traffic to the original publisher.