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
inputmodule-rsOfficial Framework firmware + CLI + Python tools2
led-matrix-managerQt GUI for LED matrix management
fw16-led-matrixdCross-platform Rust daemon with image rendering and pair mode
CAVAConsole-based audio visualizer for Linux (used as audio source)

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) 2