Raspberry Pi multichannel audio interface recommendations

Hi,

Anyone can recommend a decent multi-channel usb audio interface for the Raspberry Pi?

There is success with M-Audio Quattro (http://usb-midi-fw.sourceforge.net/), however only 4 outputs, needing 8, 16. This is amazing product, anyone tested it with Debian + OF? https://www.m-audio.com/products/view/m-track-eight

Hi @alice,

Sounds like a nice interface. Better check another if it runs on Linux before you get it.

I am trying out an M-Audio Quattro. Current Linux kernel system support is out of the box, but displays the Quattro as two separate USB interfaces.

$ lsusb
Bus 003 Device 005: ID 0763:2001 M-Audio M Audio Quattro
Bus 003 Device 004: ID 0000:0538 M Audio USB Audio Quattro

Not sure if openframeworks supports sending audio to two separate audio cards at the same time. Does it? Two audio streams?

What I’ve already tried on this machine, using the soundBufferExample, on setup:

// start the sound stream with a sample rate of 44100 Hz, and a buffer
	// size of 512 samples per audioOut() call
	ofSoundStreamSettings settings;
	settings.numOutputChannels = 2;
	// settings.numOutputChannels = 4;
	settings.sampleRate = 44100;
	settings.bufferSize = 512;
	settings.numBuffers = 4;
	// settings.setApi(ofSoundDevice::Api::PULSE);
	settings.setApi(ofSoundDevice::Api::ALSA);

	settings.setOutListener(this);
	// soundStream.setup(settings);

	std::vector<ofSoundDevice> devices = soundStream.getDeviceList();
	cout << devices << endl;

	settings.setOutDevice(devices[2]);

	soundStream.setup(settings);

The output of my devices:

Unkown API: 0] hw:HDA Intel,0 [in:2 out:2] (default in) (default out)
[Unkown API: 1] hw:HDA Intel,2 [in:2 out:0]
[Unkown API: 2] hw:USB Audio Quattro,0 [in:2 out:2]
[Unkown API: 3] hw:USB Audio Quattro,1 [in:2 out:2]
[Unkown API: 4] hw:HDA NVidia,3 [in:0 out:8]
[Unkown API: 5] hw:HDA NVidia,7 [in:0 out:8]
[Unkown API: 6] default [in:32 out:32]

The sketch runs, the wave is displayed and updated, but there is no sound out of the Quattro. Tried both soundDevices (2 & 3).

It’s weird that under Linux this card appears as two interfaces. Weird that it’s not working. Neither the ofSoundDevice::Api::, even though I set to ALSA or PULSE, output of soundStream.getDeviceList(); gives Unkown.

Anyone managed to get USB audio interfaces up and running on Linux?

Thanks,

&c

Here is another approach.
http://www.audioinjector.net/rpi-octo-hat

Hi @coding

That was my worry, getting an audio interface, and then it doesn’t work, thanks for the example code, I’ll try with my Quattro on the Raspi and let you know how it goes. Nice that we have same interface!

Hi @fresla

Thank you for the so sweet device pointer! Looks amazing!, and just what I would need. But I am more inclined to a portable usb, this would lock me in GPIO world.

This looks nice too https://www.esi-audio.com/products/gigaporthd+/

Super nice resource from the Ardour world https://discourse.ardour.org/t/audio-interfaces-under-linux/87896

1 Like

I have a couple of the gigaport HDs and I really like them (no inputs though). I never tried it with my Raspberry Pi, but it is linux compatible according to this : https://kb.esi-audio.com/?goto=KB00231EN

BTW I did use a simple soundblaster USB output on raspberry pi with OF.

@coding The Quattro works fine here on the raspi, very good news. Bad news is the same as your machine, gets identified as two separate interfaces. Though I can send sound to 1+2, or 3+4.

 make run
VER ID IS 10
using newer build and GLFW window
[Unkown API: 0] hw:bcm2835 HDMI 1,0 [in:0 out:2]
[Unkown API: 1] hw:bcm2835 Headphones,0 [in:0 out:2]
[Unkown API: 2]  [in:0 out:2]
[Unkown API: 3] hw:USB Audio Quattro,0 [in:2 out:2]
[Unkown API: 4] hw:USB Audio Quattro,1 [in:2 out:2]
[Unkown API: 5] default [in:0 out:10000]


RtApiAlsa::getDeviceInfo: pcm device (hw:2,0) data format not supported by RtAudio.


RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (default), No such file or directory.



Q to oF audio gurus. I could put a separate listener to a second soundStream, how would I go abouts syncing output of a single multichannel dsp chain to two soundStreams? Suppose my chain outputs 4*bufferSize, 1,2 go to interface 1, 3,4 go to interface 2, in sync?

@seb_ly Thanks a lot for that info from esi-audio! I won’t be needing any sound inputs so this card looks great! Lets just hope it does not happen the same as the Quattro, would be very weird to sync 4x2ch.

@alice I’ve never tried running two soundStream callbacks, not sure it’s possible. I’m assuming you’re trying to get 8 outs by doubling up your devices?

I have an RME Multiface gathering dust that was capable of 8 outs under Linux but it won’t work with an RPI as it needs a special interface.

Here’s some other 8 channel options:

I have a 4 channel Focusrite Scarlett 4i4 which works well under Linux, and I’m pretty sure I got it working on an RPI after some fiddling. You could also try the Scarlett 18i8:
https://linuxmusicians.com/viewtopic.php?t=19193

If you only need outputs and want USB I would try something very simple with class compliant drivers, like a budget 7.1 usb sound card. They do not have the flexibility of a more pro soundcard, that usually have some mid level interface for routing and mixing and duplexing, but the chances of compatibility seem a little higher.

Take a look at this the StarTech.com 7.1 USB Sound Card, it has a good chance of working as it is designed for 7.1 (which will give you 8 discrete channels) and is class compliant so no drivers should be needed.

Hi @Alice.

Try something like this to handle manually sewing and syncing 2+ ofSoundStream's

struct SoundGen {
	int 			bufferSize;
	int 			numChannels;
	int 			sampleRate;
	int 			samples;
	vector<float>	AudioLine;
	float 			wavePhase, pulsePhase;
	// ofSoundBuffer lastBuffer;
	void setup(int bs, int nc, int sr){
		bufferSize = bs;
		numChannels = nc;
		sampleRate = sr;
		samples = bs*nc;
		wavePhase = pulsePhase = 0.0f;
		AudioLine.clear();
		AudioLine.assign(samples, 0.0f);
	}
	virtual void genTick(){
		// base frequency of the lowest sine wave in cycles per second (hertz)
		float frequency = 86.25; //172.5;
		// mapping frequencies from Hz into full oscillations of sin() (two pi)
		float wavePhaseStep = (frequency / (float)sampleRate) * TWO_PI;
		float pulsePhaseStep = (0.5 / (float)sampleRate) * TWO_PI;
		// this loop builds a buffer of audio containing 3 sine waves at different
		// frequencies, and pulses the volume of each sine wave individually. In
		// other words, 3 oscillators and 3 LFOs.
		for(size_t i=0; i<bufferSize; i++){
			// build up a chord out of sine waves at 3 different frequencies
			float sampleLow = sin(wavePhase);
			float sampleMid = sin(wavePhase * 1.5);
			float sampleHi = sin(wavePhase * 2.0);
			// pulse each sample's volume
			sampleLow *= sin(pulsePhase);
			sampleMid *= sin(pulsePhase * 1.04);
			sampleHi *= sin(pulsePhase * 1.09);
			float fullSample = (sampleLow + sampleMid + sampleHi);
			// reduce the full sample's volume so it doesn't exceed 1
			fullSample *= 0.333333333333333333333;
			// write the computed sample to the left and right channels
			int idx = i*numChannels;
			for(size_t ach = 0; ach < numChannels; ach++ ){
				AudioLine[idx + ach] = fullSample;
			}
		}
		// get the two phase variables ready for the next sample
		wavePhase += wavePhaseStep;
		pulsePhase += pulsePhaseStep;
		// wrap big nums
		if(wavePhase>1e33){ wavePhase -= 1e33; pulsePhase -= 1e33; }
	}

	float * getAudioLine(){ return &AudioLine[0]; }

	// inneficient, deallocate after requesting
	float * requestPartialAudioLine(vector<int>channelIds){
		float * music = new float[bufferSize*channelIds.size()];
		float * audioline = getAudioLine();
		for(size_t i=0; i<bufferSize;i++){
			int idx = i*numChannels;
			for(size_t ach = 0; ach < channelIds.size(); ach++){
				music[idx + ach] = audioline[i + channelIds[ach]];
			}
		}
		return music;
	}
};

Then you can try a class to hold separate audioOut methods, only one class calls genTick, and requestPartialAudioLine with the channels for different devices. Remember to deallocate, otherwise you’ll quickly run out of Ram. Should sync a single DSP chain to multiple audio devices with different channel nums. All under the same bufferSize and sampleRate. There are probably much more efficient ways to pull this of, but this should work.

Hi @grimus, Thank you for device pointers. I am simply trying to get 4 chan out out of my Quattro interface, Which default Alsa / Linux Raspi kernel drivers state it’s like two stereo devices, each one with stereo in, stereo out. So i don’t have 4 chan, I just have two times 2 chan. So I’m trying to get 4 chan out, first try to open two devices and send sync’ed audio to both at same time. Did something like this happened to you on other USB cards you mention, i.e., not one device, but two or more show up in the device listing?

Looks very nice, Thank you. By fiddling you mean you did something similar to the post you linked? Or did you try other stuff? Do you think I could fiddle around with alsa setup and get 4 chan in/out straight out of one device with my Quattro / Raspi config?

Hi @fresla. Thank you, this is exactly all I need, I can calibrate code to output controlled sound levels, or even equalize / compress it at source, so basically just a piece of hardware that can perform the DAC conversion. The card you refer looks very nice, thank you for the reference.

Hi @as1er. Thanks! That’s exactly what I need to test out the Quattro. BTW you should pass a ref instead of copying the vector-