refactor: styles own their ringing tone directly (Pattern C)
Drop the injected AlarmSound Protocol and the wecker.Sound class. Each style now owns its tone by using pygame directly; the runner owns only the audio engine lifecycle (mixer init/quit), button sampling, and cleanup. This is the seam for future styles that handle their own tone — a 'talk' style would just import pygame and play speech, with no shared interface to extend. - styles/base.py: AlarmStyle.__init__(set_led, music_file) + start() + update() - styles/blink.py: start() loads+plays music via pygame.mixer.music - styles/simple.py: owns its beep — synthesises a square-wave buffer in module (stdlib array+math) and plays it via pygame.mixer.Sound - wecker.py: setup() brings up the mixer only; run_alarm constructs the style and guards start() with a clean log+exit on failure Tests: a shared tests/conftest.py stubs RPi.GPIO/pygame in sys.modules before any SUT import (order-independent, removes duplicated inline mocking); the wecker mock_pygame fixture patches one fresh pygame mock into wecker + both style modules so assertions see the same calls. README: tone-ownership and plugin-contract updated.
This commit is contained in:
@@ -150,9 +150,9 @@ Each alarm has a **style** that decides how you turn it off. Set it per alarm vi
|
||||
| `simple` | A repeating, ordinary-alarm-clock **beep** (no music file needed). | Press the button once. The LED stays solid on so the button is findable in the dark. **Default for new alarms.** |
|
||||
| `blink` | A music file on an endless loop (from `--music-file` / `MUSIC_FILE` / the default track). | The memory-and-attention puzzle described in [How the Puzzle Works](#how-the-puzzle-works). |
|
||||
|
||||
**The style owns its ringing tone.** The runner hands each style an audio capability (`play_music(path)` and `play_beep()`); the style decides which to use and when. This is the seam for future styles that handle their own tone.
|
||||
**The style owns its ringing tone.** The runner brings up the audio engine (the pygame mixer) and hands each style the button + LED; the style then produces its own tone directly — `blink` plays a music file, `simple` synthesises a beep, a future `talk` style would play speech. Styles use pygame directly (it's the audio engine, not hardware); the runner still owns mixer init and cleanup. This direct ownership is the seam for future styles that handle their own tone.
|
||||
|
||||
Adding a style is a plugin-style drop-in: add a class under `styles/` implementing the `AlarmStyle` contract (`__init__(set_led, sound, music_file)` + `start()` + `update(now, is_pressed) -> bool`) and register one line in `styles/__init__.py`.
|
||||
Adding a style is a plugin-style drop-in: add a class under `styles/` implementing the `AlarmStyle` contract (`__init__(set_led, music_file)` + `start()` + `update(now, is_pressed) -> bool`) and register one line in `styles/__init__.py`.
|
||||
|
||||
**Backward compatibility:** existing cron entries created before this feature have no `--style` flag and keep running the `blink` puzzle, so an upgrade never silently changes an alarm. To switch an existing alarm to `simple`, re-save it with `setAlarm(id: ..., cronExpression: ..., style: "simple")`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user