DEV Community

Cover image for How I made any keyboard play a little tune, with no audio files
Prakash S
Prakash S

Posted on AI-assisted

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.

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;
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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 });
}
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)