• WANTED: Happy members who like to discuss audio and other topics related to our interest. Desire to learn and share knowledge of science required. There are many reviews of audio hardware and expert members to help answer your questions. Click here to have your audio equipment measured for free!

Using a Raspberry Pi as equaliser in between an USB source (iPad) and USB DAC

Add a note that this is not always the case -- the current recommended version is still 32bit.
CDSP runs in float64 internally. I use aarch64 only and never had any problem, IMO no reason to stay with 32bit when preparing new setups. The only disadvantage I met is the RPi VC4 tools are still 32bit only which is stupid and kind of sucks...
 
As of the USB gadget name - the proper (and officially only-recommended) way is to use the composite gadget with the uac2 function, e.g. https://training.ti.com/sites/default/files/docs/USB-M6-USB-in-Device-Mode.pdf . The function has more parameters (some inherited from the generic gadget layer) than the legacy module g_audio.ko (for which developers are increasingly reluctant to accept patches). E.g. https://wiki.tizen.org/USB/Linux_USB_Layers/Configfs_Composite_Gadget/General_configuration , http://trac.gateworks.com/wiki/linux/OTG or many other composite-gadget tutorials online - the configfs way allows configuring product name, etc.

The composite gadget is the only path for CDSP as an embedded device as it allows configuring a composite audio and ethernet device, allowing to configure the embedded device via browser running on the USB host.
 
Last edited:
CDSP runs in float64 internally. I use aarch64 only and never had any problem, IMO no reason to stay with 32bit when preparing new setups. The only disadvantage I met is the RPi VC4 tools are still 32bit only which is stupid and kind of sucks...
right. I just wanted to point out that not everyone are using 64 bits in their existing set up.
For new setups that doesn't has 32bit dependencies, choose 64.

As of the USB gadget name - the proper (and officially only-recommended) way is to use the composite gadget with the uac2 function, e.g. https://training.ti.com/sites/default/files/docs/USB-M6-USB-in-Device-Mode.pdf . The function has more parameters (some inherited from the generic gadget layer) than the legacy module g_audio.ko (for which developers are increasingly reluctant to accept patches). E.g. https://wiki.tizen.org/USB/Linux_USB_Layers/Configfs_Composite_Gadget/General_configuration , http://trac.gateworks.com/wiki/linux/OTG or many other composite-gadget tutorials online - the configfs way allows configuring product name, etc.

The composite gadget is the only path for CDSP as an embedded device as it allows configuring a composite audio and ethernet device, allowing to configure the embedded device via browser running on the USB host.
many thanks for your informative reply! I'll have a try.
 
As of the composite audio + ethernet gadget - it will take some major trial/error to identify a config combination working on all major OSes. Windows is picky, as always... But I am optimistic :) At worst a dip switch could flip the configs, should it turn out necessary.
 
Hmmm, this looks a bit weird, though, right?
1652265501127.png
 
IMO your binary gets started at every time the rate kicks in, most likely your change does not work as intended.
 
I have a naive question --- is it possible to route the gadget capture to two different programs?
I want camilladsp to do the dsp and send it to my DAC, and another program (such as cava) to do some visualization.
On Mac two programs can use the same audio inputs. Not sure how to do this on Linux.
Should I do a slave loopback? How can can sync the clock correctly in this case?
 
That change has no date specified :)
I understand you have other higher priorities.
Now I found this is not only a setup complexity issue.
The more serious issue here is camilladsp will stall briefly and then continue to play the captured audio in a wrong sample rate, until outside program (such as your gaudio_ctl) tells it to stop and change rate. Pretty annoying that strange sound is produced. Making it INACTIVE is surely preferred.
 
I understand you have other higher priorities.
Actually, it's not only about me. This feature is required only for linux alsa and would use alsa-only code (subscribing to and reading alsa ctl values), in the very top layer where the config gets reloaded. I am not sure Henrik would accept such a change, he is very careful about clean design of his truly multiplatform project.
But e.g. CDSP could persist the global struct with volume, mute, etc.) upon clean exit and reload it at next startup. That could be a useful feature for any platform, and allow using the universal client-clueless gaudio_ctl as is.
Now I found this is not only a setup complexity issue.
The more serious issue here is camilladsp will stall briefly and then continue to play the captured audio in a wrong sample rate, until outside program (such as your gaudio_ctl) tells it to stop and change rate. Pretty annoying that strange sound is produced. Making it INACTIVE is surely preferred.
I am not sure I understand your point. Of course the solution would have to read the new rate first and config CDSP accordingly.
 
This feature is required only for linux alsa and would use alsa-only code (subscribing to and reading alsa ctl values), in the very top layer where the config gets reloaded.
The existing design already subscribed for CoreAudio and WASAPI format changes and triggers STOP and throws CAPTUREFORMATCHANGE. So I don't think it's a linux specific feature. Nor will it mess up with the existing clean design as it's already there for other systems.

Take CoreAudio as example, it has two logics: Here it gets the rate event from the system and trigger CAPTUREFORMATCHANGE, regardless of user defined stop_on_rate_change value. This detection is based on CoreAudio's rate listener. And here it check if the measured rate is off 4% and trigger CAPTUREFORMATCHANGE if stop_on_rate_change = true

You can search code for WASAPI output and find similar implementation as CoreAudio.

On ALSA the latter test is implemented here, but no former equivalent. IMHO ALSA has an incomplete implementation now. Subscribing to Ctl values completes the implementation, rather than mess up the existing clean design.

I am not sure I understand your point. Of course the solution would have to read the new rate first and config CDSP accordingly.
So currently it go through a few stages:

* cdsp plays 44.1
-> user change to 96
* cdsp still plays 44.1 but reporting a rate mismatch if stop_on_rate_change is false (a)
-> gaudio_ctl gets notified and calling python script to reset config
* cdsp gets message and stop the current stream, switches to 96 and plays again

here, step marked with (a) is the annoying part because it plays 96khz material in 44.1khz, at least for 2 seconds.
user could set stop_on_rate_change = true to make it shorter, but no matter what rate_measure_interval you choose the hiccup is still there.
The problem does not present in CoreAudio nor WASAPI, as format changes stops the stream directly.

What should be done is to implement similar event listener as CoreAudio, and stop much earlier.

also can you shed light on this question?
 
Last edited:
I have a naive question --- is it possible to route the gadget capture to two different programs?
I want camilladsp to do the dsp and send it to my DAC, and another program (such as cava) to do some visualization.
On Mac two programs can use the same audio inputs. Not sure how to do this on Linux.
Should I do a slave loopback? How can can sync the clock correctly in this case?
The short answer is yes. ALSA has a number of plugins covering routing. It used to be common to use the dsnoop plugin to share access to capture streams, but there's also a copy plugin which might work in combination with others. I've not had cause to think how these interact with the sync before.
 
The short answer is yes. ALSA has a number of plugins covering routing. It used to be common to use the dsnoop plugin to share access to capture streams, but there's also a copy plugin which might work in combination with others. I've not had cause to think how these interact with the sync before.
Here's what I have.

Code:
pcm.gadget {
    type dsnoop
    ipc_key 1201
    ipc_key_add_uid yes
    slave {
        pcm "hw:CARD=UAC2Gadget"
    }
}

My camilladsp is using hw:CARD=UAC2Gadget, and point cava to 'gadget', the latter still gives
ALSA function 'snd_pcm_open' failed with error 'EBUSY: Device or resource busy'

Seems there's no way to have two program access the same capture device?
 
Here's what I have.

Code:
pcm.gadget {
    type dsnoop
    ipc_key 1201
    ipc_key_add_uid yes
    slave {
        pcm "hw:CARD=UAC2Gadget"
    }
}

My camilladsp is using hw:CARD=UAC2Gadget, and point cava to 'gadget', the latter still gives
ALSA function 'snd_pcm_open' failed with error 'EBUSY: Device or resource busy'

Seems there's no way to have two program access the same capture device?
You would have to use 'gadget' in both camilladsp and cava, or perhaps dsnoop:CARD=UAC2Gadget which may be exposed by your default alsa config. I don't know what this would do to the sync though.

I'm wondering whether it might be better to put cava on an output from camilladsp rather than an input, but that might have its own complications.
 
So currently it go through a few stages:

* cdsp plays 44.1
-> user change to 96
* cdsp still plays 44.1 but reporting a rate mismatch if stop_on_rate_change is false (a)
-> gaudio_ctl gets notified and calling python script to reset config
* cdsp gets message and stop the current stream, switches to 96 and plays again

When user changes samplerate on USB host, the playback is interrupted and restarted at the new rate. The gadget flips the ctl CAPTURE_RATE to zero and gaudio_clt kills the executed binary. Or it should issue stop command to CDSP when controlled via websockets. After that stream at the new rate starts and the CAPTURE_RATE ctl reports the new value to gaudio_ctl, letting CDSP start at the new rate.

The python wrapper must process the zero, just like gaudio_ctl does so https://github.com/pavhofman/gaudio_ctl/blob/master/src/bin.rs#L215 . Also gaudio_ctl must be modified to report the zero instead of killing the binary.

You proposal to monitor the CAPTURE_RATE ctl in the alsadevice module and send appropriate messages to the upper layer, instead of doing it directly in the top layer, is likely viable. But still the top layer should be modified to handle the rate-change message directly (i.e. loading a config corresponding to the new rate and restarting).
 
ALSA function 'snd_pcm_open' failed with error 'EBUSY: Device or resource busy'
If it's busy, some other process is accessing the device. Typically pulseaudio is quite greedy. Just make sure dsnoop is not forced to resample (it's basically dmix in the capture direction).

As of syncing - DAC -> gadget - the capture side will still run at the gadget speed. Of course the gadget ctl must be controlled, therefore the ctl.gadget config should point to the UAC2Gadget card so that CDSP correctly locates its "Capture Pitch 1000000" ctl.
 
If it's busy, some other process is accessing the device. Typically pulseaudio is quite greedy. Just make sure dsnoop is not forced to resample (it's basically dmix in the capture direction).
Yes it is surely accessing by another thread (camilladsp). My original question is : I want camilladsp to capture the audio, do the dsp and play it on DAC, and another program (such as cava) to capture the same audio from the same device, and do the visualization.

So how can I make two programs access the UAC2Gadget at the same time?

creating dsnoops like above doesn't seem to solve the issue.
 
All clients must access the dsnooped PCM device. My 2 cents one of your processes is configured to access the gadget directly and the other through the dsnoop https://alsa.opensrc.org/Dsnoop
Here's my asoundrc. All slaves are created new. I also stopped all audio processes (camilladsp, gaudio_ctl, etc) so nothing should be using audio now.

Code:
> cat ~/.asoundrc
pcm.gadget1 {
    type dsnoop
    ipc_key 1201
    ipc_key_add_uid yes
    slave {
        pcm "hw:CARD=UAC2Gadget"
    }
}
pcm.gadget2 {
    type dsnoop
    ipc_key 1202
    ipc_key_add_uid yes
    slave {
        pcm "hw:CARD=UAC2Gadget"
    }
}

Now run

Code:
> arecord -c 2 -fS32_LE -r192000 -D gadget1 foo.wav  
Recording WAVE 'foo.wav' : Signed 32 bit Little Endian, Rate 192000 Hz, Stereo

works very fine, and is recording to file. keep that running, open a new terminal, and run

Code:
> arecord -c 2 -fS32_LE -r192000 -D gadget2 foobar.wav
ALSA lib pcm_dsnoop.c:638:(snd_pcm_dsnoop_open) unable to open slave
arecord: main:828: audio open error: Device or resource busy

did i miss anything?
 
Either capture from the same dsnoop PCM device in both processes, or use the same IPC key in both PCM devices.
 
Back
Top Bottom