PipeASIO lets Windows music software running under Wine or Proton use fast, low-latency audio on Linux.
ASIO is the standard low-latency audio driver on Windows. Music programs (DAWs) such as FL Studio, Ableton Live, and Reaper rely on it for responsive playback and recording. PipeASIO provides that driver inside Wine and connects it straight to PipeWire, the audio system modern Linux distributions use. Your DAW sees a normal ASIO device. PipeWire sees a normal audio app it can route anywhere.
It works in plain Wine and inside Proton and Steam (Faugus, Proton-CachyOS), and it installs safely next to WineASIO: your DAW lists them as two separate drivers.
Note
PipeASIO is at 1.10.0. It is verified with FL Studio under Proton-CachyOS and with the VB-Audio ASIO Test utility (64-bit and 32-bit). Reaper should work but is not yet confirmed. Ableton Live has played audio on ARM64 under FEX, see ARM64. x86_64, with experimental opt-in 32-bit (WoW64) support. Bug reports are very welcome on the issue tracker.
If PipeASIO is useful to you, you can support its development on Ko-fi:
Issues are open to everyone. Bug reports, questions and feature requests are welcome on the issue tracker - no invitation needed, and a good bug report is usually worth more than a patch.
Pull requests are only reviewed from manually selected contributors. PipeASIO has one maintainer, and the repository was attracting pull-request spam from botted accounts; sifting through it was eating the time that goes into the driver.
If you would like to work on PipeASIO, come and say so in the Fluxer guild, with a rough outline of what you want to change:
Once you are on the contributor list the usual rules apply: run clang-format
(the config is in-tree) before submitting. The driver is C11 and must keep
building for x86_64, i386 (WoW64) and aarch64. The manager and panel are C++17
with Qt 6.
Pull requests from outside the list are closed without review - open an issue or
reach out in the guild instead.
Steam, Faugus, Bottles or a custom Wine prefix: download
pipeasio-manager-<tag>-x86_64.AppImage from the
releases page, mark it
executable and open it. It installs the driver into the prefix you pick and
checks that it loads. See GUI manager.
Arch Linux and derivatives (CachyOS, EndeavourOS, Manjaro): install
pipeasio from the AUR. It
includes the manager. Use it, or register by hand in the current Wine prefix:
paru -S pipeasio # or: yay -S pipeasio
pipeasio-registerEverywhere else, build from source and install where your Wine reads its modules:
cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build
sudo cmake --install build --prefix /usr
pipeasio-registerThat installs into /usr/lib/wine, where Wine looks on Arch. Fedora's Wine
looks in /usr/lib64/wine and Debian/Ubuntu's in
/usr/lib/x86_64-linux-gnu/wine: add -DPIPEASIO_WINE_INSTALL_ROOT=<that dir>
to the first cmake (see Installing).
A user-local install (--prefix "$HOME/.local", no sudo) is what Proton,
Steam and Faugus need. It only loads when the launcher, or wine, runs with
WINEDLLPATH=$HOME/.local/lib/wine. See
Proton / Steam / Faugus.
PipeASIO Manager adds an Installations tab to the existing settings and monitor application. It discovers Steam games that have run through Proton, Faugus applications and native Bottles configurations without starting Wine. Flatpak Bottles are listed but not supported (#36): the manager only removes an installation it already made there. Flatpak Steam is not supported, for the same reason. Bottles support is experimental, see Bottles. Add prefix accepts an existing custom Wine prefix and its owning Wine executable.
Download pipeasio-manager-<tag>-x86_64.AppImage from the
releases page: every release
since 1.8.0 carries it. It bundles the native Qt/C++ manager, its libraries,
and the installation probes. Mark it executable in your file manager and open
it. It requires neither Python nor sudo and does not compile the driver. It
installs any driver release from 1.7.0 on.
The AppImage defaults to Qt's Fusion widgets and desktop-portal appearance
integration. It reads the desktop's light/dark preference at startup and uses
KDE's configured palette on Plasma. Exact third-party widget styles such as
Darkly are not bundled. Restart the manager if a desktop theme change is not
reflected while it is open. Explicit QT_QPA_PLATFORMTHEME and
QT_STYLE_OVERRIDE overrides remain available.
- Select the application or prefix. Installed prefixes are listed first, and the filter field above the list narrows it by name, launcher, status or version. Close its Windows applications and the launcher, including the Faugus tray process, before changing the installation. Steam can stay open.
- Choose Install or Update. Review the selected runner, release, and any Flatpak permission requests before confirming.
- The manager downloads an official GitHub release, checks its SHA256, stages its driver files outside the runner, and configures that launcher's library path. Steam and Faugus registration runs through umu-run with the game's Proton. Bottles uses its configured Wine inside the correct native or Flatpak environment.
- A successful installation must pass registration, native-library loading, and PipeWire connection checks inside that runner. These checks do not start audio playback or connect to hardware.
Repair reinstalls the recorded release. Check repeats the runtime check. Remove restores the files, registration, and owned environment values that preceded manager installation. Existing WineASIO and unrelated settings are not removed. Files or settings changed outside the manager are not silently deleted. If permission cleanup is interrupted, Remove can resume it without changing the already-restored prefix.
For a custom Wine prefix, the manager creates a launch wrapper and displays its
path. Pass the Windows application to that wrapper, for example
"/path/shown/by/the/manager/launch" "/path/to/application.exe". Direct wine
launches do not inherit its WINEDLLPATH. Faugus and Bottles retain the setting
in their own application configuration.
For a Steam game, the manager shows the launch options to set in the game's
Properties > General, keeping its other options. Its WINEDLLPATH replaces
one the game already sets. The manager reads Steam's settings to tell when the
options are set, but never writes them, since Steam rewrites its settings files
while it runs. After Remove, it shows the options to set back, with the
values they had before. Steam games need umu-run, from the umu-launcher
package or the copy Faugus includes. A game appears once it has run through
Proton, or once a Proton is selected for it in Steam. The manager uses the
game's own Compatibility choice, otherwise the Proton the game last ran
with. If you changed Steam's default Proton since then, launch the game once
and refresh.
Driver payloads and backups normally live under
${XDG_DATA_HOME:-$HOME/.local/share}/pipeasio. Flatpak Bottles payloads stay in
its own app data directory. Required Flatpak grants are explicit and shared
across managed bottles. Removing the last managed bottle restores the original
grants while preserving unrelated permission entries.
Prebuilt availability is currently x86_64. The Arch-built driver archive is not a universal binary: the selected runner must be able to load its native half. An incompatible runtime fails the check and restores the previous installation. Experimental 32-bit support is opt-in and requires a working new-WoW64 runner. Bottles' additional per-bottle sandbox, Steam-runtime integration, and named Flatpak installations are reported as unsupported rather than falling back to host Wine.
pipeasio-manage is the same backend the GUI uses, and --help lists its
commands. pipeasio-manage --json list emits discovered targets without
starting Wine, and releases lists installable releases.
add --prefix <dir> --wine <executable> [--name <label>] adds a custom prefix
as a target. preview, install, check, and remove take the --target ID
from list. Use --release v1.8.1 to pin a release, --include-32 for the
experimental front end, and --allow-permissions only after reviewing the
preview's grants.
To build the manager without compiling the driver or requiring a Wine SDK:
cmake -S . -B build-manager -DCMAKE_BUILD_TYPE=Release \
-DBUILD_DRIVER=OFF -DBUILD_SETTINGS_PANEL=ON -DBUILD_MANAGER=ON -DBUILD_TESTS=OFF \
-DPIPEASIO_CHECK_EXECUTABLE=/absolute/path/to/pipeasio-check.exe
cmake --build build-manager
cmake --install build-manager --prefix "$HOME/.local" --component ManagerThis needs a native C/C++ toolchain, Qt6 Core/Network/Widgets, PipeWire development
files, yaml-cpp, libarchive, and zlib. The prebuilt probe comes from a manager
package or a newer driver archive. Supply PIPEASIO_CHECK32_EXECUTABLE as well for
32-bit checks. A normal full build produces both probes when
BUILD_WOW64_32=ON. From a full source build, run build/gui/pipeasio-settings.
BUILD_MANAGER defaults to the panel setting. Use -DBUILD_MANAGER=ON with
-DBUILD_SETTINGS_PANEL=OFF to build the native CLI without the GUI.
scripts/package-manager.sh build-manager output.AppImage packages the Manager
install component with its runtime dependencies and probes. The tagged release
workflow builds the manager in the Steam Runtime 4 SDK, separately from the
driver job. The AppImage still relies on the host kernel and glibc.
CMake only. The driver is 64-bit. Opt-in 32-bit (WoW64) support for 32-bit Windows hosts is covered in 32-bit applications.
The driver is two halves, the layout Wine uses for its own modules: a PE
DLL (pipeasio64.dll, the COM object and ASIO surface) and a unixlib
(pipeasio64.so, the PipeWire client) that the PE reaches through
__wine_unix_call. The PE half is linked by winegcc exactly as Wine links
its own DLLs, against Wine's headers and import libraries, with a cross
compiler; the unixlib is built with the host compiler. Nothing in the PE
half links libpipewire, and nothing in the unixlib knows about COM.
Requirements: cmake (3.20 or newer), ninja (recommended) or GNU make,
gcc, pkg-config, the Wine SDK (headers, winebuild, winegcc and the
lib/wine/<arch>-windows import libraries), a cross compiler for the PE
half, and the PipeWire development headers. The cross compiler is either
the MinGW gcc and g++ for x86 targets (mingw-w64-gcc on Arch,
gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 on Debian/Ubuntu, mingw64-gcc mingw64-gcc-c++ on Fedora; winegcc looks for both even for C) or
clang with lld, which is what Wine itself cross-builds with and the
only choice for ARM64; PIPEASIO_PE_COMPILER=gcc|clang forces one. Debian
and Ubuntu ship no unixlib.h; the build carries a copy for them. The optional
panel and manager need a native C++ compiler and Qt6. Driver-only builds can set
-DBUILD_SETTINGS_PANEL=OFF -DBUILD_MANAGER=OFF.
The native manager backend uses Qt6 Core/Network, yaml-cpp, libarchive, and
zlib. The panel additionally uses Qt6 Widgets.
Package names differ per distribution. These are the sets CI builds against, plus the Qt6 package for the optional panel:
# Arch / CachyOS / EndeavourOS / Manjaro
sudo pacman -S --needed cmake ninja gcc pkgconf wine libpipewire qt6-base \
mingw-w64-gcc yaml-cpp libarchive zlib
# Fedora
sudo dnf install cmake ninja-build gcc gcc-c++ pkgconf \
wine-devel pipewire-devel qt6-qtbase-devel mingw64-gcc mingw64-gcc-c++ \
yaml-cpp-devel libarchive-devel zlib-devel
# Debian / Ubuntu
sudo apt install cmake ninja-build gcc g++ pkg-config \
wine64-tools libwine-dev libpipewire-0.3-dev qt6-base-dev \
gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 libyaml-cpp-dev libarchive-dev zlib1g-devThere is no libpipewire-0.3-dev or winehq-*-dev on Fedora, and no
wine-devel on Debian; installing the wrong name makes the whole transaction
fail, and the build then stops at libpipewire-0.3 not found or Wine SDK headers not found. Those are the distributions' own packages. Wine from the
WineHQ repositories works differently (see
Wine outside /usr): Fedora's wine-devel is a headers
package in /usr/include/wine, while WineHQ's wine-devel is a whole Wine
branch in /opt/wine-devel.
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build buildThe WineHQ packages install into /opt/wine-{devel,stable,staging}, and some
installer scripts drop a private Wine under $HOME. Put that Wine's bin/ on
PATH: CMake finds winebuild there and takes the headers from the same
prefix, so the SDK belongs to the Wine you build against.
PATH=/opt/wine-devel/bin:$PATH cmake -B build -DCMAKE_BUILD_TYPE=ReleaseThis works only if the SDK is installed in that prefix too. WineHQ splits every
branch in two: the branch package ships bin/ (including winebuild), while a
separate companion ships include/wine/. An /opt/wine-devel with no
include/ directory is the usual case:
# Fedora, WineHQ repository - match the branch you installed
sudo dnf install wine-devel-devel # or wine-stable-devel / wine-staging-devel
# Debian / Ubuntu, WineHQ repository
sudo apt install wine-devel-dev # or wine-stable-dev / wine-staging-devConfigure warns when winebuild comes from a prefix whose include/ has no
SDK and another Wine's headers are used instead.
Only if that fails, override the probe with -DWINE_INCLUDE_DIRS - and pass
the include directories, not the install root. All three matter: the root
resolves wine/debug.h, wine/ holds unixlib.h (needed by the 32-bit WoW64
halves), and wine/windows/ is the Win32 SDK:
cmake -B build -DCMAKE_BUILD_TYPE=Release \
-DWINE_INCLUDE_DIRS="/opt/wine-devel/include;/opt/wine-devel/include/wine;/opt/wine-devel/include/wine/windows"Debian's libwine-dev nests one level deeper (/usr/include/wine,
/usr/include/wine/wine, /usr/include/wine/wine/windows). Configure checks
the list before compiling and names whichever header it cannot reach.
Debug build (assertions and Wine debug-channel macros):
cmake -B build-debug -DCMAKE_BUILD_TYPE=Debug
cmake --build build-debugparu -S pipeasioThe package installs the driver system-wide under /usr, including the 32-bit
WoW64 front end since 1.8.1-2, plus the pipeasio-settings panel with a desktop
entry and icon. Note that a system-wide install is invisible to Proton's
container. See the Proton / Steam / Faugus section below.
If you installed the 32-bit front end by hand before 1.8.1-2, the upgrade stops
with exists in filesystem: pacman does not own those files and will not
overwrite them. Check with pacman -Qo that no package owns them, remove them,
and upgrade again:
sudo rm /usr/lib/wine/i386-windows/pipeasio32.dll /usr/lib/wine/x86_64-unix/pipeasio32.soReleases carry prebuilt driver
tarballs: pipeasio-<version>-archlinux-x86_64.tar.gz (the 64-bit driver plus
the opt-in 32-bit WoW64 front end) for the Arch / CachyOS family, and
pipeasio-<version>-debian-aarch64.tar.gz (the aarch64 driver plus the
pipeasio-manage CLI) built on Debian stable for ARM64 hosts. There is no
ARM64 AppImage: run bin/pipeasio-manage from that tarball, or build the GUI
from source. Extract the tarball for your architecture over a prefix (the
x86_64 name is shown):
# user-local (required for Proton / Faugus / Steam, see below)
tar -xzf pipeasio-*-archlinux-x86_64.tar.gz -C "$HOME/.local"
# or system-wide
sudo tar -xzf pipeasio-*-archlinux-x86_64.tar.gz -C /usrthen register. The download is scoped: its BUILD-INFO.txt
lists the exact Wine, glibc, and PipeWire it was built against. A different Wine
version or an older glibc can fail to load (regsvr32 c0000135). Build it
from source in that case.
System-wide:
sudo cmake --install build --prefix /usrThat puts the driver under /usr/lib/wine, which is where distro Wine reads
it on Arch and similar layouts. Elsewhere Wine's library dir differs:
/usr/lib64/wine on Fedora, /usr/lib/x86_64-linux-gnu/wine on
Debian/Ubuntu, and lib/wine inside the tree for WineHQ builds under
/opt/wine-<branch>. For those, point the driver files at the right root (the
tools still land under the normal prefix):
# Fedora
cmake -B build -DPIPEASIO_WINE_INSTALL_ROOT=/usr/lib64/wine
sudo cmake --install build --prefix /usr
# Debian/Ubuntu
cmake -B build -DPIPEASIO_WINE_INSTALL_ROOT=/usr/lib/x86_64-linux-gnu/wine
sudo cmake --install build --prefix /usr
# WineHQ (e.g. wine-staging)
cmake -B build -DPIPEASIO_WINE_INSTALL_ROOT=/opt/wine-staging/lib/wine
sudo cmake --install build --prefix /usrUser-local (no sudo, under $HOME, required for Proton / Faugus / Steam, see
below):
cmake --install build --prefix "$HOME/.local"Either one lays down:
<prefix>/lib/wine/x86_64-windows/pipeasio64.dll (PE front end)
<prefix>/lib/wine/x86_64-unix/pipeasio64.so (unixlib)
Upgrading from 1.6.0 or older: those installs staged a 2 KB PE stub into
every registered prefix's system32, and the new layout has no .dll.so
for that stub to find. Run pipeasio-register again in each prefix; it
replaces the stub with the real PE.
By default the driver installs under <prefix>/lib/wine, matching Wine's
upstream layout (CMAKE_INSTALL_LIBDIR does not move it);
PIPEASIO_WINE_INSTALL_ROOT overrides that root with an absolute path. Where
the driver should go depends on your Wine; see Registering
for why it matters at runtime.
After installing, register the driver in each Wine prefix. A helper script is provided:
pipeasio-registerThis activates PipeASIO for the current Wine prefix (the default is ~/.wine).
To target another prefix:
env WINEPREFIX="$HOME/asioapp" pipeasio-registerpipeasio-register searches for the install root in this order:
$PIPEASIO_PREFIX/lib/wine, then $HOME/.local/lib/wine, then
/usr/local/lib/wine, then /usr/lib/wine, then distro variants, then
/opt/wine-{devel,stable,staging}/lib{,64}/wine. Set PIPEASIO_PREFIX to
point it at a non-standard install, or PIPEASIO_REGISTER_CANDIDATES to
replace the built-in list entirely (colon-separated; PIPEASIO_PREFIX is
still searched first).
Registration only makes the driver visible to a prefix. At launch, Wine
resolves the driver's Unix half only in its own library dir and in
WINEDLLPATH, so the install root must be that library dir: /usr/lib/wine
on Arch/Fedora layouts, /usr/lib/x86_64-linux-gnu/wine on Debian/Ubuntu, or
the lib/wine inside a WineHQ /opt/wine-<branch> tree.
pipeasio-register compares the install root against the wine on your
PATH and warns when they mismatch. The fix is to install into the matching
root (-DPIPEASIO_WINE_INSTALL_ROOT=..., see Installing) or to
set WINEDLLPATH=<driver-install-root> in the host's launch environment.
The script runs whatever wine is on PATH; WINE=<command> substitutes
another launcher, umu-run included. Proton prefixes (anything with a
tracked_files) and Bottles bottles (anything with a bottle.yml) are refused
unless WINE is set, see Proton / Steam / Faugus and
Bottles.
PipeASIO is 64-bit by default. A front end for 32-bit Windows ASIO hosts
(foobar2000 foo_out_asio, older REAPER builds, ...) can be built opt-in via
Wine's new WoW64: it is the same PE front end compiled for i386, over a
unixlib built from the same sources as the 64-bit one. There is no 32-bit
libpipewire and no 32-bit Linux userspace - only the Windows-facing half is
i386.
Experimental, off by default. The 64-bit driver is byte-for-byte unaffected. The 32-bit path is validated end-to-end by the
asio_probe32host and by VB-Audio's VBASIOTest32 (a real i386 ASIO host): COMInit -> CreateBuffers -> Start, real-time streaming, autoconnect to the selected hardware, and live config reload all work. Bit-exact loopback validation on 32-bit is still pending.
It needs the i686 MinGW cross-compiler on top of the normal build
requirements (mingw-w64-gcc on Arch covers both; Debian/Ubuntu split it):
sudo apt install gcc-mingw-w64-i686 # Debian / UbuntuConfigure with -DBUILD_WOW64_32=ON (default OFF). Set WINE_LIB_ROOT if your
Wine library prefix is not /usr/lib/wine:
cmake -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_WOW64_32=ON
cmake --build buildInstalling then lays the 32-bit halves alongside the 64-bit ones:
<prefix>/lib/wine/i386-windows/pipeasio32.dll (PE front end)
<prefix>/lib/wine/x86_64-unix/pipeasio32.so (unixlib, 64-bit ELF)
pipeasio-register handles both architectures automatically: it registers the
CLSID under the 64-bit registry view and, when pipeasio32.dll is present, the
same CLSID under the 32-bit view (regsvr32 /reg:32). 32-bit and 64-bit hosts
can then use PipeASIO from the same prefix.
Under Proton, 32-bit apps additionally need PROTON_USE_WOW64=1 (or Faugus's
WoW64 toggle) so Proton runs them through new WoW64 - see
Proton / Steam / Faugus.
The GUI manager does this for Faugus games. For Steam games it does everything but step 2, and shows the launch options to paste. The manual steps follow.
Proton runs Wine inside a pressure-vessel container (steamrt4). The container does
not expose the host's /usr/lib/wine/, so a system-wide install is invisible to
Proton's Wine. Two things make PipeASIO work inside Proton (32-bit apps need a
third, see step 3):
-
Install PipeASIO under
$HOME(pressure-vessel exposes the home directory by default):cmake --install build --prefix "$HOME/.local" -
Set
WINEDLLPATH=$HOME/.local/lib/winein the launcher's per-game environment so Proton's Wine finds the ELF.sohalf. Proton has honored a host-providedWINEDLLPATHsince PR #9420, and Proton-CachyOS ships this fix.-
Steam: put it in the game's launch options (right-click the game > Properties > General):
WINEDLLPATH=/home/<you>/.local/lib/wine %command% -
Faugus: put it in the per-game "Launch options" environment field:
WINEDLLPATH=/home/<you>/.local/lib/wine
Use the absolute path. Faugus does not expand
~or$HOMEin that field. -
-
32-bit games and hosts only: enable Proton's new WoW64 mode, which the 32-bit front end requires (see 32-bit applications). By default Proton runs 32-bit apps through the classic split-WoW64 Wine libraries, which cannot load PipeASIO's 32-bit half.
-
Steam: add
PROTON_USE_WOW64=1alongsideWINEDLLPATHin the game's launch options:PROTON_USE_WOW64=1 WINEDLLPATH=/home/<you>/.local/lib/wine %command% -
Faugus: enable the WoW64 option in the game's settings, or add
PROTON_USE_WOW64=1to the same per-game "Launch options" environment field asWINEDLLPATH.
64-bit games and hosts do not need this.
-
Then register PipeASIO in the Proton wineprefix through the runner, not
through the host's wine: umu-run runs a Windows executable inside the same
runner and container the game uses, and pipeasio-register runs whatever
WINE names in place of wine:
env WINEPREFIX="$HOME/Faugus/<game>" \
WINE=umu-run \
PROTONPATH="$HOME/.local/share/Steam/compatibilitytools.d/<runner>" \
GAMEID=umu-<game> \
pipeasio-registerPROTONPATH is the full path of the runner directory the game is configured
with, under ~/.local/share/Steam/compatibilitytools.d/ or
/usr/share/steam/compatibilitytools.d/; a bare name only resolves for runners
in the user directory. GAMEID is any stable label; without one umu falls back
to umu-default. Faugus bundles umu-run at
~/.local/share/faugus-launcher/umu-run if the umu-launcher package is not
installed. For a Steam game the prefix is
~/.steam/steam/steamapps/compatdata/<appid>/pfx. The PE stub lands in
<prefix>/drive_c/windows/system32/ and the CLSID registration persists in
the prefix registry, both shared across Wine versions.
pipeasio-register refuses a Proton prefix when WINE is unset. Host Wine is
a different build from the runner's, and the first host-Wine process in a
prefix runs Wine's prefix update, rewriting the registry and system32 for the
host build (#22). Unregistering
uses the same environment, see Uninstalling.
Note
Bottles support is experimental and not actively maintained. In my use, Bottles has been too unreliable to build on: some of its buttons do not render properly, the ones that do treat a click as a suggestion, and its updates break these steps and the manager's Bottles integration often enough to keep things interesting. Bottles Next, the rewrite announced in October 2023, has been "next" ever since. Reports are welcome, but Bottles-specific problems may not get fixed. PipeASIO focuses on plain Wine prefixes and Faugus.
Bottles runs each bottle with its own downloaded runner (Soda, Caffe, a GE
build), never the host's Wine, and the Flatpak build runs it inside a sandbox
that sees neither /usr/lib/wine nor $HOME/.local/lib/wine. The driver
stays where cmake --install put it; the bottle gets the PE stub and a
WINEDLLPATH pointing at the ELF half, and registration runs through Bottles'
own launcher so the bottle's runner is the Wine that registers it. Verified
with the Flatpak (com.usebottles.bottles 67.2, Soda 11.0) against a driver
installed under $HOME/.local:
# Once: let the sandbox read the driver and reach PipeWire at run time.
flatpak override --user --filesystem="$HOME/.local/lib/wine:ro" com.usebottles.bottles
flatpak override --user --filesystem=xdg-run/pipewire-0 com.usebottles.bottles
BOTTLE="$HOME/.var/app/com.usebottles.bottles/data/bottles/bottles/<name>"
CLI="flatpak run --command=bottles-cli com.usebottles.bottles"
# The PE stub goes where regsvr32 finds it by name; the ELF half is reached
# through WINEDLLPATH in the bottle's environment.
cp "$HOME/.local/lib/wine/x86_64-windows/pipeasio64.dll" "$BOTTLE/drive_c/windows/system32/"
$CLI edit -b <name> --env-var "WINEDLLPATH=$HOME/.local/lib/wine"
$CLI shell -b <name> -i "regsvr32 /s pipeasio64.dll"
$CLI shell -b <name> -i "reg query HKLM\\Software\\ASIO\\PipeASIO"
# 32-bit hosts, if the install carries the 32-bit half:
cp "$HOME/.local/lib/wine/i386-windows/pipeasio32.dll" "$BOTTLE/drive_c/windows/syswow64/"
$CLI shell -b <name> -i "C:\\windows\\syswow64\\regsvr32.exe /s pipeasio32.dll"<name> is the bottle's directory name under data/bottles/bottles/; shell
needs the backslashes doubled as shown. The PipeWire override is what the
driver needs at run time, not for registering: without it the sandbox holds an
empty file at the socket's path. Native Bottles (the distribution package)
keeps its data under ~/.local/share/bottles/ and runs the same bottles-cli
directly, with no flatpak override lines. Copying the driver into the
runner's own lib/wine/ works as well but a runner update wipes it.
pipeasio-register refuses a bottle (anything with a bottle.yml) when WINE
is unset, for the reason given for Proton above: host Wine in a bottle
re-stamps it for the host build, and the next Bottles launch stamps it back,
so the two keep migrating the prefix between builds. For native Bottles
WINE=~/.local/share/bottles/runners/<runner>/bin/wine makes the script
register through the runner instead.
ARM64 Linux runs Windows audio hosts two ways: native ARM64 builds (FL Studio
24.1+ has one), and x86_64 builds under Wine with FEX (Ableton, older FL
Studio, most of what exists). The driver's front end for both is one
aarch64-windows/pipeasio64.dll over the aarch64 unixlib
(#23).
To serve both kinds of host from one install, that DLL is an ARM64X hybrid
carrying aarch64 and arm64ec code in one file. A Wine built for both aarch64
and arm64ec keeps no separate arm64ec-windows directory: its
aarch64-windows libraries hold both halves, and Wine finds builtins for
native and x86_64 programs in that one directory, WINEDLLPATH included. A
plain aarch64 DLL only loads into native ARM64 hosts. A plain arm64ec DLL loads
for x86_64 hosts only when copied into system32 by hand, because Wine finds
no arm64ec-windows directory through WINEDLLPATH. The hybrid is what lets
pipeasio-register and the manager install one file for both.
Building needs clang and lld (there is no MinGW gcc for these targets)
and Wine's lib/wine/aarch64-windows/ import libraries. BUILD_ARM64
(default on) links the ARM64X hybrid when those libraries carry arm64ec code
and the linker is LLD 20 or newer, and a plain aarch64 DLL otherwise.
Configure prints which one, and why when it falls back:
-- ARM64 front end: ARM64X (aarch64 + arm64ec)
A Wine built with --enable-archs=aarch64,arm64ec (Hangover's packages, for
example) gives the hybrid. Debian stable's own LLVM is 19, so take clang-21
and lld-21 from trixie-backports and put /usr/lib/llvm-21/bin first on
PATH. Debian's libwine-dev on arm64 has no arm64ec code, so the Debian
aarch64 release tarball serves native ARM64 hosts only.
Fedora does not build Wine for aarch64 at all. On an x86_64 host only the PE
half can be cross-built; the unixlib is always the host's.
Status: CI builds both forms on an ARM64 runner. Against Hangover's Wine it links the hybrid, registers it, and loads it from an x86_64 program under FEX, which is the path Ableton takes. Ableton Live has played audio on real ARM64 hardware through the ARM64X hybrid from 1.10.0 (Lenovo IdeaPad Duet 3, Fedora in a container, FEX, Wine 11.13). At 512 frames it crackles occasionally there, with nothing else running (#23). No report yet covers a native ARM64 host. Reports from Asahi or other ARM64 machines go on the tracking issue.
Active support targets Arch Linux and its derivatives (CachyOS, EndeavourOS,
Manjaro), but PipeASIO itself is distribution-agnostic: it is plain
libpipewire-0.3 plus Wine, with no distro-specific code paths, so it runs
wherever those are available. A few environment details differ between distros
and are the usual causes of trouble elsewhere:
- Wine library layout. Both DLL halves must land under the distro's
lib/wine/x86_64-{windows,unix}/directory:/usr/lib/wineon Arch,/usr/lib/x86_64-linux-gnu/wineon Debian/Ubuntu,/usr/lib64/wineon Fedora. Match it with-DPIPEASIO_WINE_INSTALL_ROOT=...at configure time (see Installing);WINE_LIB_ROOTonly locates the 32-bit import libraries at build time and does not affect install locations. A user-local--prefix "$HOME/.local"install plusWINEDLLPATHsidesteps the question entirely. - Wine version. Tested with Wine 10.0 and 11 and with Proton 10 and 11.
Proton 10 runs in Steam Runtime 3, whose PipeWire library is 0.3.65. The
driver runs against it unchanged. The experimental 32-bit front end
additionally requires Wine's new WoW64, at any version: Proton's
PROTON_USE_WOW64=1(Faugus's WoW64 option) or a Wine built for new WoW64. Split-WoW64 Wine cannot load it. - PipeWire version. 1.4.2 or newer, the version Steam Runtime 4 and Debian
13 ship; configure refuses anything older. The forced quantum/rate that pins
low latency is not what sets this floor - those properties have existed since
PipeWire 0.3.45. What does raise latency is the daemon clamping the forced
quantum to
clock.min-quantum/clock.max-quantum, at any version; the driver logs a warning naming both when that happens. - Real-time priority. The driver runs at normal scheduling by default;
SCHED_FIFOpriority 15 is opt-in. See Performance for access requirements.
PipeASIO talks to PipeWire 1.4.2+ natively through libpipewire-0.3. The graph
quantum is locked to the ASIO host's negotiated buffer size with
PW_KEY_NODE_FORCE_QUANTUM (unless follow_device_clock is set, in which case the
target device drives the cycle). The sample rate follows the graph unless pinned
with sample_rate, in which case PW_KEY_NODE_FORCE_RATE is set.
Settings live in a flat INI file at $XDG_CONFIG_HOME/pipeasio/config.ini
(fallback ~/.config/pipeasio/config.ini). The driver reads it at startup and
re-reads it while running, so saving in the settings panel applies within about a
second without reselecting the driver or restarting the host. Every option can
also be overridden by an environment variable. A missing file means built-in
defaults, and unknown keys are ignored. The file has a single [pipeasio]
section.
Number of PipeWire DSP ports PipeASIO opens. Default 2 / 2.
Env: PIPEASIO_NUMBER_INPUTS, PIPEASIO_NUMBER_OUTPUTS.
Default 1: connect the channels to a hardware device on start. Set to 0 to leave
the node unconnected and patch it yourself in a PipeWire patchbay.
Env: PIPEASIO_CONNECT_TO_HARDWARE (on/off).
The PipeWire node.name of the sink (output) and source (input) to auto-connect
to. Empty (the default) follows the PipeWire default sink/source, re-resolved each
time the driver reconnects.
Env: PIPEASIO_OUTPUT_DEVICE, PIPEASIO_INPUT_DEVICE.
0 (default) follows the PipeWire graph rate, and lets the ASIO host choose one:
CanSampleRate() then offers 44100, 48000, 88200, 96000, 176400 and 192000, and
SetSampleRate() pins the graph to the host's choice with
PW_KEY_NODE_FORCE_RATE on the next activation. A non-zero value pins the rate
here instead and the host can no longer change it, the same way
fixed_buffer_size takes the buffer size away from the host. Hosts that demand a
specific rate need this left at 0; Rocksmith through RS_ASIO requires 48 kHz.
Env: PIPEASIO_SAMPLE_RATE.
Default 1: the buffer size is controlled by PipeWire and the ASIO host cannot
change it. Set to 0 to let the host change PipeWire's quantum (via
PW_KEY_NODE_FORCE_QUANTUM) in CreateBuffers().
Env: PIPEASIO_FIXED_BUFFERSIZE (on/off).
Default 0 (off): the driver pins the PipeWire graph quantum to the host's buffer
size, runs as its own low-latency clock master, and is scheduled synchronously.
Set to 1 and two properties change together. The driver drops FORCE_QUANTUM,
so the target device drives the cycle and dictates the buffer size (the driver
settles to the device's quantum after one automatic reset), and the node turns
asynchronous (PW_KEY_NODE_ASYNC), which pw-top marks = instead of +.
Asynchronous costs one more buffer period of round trip and in exchange absorbs
a callback that overruns instead of stalling the graph. The settings panel's
read-only Scheduling row names the resulting mode and that extra period.
Reach for it when a Bluetooth sink is silent or drifts: its clock is the radio
link and cannot always be slaved to the host, and PipeWire then drops the links.
Not every Bluetooth sink needs it; some accept a forced quantum and run
synchronously.
Env: PIPEASIO_FOLLOW_DEVICE_CLOCK (on/off).
The preferred size returned by GetBufferSize(). Must be a power of two within
[32, 8192]. Out-of-range values fall back to 1024. The floor is 32 rather than 16
because hosts mishandle smaller ASIO buffers (Max/MSP crashes on them), and
RS_ASIO rounds every request up to a multiple of 32 regardless.
Env: PIPEASIO_PREFERRED_BUFFERSIZE.
A size the hardware does not support makes PipeWire reject the request or insert resampling, and either way you may get xruns.
Overrides the PipeWire client/node name (otherwise derived from the host program
name).
Env: PIPEASIO_CLIENT_NAME.
Default 0 (off), experimental. When enabled, the thread carrying the host's
bufferSwitch callback uses SCHED_FIFO priority 15, covering both the native
PipeWire data loop and the WoW64 PE pump.
Only that one thread is elevated. A host that dispatches DSP work from the
callback to its own worker threads leaves those workers at SCHED_OTHER, and
the resulting priority asymmetry can make things much worse: measured on FL
Studio 2025 under Wine at 64 frames / 48 kHz, enabling this produced roughly 39x
more xruns on the PipeASIO node than leaving it off.
In FL Studio, also turn Mix in buffer switch off (Options > Audio settings >
Input / output) before enabling this. That option makes FL Studio run its mixing
and plugin processing inside the ASIO bufferSwitch callback, which the driver
delivers on the PipeWire data loop. With
follow_device_clock off the driver is scheduled
synchronously (see Performance), so the callback has one buffer
period to return and a full mixer pass does not fit: the graph stalls instead of
absorbing the overrun. With Mix in buffer switch off, FL Studio mixes on its
own threads and the callback only hands over buffers that are already filled.
Useful as a diagnostic for the scheduling-related xruns in #4, not as a fix for them. It takes effect the next time the host starts the driver.
Env: PIPEASIO_RT_PRIORITY (off/on). The environment overrides the file.
A few knobs affect xrun-free, low-latency operation:
- Real-time scheduling. The callback thread runs at normal scheduling by
default;
SCHED_FIFOis opt-in viarealtime, and on multi-threaded hosts it often costs more xruns than it saves. When you do opt in, the requested priority is 15 (the previous native/WoW64 defaults were 77/80). It must stay below the PipeWire daemon's data loop: RTKit caps that loop at 20 on stock desktops, while PAM/realtime-group setups may run it higher, where either value is below the daemon. On other distributions you usually set real-time access up yourself; the driver does not use RTKit. Without the grant the thread stays at normal scheduling. Verify withulimit -r(at least 15; use a higher limit only if you pinloop.rt-prio). - Channel count. Every input and output is a PipeWire port the graph must
schedule. Defaults are 2 in / 2 out. Raise
inputs/outputsonly to what you route. Fewer ports mean a smaller graph and less overhead. - Buffer size. Smaller buffers cut latency but raise CPU and xrun risk.
- Graph scheduling. The driver runs synchronously in the graph, so the round
trip is one buffer period instead of two. The trade is that a callback which
overruns stalls the graph instead of being absorbed, so pick a buffer size
the host can meet.
follow_device_clockschedules asynchronously instead, which adds a buffer period and absorbs the overrun;pw-topmarks the node=when it is asynchronous and+when it is not. - Host-side callback work. Whatever the host does inside
bufferSwitchruns inside the driver's cycle and counts against that same deadline. Hosts that offer to mix there - FL Studio's Mix in buffer switch - should have it turned off, so the callback only exchanges buffers a host thread has already prepared. - Reported latency.
GetLatencies()returns one buffer period plus whatever the connected device chain reports through PipeWire, so a host's delay compensation lines up with the real hardware instead of assuming the buffer is the only delay. Measured on a wired card at 1024/48000 the figure is 2080 in and 2048 out; a USB or Bluetooth chain declares more. The driver relayskAsioLatenciesChangedwhen it moves, so a host can re-read it without a full reset. - Xruns. When the graph runs a cycle the driver was too slow for, it logs
xrun: missed the cycle deadlinewith a running count for the activation (the first, then every 64th, so a storm cannot flood the log). That is the driver's own accounting; the settings panel's counter is PipeWire's per-node figure, read from the graph's Profiler interface (the same sourcepw-topuses), which covers the whole graph. - Debug logging.
PIPEASIO_DEBUG=1makes the driver log on the audio path. Leave it off for normal use. The log opens with the build the host loaded: version, commit, which front end (x86_64,i386WoW64, or theaarch64orarm64echalf of an ARM64X hybrid), the Wine build and the kernel. The unixlib'saudio_openline repeats the version, commit and architecture, so a front end and unixlib from different builds stand out. Include both lines in bug reports. Where git cannot read the checkout (a source tarball, or a container building as root on a checkout owned by another user) the commit isunknown. Pass-DPIPEASIO_GIT_COMMIT=<sha>, or set the environment variable of the same name at configure time, to supply it.
The native settings panel (pipeasio-settings, C++/Qt6 Widgets) is built from the
gui subdirectory and installed to bin, together with a desktop entry and icon,
so it also appears in the application menu as PipeASIO Manager. It is built
only when Qt6 Widgets is found at configure time - otherwise configure warns,
the driver still builds, and no panel binary is produced. It runs on
your Linux host. The in-app ASIO control-panel button shows a message pointing
here, because the Qt panel cannot run inside the Wine/Proton container the host
loads the driver into.
The Monitor tab is a native PipeWire client: it binds the graph's Profiler
interface and is pushed one timing point per audio cycle, the same source
pw-top reads, so quantum, rate, xruns and DSP load match the CLI. That
interface comes from PipeWire's module-profiler, which stock configurations
load; if yours does not, the tab says no Profiler interface (load PipeWire's module-profiler) instead of showing telemetry. The connection is held only
while the Monitor tab is showing, so the panel holds none of it while parked on
another tab. The device combos on the Settings tab enumerate through
pw-dump.
Configure fails with libpipewire-0.3 not found or Wine SDK headers not found. The development packages are missing or named differently on your distribution - see Building for the per-distro sets. Fedora has pipewire-devel and wine-devel, not libpipewire-0.3-dev or winehq-*-dev.
Configure fails with Package 'libpipewire-0.3' has version 'X', required version is '>= 1.4.2'. Your distribution's PipeWire predates the minimum. Ubuntu 24.04 LTS (1.0.5) is the case that actually hits people; Ubuntu 25.10 (1.4.7), Ubuntu 26.04 LTS (1.6.2), Debian 13 (1.4.2), Fedora 43 (1.4.8), Fedora 44 (1.6.2) and Arch are all above the floor. There is no workaround in the driver: src/audio.c uses spa_json_str_object_find(), added in PipeWire 1.4.0, so an older PipeWire could never build - it only used to fail later with implicit declaration of function. Upgrade the distribution, or build PipeWire 1.4.2+ yourself and point PKG_CONFIG_PATH at it. The build then links that copy by absolute path rather than by -l name, so it cannot silently fall back to the system library - but the runtime loader still has to find it, via LD_LIBRARY_PATH or an ldconfig entry.
Build fails with wine/debug.h or unixlib.h: No such file or directory. Configure picked an SDK that does not hold the headers. For Wine outside /usr, install its SDK companion (wine-devel-devel on Fedora, wine-devel-dev on Debian/Ubuntu, matching your branch) and put that prefix's bin/ on PATH. A manual -DWINE_INCLUDE_DIRS must list the include directories, not the install root, and needs all three: /opt/wine-devel/include;/opt/wine-devel/include/wine;/opt/wine-devel/include/wine/windows. The wine/ one carries unixlib.h, used only by the 32-bit WoW64 build.
... holds no Wine SDK, so ... is used instead. winebuild came from a private prefix with no headers beside it, so another Wine's SDK was used. Install the matching -devel/-dev companion package, or the driver is compiled against a different Wine version than it runs on.
Qt6 Widgets not found - skipping the settings panel. The driver still builds, but pipeasio-settings does not, so there is no panel to open. Install Qt6 Widgets (qt6-base on Arch, qt6-qtbase-devel on Fedora, qt6-base-dev on Debian/Ubuntu), then re-run configure, rebuild and re-install. Run it from a host terminal or the PipeASIO Manager menu entry; your DAW's ASIO control-panel button never opens it, with or without Qt, and only shows a message pointing here. Pass -DBUILD_SETTINGS_PANEL=OFF if you want no panel.
No sound, or the driver does not load under Proton. Proton's container cannot see /usr/lib/wine. Install under $HOME and set WINEDLLPATH in the game's launch options (Steam: WINEDLLPATH=/home/<you>/.local/lib/wine %command%; Faugus: the same variable in the per-game environment field), then register in that prefix.
A 32-bit game or host does not list PipeASIO under Proton. Proton runs 32-bit apps through classic split WoW64 by default, which cannot load the 32-bit front end. In Steam, add PROTON_USE_WOW64=1 alongside WINEDLLPATH in the game's launch options (PROTON_USE_WOW64=1 WINEDLLPATH=/home/<you>/.local/lib/wine %command%). In Faugus, enable the WoW64 option in the game's settings. The install must also include the 32-bit half (-DBUILD_WOW64_32=ON).
Registering fails with status c0000135. Wine loaded the PE half but could not load its unixlib (pipeasio64.so). Either Wine is not looking where it is installed (set WINEDLLPATH to the install's lib/wine, or install into Wine's own library dir, see Registering), or the unixlib was built against a different Wine or glibc than the one running (a prebuilt tarball on the wrong host; rebuild from source). An install from 1.6.0 or older that was never re-registered fails the same way, since the stub it left in system32 looks for a .dll.so that no longer exists: run pipeasio-register again.
Bluetooth headphones produce no sound. Turn on follow_device_clock (or set PIPEASIO_FOLLOW_DEVICE_CLOCK=on). A Bluetooth sink's clock is the radio link and cannot always be slaved to the host, so the driver follows it instead. Some Bluetooth sinks do accept a forced quantum and work with the option off, which keeps the synchronous scheduling and its lower latency, so try it both ways.
FL Studio crackles or xruns constantly, especially with realtime enabled. Turn Mix in buffer switch off in Options > Audio settings > Input / output. It makes FL Studio mix and run plugins inside the ASIO callback, which the driver delivers on the PipeWire data loop with one buffer period to return; a full mixer pass overruns that, and with follow_device_clock off the driver is scheduled synchronously, so the overrun stalls the graph rather than being absorbed. With it off, FL Studio mixes on its own threads and the callback only hands over ready buffers.
Does it conflict with WineASIO? No. PipeASIO has its own CLSID and registry identity, so it installs side by side with WineASIO and hosts list them as separate drivers.
How do I select it in my DAW? After registering, pick PipeASIO from the host's ASIO device list. In FL Studio that is Options > Audio settings > Device.
Where is it in my volume mixer? The driver's node is a playback stream
(media.class = Stream/Output/Audio), so it appears under the host's name in
pavucontrol, plasma-pa, pulsemixer and wpctl status, with a volume slider and
mute like any application. The slider scales what the host plays, per output
channel, inside the driver; the host's inputs are not affected. WirePlumber
remembers the level per host the way it does for every stream, so a level you
set for FL Studio comes back the next time FL Studio starts the driver. The
node is not auto-routed by WirePlumber (it carries no node.autoconnect);
auto_connect and the device settings still decide where it
links.
Unregister from each Wine prefix you registered, then remove the files:
# Unregister (set WINEDLLPATH the same way pipeasio-register does)
env WINEDLLPATH="$HOME/.local/lib/wine" wine regsvr32 /u pipeasio64.dll
# Proton prefix: same, through the runner, never host wine
env WINEDLLPATH="$HOME/.local/lib/wine" PROTONPATH=<runner dir> GAMEID=umu-<game> \
umu-run regsvr32 /u pipeasio64.dll
rm -f "$WINEPREFIX/drive_c/windows/system32/pipeasio64.dll"
# Remove the installed files (CMake records them at install time)
xargs rm -f < build/install_manifest.txtRecommended VS Code extensions are listed in .vscode/extensions.json. The build
emits build/compile_commands.json for clangd. The in-tree .clang-format and
.editorconfig keep diffs clean.
PipeASIO is a fork of WineASIO that
talks to PipeWire directly through libpipewire-0.3, with no libjack.so.0
runtime dependency. The fork exists because the Steam Runtime steamrt4
container that Proton uses ships libpipewire-0.3 but not libjack.so.0,
which makes upstream WineASIO crash on dlopen.
The driver has its own COM identity: CLSID
{2D3CA9E2-1193-4C5D-B5FD-38798F3DC074}, ASIO registration under
HKLM\Software\ASIO\PipeASIO, and DLL filename pipeasio64.dll. That is why
it coexists with WineASIO: neither overrides the other.
It is built the way Wine builds its own modules: a PE half (src/asio.c,
src/main.c, src/regsvr.c, src/unixlib/audio_proxy.c, cross-compiled with
MinGW) and a unixlib (src/audio.c, src/unixlib/audio_unix.c, host gcc)
that talk over the call table in include/pipeasio_unix_abi.h. The ABI is
handles and fixed-width integers, never pointers, so one unixlib serves both
the x86_64 and the i386 front end. The PipeWire data loop runs in the
unixlib; a PE-side pump thread blocks in PAU_WAIT_CALLBACK, is woken once
per cycle, and carries the host's bufferSwitch. Measured against the older
single-ELF build at 128 frames, the handoff costs no round-trip latency and
no xruns. The split is also what aarch64 and arm64ec Wine require.
ctest --test-dir build runs the Linux-native unit and contract tests plus the
Wine integration tests below (they SKIP without wine, pw-cli, a running
PipeWire daemon, and an installed driver). The two Wine-based tools can also be
run directly against a live PipeWire session:
./build/tests/asio_probe/run.sh # COM lifecycle + bufferSwitch cycle rate
./build/tests/asio_loopback/run.sh # digital loopback analyzer
SWEEP=1 ./build/tests/asio_loopback/run.sh # buffer-size x sample-rate matrixThe loopback analyzer plays a per-channel frame counter out of the driver's
output ports and verifies it on the input ports after a PipeWire null-sink
loopback. Because PipeASIO is float32 end-to-end, the round trip must be
bit-exact. The tool fails on any corrupted sample, dropped or duplicated
buffer, swapped channel, or a measured round-trip latency that disagrees with
GetLatencies() by more than one buffer. SWEEP=1 repeats this across buffer
sizes 128-1024 and forced sample rates 44.1/48/96 kHz, re-negotiating buffers
in-process the same way a DAW does when you change the buffer size.
When built with -DBUILD_WOW64_32=ON, a 32-bit analogue of the probe exercises
the full COM + real-time round trip on a 32-bit (WoW64) host:
./build/tests/asio_probe/run32.sh # 32-bit WoW64 driver (needs MinGW + a 32-bit prefix)Cross-distro builds (needs distrobox plus podman or
docker) exercise the same Release configure against each distro's injected
package-build flags - the path that broke on Fedora's -flto=auto before
#6 was fixed:
./tests/distro/run.sh # fedora + ubuntu + arch
DISTROS="fedora ubuntu" ./tests/distro/run.sh
FRESH=1 ./tests/distro/run.sh # recreate containers first
./tests/distro/run.sh --clean # remove harness containersThe script SKIPs (exit 77) when distrobox or a container backend is missing.
CI runs the Fedora and Ubuntu legs on every push/PR via the build-distros
matrix job.
If you package PipeASIO, consider installing the pipeasio-register helper script
as part of the package.
PipeASIO builds on WineASIO and the work of its authors: Robert Reif, Ralf Beck, Johnny Petrantoni, Stephane Letz, William Steidtmann, Peter L Jones, Torben Hohn, Nedko Arnaudov, Christian Schoenebeck, Joakim Hernberg, and Filipe Coelho.
PipeASIO is licensed under the GNU General Public License, version 3 or later
(GPL-3.0-or-later). See COPYING. It is a fork of WineASIO and
retains the original authors' copyright notices, and every source file carries
an SPDX-License-Identifier tag.
See CHANGELOG.md.
