Skip to main content

fw16-ledvu

fw16-ledvu is an audio visualizer for the Framework Laptop 16 LED Matrix modules that displays a real-time VU/equalizer driven from PipeWire audio via CAVA (Console Audio Visualizer). Developed by community member Jack Burch (GitHub: JackMBurch), it runs as a lightweight systemd user service on Linux and writes directly to the LED Matrix modules over persistent serial connections for low-latency updates1.

How It Works​

The tool pipes audio level data from PipeWire through CAVA's raw ASCII output, processes the frequency bars with configurable gain, gamma, compression, and smoothing, and renders the result as a 9-band equalizer on the LED Matrix modules using Framework's serial protocol1.

The equalizer renders bars centered vertically on the 9x34 display — each of the 9 columns represents a frequency band, growing upward and downward from the middle row1.

Audio Modes​

ModeBehavior
monoSingle CAVA instance averages L+R channels; both modules show the same EQ
stereoTwo CAVA instances (left channel, right channel); left module shows left audio, right module shows right audio

Rendering Pipeline​

The processing chain for each frame of audio data is1:

  1. CAVA capture — raw ASCII bar values (0–255) from PipeWire
  2. Gain — linear boost of quiet signals (gain > 1.0)
  3. Gamma curve — nonlinear mapping (gamma < 1.0 boosts quiet signals, > 1.0 tames them)
  4. Compression — simple threshold/ratio compressor to tame loud signals
  5. Noise gate (floor) — suppresses values below a configurable threshold
  6. Asymmetric smoothing — separate rise and fall smoothing for snappy attack, slower decay
  7. Peak hold — optionally holds peaks for a configurable duration for readability
  8. Mirroring — per-module bar order reversal (mirror_left, mirror_right)
  9. Serial write — persistent serial connection sends a 39-byte Draw command per module

Battery Saver​

When enabled, the service detects AC/battery state via /sys/class/power_supply and turns the LED displays off while on battery, restoring them when AC power returns1.

Features​

FeatureDetails
LanguagePython
Audio backendPipeWire (via pipewire-pulse) + CAVA
RenderingPersistent serial (pyserial) with ledmatrixctl/library fallback
EQ bands9 (matching the 9-column LED matrix)
Stereo supportSeparate L/R CAVA instances
Bar mirroringPer-module configurable
Config hot-reloadEdits to config.ini auto-apply within ~1 second
Battery saverBlank displays on battery, restore on AC
Wake keep-alivePeriodic wake commands prevent module sleep
Silence throttlingReduced update rate during silence
InstallationOne-command systemd user service install

Installation​

Dependencies (Arch Linux)​

sudo pacman -S --needed cava python

The ledmatrixctl command from the official framework16-inputmodule Python package must also be available (used as fallback if pyserial is not present)12.

Install as systemd user service​

Clone and run the install script1:

git clone https://github.com/JackMBurch/fw16-ledvu.git
cd fw16-ledvu
bash ./install.sh

To use a specific Python interpreter (e.g., from a venv with framework16-inputmodule)1:

FW16_LED_VU_PYTHON=/path/to/venv/bin/python bash ./install.sh

The install script creates config.ini from config.example.ini (if missing), generates a systemd user unit at ~/.config/systemd/user/fw16-ledvu.service, and enables/starts it immediately1.

Configuration​

All settings live in config.ini alongside the repo. Edits are auto-applied by the running service without restart1.

Device paths​

Device symlinks are resolved via readlink -f before opening serial connections. This works well with persistent udev symlinks1:

[devices]
left = /dev/fw16-ledmatrix-left
right = /dev/fw16-ledmatrix-right

Equalizer tuning​

SettingDefaultDescription
bars9Number of EQ bands
max_value34Maximum bar height (must be ≤ 34, the module height)
update_hz50Target update rate in Hz
gain1.0Linear gain boost
gamma1.2Power curve exponent
compress_threshold1.0Normalized threshold (1.0 = disabled)
compress_ratio1.0Compression ratio (1.0 = disabled)
rise_smoothing0Smoothing for rising values (0 = instant)
fall_smoothing0.25Smoothing for falling values
floor0Noise gate threshold
peak_hold_ms0Peak hold duration (0 = disabled)
silence_floor2Threshold to consider audio silent
silent_update_hz2Reduced update rate during silence
brightness5LED brightness (0–255)
mirror_lefttrueReverse bar order on left module
mirror_rightfalseReverse bar order on right module

Technical Details​

DetailValue
LicenseNo license file (all rights reserved)
Serial protocolFramework magic bytes 0x32 0xAC + command byte + payload
Draw command0x06 + 39-byte bit-packed 9x34 B&W bitmap
Serial baud rate115200
CAVA outputRaw ASCII, ; bar delimiter, @ frame delimiter
Config formatINI (Python configparser)

The fast rendering path uses persistent pyserial connections to avoid the latency of reopening /dev/ttyACM* every frame. It falls back to the framework16-inputmodule Python library, and finally to spawning ledmatrixctl subprocess calls1.

ProjectDescription
led-matrix-managerQt GUI for LED matrix management
fw16-led-matrixdCross-platform Rust daemon with image rendering and pair mode
LED Matrix MonitoringSystem metrics visualization for FW16 LED Matrix

Footnotes​

  1. JackMBurch/fw16-ledvu — GitHub ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12

  2. FrameworkComputer/inputmodule-rs — Framework Laptop 16 Input Module Firmware/Software (GitHub) ↩