From c9895df5124d192168c830aa8c22ca53b03714a3 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 25 May 2026 21:55:46 +1200 Subject: [PATCH] fix(presets): phase-lock blink and one tick on re-select Co-authored-by: Cursor --- src/presets.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/presets.py b/src/presets.py index 839f3ec..9c1011b 100644 --- a/src/presets.py +++ b/src/presets.py @@ -201,16 +201,13 @@ class Presets: self.fill((0, 0, 0)) self.selected = preset_name return True - # Manual single-shot patterns: if this select arrives before the main loop has - # tick()'d the previous frame, completing it first keeps step in sync with beats. + # If re-selecting the same preset before the main loop has tick()'d the + # previous frame, run one pending tick so step stays in sync. if ( preset_name == self.selected - and not preset.a - and preset.p in ("chase", "pulse") and self.generator is not None ): - while self.generator is not None: - self.tick() + self.tick() # Set step value if explicitly provided if step is not None: self.step = step @@ -274,11 +271,22 @@ class Presets: colors = preset.c if preset.c else [(255, 255, 255)] bg_color = self.apply_brightness(preset.background_or(colors), preset.b) color_index = 0 - state = True - last_update = utime.ticks_ms() + delay_ms = max(1, int(preset.d)) + period = delay_ms * 2 + now = utime.ticks_ms() + # Phase-lock to wall time so group identify (broadcast select) stays in sync even + # when devices process the packet on different main-loop iterations. + phase = now % period if period else 0 + state = phase < delay_ms + last_update = utime.ticks_add(now, -phase) + if state: + base = colors[color_index % len(colors)] + self.fill(self.apply_brightness(base, preset.b)) + color_index += 1 + else: + self.fill(bg_color) while True: now = utime.ticks_ms() - delay_ms = max(1, int(preset.d)) if utime.ticks_diff(now, last_update) >= delay_ms: if state: base = colors[color_index % len(colors)]