Current GitHub tag: v0.1.4
Guitar Helio is a guitar trainer with:
- A Start Screen with song catalog,
MIDI/MP3/OGGimport, tuner, and session settings. - A Play Scene with simplified target notes, beat-gated progression, scoring, and timeline minimap.
- A Hybrid playback mode: uses backing audio (
mp3/wav/ogg) when available, otherwise falls back to MIDI synth playback. - Local persistence: best score per song plus saved difficulty/string/finger/fret settings.
- Structural map of the codebase and file search guide:
REPO_STRUCTURE.md
npm run install:linux-android # install dipendenze per server Linux + Android flow
npm run install:windows # install dipendenze in ambiente Windows (include fix Rollup Win-only)
npm run dev # local web development
npm run dev:mobile # LAN development (phone on the same network)
npm run build # typecheck + production build
npm run preview # preview production build
npm run desktop:start # run desktop app via Electron (local)
npm run build:windows # build Windows installer (.exe) + portable package
npm run build:windows:clean # force clean locked win-unpacked folder, then build Windows artifacts
npm run test # unit tests (Vitest)
npm run lint # TypeScript typecheck without emit
npm run pitch:offline:manifest # generate offline benchmark session manifest
npm run pitch:offline:infer-manifest # infer manifest timings directly from a WAV take
npm run pitch:offline:bench # run offline pitch benchmark (pass --manifest/--wav/--out args)- Workflow and scripts are documented in
tools/pitch-offline-bench/README.md.
- Host-side Rust runtime workflow (architecture split, build/run/test/benchmark):
docs/FRETNET_HOST_RUNTIME.md
- Convenience npm scripts:
npm run fretnet:host:run -- --helpnpm run fretnet:host:testnpm run fretnet:host:bench -- --help
GuitarHelio uses a custom candidate-guided spectral harmonic detector for gameplay:
spectral_game_runtime_unified_v3.
Benchmark and tuning reference:
- README.md (
tools/pitch-agent-lab) tools/pitch-agent-lab/config/candidates.spectral.game-runtime.baseline.toml
Runtime integration points:
- Preset wiring in
src/audio/pitchWorklet.jsandsrc/audio/pitchDetector.ts. - Gameplay usage in
src/ui/play/controllers/PlaybackController.ts. - Practice usage in
src/ui/PracticeScene.ts. - Candidate model generation in
src/audio/spectralRuntimeModel.ts. - DSP implementation in
tools/gh_dsp_core/src/lib.rs(PitchDetectorPreset::SpectralGameRuntimeUnifiedV3).
Processing pipeline (runtime):
- Mic/reference alignment + NLMS echo suppression produce a residual analysis buffer.
- Residual audio is windowed (Hann), transformed with FFT, and converted to a magnitude spectrum.
- Optional spectral shaping is applied (magnitude compression + local whitening).
- For each candidate note, harmonic-band energy is accumulated across partials (weighted by harmonic order).
- Best note (
midi_estimate) is selected and confidence is computed from contrast + energy terms. - Optional polyphonic candidates are selected with harmonic suppression/deduplication.
- Chord-level scores are computed from candidate note scores.
Runtime outputs used by gameplay logic:
midi_estimate,confidencebest_note_id,detected_string,detected_fretselected_notes[],chord_scores[]
Model behavior:
- The detector is candidate-guided: it only scores notes/chords present in the runtime spectral model.
- In songs, the model is built from chart targets (
buildSpectralRuntimeModelFromTargets). - In free practice, the model is generated from the full guitar fretboard range (
buildPracticeSpectralRuntimeModel).
Direct npm packages used by this repository.
| Package | Role | Official reference |
|---|---|---|
@capacitor/core |
Capacitor runtime bridge | https://capacitorjs.com/docs |
@capacitor/filesystem |
Cross-platform file persistence APIs | https://capacitorjs.com/docs/apis/filesystem |
@fontsource/montserrat |
Embedded Montserrat font files | https://fontsource.org/fonts/montserrat |
@tonejs/midi |
MIDI parsing/writing utilities | https://github.com/Tonejs/Midi |
audio-decode |
Browser/Node audio decode helper | https://github.com/audiojs/audio-decode |
jzz |
MIDI I/O and routing toolkit | https://jazz-soft.net/doc/JZZ/ |
jzz-synth-tiny |
Tiny synth used for MIDI playback | https://github.com/jazz-soft/JZZ-synth-Tiny |
phaser |
2D game framework used for UI/gameplay scenes | https://docs.phaser.io/ |
vite |
Dev server, production bundler, and embedded preview runtime for desktop packaging | https://vite.dev/guide/ |
| Package | Role | Official reference |
|---|---|---|
@capacitor/android |
Android platform package for Capacitor | https://capacitorjs.com/docs/android |
@capacitor/cli |
Capacitor CLI tooling | https://capacitorjs.com/docs/cli |
electron |
Desktop runtime wrapper for packaged Windows builds | https://www.electronjs.org/docs/latest |
electron-builder |
Windows installer/portable package generation | https://www.electron.build/ |
typescript |
TypeScript compiler and type system | https://www.typescriptlang.org/docs/ |
vitest |
Unit test runner | https://vitest.dev/guide/ |
| Package | Role | Official reference |
|---|---|---|
@tonejs/midi |
MIDI generation in converter workflow | https://github.com/Tonejs/Midi |
audio-decode |
Audio decoding in converter workflow | https://github.com/audiojs/audio-decode |
| Dependency | Role | Official reference |
|---|---|---|
AUDIO-to-MIDI workflow |
End-to-end audio-to-MIDI conversion workflow integrated in this repo | https://github.com/markod0925/AUDIO-to-MIDI |
TempoCNN |
Tempo estimation model/runtime used to enrich MIDI tempo metadata | https://github.com/hendriks73/tempo-cnn |
NeuralNote |
Core note transcription backend used by the native converter pipeline | https://github.com/tiborvass/NeuralNote |
- Install Node.js 22+ on your computer.
- Install dependencies:
npm install
- Build the C++/ONNX converters (NeuralNote + Tempo-CNN):
npm run build:nn:cli npm run build:tempo:cli
- Start LAN mode:
npm run dev:mobile
- Open the URL shown as
Networkfrom your phone (same Wi-Fi), for example:http://192.168.1.10:5173
EscorBackkey (mobile): open/close the pause menu (Continue,Reset,Back to Start).- Bottom-left pause button: pause/resume gameplay directly without opening the menu.
- Top speed slider:
25%->125%(default100%), synchronized with timeline and backing audio. Debug Notebutton: play the current target note.F3(debug/dev): toggle central diagnostics overlay.
The project uses a vendored C++/ONNX pipeline in:
third_party/neuralnote_core(note transcription)third_party/tempocnn_core(ONNX tempo estimation)third_party/tempo_cnn/tempocnn/models/fcn.onnx(Tempo-CNN model)third_party/onnxruntime/<platform>/lib(shared ONNX runtime)
Node wrapper used by the Vite API:
tools/audio-midi-converter/src/neuralnote.mjs
Mode compatibility:
legacyandneuralnoteare aliases of the same C++/ONNX backend.abis disabled (explicit error on server/native side).
Active preset: balanced.
Yes, this is supported. The project is ready for Capacitor packaging.
- Capacitor dependencies in
package.json(@capacitor/core,@capacitor/cli,@capacitor/android,@capacitor/filesystem). capacitor.config.tswith:appId: com.guitarhelio.appappName: GuitarHeliowebDir: dist
- Dedicated npm scripts for init/sync/open Android Studio/debug APK build.
NeuralNoteConverterCapacitor plugin (Java + JNI C++) for native audio import with NeuralNote + Tempo-CNN.- NeuralNote model files included in Android assets (
android/app/src/main/assets/neuralnote-model/). - Tempo-CNN model included in Android assets (
android/app/src/main/assets/tempo-model/fcn.onnx).
- Install dependencies:
npm install
- Build the web app:
npm run build
- Add the Android platform:
npm run cap:add:android
- Sync web assets into the Android project:
npm run cap:sync
- Open Android Studio:
npm run cap:open:android
Note: Android build requires NDK/CMake toolchains installed in Android Studio to compile the converter JNI bridge.
npm run android:apk:debugExpected APK location:
android/app/build/outputs/apk/debug/app-debug.apk
The app uses the microphone, so Android must include RECORD_AUDIO in:
android/app/src/main/AndroidManifest.xml
Expected snippet:
<uses-permission android:name="android.permission.RECORD_AUDIO" />The permission must also be requested at runtime (Capacitor/Android) before pitch detection starts.
The project can be packaged as a Windows desktop app via Electron.
npm install
npm run build:windowsArtifacts are generated in:
release/
Expected outputs:
- NSIS installer (
.exe) - Portable executable (
.exe)
Notes:
- The desktop app runs an embedded local preview server internally (no manual terminal server required).
- Runtime imported songs are stored in the Electron user-data folder (
.../AppData/Roaming/GuitarHelio/songs) instead of the installation directory. - If
electron-builderreports "Access is denied" while removingrelease/win-unpacked/*, runnpm run build:windows:clean.
- GDD implementation compliance checklist:
IMPLEMENTATION_QA_CHECKLIST.md - Runtime manual test suite (Desktop + Android):
MANUAL_QA_RUNTIME_SUITE.md - Automated tests:
npm run test - Full build verification:
npm run build
Minimum prerequisites:
Node.js 22+- Local C++ toolchain (
cmake,g++,make) for NeuralNote/Tempo-CNN CLIs - Android SDK/NDK installed (for APK build)
- JDK 17 active for Gradle/Capacitor Android
Server checklist (Node wrapper + C++/ONNX CLI):
- Build C++ converters:
npm run build:nn:cli npm run build:tempo:cli
- Verify binaries:
ls -la third_party/neuralnote_core/bin/nn_transcriber_cli ls -la third_party/tempocnn_core/bin/tempo_cnn_cli
- Run quick conversion on an audio file:
node tools/audio-midi-converter/bin/convert-audio-to-midi.mjs --input /path/to/audio.wav --output /tmp/smoke.mid
- Expected result:
- progress output reaches
Conversion complete /tmp/smoke.midis created and non-empty- tempo metadata exists in MIDI (base tempo + tempo map when available)
- progress output reaches
Native Android checklist (Capacitor plugin + JNI):
- Build web + sync:
npm run build npm run cap:sync
- Build debug APK:
npm run android:apk:debug
- Expected result:
BUILD SUCCESSFUL- APK exists at
android/app/build/outputs/apk/debug/app-debug.apk
- Functional smoke test on device/emulator:
- open app and go to
Import MP3/OGG - import a short audio file (5-15s)
- verify progress reaches
Conversion complete - verify a new song with usable
song.midappears in gameplay catalog
- open app and go to
Each song lives in a dedicated folder under public/songs/<song-id>/.
Manifest data structure (public/songs/manifest.json):
{
"songs": [
{
"id": "example",
"name": "Example Song",
"folder": "example",
"cover": "cover.svg",
"midi": "song.mid",
"audio": "song.mp3"
}
]
}Fallback rules:
- If
midiis missing in manifest: the song is not shown in Start Screen. - If
midiexists but file is unreachable: session start fails with explicit error, without blocking Start Screen. - If
coveris missing/invalid: usespublic/ui/song-cover-placeholder-neon.png. - If
audiois missing/invalid: uses MIDI as audio reference. - In gameplay: if
audiopoints to a valid WAV/MP3/OGG, it is used as backing track; otherwise MIDI playback is used.
Web startup policy:
- Start Screen is shown immediately (without waiting for full asset validation).
- Song list updates in background.
- Covers are lazy-loaded (visible first, then the rest).
The Start Screen includes an Import MIDI/MP3/OGG button.
Flow:
- select a
.mid/.midior.mp3/.oggfile - a song folder is created using the filename (without extension)
- for MP3/OGG input: original audio is saved as
song.mp3orsong.ogg - for MP3/OGG input: audio -> MIDI conversion starts with progress bar
- for MIDI input: file is saved directly as
song.mid(no audio conversion) - for MP3/OGG input: if embedded cover art exists in metadata, it is extracted and saved as
cover.* - song catalog is updated and Start Screen list reloads automatically
Persistence by platform:
- Web/Vite dev/preview: files and manifest are written to
public/songs/(public/songs/manifest.json). - Android standalone (Capacitor): files and manifest are stored in app storage (
Directory.Data/songs/manifest.json) via@capacitor/filesystem.
Import source debug selector:
- In debug/dev builds, the
Import Sourceselector (Auto,Server,Native) is visible below the import button. Autouses the correct path by platform (server on web, native on Capacitor).- On Capacitor Android native import, debug file-log instrumentation is available but disabled by default (
IMPORT_DEBUG_LOG_ENABLED = falsein TS + Android plugin). - When debug logging is re-enabled, a persistent debug file log is written during conversion:
- primary path:
<external-files>/import-debug/song-import-debug.log - fallback path:
<internal-files>/import-debug/song-import-debug.log - file contains JS pre-native checkpoints (
decode/downmix/resample/base64/temp-write) plus native stage transitions. - file also contains watchdog heartbeats, resolved input/model paths, and full stack traces on failure.
- primary path:
- Start Screen includes a native-only
Share Logaction next to import controls when debug logging is enabled:- opens Android share sheet (
ACTION_SEND) to share the latest import debug log - Quick Share can be selected directly from the standard Android chooser
- fallback order:
song-import-debug.log->song-import-debug.prev.log
- opens Android share sheet (
To measure catalog startup cost:
npm run perf:startupUseful options:
node scripts/benchmark-startup.mjs --mode current --repeat 20
node scripts/benchmark-startup.mjs --mode optimized --repeat 20
node scripts/benchmark-startup.mjs --mode both --manifest public/songs/manifest.json --repeat 30Output:
- console summary with
avg/p50/p95/max - full JSON saved at
/tmp/guitarhelio-startup-benchmark.json
- Fret labels in gameplay use pooling (object reuse) to avoid per-frame creation/destruction.
- HUD score and streak are updated incrementally on scoring events, reducing work in the runtime loop.
- Pause menu actions are clickable both on button and text (desktop/touch).
- Native import/conversion features (NeuralNote + Tempo-CNN, native song catalog, native high-score persistence) are loaded on-demand via
import()only when needed from Start Screen or at end of session.
- Vite warning
Some chunks are larger than 500 kBflags any chunk above threshold, including lazy chunks, not only the initial bootstrap. - In the current build, a large core chunk remains (Phaser runtime + gameplay/audio required by app).
- The previously very large lazy chunk tied to WASM audio decoders is no longer in the frontend bundle: decoding now uses runtime-native WebAudio.
- This repository includes MP3 files generated with Suno.
- Suno-generated MP3 assets in this repository are provided for development/testing context and are not licensed for commercial use.