webdevpuneet.com

Virtual Piano Keyboard — Web Audio Synth, Chords & MIDI

Virtual Piano Keyboard · Media · Plain HTML, CSS & JS · Live preview

Copy & paste

Source Code

<div class="studio">
  <header class="top">
    <div class="brand">
      <h2>Virtual Piano</h2>
      <p>25 keys · Web Audio synth · no samples</p>
    </div>
    <div class="chord" aria-live="polite">
      <span class="chord-name" id="chordName">—</span>
      <small class="chord-notes" id="noteList">Press a key to play</small>
    </div>
  </header>

  <div class="controls">
    <div class="seg" id="voices" role="group" aria-label="Sound">
      <button type="button" data-voice="piano" aria-pressed="true">Piano</button>
      <button type="button" data-voice="epiano" aria-pressed="false">E-Piano</button>
      <button type="button" data-voice="organ" aria-pressed="false">Organ</button>
      <button type="button" data-voice="pad" aria-pressed="false">Pad</button>
    </div>
    <label class="slider"><span>Volume</span><input id="vol" type="range" min="0" max="1" step="0.01" value="0.75"></label>
    <label class="slider"><span>Reverb</span><input id="rev" type="range" min="0" max="1" step="0.01" value="0.3"></label>
    <div class="octave" role="group" aria-label="Octave shift">
      <button type="button" id="octDown" aria-label="Octave down">−</button>
      <span id="octVal">Oct 0</span>
      <button type="button" id="octUp" aria-label="Octave up">+</button>
    </div>
    <button type="button" class="pill" id="sustainBtn" aria-pressed="false">Sustain <kbd>Space</kbd></button>
    <button type="button" class="pill" id="labelsBtn" aria-pressed="true">Labels</button>
    <div class="rec">
      <button type="button" class="pill rec-btn" id="recBtn">● Rec</button>
      <button type="button" class="pill" id="playBtn" disabled>▶ Play</button>
      <span class="rec-info" id="recInfo"></span>
    </div>
    <button type="button" class="pill" id="midiBtn" hidden>MIDI</button>
  </div>

  <div class="stage">
    <canvas class="rise" id="rise" aria-hidden="true"></canvas>
    <div class="piano" id="piano" role="group" aria-label="Piano keyboard"></div>
  </div>
  <p class="hint">Computer keys: <kbd>Z</kbd>–<kbd>M</kbd> lower row, <kbd>Q</kbd>–<kbd>I</kbd> upper row · <kbd>Space</kbd> sustain · <kbd>←</kbd><kbd>→</kbd> octave · drag across the keys for a glissando · press lower on a key to play it louder</p>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Two octaves, generated keys
25 keys (C4–C6) built from a loop over MIDI numbers, with black keys positioned from the white-key grid so the layout stays exact.
Four synthesized voices
Piano, E-Piano, Organ and Pad recipes of oscillators, filter and envelope, with no samples or files.
Reverb and compressor
A generated impulse-response reverb and a compressor so big chords stay clean.
Velocity, glissando and multi-touch
Press height sets loudness, dragging across keys plays a glissando, and every pointer is tracked separately.
Sustain pedal
Space (hold) or a latch button, with correct re-strike handling and MIDI pedal support.
Live chord detection
Names major, minor, diminished, augmented, sus, 6, add9 and seventh chords, including inversions as slash chords.
Rising note bars
A canvas draws colour-coded bars that grow while a key is held and float up after release, with retina-sharp rendering.
Recorder and MIDI
Record and replay your playing, and connect a real MIDI keyboard with Web MIDI after a click-to-allow permission.

About this UI Snippet

Virtual Piano Keyboard — A Playable Web Audio Synth with Chord Detection, Recording and MIDI

Screenshot of the Virtual Piano Keyboard snippet rendered live

Most "piano" demos on the web are static images or buttons that toggle a colour with no real sound. This snippet is a genuine playable instrument: 25 keys across two octaves (C4 to C6), every note synthesized live in the browser with the Web Audio API — no audio files, no samples, no libraries — and wrapped in a small studio: four sounds, reverb, a sustain pedal, chord detection, a recorder and optional MIDI keyboard input.

A keyboard layout built from maths, not hand-tuned CSS

The keys are generated by a short loop over MIDI note numbers 60 to 84. White keys are a display: flex row, each taking an equal share. Black keys live in the same container with position: absolute; each one is placed at left = whiteKeysBefore / totalWhiteKeys − halfBlackWidth, which is why the gaps between E and F and between B and C stay empty exactly like a real piano. The same geometry is stored in a geom map and reused by the note-bar animation, so changing the number of octaves means changing one constant.

Synthesis: voices, envelopes and a filter

Each voice is a recipe of oscillators (type, harmonic multiple, level, detune), mixed into a low-pass filter and a gain envelope. The Piano is a triangle wave plus quiet 2nd–4th harmonics with a fast attack and a decay that settles to a low sustain level, using setTargetAtTime for a natural exponential fall. The E-Piano is a bell-like sine blend, the Organ is additive sines with no decay and a very short release, and the Pad is two detuned sawtooths plus a sub with a slow swell. The filter cutoff follows the note's pitch and starts brighter than it ends, so notes mellow as they ring. Frequencies come from equal temperament: 440 × 2^((midi − 69) / 12).

Mixing: compressor and a generated reverb

All voices feed one bus that splits into a dry path and a ConvolverNode reverb, then into a DynamicsCompressor so big chords do not clip, then a master volume. The reverb's impulse response is not a file: it is two channels of random noise multiplied by a decaying curve, generated at start-up, which gives a convincing synthetic room for zero bytes of download. The Reverb slider is simply the wet gain.

Playing it: velocity, glissando, multi-touch and pedal

Pointer Events handle mouse, pen and touch together. Pressing lower on a key plays it louder, because velocity is computed from the press position inside the key's rectangle. A pointermove handler uses document.elementFromPoint to move a held pointer onto a new key, releasing the old note and pressing the new one, which gives a real glissando, and every pointer is tracked separately so multi-touch chords work. Each note remembers which sources are holding it (mouse, a computer key, MIDI), so two inputs on the same note never cut each other off. The computer keyboard uses event.code, so the layout is positional on any keyboard language, with Z–M and Q–I as two rows and Space as the sustain pedal.

Sustain pedal logic

When the pedal is down, releasing a key moves its voice into a sustained map instead of stopping it; lifting the pedal stops them all. Striking a pedalled note again fades the old voice quickly before starting the new one so there is no phasing. A button latches the pedal for touch users.

Chord detection

Every time a note starts or stops, the sounding notes are reduced to their distinct pitch classes. Each one is tried as a root: intervals above it are sorted and compared with a table of shapes (major, minor, diminished, augmented, sus2, sus4, 6, add9, 7, maj7, m7, m7♭5, dim7). The bass note is tried first, so inversions are labelled as slash chords (C/E). It turns the toy into a hands-on music theory tool.

Visual feedback and recording

Each key lights up in a colour derived from its pitch class, and a canvas above the keyboard draws Synthesia-style bars that grow while a note is held and float upward after release. The recorder logs note on/off events with timestamps and replays them with setTimeout; pressing Stop closes any notes still held so the replay never hangs. The canvas is scaled by devicePixelRatio for sharp rendering.

MIDI keyboard support

If the browser supports the Web MIDI API, a MIDI button appears. It only asks for permission when clicked, then wires every input: note-on (with velocity), note-off, and controller 64 for a hardware sustain pedal. Settings (sound, volume, reverb) are remembered in localStorage, and all held notes are released when the window loses focus so nothing gets stuck. For more instruments see the tone synth pad, the Tone.js synth pad and the audio metronome.

Step by step

How to Use

  1. 1
    Play with mouse, touch or keyboardClick or tap keys, or use the computer keyboard: Z S X D C V G B H N J M for C4 to B4 and Q 2 W 3 E R 5 T 6 Y 7 U for C5 to B5, with I for C6. The key letters are printed on the keys. Press lower on a key to play it louder.
  2. 2
    Slide for a glissandoHold the mouse button or a finger and drag across the keys. Each key you cross plays and the one you leave is released. With two fingers you can slide two hands at once.
  3. 3
    Change the soundSwitch between Piano, E-Piano, Organ and Pad. Use Volume and Reverb to shape the mix, and the − / + buttons (or the ← → keys) to shift the pitch by an octave.
  4. 4
    Use the sustain pedalHold Space for a pedal, or click Sustain to latch it. Released notes keep ringing until you lift the pedal.
  5. 5
    Read the chordsHold C, E and G together (Z, C, B). The display shows C, and adding another note changes it to Cmaj7 or C7. Rolling a chord over different bass notes shows slash chords.
  6. 6
    Record and replayClick Rec, play something, then click Stop and Play. The note count and length appear next to the buttons. If you own a MIDI keyboard, click MIDI to play it through the same synth.

Real-world uses

Common Use Cases

Teaching the Web Audio API
A complete, readable example of oscillators, gain envelopes, filters, a convolver and a compressor in one playable app. Pair it with the tone synth pad for a simpler start.
Music theory and ear-training tools
The chord readout and note names make it an instant teaching widget for triads, sevenths and inversions. Add a quiz that plays a chord and asks the user to name it.
Delightful hero or landing-page element
A real instrument is a memorable interaction for a music-software site or portfolio. The coloured rising bars look striking next to a waveform visualizer.
Starter for a DAW-style app
The note on/off event log, voice engine and MIDI input are the foundation of a sequencer or a loop recorder. Add a tempo grid with the audio metronome.
Pointer-event reference
Multi-touch tracking by pointerId, slide-to-change with elementFromPoint, and multi-source note ownership are patterns reusable in any touch instrument or drawing tool.

Got questions?

Frequently Asked Questions

Browsers only allow an AudioContext to start after a user gesture. The snippet creates it on the first key press and calls resume() if it was suspended. If you still hear nothing, check that the tab is not muted and that your volume is up.

With equal temperament: frequency = 440 × 2^((midi − 69) / 12), where 69 is A4. The octave buttons add 12 semitones per step, so shifting an octave multiplies the frequency by two.

The ConvolverNode needs an impulse response. The snippet builds one in code: two channels of random noise multiplied by a curve that fades to silence over two seconds. The Reverb slider controls how much of that signal is mixed in.

While the pedal is down, a released key moves its voice into a "sustained" list instead of stopping it. When the pedal is lifted, all sustained voices fade out. Pressing the same key again while pedalled fades the old voice quickly first.

The sounding notes are reduced to distinct pitch classes. Each is tried as a root, the intervals above it are sorted, and the result is looked up in a table such as 0,4,7 for major. The lowest note is tried first, so inversions get a slash-chord name.

Yes, in browsers that support Web MIDI (Chromium-based ones). Click the MIDI button and allow access. Note on, note off with velocity and the sustain pedal controller are supported. The button is hidden where Web MIDI is not available.

Create the AudioContext lazily in a ref on the first gesture and keep voices in a ref, not state. Render keys from the MIDI range, put the key pointer handlers on the container, and stop all voices in the unmount cleanup. Use the export buttons on this page for the markup and styles.