Desktop Audio Visualizer with i3 and Cava on WSL
After seeing pictures of people running desktop audio visualizers on Reddit, I started to think if it is possible to replicate the effect on my i3-gaps setup running on Windows Subsystem for Linux (WSL).
If you are interested in the basic idea of running i3 on WSL, you can check out this post, which describes the basic setup.
Okay, now that you know how to do the basic setup, we can now discuss the details.
Running the Visualizer on the Desktop
i3 does not support the EWMH hint _NET_WM_WINDOW_TYPE_DESKTOP
, which
tells the window manager to render the window on the desktop, behind all other
windows. This makes it difficult to display things like visualizers on the
desktop.
Fortunately, the authors of GLava managed to find a solution involving
unmanaged windows (override_redirect
) and XLowerWindow
. Unfortunately, GLava
does not run very well on WSL, requiring software rendering since the X11 server
runs on Windows and is being treated as remote. On my machine, GLava runs, but
consumes around 80% of the CPU on all cores. Clearly, another solution is
needed.
Cava is a visualizer that runs in the terminal. The obvious solution here
is to run Cava in a terminal emulator. I used urxvt
as recommended by the
author of Cava for its performance.
However, urxvt
does not support running as a desktop window, and definitely
does not support GLava’s hack to do it on i3. The same is true for any other
terminal emulator that I am aware of. While it is possible to run a patched
version with the hack builtin, I consider such a solution inelegant.
I recalled that urxvt
supported embedding into another window, and thought
that perhaps embedding urxvt
into a window that is configured to run on the
desktop would work. I tried out the idea it worked. And thus i3bgwin
was born.
The command to run i3bgwin
with a transparent rxvt
running cava
inside is:
$ i3bgwin urxvt -depth 32 -bg '[00]black' --color6 '[50]cyan' +sb -embed {windowid} -e cava
To run this automatically with i3
, put the following in ~/.config/i3/config
:
exec_always --no-startup-id killall cava; exec i3bgwin urxvt -depth 32 -bg '[00]black' --color6 '[50]cyan' +sb -embed {windowid} -e cava
Now, assuming you have Cava setup somehow, you should have Cava transparently over the desktop, and any i3-managed window should show up over it.
Sourcing the Windows Audio Output
Cava can only source audio from ALSA, PulseAudio or MPD via a FIFO (a named pipe). Clearly, ALSA is not possible.
It is possible to run the PulseAudio server on Windows and let Cava source audio from that, but it forces you to play music from inside WSL. In a future post, I might explain more about how to set up PulseAudio this way.
The last option is MPD. You can definitely run MPD on WSL and output to a named pipe, but it still forces you to play music from inside WSL.
Taking a closer look at the MPD option, I found that Cava simply expects raw signed 16-bit PCM audio sampled at 44100 Hz in the named pipe. So theoretically, it is possible to pipe in audio from any source, as long as it is in the correct format… even if the audio comes from Windows.
Update (2021-3-17): You are now recommended to use winscap
instead of
fmedia
.
Using winscap
I wrote winscap
for this precisely this task. To use it, you can simply
download the binaries or source code from GitHub.
You can then simply run the following commands to:
$ mkfifo <named pipe location>
$ /mnt/c/path/to/winscap.exe 2 48000 16 > <named pipe location>
You should replace <named pipe location>
with the desired path for your named
pipe, as well as /mnt/c/path/to/winscap.exe
.
Using fmedia
(old)
I found that fmedia
supports capturing audio via WASAPI loopback, which
is used to record the sound output. While other recording tools may work, the
ones I tried could only record sound from input devices. You can use the hidden
“Stereo Mix” input device on Windows to record the sound, but this makes
Windows 10 display a microphone icon, warning that your microphone is being
used. This makes it impossible to tell when your actual microphone is being
used, defeating the privacy feature.
Update (2021-3-17): Note that winscap
does not make Windows think the
microphone is being used.
The following fmedia
command will record your audio output to stdout
:
fmedia.exe --notui --record --dev-loopback=1 --format=int16 --rate=44100 --channels=2 -o @stdout.wav
You might need to change --dev-loopback=1
to reflect your actual output
device. The command to view the list of devices is fmedia.exe --list-dev
.
Now, we simply need to feed this into a named pipe. We can easily achieve this
with socat
:
socat PIPE:<named pipe location> EXEC:"/mnt/c/path/to/fmedia.exe --notui --record --dev-loopback=1 --format=int16 --rate=44100 --channels=2 -o @stdout.wav"
You should replace <named pipe location>
with the desired path for your named
pipe, as well as /mnt/c/path/to/fmedia.exe
.
Configuring cava
Then, you can configure cava
to use this pipe:
[input]
method = fifo
source = <named pipe location>
Then, you can run cava
to see your Windows audio output visualized.
To automatically start winscap
when i3 starts, put this in
~/.config/i3/config
:
exec_always --no-startup-id pkill winscap.exe; exec /mnt/c/path/to/winscap.exe 2 48000 16 > <named pipe location>
Autostart fmedia
(old)
To automatically start socat
and fmedia
when i3 starts, put this in
~/.config/i3/config
:
exec_always --no-startup-id pkill -f -- '--record --dev-loopback=1'; exec socat PIPE:<named pipe location> EXEC:"/mnt/c/path/to/fmedia.exe --notui --record --dev-loopback=1 --format=int16 --rate=44100 --channels=2 -o @stdout.wav"
Also, you may notice that there is a delay, and the movement is not smooth. This is because
fmedia
buffers. To fix this, open up fmedia.conf
, find
mod_conf "#file.stdout"
and change the section to:
mod_conf "#file.stdout" {
buffer_size 4k
}
I hope you found this guide helpful in creating your dream workspace.