Skip to content

Real-time pitch, BPM & rhythm analysis web app - #1

Open
silas-dsc wants to merge 11 commits into
mainfrom
claude/audio-analysis-web-app-Ep5mc
Open

Real-time pitch, BPM & rhythm analysis web app#1
silas-dsc wants to merge 11 commits into
mainfrom
claude/audio-analysis-web-app-Ep5mc

Conversation

@silas-dsc

Copy link
Copy Markdown
Owner

Summary

A mobile-friendly, dependency-free web app that analyzes audio in real time to measure pitch, tempo (BPM) and rhythm, and shows how far each note strays from perfect pitch and perfect time. Everything runs locally in the browser via the Web Audio API — no audio leaves the device.

Features

  • 🎤 Live microphone analysis and 📁 audio-file upload (any browser-decodable format; file plays back while analyzed).
  • 🎵 Live pitch — note, octave, frequency, and a color-coded cents-deviation tuning meter.
  • 🥁 Live tempo — estimated BPM with confidence indicator and beat pulse.
  • 📊 Rhythm timeline — onsets drawn against the estimated beat grid, colored by timing error.
  • 🏆 Top-3 worst offenders — most out of tune notes and most out of time onsets.
  • 📜 Note history table with per-note cents and ms timing error.
  • 🎚️ Adjustable A4 reference (default 440 Hz).

How it works

Concern Technique File
Pitch Autocorrelation + parabolic interpolation → nearest equal-temperament note + cents js/pitch.js
Onsets Spectral flux with adaptive peak-picking js/rhythm.js
Tempo Autocorrelation of the onset-strength envelope (50–210 BPM, octave-folded) js/rhythm.js
Timing Beat-grid phase fitting → per-onset error in ms js/rhythm.js
Audio graph & loop AnalyserNode polled per animation frame js/analyzer.js
UI Live readouts, canvas timeline, offender lists, history js/app.js

Running & testing

npm start   # http://localhost:5173 (localhost is a secure context, so mic works)
npm test    # Node unit tests for the DSP / music-theory math

The pure DSP functions are covered by 9 passing unit tests (note identification, cents deviation, autocorrelation pitch detection, tempo estimation, timing-error analysis).

Notes / limitations

  • Monophonic pitch tracking (single dominant pitch, not chords).
  • Tempo/timing sharpen after a few seconds of articulated playing.
  • Onset timing resolution is bounded by the animation-frame rate (~16 ms).

https://claude.ai/code/session_01Df9csCTPk457zYQLYJcWaV


Generated by Claude Code

silas-dsc added 11 commits May 29, 2026 21:51
Mobile-friendly, dependency-free web app using the Web Audio API:

- Microphone and audio-file input
- Autocorrelation pitch detection with cents deviation from perfect pitch
- Spectral-flux onset detection and onset-envelope autocorrelation for BPM
- Beat-grid fitting with per-onset timing error in ms
- Live note/cents/BPM readouts, rhythm timeline, note history
- Top-3 most out-of-tune notes and most out-of-time onsets
- Zero-dependency static dev server and Node unit tests for the DSP math

https://claude.ai/code/session_01Df9csCTPk457zYQLYJcWaV
If PORT is not set explicitly and the default port (5173) is busy, the
dev server now binds an OS-assigned free port instead of crashing. An
explicitly-requested PORT still errors clearly so the user's choice is
respected.

https://claude.ai/code/session_01Df9csCTPk457zYQLYJcWaV
The score draws each note on a treble/bass grand staff at its perfect
pitch and beat position (hollow target), with a colour-coded overlay
showing the actual performance offset left/right for early/late and
up/down for sharp/flat. Green/yellow/red encodes accuracy.

Adds independent pitch and rhythm strictness sliders that drive the
score colours, offender lists, history table and tuning meter via a new
pure tolerance module. New staff-position module maps MIDI notes to
diatonic grand-staff steps including sharps. Both are unit-tested.

https://claude.ai/code/session_01Df9csCTPk457zYQLYJcWaV
The piano roll shows pitch (vertical lanes with a keyboard gutter) vs.
time (scrolling). Each note draws a hollow target bar at its perfect
pitch lane and quantized beat, plus a colour-coded actual bar offset
left/right for early/late and up/down within the lane for sharp/flat
(one semitone = one lane). Black-key lanes are shaded and octaves are
labelled.

Removes the now-unused staff-position module and its tests; pitch is
mapped directly from MIDI. Strictness sliders and accuracy colours are
unchanged.

https://claude.ai/code/session_01Df9csCTPk457zYQLYJcWaV
- Note history now stores and renders the full session (not just the
  last 60), with row metadata for navigation.
- When the mic is stopped or a file ends, the piano roll can be scrolled
  and dragged back through the whole performance; the history table
  highlights and follows the visible window.
- Tap tempo via a button or the Enter key sets a manual BPM; min/max
  bounds constrain auto-detection and disambiguate octave errors.
- Clicking a "most out of tune/time" entry jumps to that note in the
  history (and centres it in the roll when paused).
- Tempo detection is smoothed with octave-folding inertia (smoothBpm)
  so it stays steady instead of flickering.

https://claude.ai/code/session_01Df9csCTPk457zYQLYJcWaV
- Capture the mic take (MediaRecorder -> decoded AudioBuffer); uploaded
  files are reused directly. After stopping, a playback transport
  appears.
- New Playback module plays the buffer with a continuous media-time
  position so the piano roll scrolls in sync and the history window
  follows. A unified transport slider doubles as review scrubber and
  playback seek; the roll can also be scrolled/dragged.
- Metronome click track locked to the detected/tapped beat grid
  (accented downbeats), toggle on/off.
- Variable playback speed 0.3x–2x in 0.1 steps; click and roll stay in
  sync via rate-rebased position tracking.
- beatGrid() finds the beat phase for the click; covered by tests.

https://claude.ai/code/session_01Df9csCTPk457zYQLYJcWaV
- Play back through an <audio> element so variable speed (0.3x–2x)
  preserves pitch instead of transposing it.
- Add a synthesized piano voice ("MIDI notes") for the detected notes,
  toggleable like the click track and scheduled against the audio clock.
- Add horizontal (time) and vertical (pitch) +/- zoom controls for the
  piano roll.
- Stop piano-roll wheel/drag/touch from scrolling the page
  (touch-action: none + preventDefault).
- Analyzer now exposes a playback URL + duration (object URLs, revoked
  on reset) instead of a decoded buffer.

https://claude.ai/code/session_01Df9csCTPk457zYQLYJcWaV
History sync used element.scrollIntoView(), which scrolls the whole
window — so any control click / redraw yanked the page down to the
history table. Scroll the history table's own container instead, leaving
the page scroll position untouched.

https://claude.ai/code/session_01Df9csCTPk457zYQLYJcWaV
When the piano roll is vertically zoomed in, the visible pitch window
now follows the pitch under the playhead (notes sounding at the current
time, else the nearest note) instead of staying centred on the global
range — so during playback and zoom the current notes stay on screen.
Falls back to the full range when not zoomed.

https://claude.ai/code/session_01Df9csCTPk457zYQLYJcWaV
Refactor the piano roll's vertical mapping to be centre-based with a
fractional centre, so the pitch-follow glides by sub-lane amounts
instead of jumping a whole semitone at a time. The centre eases toward
the playhead's pitch while playing/recording and snaps when paused so
zoom/seek still frame instantly.

https://claude.ai/code/session_01Df9csCTPk457zYQLYJcWaV
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant