mirror of
https://github.com/9x/sheetmusictrainer.git
synced 2026-11-03 22:03:54 +01:00
- 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.
22 lines
794 B
TypeScript
22 lines
794 B
TypeScript
/**
|
|
* Beat clock shared between the phrase trainer's scheduler and the global
|
|
* metronome widget. The phrase run emits every beat (count-in + score beats)
|
|
* here; the metronome widget mirrors them on its pendulum so the visual
|
|
* stays in sync with the audible phrase click. Beats carry an absolute
|
|
* AudioContext timestamp so the widget can schedule the visual swing at the
|
|
* right moment even when callbacks fire ahead of time.
|
|
*/
|
|
type BeatListener = (beat: number, at: number) => void;
|
|
|
|
const listeners = new Set<BeatListener>();
|
|
|
|
export const phraseBeatBus = {
|
|
emit(beat: number, at: number): void {
|
|
listeners.forEach(l => l(beat, at));
|
|
},
|
|
subscribe(l: BeatListener): () => void {
|
|
listeners.add(l);
|
|
return () => { listeners.delete(l); };
|
|
},
|
|
};
|