Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

notepat: kill the spacebar-toggle metronome silence gap

The metronome firing logic compares beatNumber !== metronomeBeatCount
to decide when to play a click. The toggle-on path was seeding
metronomeBeatCount to floor(now / msPerBeat) — exactly what beatNumber
will compute on the next sim tick — so the comparison was a no-op and
the first click only fired once wall-clock crossed the *next* beat
boundary. That gave you up to one full beat-interval of silence on
every toggle-on (~333 ms at 180 BPM, scaling with BPM).

Fix: seed to (floor(now / msPerBeat) - 1) so the very next sim tick
detects a new beat and fires the click on the press itself. The
metronome remains UTC-synced — subsequent clicks land on the same
global beat-grid as before.

Applied in four places in fedac/native/pieces/notepat.mjs (toggle,
dj-tap-derived BPM, BPM increment/decrement) and once in the system
copy (the spacebar toggle — the others use a different control flow
in the system version).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

+11 -6
+4 -4
fedac/native/pieces/notepat.mjs
··· 580 580 if (avg > 150 && avg < 2000) { 581 581 djDerivedBPM = Math.round(60000 / avg); 582 582 metronomeBPM = Math.max(20, Math.min(300, djDerivedBPM)); 583 - metronomeBeatCount = Math.floor(syncedNow() / (60000 / metronomeBPM)); 583 + metronomeBeatCount = Math.floor(syncedNow() / (60000 / metronomeBPM)) - 1; 584 584 djMsg(`${djDerivedBPM} bpm`); 585 585 } 586 586 } ··· 2688 2688 if (key === "f9") { 2689 2689 metronomeEnabled = !metronomeEnabled; 2690 2690 if (metronomeEnabled) { 2691 - metronomeBeatCount = Math.floor(syncedNow() / (60000 / metronomeBPM)); 2691 + metronomeBeatCount = Math.floor(syncedNow() / (60000 / metronomeBPM)) - 1; 2692 2692 } 2693 2693 return; 2694 2694 } ··· 2829 2829 } 2830 2830 if (key === "-") { 2831 2831 metronomeBPM = Math.max(20, metronomeBPM - 5); 2832 - metronomeBeatCount = Math.floor(syncedNow() / (60000 / metronomeBPM)); 2832 + metronomeBeatCount = Math.floor(syncedNow() / (60000 / metronomeBPM)) - 1; 2833 2833 return; 2834 2834 } 2835 2835 if (key === "=") { 2836 2836 metronomeBPM = Math.min(300, metronomeBPM + 5); 2837 - metronomeBeatCount = Math.floor(syncedNow() / (60000 / metronomeBPM)); 2837 + metronomeBeatCount = Math.floor(syncedNow() / (60000 / metronomeBPM)) - 1; 2838 2838 return; 2839 2839 } 2840 2840
+7 -2
system/public/aesthetic.computer/disks/notepat.mjs
··· 7280 7280 if (e.is("keyboard:down:space") && !e.repeat) { 7281 7281 metronomeEnabled = !metronomeEnabled; 7282 7282 if (metronomeEnabled) { 7283 - // Seed beat count to current beat so first tick doesn't fire immediately 7283 + // Seed beat count to (current beat - 1) so the very next sim 7284 + // tick computes a fresh beatNumber and fires the click on the 7285 + // press itself. Previously we seeded to the *current* beat, 7286 + // which made the comparison at line 1844 a no-op and forced a 7287 + // wait of up-to-one full beat-interval before the first click 7288 + // (~333ms of silence at 180 BPM, every toggle-on). 7284 7289 const now = metronomeClockRef?.time?.()?.getTime?.() ?? Date.now(); 7285 - metronomeBeatCount = Math.floor(now / (60000 / metronomeBPM)); 7290 + metronomeBeatCount = Math.floor(now / (60000 / metronomeBPM)) - 1; 7286 7291 } else { 7287 7292 metronomeVisualPhase = 0; 7288 7293 metronomeBallPos = 0;