
A step-by-step guide to turn a stock Kubuntu 26.04 LTS install into a low-latency audio workstation that can run Windows VST2 / VST3 / CLAP plugins in a native Linux DAW (REAPER, Bitwig, Ardour, etc.) through **yabridge**.

> [!info] Assumptions
> - Fresh(ish) Kubuntu 26.04 LTS, 64-bit, default **PipeWire** audio stack.
> - Your user has `sudo` rights.
> - Commands are run in **Konsole** using bash.
> - Codename used below: `$(lsb_release -sc)` resolves automatically, so you don't need to type it.

---

## 1. Update the system

```bash
sudo apt update && sudo apt full-upgrade -y
sudo apt install -y curl wget gpg software-properties-common lsb-release
```

Reboot if a new kernel was installed:

```bash
sudo reboot
```

---

## 2. Grant realtime privileges to your user

Audio threads need realtime scheduling priority and locked memory.

### 2.1 Add yourself to the `audio` group

```bash
sudo usermod -aG audio "$USER"
```

### 2.2 Set realtime limits for the `audio` group

```bash
sudo tee /etc/security/limits.d/95-audio.conf > /dev/null <<'EOF'
@audio   -  rtprio     95
@audio   -  memlock    unlimited
@audio   -  nice       -19
EOF
```

### 2.3 Make sure RTKit is present (PipeWire uses it for RT threads)

```bash
sudo apt install -y rtkit
```

> [!note] Log out and back in (or reboot) for the group and limit changes to take effect.

Verify after logging back in:

```bash
groups | grep -w audio
ulimit -r   # should print 95
ulimit -l   # should print unlimited
```

---

## 3. Kernel: full preemption + threaded IRQs

Ubuntu's generic kernel supports `PREEMPT_DYNAMIC`, so you can switch it to full preemption at boot time instead of installing a separate low-latency kernel.

### 3.1 Add kernel parameters to GRUB

```bash
sudo cp /etc/default/grub /etc/default/grub.bak
sudo sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT="\(.*\)"/GRUB_CMDLINE_LINUX_DEFAULT="\1 preempt=full threadirqs"/' /etc/default/grub
grep GRUB_CMDLINE_LINUX_DEFAULT /etc/default/grub
sudo update-grub
sudo reboot
```

### 3.2 Verify after reboot

```bash
cat /proc/cmdline | tr ' ' '\n' | grep -E 'preempt|threadirqs'
sudo cat /sys/kernel/debug/sched/preempt   # active mode is shown in (brackets), want: (full)
```

> [!tip] Optional – Ubuntu Studio tooling
> If you prefer a GUI way to manage these tweaks, `sudo apt install ubuntustudio-installer` and enable the audio/low-latency options from there. Don't apply both methods at once.

---

## 4. CPU & system tuning

### 4.1 Use the performance power profile

Prevents the CPU from down-clocking mid-buffer (a common cause of xruns).

```bash
powerprofilesctl list
powerprofilesctl set performance
```

To check the actual governor:

```bash
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor | sort | uniq -c
```

### 4.2 Lower swappiness

```bash
echo 'vm.swappiness = 10' | sudo tee /etc/sysctl.d/99-audio.conf
sudo sysctl --system
```

### 4.3 Allow access to high-resolution timers (needed by some JACK/MIDI apps)

```bash
sudo tee /etc/udev/rules.d/40-timer-permissions.rules > /dev/null <<'EOF'
KERNEL=="rtc0", GROUP="audio"
KERNEL=="hpet", GROUP="audio"
EOF
sudo udevadm control --reload-rules && sudo udevadm trigger
```

---

## 5. Configure PipeWire for low latency

### 5.1 Install PipeWire's JACK + ALSA pieces

```bash
sudo apt install -y pipewire pipewire-audio pipewire-jack pipewire-alsa \
  wireplumber qpwgraph pavucontrol
```

### 5.2 Route all JACK applications through PipeWire

This makes DAWs that use JACK talk to PipeWire automatically (no need to prefix `pw-jack`).

```bash
sudo cp /usr/share/doc/pipewire/examples/ld.so.conf.d/pipewire-jack-*.conf /etc/ld.so.conf.d/
sudo ldconfig
```

### 5.3 Set the sample rate and buffer size (quantum)

#### 5.3.1 Profile your audio interface first

Before choosing rates, find out what your interface actually supports. List the cards:

```bash
cat /proc/asound/cards
aplay -l
```

For **USB interfaces**, the kernel exposes the supported formats and rates directly (replace `1` with your card number):

```bash
cat /proc/asound/card1/stream0
```

Look for the `Rates:` lines, e.g. `Rates: 44100, 48000, 88200, 96000, 176400, 192000`.

For any interface (USB or PCIe), ask ALSA for the hardware parameters. PipeWire holds the device open, so stop it briefly:

```bash
systemctl --user stop pipewire.socket pipewire-pulse.socket pipewire pipewire-pulse wireplumber
aplay -D hw:1,0 --dump-hw-params /dev/zero     # playback  (Ctrl+C after it prints)
arecord -D hw:1,0 --dump-hw-params /dev/null   # capture   (Ctrl+C after it prints)
systemctl --user start pipewire.socket pipewire-pulse.socket pipewire pipewire-pulse wireplumber
```

The `RATE:` line shows the supported range (e.g. `[44100 192000]`). The `PERIOD_SIZE` and `BUFFER_SIZE` lines show the smallest buffers the hardware accepts, which sets the lower limit for `min-quantum`.

#### 5.3.2 Write the config using those values

Put **only rates your interface reports** in `allowed-rates`. If you add a rate it doesn't support, PipeWire has to resample instead of switching the hardware clock. The example below assumes an interface that goes up to 192 kHz:

```bash
mkdir -p ~/.config/pipewire/pipewire.conf.d
tee ~/.config/pipewire/pipewire.conf.d/10-lowlatency.conf > /dev/null <<'EOF'
context.properties = {
    default.clock.rate          = 48000
    default.clock.allowed-rates = [ 44100 48000 88200 96000 176400 192000 ]
    default.clock.quantum       = 256
    default.clock.min-quantum   = 64
    default.clock.max-quantum   = 2048
}
EOF
```

- `default.clock.rate` is the rate PipeWire uses when nothing asks for another one. 48 kHz is a good default even if the interface can do 192 kHz: higher rates cost more CPU per second of audio, and many plugins (especially through Wine/yabridge) gain little from them.
- `allowed-rates` lets PipeWire switch the hardware to a project's native rate (e.g. a 96 kHz session) instead of resampling. This only works when a single app is using the device.

Latency ≈ `quantum / rate`:

| Quantum | 48 kHz  | 96 kHz  | 192 kHz |
| ------- | ------- | ------- | ------- |
| 64      | 1.3 ms  | 0.7 ms  | 0.3 ms  |
| 128     | 2.7 ms  | 1.3 ms  | 0.7 ms  |
| 256     | 5.3 ms  | 2.7 ms  | 1.3 ms  |
| 1024    | 21.3 ms | 10.7 ms | 5.3 ms  |

At higher rates, you need a larger quantum to get the same latency in milliseconds, which is why `max-quantum` is raised to 2048 above. Start at 256 and go down to 128 or 64 once things are stable. Don't go below the minimum period size `--dump-hw-params` reported.

Restart PipeWire:

```bash
systemctl --user restart pipewire pipewire-pulse wireplumber
```

### 5.4 Change the buffer size on the fly (no restart)

```bash
pw-metadata -n settings 0 clock.force-quantum 128   # force 128 frames
pw-metadata -n settings 0 clock.force-rate 48000    # force 48 kHz
pw-metadata -n settings 0 clock.force-quantum 0     # back to default
```

### 5.5 Monitor xruns and latency

```bash
pw-top
```

Watch the `ERR` column — it should stay at 0 while playing audio.

---

## 6. Check the setup with rtcqs

`rtcqs` scans the system for common realtime audio misconfigurations.

```bash
sudo apt install -y pipx
pipx ensurepath
source ~/.bashrc
pipx install rtcqs
rtcqs
```

Fix anything it flags as a warning before moving on.

---

## 7. Install Wine (Staging)

Yabridge works best with **Wine Staging** from WineHQ.

### 7.1 Enable 32-bit architecture

```bash
sudo dpkg --add-architecture i386
```

### 7.2 Add the WineHQ repository

```bash
sudo mkdir -pm755 /etc/apt/keyrings
wget -O - https://dl.winehq.org/wine-builds/winehq.key \
  | sudo gpg --dearmor -o /etc/apt/keyrings/winehq-archive.key -
sudo wget -NP /etc/apt/sources.list.d/ \
  "https://dl.winehq.org/wine-builds/ubuntu/dists/$(lsb_release -sc)/winehq-$(lsb_release -sc).sources"
sudo apt update
```

> [!warning] If the `wget` of the `.sources` file returns 404
> WineHQ hasn't published packages for 26.04 yet. Either use Ubuntu's own Wine instead:
> ```bash
> sudo apt install -y wine wine64 wine32:i386
> ```
> …or temporarily point at the previous LTS (`noble`) repo by replacing `$(lsb_release -sc)` with `noble` above.

### 7.3 Install Wine Staging

```bash
sudo apt install -y --install-recommends winehq-staging
wine --version
```

### 7.4 (Optional) Pin a known-good Wine version

Newer Wine releases occasionally break plugin GUIs under yabridge. If you hit regressions, list the available versions and pin one:

```bash
apt list -a winehq-staging
# replace VERSION with an entry from the list above, e.g. 9.21~noble-1
VERSION="9.21~noble-1"
sudo apt install -y --allow-downgrades \
  winehq-staging="$VERSION" wine-staging="$VERSION" \
  wine-staging-amd64="$VERSION" wine-staging-i386:i386="$VERSION"
sudo apt-mark hold winehq-staging wine-staging wine-staging-amd64 wine-staging-i386
```

Undo the hold later with `sudo apt-mark unhold winehq-staging wine-staging wine-staging-amd64 wine-staging-i386`.

---

## 8. Create the Wine prefix and install common libraries

### 8.1 Install the latest winetricks

The distro version is often outdated, so grab the upstream script:

```bash
sudo apt install -y cabextract unzip p7zip-full zenity
mkdir -p ~/.local/bin
wget -O ~/.local/bin/winetricks \
  https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks
chmod +x ~/.local/bin/winetricks
```

### 8.2 Initialize a 64-bit prefix

```bash
export WINEPREFIX="$HOME/.wine"
wineboot -u
```

Click **Install** if Wine asks for Mono/Gecko.

### 8.3 Install the runtime libraries most VST plugins need

```bash
winetricks -q corefonts                 # Arial, Times etc. – fixes missing/ugly GUI text
winetricks -q vcrun2022                 # Visual C++ 2015-2022 runtime (most modern plugins)
winetricks -q vcrun2019 vcrun2013 vcrun2010 vcrun2008   # older plugins/installers
winetricks -q d3dcompiler_47            # needed by many GPU-rendered GUIs (JUCE/OpenGL/DirectX)
winetricks -q gdiplus                   # GDI+ drawing for some older GUIs
winetricks -q msxml6                    # some installers / licence managers
winetricks fontsmooth=rgb               # sub-pixel font smoothing
```

> [!tip] Optional – DXVK
> Some plugins with DirectX-based GUIs (e.g. certain Native Instructions / Arturia / iZotope versions) render better or only work with DXVK. Others break with it. Install only if you see black/blank plugin windows:
> ```bash
> winetricks -q dxvk
> ```
> Remove with `winetricks -q d3d11=builtin d3d10core=builtin dxgi=builtin`.

### 8.4 Wine settings worth checking

```bash
winecfg
```

- **Graphics → Screen resolution (DPI):** raise to 120–144 on HiDPI screens.
- **Graphics:** untick *Allow the window manager to decorate the windows* if plugin windows get KDE title bars.

---

## 9. Install yabridge

### 9.1 Download the latest release

```bash
cd /tmp
YABRIDGE_URL=$(curl -s https://api.github.com/repos/robbert-vdh/yabridge/releases/latest \
  | grep -oP '"browser_download_url": "\K[^"]*yabridge-[0-9.]+\.tar\.gz')
echo "$YABRIDGE_URL"
wget -O yabridge.tar.gz "$YABRIDGE_URL"
```

> Use the generic `yabridge-X.Y.Z.tar.gz`, **not** the `-ubuntu-20.04` build — that one is only for old distros.

### 9.2 Extract it to `~/.local/share`

```bash
rm -rf ~/.local/share/yabridge
tar -C ~/.local/share -xavf yabridge.tar.gz
```

### 9.3 Put yabridge on your `PATH`

```bash
echo 'export PATH="$HOME/.local/share/yabridge:$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
yabridgectl --version
```

### 9.4 Optional helper packages

```bash
sudo apt install -y libnotify-bin   # desktop notifications on yabridge errors
```

---

## 10. Install Windows plugins and sync them with yabridge

### 10.1 Run the Windows plugin installer through Wine

```bash
cd ~/Downloads
wine ./SomePluginSetup.exe        # .exe installers
wine msiexec /i ./SomePlugin.msi  # .msi installers
```

Accept the default install paths (VST3 goes to `C:\Program Files\Common Files\VST3`).

### 10.2 Tell yabridge where the Windows plugins live

```bash
yabridgectl add "$HOME/.wine/drive_c/Program Files/Common Files/VST3"
yabridgectl add "$HOME/.wine/drive_c/Program Files/Common Files/CLAP"
yabridgectl add "$HOME/.wine/drive_c/Program Files/Steinberg/VstPlugins"
yabridgectl add "$HOME/.wine/drive_c/Program Files/VstPlugins"
```

(Only add folders that actually exist; `yabridgectl list` shows what's registered.)

### 10.3 Create the Linux bridge files

```bash
yabridgectl sync
yabridgectl status
```

`yabridgectl status` should report every plugin as `synced`, and the Wine + yabridge-host check should pass.

> [!important] Re-run `yabridgectl sync` every time you install, update or remove a Windows plugin.

### 10.4 Point your DAW at the bridged plugins

| Format | Linux path to add in the DAW |
| ------ | ---------------------------- |
| VST2   | `~/.vst/yabridge`            |
| VST3   | `~/.vst3/yabridge`           |
| CLAP   | `~/.clap/yabridge`           |

Most DAWs (REAPER, Bitwig, Ardour) scan `~/.vst3` and `~/.clap` by default; VST2 usually needs `~/.vst` added manually. Then rescan plugins.

In the DAW's audio settings select **JACK** (or PipeWire) as the audio system. Thanks to step 5.2 it will connect to PipeWire with your configured buffer size.

---

## 11. Troubleshooting

### Plugin fails to load / crashes

```bash
export YABRIDGE_DEBUG_LEVEL=1
export YABRIDGE_DEBUG_FILE=/tmp/yabridge.log
reaper   # or: bitwig-studio, ardour8 ... started from the same terminal
less /tmp/yabridge.log
```

### Stuck Wine processes after a DAW crash

```bash
wineserver -k
pkill -f yabridge-host
```

### Re-check realtime setup

```bash
rtcqs
pw-top
```

### Per-plugin tweaks

Create `yabridge.toml` in the plugin folder (e.g. `.../Common Files/VST3/yabridge.toml`):

```bash
tee "$HOME/.wine/drive_c/Program Files/Common Files/VST3/yabridge.toml" > /dev/null <<'EOF'
# Run all plugins in this folder in one shared Wine process (less RAM, inter-plugin comms)
["*"]
group = "all"

# Example: fix a plugin whose GUI has mouse offset issues
["SomePlugin.vst3"]
editor_force_dnd = false
editor_coordinate_hack = true
EOF
yabridgectl sync
```

---

## Quick checklist

- [ ] User in `audio` group, `ulimit -r` = 95
- [ ] Kernel booted with `preempt=full threadirqs`
- [ ] Power profile = performance
- [ ] PipeWire quantum configured, `pw-top` shows no xruns
- [ ] `rtcqs` clean
- [ ] Wine Staging installed, prefix initialised
- [ ] winetricks: corefonts, vcrun2022, d3dcompiler_47, gdiplus
- [ ] yabridge on `PATH`, plugin folders added, `yabridgectl sync` done
- [ ] DAW scanning `~/.vst/yabridge`, `~/.vst3/yabridge`, `~/.clap/yabridge`
