A native GTK4/libadwaita control center for PipeWire — for any Linux distro running PipeWire (packaged on the AUR, install instructions for Fedora, Ubuntu/Debian and others below). Everything under PipeWire's Configuration documentation — clock/quantum tuning, stream processing, session policy, filter chains, HRIR virtual surround — exposed as toggles and dropdowns, plus Signal Paths for building the route your audio actually takes (new in v0.4.0), live level meters on every volume control, a parametric equalizer and microphone cleanup (new in v0.3.6), a live patchbay, performance monitoring, virtual devices, routing snapshots, per-application policies and LADSPA/LV2 effect inserts (new in v0.3.0).
More screenshots: Signal Paths, one source and one mix · Signal Paths, a mix on its own · Signal Paths, dark mode · Template browser · Template cards close-up · Adding a stage · Delete strips · Output Devices · Output Devices with ports · Output Devices, stepped volume · Playback tab · Recording tab · Session and Bluetooth · HRIR Library · Filter Chains · Filter Chains + HRIR close-up · New filter chain · Surround Setup wizard · Surround Setup, advanced mode · Device presets · Volume style picker
📋 For highlights of every release — including v0.3.5 (card configuration as its own control) and v0.3.4 (import your existing virtual devices) — see the changelog.
Signal Paths — a new page, and the first one that is about the shape of your audio rather than about settings. A source is where sound enters — one app, a microphone, or everything on the default output — and carries its own chain of processing. A mix carries a chain of its own and feeds real devices. Sources sit on the left, mixes on the right, and the sends between them are drawn as curves, so a glance tells you what is going where.
One source and one mix is a straight line, which is what most setups are. The second column earns its place once a chain has to split — one source corrected four different ways for four different pieces of hardware, without building it four times.
Templates, from a plain speaker mix to a full broadcast chain. An empty board is the catalog: four complete paths that build both halves in one click, then twenty-six ready-made strips running from the simplest at the top to the ones people actually run for broadcast at the bottom — bass boost, a loudness curve for listening quietly, crossfeed for headphones, a turntable chain, the gate → tone → compressor → limiter voice chain, a mastering bus. Each card draws the chain it is about to build, and anything wanting a plugin you do not have says so on the card and is left out, rather than producing a strip that will not start.
The board is handled directly, not through menus. Drag a stage along its chain to reorder it, or onto another card to move it there. Drag a card to rearrange a column, or onto the opposite column to connect the two. Drag an app from one strip to another to move what it is playing through. A single click on a stage takes it in or out of the signal; double-click or right-click opens it. While you are dragging, every place the thing could land says so.
One process per chain, not one per plugin. Every stage in a strip is compiled into a single filter graph: twenty effects are one entry in your device list and one buffer hop, instead of twenty of each. Equalizer bands are built from biquad filters rather than the preset-file kind, so frequency, gain and Q take effect while the audio plays — no restart, no gap. Send one chain to several devices and they are combined into one output for you; you never have to learn what a combine sink is.
Also new: effect racks can feed other effect racks (rack → rack was the one combination that could not be made), equalizers are no longer stereo-only — a channel layout row offers everything from mono to 7.1 — and equalizers, racks and filter chains now share one loop check, which also catches rings running through a mix of them.
Live level meters — every volume control in the app now shows the audio actually flowing through it: the Dashboard mixer, both device tabs, the Devices page and the equalizers. You can see at a glance which app is making noise and how loud it is. Meters are dB-mapped, so normal listening fills the bar rather than sitting near zero, and each carries a peak-hold marker. They cost effectively nothing — PipeWire's own resampler reports the peaks, so a meter reads about 100 bytes per second instead of streaming audio. They run only while their row is on screen, can't keep a device awake, and never show up as nodes in the Patchbay.
Equalizer — parametric-equalizer outputs you route audio through. Import
an AutoEQ / APO ParametricEq.txt (browse, or drag the file onto the row), or
dial the bands in by hand: each band has its own type, frequency, gain and Q,
plus its own switch so you can hear one filter in isolation without deleting
it. One click makes an equalizer the default output. Live A/B compare
(beta) switches an equalizer in and out while it keeps running, so playback
never pauses.
Microphone cleanup — a clean copy of your microphone with echo and background noise removed (WebRTC). Noise suppression, automatic gain, a high-pass filter and voice-activity detection are individual switches, with extended-filter, delay-agnostic and transient suppression under Advanced. By default it uses whatever is playing on your speakers as the echo reference, so there is nothing to route — just pick the clean microphone as your input.
v0.3 grows the app from a config editor into a full graph tool: a live patchbay, performance monitoring, virtual devices, routing snapshots, per-application policies and plugin effect inserts — all built on the same "one process per thing, drop-ins only, never touch base files" foundation.
Patchbay — a live node graph of the whole session, audio and MIDI.
Drag a port onto another to connect, select a link and press Delete to
disconnect, drag nodes to arrange them (layout persists), pan/zoom, toggle
MIDI and monitor ports, and watch the signal flow animate along active
links. Double-click any node for its properties, per-node latency, and a
live metadata editor (e.g. pin a stream with target.object).
Live Monitor — per-service CPU and RAM sparklines, xrun and DSP-load
meters, a live pw-top table and a cursor-followed journal with a
warnings-only filter. Optional desktop notifications fire when a link
breaks, a service fails, or new dropouts appear.
Effects — insert racks of LADSPA/LV2 plugins into the signal path; the rack shows up as an output device you route apps through. Plugins are discovered by introspection (164 LADSPA + 71 LV2 found on the dev machine), reorderable in series, and mono plugins run as an L/R pair automatically. VST3/CLAP presence is detected with a bridge-host hint.
Virtual Devices — create null sinks, virtual microphones, combined/aggregate devices (one sink that plays on several cards at once) and buses/sub-mixes. Each runs as its own tiny process — temporary or persistent — so creating or removing one never interrupts playback.
App Policies — per-application routing rules (send an app to a fixed device, stop it auto-connecting, or pin it in place), default-device priority, and a preferred graph clock master.
Also new: routing snapshots (save / recall / export / import the whole patch by name), per-device settings on the Devices page (sample rate, bit depth, period size, headroom, rename, hide), per-device Bluetooth profile & codec, and solo toggles in the Dashboard mixer.
Rough list, no particular order, no promises on timing:
Signal Paths — sources / mixer— shipped in v0.4.0. Still to do on it:- UI design improvements.
- Proper bypass, without stopping playback to do it.
- Card dragging could be smoother.
- Pinning sources/mixers.
- …and more.
- Network audio manager — PipeWire's network side in the GUI: RAOP/AirPlay sinks, streaming between machines, discovery.
- UI improvements overall — the app has been extremely boring to look at.
The live meters in v0.3.6 and the Signal Paths board in v0.4.0 were first
steps, there's a lot more to do:
- Fix the Dashboard overview to really just be an overview.
- Move Playback, Output Devices and Recording Devices to their own top-level sidebar entries.
- …and more — I have a lot of ideas, it just takes time.
- Quality of life — scaling, where buttons actually live, gaps and spacing. Small stuff, but it adds up.
- Individual channel volume (I know, I know.)
- Hide the complicated sections behind Advanced, so opening the app isn't a wall of knobs unless you want it to be.
- Microphone cleanup button in the Input/Recording section, done cleanly — so you can clean up a mic without going hunting for it.
Getting feedback. I use this thing daily on my own setup, which means I mostly find the bugs I happen to walk into — and every PipeWire setup is wildly different. If you try it and something is broken, confusing, or just annoying, please open an issue — even a one-liner helps more than you'd think.
Any support will help me a ton and will allow me to spend more time maintaining this project and if you can't but want to support consider giving me feedback or issues you came across. Support through GitHub Sponsors, or one-off through PayPal — whichever suits you.
Completely optional — the app is GPL-3.0 and always will be, and nothing is ever locked behind a donation.
…here are some cool GitHubs to visit for sound tools:
- JDSP4Linux — JamesDSP audio effects processor for PipeWire/PulseAudio
- EasyEffects — the classic effects rack for PipeWire
- coppwr — low-level PipeWire graph inspector and patchbay
- polybar-pulseaudio-control — volume/sink switcher module for Polybar
- virtual-surround-manager — HRIR-based virtual surround setup tool for Windows and Linux
…and some goated repos for presets, HRIRs, and DDCs:
- M0Rf30/easyeffects-presets — easily the best EasyEffects preset collection
- HRIR database — big searchable HRIR database (Airtable)
- GentleDynamics — the best presets if you want add your own HRIRs
- JackHack96/EasyEffects-Presets — the default recommendation for EasyEffects presets
- JamesDSP DDC library — headphone DDC correction files
- Linux_Audio — hard stuff for large speaker systems
Linux with a running PipeWire audio session — PipeWire ≥ 1.0 and
WirePlumber ≥ 0.5 (port/profile switching uses wpctl set-route /
set-profile). GTK 4 with libadwaita ≥ 1.4, Python ≥ 3.10. Pure
Python, no build step. Developed and tested on PipeWire 1.6 /
libadwaita 1.9.
Available on the AUR:
paru -S pipewire-controller # or: yay -S pipewire-controllerThis installs everything (app, dependencies, desktop entry) — skip the Run section below. To run from a git checkout instead, install the dependencies manually:
sudo pacman -S --needed pipewire wireplumber pipewire-pulse gtk4 libadwaita \
python-gobject python-numpy python-soundfilesudo dnf install pipewire wireplumber pipewire-pulseaudio gtk4 libadwaita \
python3-gobject python3-numpy python3-soundfilesudo apt install pipewire wireplumber pipewire-pulse gir1.2-gtk-4.0 \
gir1.2-adw-1 python3-gi python3-numpy python3-soundfileOlder releases ship a libadwaita before 1.4 and won't work.
Install GTK 4 + libadwaita (≥ 1.4) with GObject introspection and PyGObject from your package manager, then grab the Python audio bits via pip if your distro doesn't package them:
python3 -m pip install --user numpy soundfileOptional extras on any distro: noise-suppression-for-voice (RNNoise mic
template), lsp-plugins-ladspa (extra LADSPA plugins for imported
chains), PipeWire built with libmysofa (SOFA spatializer templates).
git clone https://github.com/knightinfected/PipeWireController.git
cd PipeWireController
./pipewire-controllerOptional app-menu entry (the desktop file expects pipewire-controller
on your PATH, which the symlink provides):
mkdir -p ~/.local/bin ~/.local/share/applications
ln -sf "$PWD/pipewire-controller" ~/.local/bin/
cp pipewire-controller.desktop ~/.local/share/applications/Dashboard — pavucontrol-style tabs, refreshed live:
- Playback / Recording: every application stream with volume, mute and a
device dropdown that moves the stream live (
target.objectmetadata); recording streams can capture any source or any sink's monitor ("Monitor of X"). - Output / Input Devices: volume, mute, default star and port selection (speakers/headphones/HDMI, with unplugged markers).
- Overview: service states, graph rate/quantum/latency, an interactive latency calculator (with one-click "test live" via force-quantum/rate), default endpoints, stream activity, filter-chain summary.
- Four volume-slider styles — classic, stepped (5% notches), precision (−/+ nudge buttons for trackpads), LED meter (studio segment bar) — switchable from the pill in the bottom-right corner.
Patchbay — a live, draggable node graph of every node, port and link in the session (audio and MIDI). Connect by dragging a port onto another, disconnect a selected link with Delete, and double-click a node to edit its metadata and read its declared latency. Save the whole routing as a named snapshot and recall, export or import it later.
Devices — every sink and source (including virtual filter-chain sinks): set default, volume, mute. Hardware devices expand to per-device settings — sample rate, bit depth, ALSA period size, headroom, preferred quantum, suspend timeout, plus rename/hide — written as WirePlumber rules.
Virtual Devices — null sinks, virtual microphones, combined/aggregate
outputs (play on several cards at once) and buses/sub-mixes, each as its own
lightweight process; temporary or persistent across reboots. Already
hand-wrote some loopback/combine/null-sink drop-ins in pipewire.conf.d?
Import adopts them into the page — classified into the right kind and
brought under the same enable/edit/delete controls.
App Policies — per-application rules (fixed target device, disable auto-connect, pin in place), per-device default-selection priority, and a preferred graph clock master.
Effects — a LADSPA/LV2 plugin browser and a rack builder; racks become routable output devices. VST3/CLAP are detected with a bridge-host hint.
Monitor — service CPU/RAM, xrun and DSP-load meters, a live pw-top
table, a follow-along journal, and optional desktop notifications for broken
links, service failures and dropouts.
Surround Setup — a guided wizard for real 5.1/7.1 rigs: choose the layout, pick the matching sound-card profile (★ suggests the right one; applied instantly — doubles as a Bluetooth codec picker), apply recommended upmix/bass-management defaults per layout, then click each speaker on a room map to hear a test tone (the subwoofer gets 60 Hz). For headphone users there's a one-click Virtual 7.1 Headphones sink — clearly marked as virtual, never made the default automatically, and removable like any other chain.
Advanced toggle (bottom-left) reveals a curated set of deeper settings across all pages — quantum hard limit, RT scheduling, strict checks, center-extraction cutoff, rear ambience delay, stereo widen, Hilbert taps, ALSA headroom, and more — each explained in plain language.
Device presets (bookmark menu, top-right) — snapshot channel-mix settings, volume and card profile per output device, re-apply them with one click, or let the app auto-apply a device's preset whenever it becomes the default output (e.g. Bluetooth headphones reconnecting).
Server — two layers, clearly separated:
- Runtime overrides (instant, non-persistent): force sample rate, force
quantum via
pw-metadata -n settings— experiment freely, a restart resets them. - Persistent settings: default/allowed sample rates, quantum min/default/
max, power-of-two quantum, mlock, denormals, RT priority, link buffers,
strict checks, log level. The app shows the actual merged value from
/usr/share→/etc→~/.config(including distro tweaks), marks anything it has overridden with an accent bar, and offers one-click reset per row.
Streams — resampler quality (0–14), disable resampling,
stereo→surround upmix (psd/simple/none), LFE crossover, LFE folding,
normalize downmix, monitor volumes. Written to both client.conf.d and
pipewire-pulse.conf.d so native and Pulse apps behave identically.
Session & Bluetooth (WirePlumber) — never-suspend devices (fixes pops / cut-off first seconds), SBC-XQ, mSBC wideband mic, hardware volume, auto-switch to headset profile, and per-device Bluetooth profile & codec selection for each connected device.
Filter Chains — the core:
- Create / edit / clone / delete / enable / disable from the GUI; valid SPA JSON is always generated and validated before it is written.
- Each chain runs as its own process (
pwctl-chain@<id>systemd user unit runningpipewire -c). Toggling, editing or swapping the HRIR of one chain restarts only that chain's process — your main audio never skips. - Templates: Virtual Surround 7.1 / 5.1 / stereo-widener (14-ch HeSuVi HRIR), plain 7.1 passthrough sink (no HRIR), true-stereo 4-ch IR convolver, 1–2-ch stereo convolver, SOFA spatializer 7.1/5.1, headphone crossfeed (no IR needed), parametric EQ with AutoEq file support, bass boost, RNNoise noise-cancelling mic.
- The right template is auto-selected from the analyzed channel count of the
chosen IR (14 ch → HeSuVi, 4 ch → true-stereo, 1–2 ch → stereo IR,
.sofa→ spatializer). - Optional fixed output device per chain, convolver gain, per-template knobs.
- Import detects your existing hand-written drop-ins in
~/.config/pipewire/filter-chain.conf.d/(including aninactive/folder), brings them under app management verbatim, and still supports HRIR swapping and raw text editing with validation. - Per-chain journal viewer and generated-config viewer.
HRIR Library — import single files or whole folders (e.g. a downloaded
HeSuVi hrir/ directory). Every file is analyzed (channels / rate / length /
format) and classified: 14 ch = HeSuVi, 4 ch = true stereo, 1–2 ch = plain
IR, .sofa = HRTF. "New chain" on any file creates a chain with the right
template pre-selected. A built-in generator synthesizes a basic 14-channel
demo HRIR so virtual surround can be tested before downloading a real set
(get real ones from the HeSuVi project's hrir folder — use the 14-channel
wavs, not the *-.wav variants).
Tools — restart audio stack / WirePlumber, journal viewer, latency calculator, view every drop-in the app has written, open config folders, one-click reset all overrides.
| What | Where |
|---|---|
| Server settings | ~/.config/pipewire/pipewire.conf.d/99-pipewire-controller.conf |
| Stream settings | ~/.config/pipewire/{client,pipewire-pulse}.conf.d/99-pipewire-controller.conf |
| Session settings | ~/.config/wireplumber/wireplumber.conf.d/99-pipewire-controller.conf |
| Device & app policy rules | ~/.config/pipewire-controller/rules.json (regenerates the WirePlumber and stream drop-ins above) |
| Chain metadata | ~/.config/pipewire-controller/chains/*.json |
| Virtual device metadata | ~/.config/pipewire-controller/virtual/*.json |
| Routing snapshots | ~/.config/pipewire-controller/routing/*.json |
| Generated chain / virtual-device configs | ~/.config/pipewire-controller/generated/*.conf |
| HRIR library | ~/.config/pipewire-controller/hrir/ |
| UI preferences & device presets | ~/.config/pipewire-controller/ui.json |
| Chain / virtual-device runner unit | ~/.config/systemd/user/pwctl-chain@.service |
Deleting those paths removes every trace of the app. Base config files are never modified.
- A small parser/serializer for PipeWire's relaxed SPA JSON dialect
(
pwctl/spa_json.py) reads any real-world config (verified round-trip on all shipped configs) and writes idiomatic conf files. - Persistent changes surface a banner naming exactly which service needs a restart, with a one-click restart button; runtime changes apply instantly.
- All subprocess work (
pw-dump,systemctl, …) runs off the UI thread.
- Thanks to Wim Taymans, creator of PipeWire, for reviewing the Server
page's quantum and buffer settings — his feedback corrected the
link.max-buffersdescription and the quantum hard-limit range in v0.3.1.























