A rhythm game for blues harmonica (diatonic and chromatic), built in Rust with the Bevy engine. Notes scroll toward a hit line and you play them on a real harmonica — Harmonicon listens to your microphone, detects the pitches you're playing in real time, and scores you on timing.
It ships with two render modes (a clean 2D lane view and a 3D view with an animated harmonica model), a free-play Jam Session mode over a 12-bar blues backing, a guided Lessons curriculum, a Bending Trainer, a full in-game song editor, a live audio spectrogram, and a small toolchain for turning MIDI files into playable charts.
Status: early/experimental (
0.1.0), tracking Bevy0.19.
- Play with a real harmonica. Microphone input is captured with
cpaland analysed in real time with a choice of five pitch-detection algorithms (FFT, YIN, pYIN, MPM, NMF — selectable in Options) to detect the notes you play and grade them asPERFECT/GOOD/ miss. - Two gameplay modes:
- 2D — falling notes, one lane per harmonica hole (sized from the chart's harmonica — 10-hole diatonic or chromatic), with a hit line, hole indicators, and a live score/combo HUD.
- 3D — the same gameplay rendered around a 3D harmonica model that grooves to the beat, with a configurable per-model hole layout.
- Jam Session — free play over a rolling 12-bar blues chart and metronome, with a live hole map that highlights chord tones and blues-scale notes per bar of the cycle. A song authored from a MIDI file with its tracks kept separate (rather than pre-mixed) shows a per-track mute row, so you can drop out a part and play it yourself.
- Lessons — a guided curriculum grouped into units, from first breath technique through bends, rhythm, and improvisation, gated by prerequisites and tracked per player; some open-ended lessons run as an unscored Jam Session judged on scale/chord-tone adherence or phrase discipline instead of hit notes.
- Adaptive difficulty — an optional per-song setting that starts a chart with only the first slice of each phrase live, unlocking more of it as you clear it cleanly, with a manual per-phrase override on the pause menu.
- Practice tools — A–B section looping (drag a range on the song-progress waveform while paused), practice speed (50–100%), wait-for-note mode (the chart holds at each note until you play it), and a harmonica tab readout of the current phrase.
- Bending Trainer — per-hole bend/overblow/overdraw drills with progress tracked across sessions.
- Scoring system — perfect/good/miss timing windows, combo multipliers with optional decay, a post-song results screen with hit statistics and one-click latency compensation, and persistent per-song best scores.
- Note techniques — charts can annotate notes with bends, overblows, overdraws, chromatic slides, vibrato, wah-wah, and holds, shown as on-note badges and a HUD legend.
- Live spectrogram — a built-in audio visualizer (bar spectrum and oscilloscope styles) driven by the same audio pipeline used for scoring.
- Audio options — microphone device picker with visible failure/retry, pitch-algorithm selection, latency calibration screen, and music/metronome volume sliders that affect playback live.
- Song editor — author charts in-game (diatonic and chromatic): place, drag, and resize notes on a piano-roll grid with a swing/triplet-aware snap mode, multi-select and copy/paste, undo/redo, a metronome with count-in, a real variable tempo map, live recording from your own playing, MIDI import (pick a track and drop its notes straight onto the grid), a practice mode that scores your mic input against the chart as you edit, and lesson authoring alongside plain songs.
- Localization — English, Portuguese (pt-BR), and Spanish (es-ES).
- Authoring tools —
hole-editorpositions the clickable holes on a 3D harmonica model.
- A recent Rust toolchain (Rust 2024 edition; use the latest stable via rustup).
- A working microphone to play along (the game still runs without one; you just won't be able to hit notes).
- Bevy's system dependencies for your platform — see Bevy's setup guide (on Linux you'll typically need ALSA/udev and graphics dev packages).
From the repository root:
# Play the game
cargo run
# Faster, smoother frame rate (still debuggable thanks to the dev profile tweaks)
cargo run --releaseThe dev profile builds your code at opt-level = 1 while compiling all
dependencies at opt-level = 3, so debug builds are already playable.
For local iteration, the dev feature dynamic-links Bevy and enables its dev
tools and the asset file watcher (never ship a build with it — the dynamic
linking needs Bevy's .so alongside the binary):
cargo run --features dev| Key | Action |
|---|---|
Esc |
Pause / resume (opens the pause menu) |
M |
Toggle the metronome click on/off |
V |
Cycle the spectrogram visualization style |
| Mouse | Navigate menus, drag the Options volume sliders |
You play notes by blowing and drawing on your harmonica — the detected pitch is matched against the note currently in the hit window.
- Launch the game and pick Play → Play Song, then choose a render mode (2D or 3D), an artist, and a song. (Or pick Jam Session for free play.)
- A short countdown runs, then the backing track starts and notes begin to scroll toward the hit line.
- Play each note on your harmonica as it reaches the line. Good timing keeps your combo and multiplier climbing; missed notes break the combo.
- When the song ends, a results screen summarizes your perfect/good/delayed/miss counts and final score.
The crate is split into a library (src/lib.rs) so the game binary and the
helper tools can share the same subsystems.
src/
main.rs # Game entry point: wires up plugins, mic capture, pitch loop
lib.rs # Library root, re-exports the subsystems below
menu/ # App states, menu pages, Options, latency calibration, guided tour
gameplay/ # Core gameplay
gameplay_2d.rs # 2D lane renderer
gameplay_3d.rs # 3D harmonica renderer
bending_trainer.rs # bend/overblow/overdraw drills
adaptive_difficulty.rs # per-phrase note unlocking
clock.rs # the gameplay clock (audio-anchored time authority)
results.rs # end-of-song results screen
*_overlay.rs # countdown, metronome, phrase, song-progress HUDs
jam/ # Jam Session: free-play mode, generated 12-bar backing,
# MIDI multi-track playback, improv/call-response practice
lessons/ # Guided curriculum: manifest parsing, catalog discovery,
# per-player progress
scoring.rs # Pure scoring math (timing windows, combo/multiplier),
# shared by gameplay and the song editor's practice mode
song_editor/ # In-game chart editor (grid, playback synth, practice,
# MIDI import, undo/redo)
audio_system/ # Microphone capture (cpal), pitch detection algorithms,
# the additive harmonica-voice synth
song/ # Chart format, harmonica layouts, MIDI parsing, asset loader
spectrogram/ # Audio visualizers (bars, oscilloscope)
dialogs/ # Shared UI widgets (buttons, tooltips, comboboxes, file dialogs)
assets_management/ # Font loading, song/theme/harmonica discovery
profile.rs # Persistent player progress (best scores, drills)
settings.rs # Persistent settings (figment-layered JSON)
localization.rs # Fluent localization plumbing
theme.rs # Visual theme config
note_bench.rs # Pitch-detection algorithm comparison logic
bin/
hole_editor.rs # 3D harmonica hole-layout editor
note_editor.rs # Visual editor for 2D note layouts
note_bench.rs # Pitch-detection algorithm benchmark runner
assets/
songs/<artist>/<song>/ # background/elements art, 2d/3d note layouts
song/ # the chart itself (*.harpchart) + either
# music.ogg/.wav or music.mid (per-track stems)
harmonicas/3d/<name>/ # harmonica.glb + holes.json (3D model + hole layout)
lessons/<unit>/<lesson>/ # lesson.json + its own chart, for the Lessons curriculum
themes/<name>/ # theme.json + art/sounds for the theme picker
locales/<locale>/ # Fluent translations (en-US, es-ES, pt-BR)
midi/ # source MIDI files for the Song Editor's import tool
sounds/ # metronome clicks
fonts/ shaders/ # UI fonts and WGSL shaders
song_schema.dtd.json # JSON schema charts are validated against
lesson_schema.dtd.json # JSON schema lessons are validated against
Each song lives under assets/songs/<artist>/<song>/ and is loaded as a single
SongManifest made of:
song/<name>.harpchart— a JSON chart describing tempo, the harmonica layout, and the timed track of notes (validated againstassets/song_schema.dtd.json) — any filename, not a fixed name.song/music.ogg(or.wav) — the backing track, orsong/music.midto keep a MIDI file's tracks separate instead of pre-mixed, so Jam Session can play and mute them individually.background.png/elements.png— per-song artwork.
Every one of these except the chart itself is optional — a song can ship with no art, no backing track, or no separate note layouts, and Harmonicon fills in a sensible default for whatever's missing.
A chart's track is a list of timed items, each with a duration and one or more
note events (hole + blow/draw + the expected pitch), optionally carrying
technique modifiers (bend, overblow, overdraw, slide, vibrato,
wah-wah, hold). Charts declare their harmonica (diatonic or chromatic — the
lane count and overlays adapt), and can also define a loop section and scoring
windows. Songs can also be loaded from ~/Harmonicon outside the bundled
assets.
# Edit the clickable hole positions for a 3D harmonica model
cargo run --bin hole-editorTo turn a MIDI file into a chart, use the in-game Song Editor's own MIDI
import instead: pick a .mid/.midi file, choose a track, and its notes
drop straight onto the grid, auto-mapped onto the best-fitting harp key —
reaching unavailable notes with a bend/slide where possible and snapping to
the nearest playable note otherwise.
The scripts/ directory contains the Python helpers used to generate the 3D
harmonica .glb models.
- Bevy 0.19 — ECS engine, rendering, UI, audio
- cpal — cross-platform microphone capture
- rustfft — FFT for pitch detection and the spectrogram
- serde / serde_json / jsonschema — chart parsing and validation
- midly — MIDI parsing for the Song Editor's import and per-track backing
cargo build # compile the library, game, and tools
cargo test # run the unit tests (scoring, timing, charts, …)
cargo clippy # keep clean
cargo run --features dev # local iteration (dynamic linking + asset watcher)
cargo run # playMIT 2.0