96 USB sound cards in Ubuntu Studio…

I’m currently working on a sound installation that needs a lot of audio channels. Unfortunately it doesn’t have much of a budget, so I decided to test the idea of making one monster aggregate device out of a bunch of cheap USB sound cards like this one:

In the past I have used around 8 of these simultaneously. I did a quick google and found that USB protocol can – theoretically – handle 127 devices, though I suspected I would run into problems well before that. Still, I was curious to see how far I could go so jumped on aliexpress and bulk ordered 100 USB sound cards and 6 * 16 port powered USB hubs for potentially 96 inputs and 192 outputs (!)

…Unfortunately it turns out that ALSA actually has a hard coded limit of 32 audio devices (link). From what I understand it is possible to alter this to add more but would require editing the linux kernel. So for this particular installation I have instead decided to network 3 old PCs each with 32 cards. (I also had to disable the computer’s internal sound card from loading in the BIOS in order to use all 32 usb sound cards)

Tl;dr – from some brief testing sending random sine waves to each channel, the outputs sound pretty clean. The inputs however sound terrible, but stay tuned for updates

Steps to get it working

If you are using Ubuntu Studio,  ‘Studio Controls’ by default automatically adds USB sound cards to Jack when plugged in. This is generally helpful but is actually not helpful in this situation because a) for some reason it stops adding after 9 cards and b) the cards won’t necessarily load in the same order each time (unless you plug them in one by one).  To turn this off, open Studio Controls, go to the ‘Extra Devices’ tab and deselect – ‘Bridge USB Device to Jack when Plugged in’ 

With that done, plug in the sound cards, open a terminal and run:

cat /proc/asound/cards

You should see the sound cards listed. At the start is a device number, followed by the device ID in brackets. We can manually add each sound card as a Jack input or output using this device number with the alsa_in and/or alsa_out commands:

alsa_in -d hw:#devicenumber
alsa_out -d hw:#devicenumber

If you open the patch bay (connections) in Qjackctl (or Carla) you should see them appearing as available inputs and outputs.

So far so good, but unfortunately it’s not guaranteed that, each time the computer is restarted, the same USB sound card will be assigned the same device number or ID, meaning you would have to redo or at least check your physical and/or software routing every time you reboot your system. So we need to create a UDEV rule which assigns each sound card a consistent and unique ID based on which USB port the sound card is plugged into. This way whichever sound card plugged into the first usb port will always be, for example “[my_sound_card_1]”. (Thanks to this very helpful guide for this next step)

To do this we first need to find the address of each usb port. Unplug all the sound cards, open a Terminal and run:

udevadm monitor --kernel --property --subsystem-match=sound

Next plug a sound card into each USB port one by one, and make note of the DEVPATH that appears in the terminal for each port. It should look something like:

DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/sound/card1

Once you have the address of each USB port you want to use, create the file “/etc/udev/rules.d/85-my-usb-audio.rules” with the following contents:

SUBSYSTEM!="sound", GOTO="my_usb_audio_end"
ACTION!="add", GOTO="my_usb_audio_end"

DEVPATH=="/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4.3/2-1.4.3.4/2-1.4.3.4:1.0/sound/card?", ATTR{id}="MIC_1"
DEVPATH=="/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4.1/2-1.4.1.2/2-1.4.1.2:1.0/sound/card?", ATTR{id}="MIC_2"
DEVPATH=="/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4.3/2-1.4.3.3/2-1.4.3.3:1.0/sound/card?", ATTR{id}="MIC_3"

#...etc. Create an entry for each usb port you want to use.

LABEL="my_usb_audio_end"

The DEVPATHs in the above example should be replaced with your own DEVPATHS from the previous step. Note that the final digits after ‘card’ need to be replaced with a ‘?’ wildcard, and “MIC_1” after the ATTR{id}= should be replaced with whatever you want the device name to be. (It’s best if you use an ascending number naming scheme ( card_0, card_1, card_2 etc) so that we can write a simple Bash script with a for loop to load the cards later.) Make a DEVPATH entry for each USB port you want to use.

Now when you, plug in the USB devices and run:

cat /proc/asound/cards

you should see that the default device id ( [Device_1] etc),  has been replaced with your unique id. Now that we know the ID of each port we can again use alsa_in/out to open the soundcard based on its ID:

alsa_in -d hw:CARD=MIC_1

We can automate this process by writing a simple bash script that will force ALSA to load the cards in certain order. Create a script

sudo nano audioSetup.sh

with the following contents

#!/bin/bash
for i in {1..32}
	do
	#alsa_out -d hw:CARD=MIC_$i -j "output_$i" & 
	#echo "output_$i connected"
	#sleep 0.5
	
	alsa_in -c 1 -d hw:CARD=MIC_$i -j "input_$i" & 
	echo "input_$i connected"
	sleep 0.5
done

I found adding a slight delay after loading each card helped this to work more consistently, (this might be different on different systems). Make the script executable (sudo chmod +x audioSetup.sh), plug in all the cards, run it, and all the cards should be available as inputs and/or outputs in qjackctl or carla .

Leave a Reply

Your email address will not be published. Required fields are marked *