mirror of
https://github.com/9x/sheetmusictrainer.git
synced 2026-11-03 22:03:54 +01:00
Click behavior per pace: continuous in step, run-synced (incl. preview) in tempo
- 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.
This commit is contained in:
@@ -120,9 +120,12 @@ export function usePhraseTrainer(
|
|||||||
const setPhaseBoth = useCallback((p: PhrasePhase) => {
|
const setPhaseBoth = useCallback((p: PhrasePhase) => {
|
||||||
phaseRef.current = p;
|
phaseRef.current = p;
|
||||||
setPhase(p);
|
setPhase(p);
|
||||||
// Expose run state so the shared metronome can gate its click/pendulum:
|
// Gate the shared metronome only in 'sync to metronome' (tempo) pace:
|
||||||
// only running during count-in and playing, never idle/preview/paused.
|
// there the run owns the clock (clicks during count-in/playing only).
|
||||||
phraseRunBus.set(p === 'countIn' || p === 'playing');
|
// In 'at your pace' (step) the metronome ticks continuously when the
|
||||||
|
// user has it switched on — like the single-note modes.
|
||||||
|
const ownsClock = paceRef.current === 'tempo';
|
||||||
|
phraseRunBus.set(ownsClock && (p === 'countIn' || p === 'playing' || p === 'preview'));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => { paceRef.current = config.pace; }, [config.pace]);
|
useEffect(() => { paceRef.current = config.pace; }, [config.pace]);
|
||||||
@@ -493,6 +496,15 @@ export function usePhraseTrainer(
|
|||||||
if (!e.pitch) continue;
|
if (!e.pitch) continue;
|
||||||
audioEngine.scheduleNote(e.pitch.midi, t0 + (e.startTick / PPQ) * spb, (e.durationTicks / PPQ) * spb, vol, PREVIEW_GROUP);
|
audioEngine.scheduleNote(e.pitch.midi, t0 + (e.startTick / PPQ) * spb, (e.durationTicks / PPQ) * spb, vol, PREVIEW_GROUP);
|
||||||
}
|
}
|
||||||
|
// Tempo pace: click along with the preview so the rhythm is
|
||||||
|
// audible while listening (quarter beats over the full span).
|
||||||
|
if (paceRef.current === 'tempo' && configRef.current.clickSound) {
|
||||||
|
const totalTicks = events.reduce((a, e) => Math.max(a, e.startTick + e.durationTicks), 0);
|
||||||
|
const beats = Math.floor(totalTicks / PPQ);
|
||||||
|
for (let i = 0; i < beats; i++) {
|
||||||
|
audioEngine.playClickAt(t0 + i * spb, CLICK_VOLUME, i % 4 === 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
setPhaseBoth('preview');
|
setPhaseBoth('preview');
|
||||||
const totalSec = (events.reduce((a, e) => Math.max(a, e.startTick + e.durationTicks), 0) / PPQ) * spb;
|
const totalSec = (events.reduce((a, e) => Math.max(a, e.startTick + e.durationTicks), 0) / PPQ) * spb;
|
||||||
previewTimerRef.current = setTimeout(() => {
|
previewTimerRef.current = setTimeout(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user