import array import math import pygame from styles.base import AlarmStyle # Time between beep retriggers; a short beep followed by this gap gives the # classic alarm-clock "beep ... beep ... beep". BEEP_INTERVAL = 0.5 def _make_beep_buffer( freq: int = 1000, duration: float = 0.15, rate: int = 44100 ) -> bytes: """Synthesize a short square-wave beep as signed-16-bit stereo PCM. Matches the mixer format used by wecker.setup() (rate, -16, 2 channels) so it feeds straight into ``pygame.mixer.Sound``. No audio file, no extra dep. """ n = int(rate * duration) buf = array.array("h") for i in range(n): v = 32767 if math.sin(2 * math.pi * freq * (i / rate)) >= 0 else -32767 buf.append(v) buf.append(v) # duplicate to stereo return buf.tobytes() _BEEP_BUFFER = _make_beep_buffer() class SimpleStyle(AlarmStyle): """Press the button once to stop. Rings with a repeating beep. This style plays no music file; it owns its tone via a synthesised square wave played through ``pygame.mixer.Sound``. """ def __init__(self, set_led, **kwargs): super().__init__(set_led, **kwargs) self._next_beep = 0.0 self._beep = None def start(self): # LED solid on so the button is findable in the dark. self.set_led(True) self._beep = pygame.mixer.Sound(_BEEP_BUFFER) def update(self, now, is_pressed): self.set_led(True) if now >= self._next_beep: self._beep.play() self._next_beep = now + BEEP_INTERVAL return not is_pressed # first press -> False -> stop if __name__ == "__main__": # Self-check: the timer beeps on the interval and a press stops it. # Bypasses start() (which needs the audio engine) by stubbing the beep. class _Beep: def __init__(self): self.plays = 0 def play(self): self.plays += 1 style = SimpleStyle(lambda on: None) style._beep = _Beep() assert style.update(0.0, False) is True assert style._beep.plays == 1 # first tick beeps assert style.update(0.4, False) is True # before interval -> no beep assert style._beep.plays == 1 assert style.update(0.5, False) is True # at interval -> beep assert style._beep.plays == 2 assert style.update(0.6, True) is False # press -> stop print("simple self-check ok")