Go to file
Chris Nutter 743c504918 Add focused-window volume/mute control and app-group muting
- New active_window_volume/mute_active_window actions using kdotool to
  resolve the focused window under KWin/Wayland.
- New mute_group button action for muting multiple apps at once.
- New "binary:<name>" needle syntax to disambiguate generic Electron apps
  that share a PipeWire application.name with an unrelated app; fixes a bug
  where two knobs/groups matching the same generic name would fight over
  a stream's volume via the periodic reapply loop.
- Add kdotool to PKGBUILD depends, credit original author in README.
2026-08-13 18:06:53 -07:00
.github/workflows fix: sync AUR workflow .SRCINFO with repo; bump to 2.0.2 2026-02-27 21:43:38 -05:00
contrib feat: add React/Vite PWA web UI with FastAPI backend 2026-02-27 21:25:16 -05:00
src/turnup Add focused-window volume/mute control and app-group muting 2026-08-13 18:06:53 -07:00
tests fix: always apply PA stream volume for app/group knobs 2026-03-20 19:45:11 -04:00
ui fix: build frontend and fix tsc errors blocking the build 2026-03-07 23:16:05 -05:00
.SRCINFO chore: bump version to 2.1.0 2026-02-28 14:56:52 -05:00
.gitignore feat: add React/Vite PWA web UI with FastAPI backend 2026-02-27 21:25:16 -05:00
CHANGELOG.md Add focused-window volume/mute control and app-group muting 2026-08-13 18:06:53 -07:00
LICENSE Initial commit 2026-02-27 10:08:09 -05:00
PKGBUILD Add focused-window volume/mute control and app-group muting 2026-08-13 18:06:53 -07:00
README.md Add focused-window volume/mute control and app-group muting 2026-08-13 18:06:53 -07:00
pyproject.toml fix: always apply PA stream volume for app/group knobs 2026-03-20 19:45:11 -04:00
turnupd.install feat: add React/Vite PWA web UI with FastAPI backend 2026-02-27 21:25:16 -05:00

README.md

turnup

A lightweight daemon that bridges a USB serial device (physical knobs and buttons) to PipeWire/PulseAudio on Linux. Map each knob to per-sink, per-source, or per-application volume; assign buttons to mute toggles or arbitrary shell commands.

Requirements

  • Python 3.10+
  • pyserial
  • pulsectl
  • PipeWire (with pipewire-pulse) or PulseAudio
  • playerctl

Installation

Arch Linux (AUR)

yay -S turn-up-arch

Or manually:

git clone https://aur.archlinux.org/turn-up-arch.git
cd turn-up-arch
makepkg -si

From source

git clone https://github.com/sean351/turn-up-arch.git
cd turn-up-arch
pip install .

Configuration

On first run turnupd writes a default config to ~/.config/turnup/config.toml. Edit it to match your device layout. See contrib/config.example.toml for a fully annotated example.

port = "/dev/ttyACM0"
baud = 115200

[leds]
mode       = "volume"
low_color  = [255, 0, 0]   # red   at 0 %
high_color = [0, 255, 0]   # green at 100 %

[knobs.0]
action = "sink_volume"
target = "default"

[knobs.1]
action  = "group_volume"
targets = ["vlc", "spotify"]

[knobs.2]
action = "app_volume"
target = "Brave"

[knobs.3]
action = "source_volume"
target = "default"

[buttons.0]
action = "mute_sink"
target = "default"

[buttons.1]
action = "command"
target = "playerctl previous"

[buttons.2]
action = "command"
target = "playerctl play-pause"

[buttons.3]
action = "command"
target = "playerctl next"

[buttons.4]
action = "mute_source"
target = "default"

Knob actions

Action Description
sink_volume Output device volume (0150 %)
source_volume Mic / input volume (0100 %)
app_volume Single application volume, matched by name or binary
group_volume Multiple applications at once — use "targets": [...]

Button actions

Action Description
mute_sink Toggle output mute
mute_source Toggle mic mute
command Run an arbitrary shell command

Running as a service

A systemd user service unit is included:

# After install via AUR or pip:
systemctl --user enable --now turnupd.service

To view logs:

journalctl --user -u turnupd -f

Running manually

turnupd

Pass a custom config path with the TURNUP_CONFIG environment variable (planned — currently edit ~/.config/turnup/config.json directly).

Hardware

The daemon expects a USB-serial device speaking a simple binary protocol:

Frame Bytes Description
Heartbeat FE 02 FF Keepalive
Button FE 06/07 <id> FF 06 = press, 07 = release
Knob FE 03 <id> <hi> <lo> FF 10-bit ADC value, big-endian

Tested with an RP2040-based board. Any microcontroller that enumerates as a USB-CDC serial port and speaks the protocol above will work.

Credits

Originally created by Sean Doransean351/turn-up-arch. This copy tracks a personal fork with local additions (focused-window volume/mute control, app-group muting, etc.).

License

MIT — see LICENSE.