from __future__ import annotations from adafruit_ticks import ticks_diff from .util import hsv_to_rgb class RGBEffect: keyboard: Keyboard prepared: list[Any] def __init__(self, keyboard: Keyboard): self.keyboard = keyboard def prepare(self): base = self.keyboard.modes["base"] self.prepared = [self.prepare_key(key) for key in base.keys] def prepare_key(self, key: Key) -> Any: pass def tick(self, ticks_ms: int): pass def get_color(self, i: int, key: Key): pass class ColorScale(RGBEffect): def prepare_key(self, key: Key): in_scale = self.keyboard.scale.is_in_scale(key.pitch) if in_scale: return (0.1, 0.9, 0.65) else: return (0.3, 0.8, 0.0) def get_color(self, i: int, key: Key): if key.pitch < 0 or key.pitch > 127: return 0 hue, sat, key_val = self.prepared[i] base = self.keyboard.modes["base"] extra = base.extra_notes.get(key.pitch) note_for_pitch = base.notes.get(key.pitch) note_for_pitch = note_for_pitch or base.notes_expiring.get(key.pitch) if extra: return hsv_to_rgb(hue, 1.0, 1.0) if key.note: value = 1.0 elif note_for_pitch: value = note_for_pitch.expiry * 0.3 else: hue = 0.7 value = 0.0 rest = 1.0 - key_val value = key_val + value * rest return hsv_to_rgb(hue, sat, value) class Rainbow(RGBEffect): hue_shift: float = 0.0 last_ticks_ms: int def tick(self, ticks_ms: int): if hasattr(self, "last_ticks_ms"): delta = ticks_diff(ticks_ms, self.last_ticks_ms) self.hue_shift = (self.hue_shift + delta / 1000 / 6) % 1 self.last_ticks_ms = ticks_ms def prepare(self): self.hue_shift = 0.0 super().prepare() def prepare_key(self, key: Key): return (0, 0.9, 1.0) def get_color(self, i: int, key: Key): if key.pitch < 0 or key.pitch > 127: return 0 x, y = key.pos hue, sat, val = self.prepared[i] hue += x / 50 + y / 40 + self.hue_shift return hsv_to_rgb(hue, sat, val) class RainbowScale(Rainbow): def prepare_key(self, key: Key): if self.keyboard.scale.is_in_scale(key.pitch): return (0, 0.9, 1) else: return (0, 0.75, 0.1) class RainbowScaleAlt(Rainbow): def prepare_key(self, key: Key): if self.keyboard.scale.is_in_scale(key.pitch): return (0, 0.9, 1) else: return (0.2, 0.9, 0.5) RGB_EFFECTS = { "scale": ColorScale, "rainbow": Rainbow, "rainbow scale": RainbowScale, "rainbow scale alt": RainbowScaleAlt, }