My work laptop provided by SURF, a Dell Pro 14 Premium, runs a custom Dell Ubuntu 24.04 ISO since otherwise half of the peripherals don’t work. Ubuntu 24.04 comes with PipeWire so I was curious if the Digiface would work with such a setup. Well, it does, albeit with some quirks.
First of all PipeWire also doesn’t get the outputs right. With the help of WirePlumber I could map channels 33 and 34 of the phones output to Front Left and Front Right. But then the next issue popped up: weird garbled, phasing, ringing audio. When using ALSA directly with Ardour this happened too so it’s not a PipeWire issue. Tried tweaking things first and also tried a recent Liquorix kernel. To no avail. Then I started trying out different buffer sizes using pw-metadata and noticed the phasing, ringing sound would go away when changing the buffer size. And I also noticed that the garbled sound would come back if I used a buffer size higher than 64. So with the use of WirePlumber I also set that now. Another owner reported that setting a higher sample rate also alleviates the issue. I still like to figure out though why I can’t use higher buffer sizes. I think it’s related to the USB topology of this laptop as I don’t have this issue on my own laptops.
The WirePlumber configuration file to remap the phones outputs can be found here: https://codeberg.org/autostatic/gists/src/branch/main/99-rme-digiface-usb.lua. Ubuntu 24.04 uses WirePlumber < 0.5.0 so it’s still in Lua format. You can place this file in ~/.config/wireplumber/main.lua.d/. And it starts with 99- for a reason, the interwebs suggest a lower number but then it gets overwritten by global configuration files.
Below the WirePlumber configuration file that I use on the Dell Pro 14 Premium with an extra property to work around the garbled audio issue.
To answer that question let’s assume the following:
You want to do real-time audio, for instance you would like to do an overdub in a song project by using a MIDI keyboard and a soft synth.
You’re using a USB audio interface.
You’re experiencing xruns when using lower buffer sizes (64 or even lower) that result in crackling audio.
Basically all components of a desktop computer or a laptop have an IRQ. Let’s say IRQs are some sort of communication lines between the brains of your computer (the CPU) and those components. All these communication lines are more or less the same as in, none of these communication lines has priority over the other. But if you suffer from bad audio quality caused by xruns then giving the communication line that is connected to your USB device more priority than the rest could alleviate the audio issues.
This is where rtcirqus could be helpful. What rtcirqus does is detecting your USB audio interface when it gets connected, then it figures out what the IRQ of the USB bus is that your audio interface is connected to and raises the priority of the IRQ attached to that USB bus. In other words, rtcirqus gives the communication line between the USB bus that your audio interface is connected to and the CPU of your computer a higher priority. This higher priority translates into other communication lines being throttled and giving the communication line of our USB audio interface more room to transfer and receive its audio data.
rtcirqus needs to be able to prioritize that communication line though and this is where the threadirqs kernel option is for, it creates so-called threads of all available IRQs on a computer. Threads are more or less like processes running on your computer, with threadirqs enabled you can list them as such with a command like ps -eLo cmd | grep '^[irq'. So make sure this kernel option has been added to the kernel command line. In case you’re using a real-time kernel this isn’t needed as a real-time kernel uses threaded IRQs by default.
So if you find yourself in such a situation, head over to https://codeberg.org/autostatic/rtcirqus and give rtcirqus a try, maybe it helps you achieving lower latencies with your USB audio interface while retaining a clean audio output signal.
With the release of the 6.12 kernel the RME Digiface USB is supported under Linux. Since this is a very portable device with lots of IO (32 in and 34 out) it got on my radar as a possible candidate for making recordings at my rehearsal space. It took a while before I stumbled upon a second hand unit but in the end I managed to find one nearby. Hooked it up to my notebook with an up-to-date Liquorix kernel and it worked out of the box.
A lot of thanks go out to Asahi Lina for adding support for the RME Digiface USB to the 6.12 kernel. She even added the possibility to control the output format and clock source and to monitor sample rates, input formats, input sync statuses and the current sync source.
Screenshot of AlsaMixer showing all the controls available for the RME Digiface USB
Have yet to test the Digiface USB with more than one ADAT device but with one device (a Behringer ADA8200) everything seems to work really well. Did some round-trip latency tests and with a buffer size of 16 samples and putting TotalMix in DAW mode (which had to be done on a different OS unfortunately but saved another 0.2 ms) I got it down to approximately 4.2 ms. Systemic latency with a buffer size of 16 samples and a sample rate of 48 KHz is 2 ms so somewhere a bit more than 2 ms of additional latency gets added. I think about 1.4 ms gets added by that converters if I did my maths right. According to the specs of the converters they add 22 samples (10 in and 12 out at 48 KHz). That leaves about 0.8 ms unaccounted for. Probably the USB bus buffer or something in the driver stack. Well, no real deal-breaker for me.
Ardour round-trip latency measurement with a buffer size of 32 and a 48KHz sample rate
Because I’m still on Debian 12 I couldn’t fully use the device with PulseAudio though. PulseAudio only supports devices with up to 32 channels in or out and since the Digiface has 34 output channels PulseAudio refused to output any audio through it. As a fix I added the following to the ~/.asoundrc file in my home directory:
pcm.snd_rme_digiface_usb {
type multi
slaves.rme.pcm "snd_output"
slaves.rme.channels 34
bindings.0.slave rme
bindings.0.channel 32
bindings.1.slave rme
bindings.1.channel 33
}
pcm.snd_output {
type hw
card USB23800125
}
To make PulseAudio pick up this extra snd_rme_digiface_usb device I added the following to ~/.config/pulse/default.pa:
# RME Digiface USB
load-module module-alsa-sink device=snd_rme_digiface_usb
And now I can select the Digiface as an output source and use the phones output in a desktop session.
Screenshot of pavucontrol with the RME Digiface USB right in the middle
Another big bonus is the custom pouch my daughter made for it. I can now toss it in my bike bag without having to worry about dings or scratches.
RME Digiface USB tucked in a custom cotton pouch
RME Digiface USB on top of its custom cotton pouch
A new version of rtcqs is now available. A routine was added to check if a system is using Simultaneous Multithreading (SMT, also known as hyper-threading) as a system might benefit from disabling SMT. My own system does benefit from disabling it, I get less xruns in Ardour at lower latencies.
Arnout also merged a PR that fixed some typos, thanks!
A new version of rtcqs, a Linux audio performance analyzer, is now available. Most notable changes include:
Fixed inconsistent use of single and double quotes
Replaced audio group check with a group agnostic check (fixes #4)
Governor check can now deal with systems that have SMT disabled
Tickless check now deals with all CONFIG_NO_HZ* variants and with nohz being set on the kernel command line (fixes #8)
File systems check has been expanded
IRQ check now loops through /sys/kernel/irq instead of parsing /proc/interrupts
rtprio check now checks if a SCHED_FIFO priority can be set instead of a SCHED_RR priority
Improved preempt RT check, check if “preempt=full” is part of the kernel command line (fixes #7)
Refactoring, created separate classes for main app, resources and GUI
Moved all packaging directives into pyprojects.toml
While working on this release I found out PySimpleGUI is not open source anymore so rtcqs’ GUI has become a bit of a moving target. I’m looking at alternatives like pygubu or even popsicle but that will be something for in the long run. In the short run there are more improvements in the pipeline. The swappiness check needs some attention and same goes for the IRQ check. I’ve been working on a different project to automate prioritizing IRQs and I’m planning to to reuse some parts of that project for the IRQ check in rtcqs. The idea is to have rtcqs not only list the status of all audio related IRQs but also any audio devices attached to those IRQs.
rtcqs is available on Codeberg, PyPI and is also included in the AUR.
At the moment everything seems a bit like a balancing act. First on a physical level, as I’m currently recovering from surgery one of the things I have to learn again is to find my balance, literally. While recovering I can’t do very much hobby stuff in the analogue domain so I swayed a bit to the digital domain again.
About 6 years ago I bought a Mixbus 32C license but found myself using Ardour more and more. During the pandemic I took a subscription and from then on I basically started using Ardour exclusively. Still remember the first time I opened up Ardour back in the 00’s, to me it was intimidating, daunting, what did all those buttons and sliders do? But like with more things in life, sometimes you just fathom the seeming complexity of something, call it an eye opener, and then you’re like, why didn’t I start using Ardour right from the beginning?
Now Ardour is my DAW of choice. It’s running on Debian 12 with a Liquorix kernel on my old, trusted BTO and I’ve never had such a stable setup before. Yes, Debian, after 14 years of Ubuntu that has become a balancing act too. The more applications are moved into Snap the more it alienates me from the OS. While I understand the concept of self-contained applications, it’s part of my job, I don’t think this concept has a real purpose on a desktop OS. It adds another layer of complexity and makes communication between applications harder. Whole different story for another time.
Ardour 8.0 has just been released and I can wholeheartedly recommend it. Installing and setting it up is a breeze and even on my old BTO it runs like a charm. The only restriction is that I can’t use too many Dragonfly Reverb plugins within a project but once I give in to my GAS to get a Framework notebook that will be resolved too.
This release comes with a new Power Management check which checks if the audio group has read/write permissions on /dev/cpu_dma_latency. If your user is a member of the audio group and permissions are set for this group then DAW’s like Ardour and Reaper can open this file as your user, keep it open and control power management this way. This allows a user to prevent CPU sleep states for example so your CPUs are always on and instantly available which could lower the chance running into xruns.
Ardour CPU DMA latency setting Under Edit – Preferences – Performance
This release also introduces a new basic and simple tkinter-based GUI. The Qt GUI does look fancy but to use it it also needs a fancy amount of dependencies. When building binaries with PyInstaller the result of the Qt GUI is a whopping 130MB package while the tkinter version stays below 12MB.
rtcqs tkinter GUI
Future plans are to get rid of some checks:
Max user watches as it’s not related to the overall performance of your system
System timer as it’s not relevant anymore, rtcqs already checks for the more relevant stuff (high res timers and tickless kernel)
Background processes as it’s merely a placeholder which checks for two processes that don’t exist anymore on modern systems
I’m having my doubts about swappiness too as it’s not really applicable anymore for modern machines. But I’m curious if it still applies for smaller systems like RPi’s for example. I’d like to add a filesystem mount option check, for Ext it would check if the filesystem is mounted at least with the relatime option or even noatime for example. And maybe a disk scheduler check but I’m not conviced yet that it really makes a difference.
As a beta tester for MOD I thought it would be cool to play around with netJACK which is supported on the MOD Duo. The MOD Duo can run as a JACK master and you can connect any JACK slave to it as long as it runs a recent version of JACK2. This opens a plethora of possibilities of course. I’m thinking about building a kind of sidecar device to offload some stuff to using netJACK, think of synths like ZynAddSubFX or other CPU greedy plugins like fat1.lv2. But more on that in a later blog post.
So first I need to set up a sidecar device and I sacrificed one of my RPi’s for that, an RPi 3. Flashed an SD card with Raspbian Jessie Lite and started to do some research on the status of real time kernels and the Raspberry Pi because I’d like to use a real time kernel to get sub 5ms system latency. I compiled real time kernels for the RPi before but you had to jump through some hoops to get those running so I hoped things would have improved somewhat. Well, that’s not the case so after having compiled a first real time kernel the RPi froze as soon as I tried to runapt-get install rt-tests. After having applied a patch to fix how the RPi folks implemented the FIQ system the kernel compiled without issues:
Linux raspberrypi 4.9.33-rt23-v7+ #2 SMP PREEMPT RT Sun Jun 25 09:45:58 CEST 2017 armv7l GNU/Linux
And the RPi seems to run stable with acceptable latencies:
Histogram of the latency on the RPi with a real time kernel during 300000 cyclictest loops
So that’s a maximum latency of 75 µs, not bad. I also spotted some higher values around 100 but that’s still okay for this project. The histogram was created with mklatencyplot.bash. I used a different invocation of cyclictest though:
cyclictest -Sm -p 80 -n -i 500 -l 300000
And I ran hackbench in the background to create some load on the RPi:
(while true; do hackbench > /dev/null; done) &
Compiling a real time kernel for the RPi is still not a trivial thing to do and it doesn’t help that the few howto’s on the interwebs are mostly copy-paste work, incomplete and contain routines that are unclear or even unnecessary. One thing that struck me too is that the howto’s about building kernels for RPi’s running Raspbian don’t mention the make deb-pkg routine to build a real time kernel. This will create deb packages that are just so much easier to transfer and install then rsync’ing the kernel image and modules. Let’s break down how I built a real time kernel for the RPi 3.
First you’ll need to git clone the Raspberry Pi kernel repository:
This will only clone the rpi-4.9.y branch into a directory called linux without any history so you’re not pulling in hundreds of megs of data. You will also need to clone the tools repository which contains the compiler we need to build a kernel for the Raspberry Pi:
The KERNEL variable is needed to create the initial kernel config. The ARCH variable is to indicate which architecture should be used. The CROSS_COMPILE variable indicates where the compiler can be found. The CONCURRENCY_LEVEL variable is set to the number of cores to speed up certain make routines like cleaning up or installing the modules (not the number of jobs, that is done with the -j option of make).
Now that the environment variables are set we can create the initial kernel config:
cd linux
make bcm2709_defconfig
This will create a .config inside the linux directory that holds the initial kernel configuration. Now download the real time patch set and apply it:
cd ..
wget https://www.kernel.org/pub/linux/kernel/projects/rt/4.9/patch-4.9.33-rt23.patch.xz
cd linux
xzcat ../patch-4.9.33-rt23.patch.xz | patch -p1
Most howto’s now continue with building the kernel but that will result in a kernel that will freeze your RPi because of the FIQ system implementation that causes lock ups of the RPi when using threaded interrupts which is the case with real time kernels. That part needs to be patched so download the patch and dry-run it:
cd ..
wget https://www.osadl.org/monitoring/patches/rbs3s/usb-dwc_otg-fix-system-lockup-when-interrupts-are-threaded.patch
cd linux
patch -i ../usb-dwc_otg-fix-system-lockup-when-interrupts-are-threaded.patch -p1 --dry-run
You will notice one hunk will fail, you will have to add that stanza manually so note which hunk it is for which file and at which line it should be added. Now apply the patch:
And add the failed hunk manually with your favorite editor. With the FIQ patch in place we’re almost set for compiling the kernel but before we can move on to that step we need to modify the kernel configuration to enable the real time patch set. I prefer doing that with make menuconfig. You will need the libncurses5-dev package to run this commando so install that with apt-get install libncurses5-dev. Then select Kernel Features - Preemption Model - Fully Preemptible Kernel (RT) and select Exit twice. If you’re asked if you want to save your config then confirm. In the Kernel features menu you could also set the the timer frequency to 1000 Hz if you wish, apparently this could improve USB throughput on the RPi (unconfirmed, needs reference). For real time audio and MIDI this setting is irrelevant nowadays though as almost all audio and MIDI applications use the hr-timer module which has a way higher resolution.
With our configuration saved we can start compiling. Clean up first, then disable some debugging options which could cause some overhead, compile the kernel and finally create ready to install deb packages:
make clean
scripts/config --disable DEBUG_INFO
make -j$(nproc) deb-pkg
Sit back, enjoy a cuppa and when building has finished without errors deb packages should be created in the directory above the linux one. Copy the deb packages to your RPi and install them on the RPi with dpkg -i. Open up /boot/config.txt and add the following line to it:
kernel=vmlinuz-4.9.33-rt23-v7+
Now reboot your RPi and it should boot with the realtime kernel. You can check with uname -a:
Linux raspberrypi 4.9.33-rt23-v7+ #2 SMP PREEMPT RT Sun Jun 25 09:45:58 CEST 2017 armv7l GNU/Linux
Since Rasbian uses almost the same kernel source as the one we just built it is not necessary to copy any dtb files. Also running mkknlimg is not necessary anymore, the RPi boot process can handle vmlinuz files just fine.
The basis of the sidecar unit is now done. Next up is tweaking the OS and setting up netJACK.
Edit: there’s a thread on LinuxMusicians referring to this article which already contains some very useful additional information.
Next step for the synth module project was to get the Raspberry Pi 2 to run in a stable manner. It seems like I’m getting close or that I’m already there. First I built a new RT kernel based on the 4.1.7 release of the RPi kernel. Therefore I had to checkout an older git commit because the RPi kernel is already at 4.1.8. The 4.1.7-rt8 patchset applied cleanly and the kernel booted right away:
pi@rpi-jessie:~$ uname -a
Linux rpi-jessie 4.1.7-rt8-v7 #1 SMP PREEMPT RT Sun Sep 27 19:41:20 CEST 2015 armv7l GNU/Linux
After cleaning up my cmdline.txt it seems to run fine without any hiccups so far. My cmdline.txt now looks like this:
With a buffer of 64 frames latency is very low and so far I haven’t run into instruments that cause a lot of xruns with this buffer size. Not even the multi-layered ones from Will Godfrey.
So I guess it’s time for the next step, creating a systemd startup unit so that ZynAddSubFX starts at boot. And it would be nice if USB MIDI devices would get connected automatically. And if you could see somehow which instrument is loaded, an LCD display would be great for this. Also I’d like to have the state of the synth saved, maybe by saving an .xmz file whenever there’s a state change or on regular intervals. And the synth module will need a housing or casing. Well, let’s get the software stuff down first.