Background: I’m developing an analog hardware synth, and using an audio interface to send Rack control voltages. The audio interface is USB Audio to a Raspberry Pi Zero. With that I can create a USB Audio interface that supports up to 27 channels. And that’s the problem: I’m limited to only 27 control voltages.
I can add a second USB Audio interface on the same Pi Zero, for 27 additional channels. And that’s where I’m at now: rewriting the Rack module and Raspberry Pi app to go from a single interface to multiple. The module I’ve in Rack for the audio side of things inherits from audio::Port and is pretty much lifted from Audio.cpp. What I’m thinking is instantiate multiple instances of the audio::Port, one for each Audio interface the Pi exposes.
I’ve got a feeling that there’s going to be some gotchas along the way. Or maybe the Rack side of things won’t be too bad since Rack does work with multiple audio interfaces. Still investigating my use case. I’d think timing / skew between interfaces shouldn’t be a thing since both audio interfaces are on the same host device, or at least that wouldn’t be an issue on the Rack side I’d think. But before I get too deep I was wondering if things seem feasible so far and I’m not on a fool’s errand. Any enlightenment out there? Just go try it?
I use two usb audio interfaces in Rack on a mac simultaneously, but the only way I’ve been able to keep them from drifting and distorting periodically is to create an ‘aggregate audio device’, which is something that macOS supports. Then I can engage ‘Drift Correction’ on one, and I believe it effectively slaves the audio timing from one interface to the other somehow.
From Rack’s perspective they end up being one audio device. Ever since Rack 2.0, I can select two different audio devices within Rack, but I can’t seem to prevent their timing from drifting and causing clicks.
Here’s a picture of what I mean by the Aggregate Device:
Anyway, it sounds like you might be working in Linux? So this probably isn’t directly helpful, but this is my experience of running two audio devices on macOS. It is very consistent and useful, but it would be much simpler if I could just select two different devices at the same time and not worry about it.
That’s great info, thanks for the reply. And ALSA supports an aggregated interface from what I’ve read.
But hey, I did some hacks and initial results looks like sending to two PCM devices from Rack (and reading from on the Raspberry Pi / synth side) appear to work! At least, I can control from Rack devices that are assigned to either USB Audio device, and it seems to work ok. JOY! The code on the Pi shows how each synth card is assigned a range of channels and a PCM device.
2023-09-06 10:31:07 INFO [703:card_manager.c:325] allocated 6 channels on dev 0 for Zoxnoxious 3340 at start 0 (new idx 6)
2023-09-06 10:31:07 INFO [703:card_manager.c:325] allocated 6 channels on dev 0 for Zoxnoxious 3340 at start 6 (new idx 12)
2023-09-06 10:31:07 INFO [703:card_manager.c:325] allocated 6 channels on dev 0 for Zoxnoxious 3340 at start 12 (new idx 18)
2023-09-06 10:31:07 INFO [703:card_manager.c:325] allocated 16 channels on dev 1 for Zoxnoxious 5524 at start 0 (new idx 16)
2023-09-06 10:31:07 INFO [703:card_manager.c:325] allocated 7 channels on dev 0 for Zoxnoxious 3372 VCF at start 18 (new idx 25)
2023-09-06 10:31:07 INFO [703:card_manager.c:325] allocated 2 channels on dev 0 for Audio Out at start 25 (new idx 27)
Sorry, that’s not especially Rack relevant but I can’t believe this is just working. Here, this may bring it back towards more Rack relevant and I’ll close this thread out. This is essentially what’s going on under the hood: the Pi has two audio interfaces and both of them are receiving channels from Rack. In this example the Pi loops it back (just for testing here). Using Audio16 makes this test easy; this uses alsaloop on the host Pi on each USB Audio interface as proof-of-concept.
I’m curious, did you listen to those waveforms via speaker as well? In my experience, on macOS, eventually I get crackles (usually maybe after 5 or 10 minutes) that come and go, unless I turn them into an aggregate device.
But if ALSA + Rack is supporting independent audio devices with no issues, that’s definitely great!
Hey Dan, those are all LFOs so not audio rate signals / listenable. They’re scope shots of data returned from the Pi to VCV Rack, roundtrip’d. So no audible crackles there, and the waveforms look like what I’d expect. I’ve not done an exhaustive investigation, it’s “good enough” for my purposes. And my purposes are definitely non-standard: the audio interfaces are running at 4 kHz. Relatively slow. It’s control voltage values being sent to an analog synth.
After trying a Linux VCV Rack host I hooked it up to a MacOS host. I didn’t create an aggregate device there and initial results show it works there. I’ve not done any fine grained analysis on jitter/skew; it’s good 'nuff for now.
Aside: What I didn’t do in the previous post’s screenshot is overlay the original signal on any of the scopes to show latency. Here’s a shot of that:
this shows the latency of the roundtrip versus the original signal, hundredths of seconds given a small block size for the audio interfaces. Not bad at all.
I was having major problems with popping and crackles using my ES-9 with Ableton and Rack until I realized the problem was how I set up the Aggregate Device on my Mac. I really didn’t understand digital clocking, so I never suspected this could be a cause of the problem.
Since I started using my primary audio interface (UMC404HD) as the clock source and enabling drift correction on both devices, I haven’t experienced any issues. I don’t know if it’s necessary to select drift correction on both, but I did read somewhere that it is recommended to do it all devices, and it’s worked for me.
Same here! I have an aggregate device using a PreSonus Quantum, ES9, and an ES8, and drift control on both expert sleepers modules, and it works very reliably.