useGameLogic's own scheduler and the footer widget's scheduler both
played audible clicks while rhythm.active — assist->learn-notes switch
made the second one mount. Now the widget is the single click source in
non-zen modes; useGameLogic's scheduler is a silent tick source for
auto-advance (full sound only in zen mode, where the widget isn't
rendered). Also: widget honors Timer mode (60/seconds) like the trainer,
and useMetronome skips audio nodes at volume 0.
- New phase 'previewPaused': pause stops scheduled audio but keeps the
preview cursor; resume continues from the cursor position.
- Step buttons (and arrow keys) are active ONLY while the preview is
paused; each step moves the cursor one event and plays that single
note as a find-it-on-the-neck cue.
- Preview indicator now follows playback in real time: a cursor
interval advances previewIdx by audio time (event start ticks), so
the notation caret moves with the sounding note — also while
paused at the stepped position.
- Main Start button shares the semantics: while previewing it shows
Pause/Resume and routes to the preview controls (exercise and
preview transport behave consistently).
- External pause (settings dialog, tab hide) during preview now keeps
the cursor (previewPaused) instead of dropping to ready.
- Transport restructured like a music player: Start/Pause, step
back/forward buttons (while previewing), Preview, Retry, Next.
- Virtual instrument and Hint moved out of the transport row into a
separate display-toggles row using switch-style toggles (same visual
language as tuner/metronome switches) — pure show/hide, no run state.
- Preview now tracks a cursor: the current preview event is marked in
the notation (caret + color via existing currentIdx pipeline).
- Preview stepping: pause-free stepping forward/backward one event at
a time; each step replays from the cursor position so notes can be
located on the fretboard. Arrow keys ←/→ work while previewing.
- With Hint active, the fretboard/piano marks the preview cursor note
(displayIdx follows the preview cursor).
- previewIdx resets on structural changes and when the preview ends.
New game mode 'assist' — no trainer, no scoring:
- Large display of the currently mic-detected note
- Live notation staff (same pipeline as the pitch monitor)
- Live fretboard showing alternative positions for the played note
(respects the fret-window practice filter)
- Tuner and Metronome remain the shared footer tools, identical in
all modes; user can practice own-pace from paper with a free
metronome
Header mode toggle gains 'Assist'; 'm' shortcut cycles back to sight
reading from assist/phrase. Export PitchData type.
- Pace dropdown REMOVED from Phrase setup — replaced by a 'Sync to
exercise' checkbox in the Metronome widget (analog to 'Auto' in
single-note modes). pace is derived from the checkbox (checked = tempo,
unchecked = step).
- Preview clicks now registered in PREVIEW_GROUP: stopping/abandoning a
preview cancels its scheduled clicks — no more parallel ghost
metronomes after preview->stop->next exercise.
- Chord pool replaces the chord dropdown entirely (single chord AND
sequences): togglable degree list, empty = all 7.
- Giuliani figures corrected to NOTE sequences (p always takes the bass/
root): p-i-m, p-i-m-a, p-a-m-i, a-i-m, p-i-m-a-m-i, p-m-a-m-i-m,
p-e-a-m-a-m (replaced the fingering-driven patterns that made no
musical sense).
- 'Limit notes' is now one bordered section like Tuner/Metronome, with a
header, Clear-all link, and Strings behind a toggle (row hidden until
restricted).
- MetronomeWidget: the Phrase Mode switch now lives IN the widget as a
Free/Sync toggle. Free = independent metronome (own clock, starts when
toggled, with or without clicks). Sync = silent while idle, starts with
the exercise (count-in included), pendulum mirrors the run's beats.
- Fixed double phraseBeatBus.emit (leftover from an earlier edit) that
flipped the pendulum twice per beat — animation appeared frozen.
- Click decision unified: one sound checkbox governs both the widget and
(in sync mode) the run's click scheduler. 'Click 1 after count-in' is
musically the last count-in click (suppressed duplicate) — now with a
working pendulum the offset is visible rather than confusing.
- Giuliani figures extended: p-i-m-a-m-i, p-a-p-i-m-a, a-m-i-p-i-m,
m-i-a-m-i-m (six-note rolling/bass-skip/tremolo-adjacent figures).
- Arpeggio chord pool: togglable degree list (empty = all 7); functional
and random progressions honor the pool; first bar draws a random chord
from the pool.
- Tests 174/174.
- Sequence mode: bars (2/4/6/8) with one chord per bar, chosen by
functional rules (I->IV/V/vi...), diatonic cycle, or random (no immediate
repeats); deterministic via melody seed. Chord symbols per bar in the
score model (chordSymbols) rendered above the staff via setSection.
- Rhythm: quarters or eighths (cycling up/down through the pattern).
- Single-chord mode unchanged (whole path, overflow bars if needed).
- Auto-start: 'Start on first note (no count-in)' — step pace begins the
run as soon as the mic detects the first note; no start press needed.
- 'New' button re-rolls the progression (new seed).
- Tests 174/174.
- Step pace ('at your pace'): metronome ticks continuously when the user
switches it on — phraseRunBus gate no longer applies (clock stays free).
- Tempo pace ('sync to metronome'): gate now covers preview too; preview
schedules quarter-note clicks along with the notes (accented each bar)
so the rhythm is audible while listening.
- Phrase Mode (sync to metronome): the run's scheduler is the single click
source (with count-in); the metronome widget is muted and its pendulum
mirrors the run's beats via the new phraseBeatBus (audio-timestamp
scheduled). No more double clicks; clicks only while the run is active
(phraseRunBus gates the widget's own ticking).
- Schedule entries now carry continuous beat index + accent flag (downbeats
accented, count-in beat 1 accented).
- 'At your pace': optional click via the metronome toggle (kept explicit).
- Metronome widget: gate prop; in gated mode it listens to the beat bus
instead of running its own scheduler.
- Strings filter: per-string toggle buttons (replaces fret-window-only
semantics as a third 'limits notes' control); combines with fret window
and key filter in targetPool (fretted instruments).
- Key sync checkbox: display key signature can follow the target key
(major/minor mapping), default off — both remain independently settable.
- LiveNoteStaff: optional fixed clef — guitar/bass now keep their usual
clef instead of flipping at middle C; octave markers handle range.
- Unified metronome widget (MetronomeWidget) with animated linear pendulum
synced to the audible click; shown in ALL modes next to the tuner.
Phrase BPM now reads from settings.rhythm.bpm (single source); the
phrase-local BPM control was removed from the setup panel.
- Tests: 160/160; tsc + eslint clean; build ok.
- New shared PracticeFilter settings (keyTonic/keyMode/fretWindow), persisted
via AppSettings.practice, defaults off (behavior unchanged).
- music/targetPool.ts: single source for the effective target pool —
base playable range ∩ fret window ∩ key/mode pitch classes (9 modes incl.
pentatonic, same scale machinery as Phrase Mode).
- useGameLogic now builds validNotes via computeTargetPool.
- TargetNoteControls component (key on/off + tonic/mode, fret window on/off +
min/max) rendered in Controls for all game modes; key is independent of the
displayed key signature.
- Phrase Mode binds its key/fret-window setup to the same shared filter
(read/write mirror) and drops the duplicate controls in its setup panel.
- Tests: targetPool.test.ts (7 cases); suite 156/156 green, build ok.
- Pick detector per instrument range: ACF2PLUS (robust down to ~40 Hz) for
normal instruments, YIN only for the whistle register. pitchfinder's YIN
latches onto tau=2 (~20 kHz garbage) below ~100 Hz and for quiet input;
the old fixed 4096 window masked this, the smaller window exposed it.
- RMS-normalize analysis input for the YIN path only; ACF2PLUS keeps the raw
signal so its internal unpitched gate rejects quiet decayed audio instead
of amplifying noise into confident wrong pitches (tuner stuck on 'a note').
- Adaptive analysis window sized to the instrument's lowest note (~2 periods):
half the latency, a quarter of the CPU for guitar/piano/voice; bass keeps
the full window for E1.
- Reject detections implausibly below the instrument floor (mains hum).
- Clear stale pitch readings after 200 ms instead of keeping them forever.
- Shared AudioEngine singleton for all playback (was: two AudioContexts);
tracks audibility so the app stops hearing its own speaker (ear-training
self-scoring) and gates matching plus display during playback.
- MatchTracker: grace-period based note hold instead of reset-on-every-flicker
(YIN flickers during attacks/decays; the old hard reset made the 50 ms
threshold fire unreliably).
- Display damping in the producer (EMA for cents/level, 3-frame note-name
hysteresis); display components render directly without CSS transitions.
- Regression tests: synthetic signals through the exact pipeline helpers
(MatchTracker + pitchDetection test suites).