# lightcontrol Rust tooling for the **c-base mainhall** lighting rig. One TUI for animated presets driving the whole hall via `dmxbackend`, plus two focused one-shot binaries for the wall panels and the SonicPulse LED bars. Talks to: - **dmxbackend** at `dmx.cbrp3.c-base.org:8000` (REST + WebSocket) for the 48 DMX-routed fixtures. - **matelight** at `matelight.cbrp3.c-base.org:8081` (`/monitor` WS, subprotocol `matemon`) for live pixel sync of the hall lights to whatever is playing on the Mate-crate display. - **ArtNet** node at `10.0.0.146:6454` (default) for the Stairville SonicPulse LED bars that aren't on `dmxbackend`. The local microphone, optionally, for beat-driven scenes. --- ## Quick start ```bash # prerequisites (Fedora): sudo dnf install rustup alsa-lib-devel pkgconf-pkg-config rustup-init -y && source "$HOME/.cargo/env" # build everything cargo build --release # fire up the TUI against the live rig ./target/release/lightcontrol ``` On Debian/Ubuntu the equivalent of `alsa-lib-devel` is `libasound2-dev`. If you don't want microphone support and can't or won't install ALSA dev libs, see [No-mic build](#no-mic-build) below. --- ## Build The default build enables the `mic` cargo feature, which pulls in [`cpal`](https://crates.io/crates/cpal) and through it the system ALSA library. The TUI's beat-detector and the `BeatPulse` preset rely on it. ```bash cargo build --release # default: TUI + panels + bars + mic ``` ### No-mic build ```bash cargo build --release --no-default-features ``` Identical behaviour except the BeatPulse preset shows a slow cyan "waiting for mic" heartbeat instead of reacting to audio. Useful on build hosts that don't have ALSA dev headers, or on machines with no audio input. ### Quick checks ```bash cargo test # unit tests for presets + detector cargo clippy --all-targets -- -D warnings ``` --- ## Binaries ### `lightcontrol` — main TUI Animated presets driving every fixture in the mainhall through `dmxbackend`'s `/api/v1/websocket_state/` at 25 fps. ```bash ./target/release/lightcontrol # interactive TUI ./target/release/lightcontrol --preset rainbows # launch straight in ./target/release/lightcontrol --check # dump fixture list ./target/release/lightcontrol --host dmx.example:8000 # different backend ./target/release/lightcontrol --matelight ws://.../monitor # custom mate ``` Environment variables: - `DMX_HOST` — overrides `--host` - `MATELIGHT_URL` — overrides `--matelight` The TUI shows a header (host, fixture count, FPS, matelight + mic status), a live **beat detector panel** (flash bar + BPM + envelope sparkline), and the preset list with the active preset highlighted. #### Keys | Key | Preset | |-----|--------| | `1` | Rainbows | | `2` | Blue House | | `3` | 70th Disco | | `4` | Jungle | | `5` | Lasertec | | `6` | Police | | `7` | Mirror Ball (blue fade) | | `8` | Morning Light (sunrise) | | `9` | Orange/Green Mirror Ball | | `m` | Matelight Sync (live) | | `s` | Gabba Strobe (white, fast) | | `r` | Red Strobe (fast) | | `L` | Blue Strobe (fast) — capital L; `b` is blackout | | `p` | Pink Strobe (fast) | | `k` | Beat Pulse (mic-driven) | | `0` / `b` | Blackout | | `↑` / `↓` + `Enter` | Navigate list | | `q` / `Esc` / `Ctrl-C` | Quit | #### `--preset` CLI aliases Lower-cased and matched verbatim — useful for shell scripting / OBS integration: | Preset | Aliases | |--------|---------| | Rainbows | `rainbow`, `rainbows`, `1` | | Blue House | `blue`, `bluehouse`, `blue-house`, `2` | | 70th Disco | `disco`, `disco70`, `70th`, `70th-disco`, `3` | | Jungle | `jungle`, `4` | | Lasertec | `lasertec`, `laser`, `5` | | Police | `police`, `polizei`, `6` | | Mirror Ball | `mirror`, `mirrorball`, `mirror-ball`, `discoball`, `kugel`, `7` | | Morning Light | `morning`, `sunrise`, `dawn`, `sonnenaufgang`, `morgen`, `8` | | Orange/Green Ball | `orangegreen`, `orange-green`, `orange`, `green`, `kürbis`, `9` | | Matelight Sync | `matelight`, `mate`, `sync`, `m` | | Gabba Strobe | `gabba`, `strobe`, `strobo`, `stroboscope`, `s` | | Red Strobe | `red`, `rot`, `redstrobe`, `r` | | Blue Strobe | `blau`, `bluestrobe`, `blue-strobe`, `l` | | Pink Strobe | `pink`, `magenta`, `pinkstrobe`, `p` | | Beat Pulse | `beat`, `beatpulse`, `kick`, `mic`, `audio`, `k` | | Blackout | `off`, `blackout`, `0` | #### Beat detector panel ``` ┌─ beat detector ────────────────┬─ envelope (last ~4 s) ─────────────────┐ │ BEAT █████████████ │ ▂▃▆▇▆▃▁▂▇▆▃▁▂▇▆▃▁▂▃▆▇▆▃▁▂▇▆▃▁▂▇▆▃▁▂ │ │ level ████████████░░░░░░░░ │ │ │ 128.4 BPM beats=47 last 0.08s ago │ │ └────────────────────────────────┴────────────────────────────────────────┘ ``` The flash bar fires on every detected beat in the current per-beat hue palette. The level bar is the live short-window envelope. The sparkline plots the last ~4 seconds of envelope at 20 Hz, scaled with a ×2.5 boost so quiet rooms still show shape. **Pre-show diagnostic:** put on the playlist, look at the panel. Solid BPM + regular flashes → detector locked. No flashes → mic not picking up, check `pavucontrol` recording tab. Constant strobing → too much noise, raise `MIN_DELTA` in `src/beat.rs` (default `0.020`, try `0.035`). ### `panels` — Showtec PAR 56 wall panels (one-shot) Hits the `LED Par 56` fixtures via `dmxbackend`'s WebSocket, sends one frame, exits. Useful for setup checks or quick scene calls from a script. ```bash ./target/release/panels --color red # red wash ./target/release/panels --color "#1a3f8f" --dim 180 # custom hex + dimmer ./target/release/panels --color off # blackout ./target/release/panels --dry-run --color magenta # print, don't send ``` Colors: `red`, `green`, `blue`, `white`, `yellow`, `orange`, `magenta`, `cyan`, `off`, or any `#RRGGBB`. ### `bars` — Stairville SonicPulse LED Bar 10 (ArtNet direct) The bars aren't routed through `dmxbackend`, so this one talks ArtNet UDP directly to the node at `10.0.0.146:6454` (4 bars × 39 channels = 156 channels in universe 2). ```bash ./target/release/bars --color magenta # paint all 4 bars ./target/release/bars --color "#ff5500" --dim 200 ./target/release/bars --poll # ArtPoll discovery ./target/release/bars --sweep 0-15 # walk universes 0-15 to find them ./target/release/bars --broadcast --color blue # broadcast if unicast fails ./target/release/bars --dry-run --color red # print the packet, don't send ``` If `--color` does nothing visible: try `--poll` first to confirm the node is on the LAN, then `--sweep` to find which universe the bars actually listen on. The factory default is 0; many nodes are set to different universes per harness. --- ## Architecture ``` ┌──────────────────────────┐ │ c-base mainhall lights │ └──────────────────────────┘ ▲ ▲ DMX over │ │ ArtNet (UDP/6454) │ │ → 10.0.0.146 → 4 SonicPulse bars │ │ ┌────────────────────┴──┐ │ │ dmxbackend (aiohttp) │ │ │ dmx.cbrp3:8000 │ │ │ REST /api/v1/... │ │ │ WS /api/v1/ │ │ │ websocket_state │ │ └────────┬──────────────┘ │ │ │ ┌────────┴────────────────┴──┐ │ lightcontrol (this repo) │ │ │ │ ┌─────────┐ ┌─────────┐ │ ws://matelight:8081 │ │ engine │ │ matelight ─────────────/monitor (matemon) │ │ (presets│ │ feeder │ │ binary RGB frames → │ │ @25fps)│ │ │ │ drive hall via sample │ └────┬────┘ └─────────┘ │ │ │ │ local microphone (cpal) │ │ ┌─────────┐ │ ←─────────────────────── │ ├──────┤ beat │ │ energy-onset detector │ │ │ detector│ │ → BeatPulse preset │ │ └─────────┘ │ │ ▼ │ │ binaries: │ │ lightcontrol (TUI) │ │ panels (one-shot) │ │ bars (ArtNet, ad-hoc) │ └────────────────────────────┘ ``` Source layout: - `src/lib.rs` — shared types (Fixture/Element/Channel), HTTP client, re-exports. - `src/presets.rs` — the 15 animated presets + render dispatch. - `src/matelight.rs` — matelight `/monitor` WebSocket feeder + frame sampler. - `src/beat.rs` — cpal capture + energy-onset beat detector (feature `mic`). - `src/main.rs` — TUI binary, engine loop, key handling. - `src/bin/panels.rs` — wall panels one-shot. - `src/bin/bars.rs` — SonicPulse ArtNet driver. --- ## Tuning notes - **Mic input device.** On laptops with both built-in mic and a desk feed, PulseAudio/PipeWire may pick the wrong one. Fix in `pavucontrol` → Recording tab while `lightcontrol` is running. - **Beat sensitivity.** `src/beat.rs` constants: - `THRESHOLD` (default `1.35`) — ratio of short to long envelope. Higher = stricter. - `MIN_DELTA` (default `0.020`) — absolute energy rise required. Suppresses warmup-window false triggers and quiet-room noise. - `MIN_INTERVAL_MS` (default `200`) — caps detected BPM at 300. - **Matelight unreachable.** TUI header will show `matelight: connecting…` or the last error. `lightcontrol` reconnects every 3 s. The Matelight preset falls back to a slow dim-white pulse meanwhile. - **Photosensitivity.** Gabba/Red/Blue/Pink strobes are hard 12.5 Hz square-wave alternations at the engine's Nyquist rate. Don't fire them at a crowd that hasn't been warned. --- ## Related projects ### c-base backend & infrastructure - **[c-base/dmxbackend](https://github.com/c-base/dmxbackend)** — the aiohttp service this tool talks to. ArtNet/HTTP-WebSocket/MQTT bridge for the mainhall lights. Hosts the fixture API at `dmx.cbrp3.c-base.org:8000` and the live state WebSocket at `/api/v1/websocket_state/`. - **[c-base/c-base-map](https://github.com/c-base/c-base-map)** — interactive map of c-base areas and interfaces. Useful context for where the fixtures actually sit in space. - **[code.c-base.org/t/dmx-mainhall-foo](https://code.c-base.org/t/dmx-mainhall-foo)** — this repo's home. ### Matelight ecosystem - **[jaseg/matelight](https://github.com/jaseg/matelight)** — the canonical project. WS2801-in-Mate-bottles, 40×16 display, CRAP protocol (UDP/1337). Foundation everything else builds on. - **[c-base/matelight](https://github.com/c-base/matelight)** — c-base fork of the above. - **[c-base/matelight-pixel](https://github.com/c-base/matelight-pixel)** — Python/FastAPI + React frontend served at `matelight.cbrp3.c-base.org:8000`. - **[code.c-base.org/c-matelight](https://code.c-base.org/c-matelight)** — the active production org on c-base's Gitea (fresher than the GitHub mirror). Contains `matelight`, `matelight-original`, `matelight-pixel`, `c-matelight`. - **[c-base/mlaudiospectrum](https://github.com/c-base/mlaudiospectrum)** — audio-spectrum analyzer that paints the Matelight from mic input. Conceptually adjacent to our `BeatPulse` preset; if you want to push audio reactivity into the Matelight itself (instead of the hall), this is the prior art. ### Other c-base lighting - **[c-base/roboclub-lighting](https://github.com/c-base/roboclub-lighting)** — separate lighting project for the roboclub area, C/MCU-side. ### Documentation - **[cbag3.c-base.org/artefact/matelight](https://cbag3.c-base.org/artefact/matelight)** — c-base artefact guide entry for the Matelight (hardware history, build notes). - **[c-base/artefact-guide](https://github.com/c-base/artefact-guide)** — source of the artefact guide above.