CamillaDSP - Cross-platform IIR and FIR engine for crossovers, room correction etc.

:) I am a novice :) so how/why do I change that ?? and to what ??
As you appear to have setup loopback as evidenced by your aplay -l output you need to change the capture part of the config file to something like this :

capture:
type: Alsa #all our configurations are using ALSA
channels: 2 #stereo input
device: "hw:Loopback,0" #CamillaDSP capture device, an ALSA loopback will create two devices, 0 and 1, when using an ALSA loopback set this to the opposite of the device used by your player
format: S32LE #capture format, recommend to use S32LE as it will provide enough bit depth for all possible sources


This is from

RPi4 + CamillaDSP Tutorial by @mdsimon2 guide on ASR which is the the closest to what you need I think.

 
Amended the .yml as per your above post and using plughw:2,0 as you indicated for the output card. However this threw errors..
$ ./camilladsp ~/camilladsp/configs/camilladsp.yml 2022-02-22 00:42:47.873100 INFO [src/bin.rs:711] CamillaDSP version 1.0.0-rc2 2022-02-22 00:42:47.873166 INFO [src/bin.rs:712] Running on linux, x86_64 2022-02-22 00:42:47.887412 ERROR [src/bin.rs:344] Playback error: ALSA function 'snd_pcm_open' failed with error 'EBUSY: Device or resource busy' 2022-02-22 00:42:47.888078 INFO [src/alsadevice.rs:547] Capture device supports rate adjust 2022-02-22 00:42:47.888208 INFO [src/processing.rs:37] Playback thread has already stopped.

Then used the amended .yml with the original plughw:0,0 and that seems to start fine..
./camilladsp ~/camilladsp/configs/camilladsp.yml 2022-02-22 00:43:59.152979 INFO [src/bin.rs:711] CamillaDSP version 1.0.0-rc2 2022-02-22 00:43:59.153070 INFO [src/bin.rs:712] Running on linux, x86_64 2022-02-22 00:43:59.163900 INFO [src/alsadevice.rs:547] Capture device supports rate adjust 2022-02-22 00:43:59.269785 INFO [src/alsadevice.rs:155] Starting playback from Prepared state

Log of last successful start attached..

However....camillagui now shows as online and reports details but has no visual activity for the input or output channels and I still have no audio output on headphones or speakers.
Pulse volume control shows only a 'Dummy output' for Output device and a 'Monitor of Dummy Output' as an input device.

There seem to be so many variables..cards, devices, configs, sound mixers, volume controls, loopbacks, camelbacks, fresh squeezed pasta noodles...sigh how does one ever find the right sequence and setup ?

Appreciate your help and we have made progress but I might just have to park it and hope that one day a more coherent configuration method becomes available.
 

Attachments

  • log.txt
    12.4 KB · Views: 42
seashell - I keep fingers crossed for your fast recovery.
Thanks. Unfortunately it's a permanent issue with local oscillations around a downward trend. So my availability will always be limited and unreliable.

Please do not take my posts as a criticism. I am just trying to find potential issues for the sake of the project.
I generally do find your comments helpful. The accusation that I never used -Wall wasn't so constructive but you apologized and I accept so all's good.

Yes, alsa is a VERY complex API, unfortunately with lots of inconsistencies. The API is huge, but it provides level of access and features unparalleled to any other existing audio framework. My experience with the core developers (i.e. Jaroslav and Takashi) is very good, I am convinced they would/will respond to bug reports constructively.
Hopefully that means you've had more/better responses from them of late than in regards to fixing the loopback notify issue. My limited experience has not been positive with them. If you want to file a bug report I suggest starting with the exact issue that get_avail_min is not working in either the prepare or sw_params callbacks.

If they actually respond you can also ask the general question of what is the point of having hw_param / sw_param callbacks and hooks if the hw_param / sw_params values aren't even readable?

With their general unresponsiveness and my unreliability I'm not going to go down the alsa bug report rabbit hole myself.

I appreciate all the thanks and well wishes from everyone in this thread. Thank you. Of course we all know it's really Henrik's monumental efforts that make the magic here.

I shouldn't have but did spend some energy to look at the plugin tonight. I made all the io pointers unsigned and now have a separate signed status indicator instead of using the io pointers for that purpose.

I also noticed that alsa likes to pick hw buffer sizes that are not an integer multiple of the period size even without the rate plugin being used. That observation finally led me to see the reason for the revent overcalls that happen. So I fixed the logic for waking the player app from a poll and changed the overcall warning to an error as it shouldn't occur anymore. Making it an error will now print it to screen / logs with the default error report setting if it is still happening.

I encourage people to try the new version when they get a chance.

Henrik, I noticed one thing while testing to make sure that pause still worked ok. When I use VLC as the player and pause and then resume from pause there is often a glitch in the audio after play resumes. Camilla of course complains about an underrun since there's no way to tell it that it's a pause. Anyway I don't know if the glitches are a plugin problem or a Camilla problem. I don't see anything odd happening counter-wise in the plugin but that's not exactly exhaustive testing. It might be worth testing VLC with loopback instead of the plugin. VLC does not use poll so it's different than many audio players such as aplay. I don't think aplay has a pause function though.

I did not test that the new code still pauses/resumes ok with a player that uses poll as I didn't have one readily available that I could easily redirect to alsa instead of pulseaudio.
 
Thanks for the updates.

I have been testing it (on Debian 11 backports ) piping [FLOAT64LE, stereo, 44.1-176.4kHz] into CamillaDSP fanning out to [FLOAT64LE, 8-channel, 176.4kHz] and the changes appear stable so far.

Henrik's and your software is much appreciated.
And now I've gone and changed everything again. :p

Are you using an 8 channel USB interface? If so I'd be curious which one.

Mentioning Debian 11 it occurs to me I only complied and tested on Debian 10, so it's possible I and the compiler missed some signed/unsigned issues still.
 
Very nice, I like your changes, thanks!
Mixing of result and value in one variable in some (not only) alsa calls is so error prone. And one does not know how to call the variable (result = error or value). The Result enum of Rust is SO useful...
Yeah the overall pointer handling is cleaner now. I think the biggest change was the catch of what was causing poll event overcalls.

I just tested a compile with Debian 11 and no complaints. I also dug out the alsa boundary computation put it directly in the plugin and now check the value provided from reading the sw_param with the direct calculation to make sure they're matching using an assert. Because I wasn't sure the value coming from reading the boundary was correct.
 
And now I've gone and changed everything again. :p

Are you using an 8 channel USB interface? If so I'd be curious which one.

Mentioning Debian 11 it occurs to me I only complied and tested on Debian 10, so it's possible I and the compiler missed some signed/unsigned issues still.
I forgot to mention. I noticed I couldn't get it originally to work with the player on Debian 11 due to unresolved symbols after working fine on Debian 10. It turned out to be a linker issue. One of the symbols in lsound had a slightly different name between 10 and 11. If anyone is interested in the specifics, I can dig up the specifics and repost.

I am using an 8-channel USB interface between CamillaDSP and an OKTO Research DAC8. I settled on 176.4 sampling rate because that is the highest rate I could get a stable slave-clock to the 3rd Gen Focusrite Scarlett 8i6 mic input for measurement and DRC purposes. I am slave clocking the Scarlett via its S/PDIF input from the DAC8's AES/EBU output as the master clock with a Canare passive AES/EBU to S/PDIF converter. The DAC8 supports up to 192kHz I/O and the Scarlett says it supports 192kHz, but I can't get the Scarlett to maintain stable slave lock at that sampling rate. I had to update a Scarlett ALSA Mixer to add the clock sync indicator, internal/external clock switch control and work with the Gen 3 on Linux since Focusrite doesn't formally support Linux.

I wrote a Linux VST3 plugin that reads/writes FLOAT64LE so I can let CamillaDSP do all of the DSP heavy lifting in 64bit without dropping down to 32bit in the middle of the audio chain. It allows me to chose who does the resampling and DST, the upstream host player or downstream CamillaDSP. No need for the player to split into 8 channels since CamillaDSP does it very well and reduces the number of channels upstream. The player does do the format conversions to raw (e.g. DSD, FLAC, WAV, etc.). The VST3 plugin currently only handles stereo, but could easily be upgraded to interlace more channels if there is enough CPU bandwidth and need.

The VST3 plugin simply interlaces the raw F64 mono-streams in the callback and places the interlaced buffers into a mutex protected ring buffer. A client thread handles all of the ALSA handshakes including reading from the ring buffer and blocked writei() to ALSA. The VST3 plugin doesn't get any hints from the host of any [PAUSE/STOP] / [RESUME/START] events (but does detect sample rate changes), so I keep track of the last time the Process() callback was called and then arbitrarily chose a greater than 2 seconds callback gap to trigger a Close/Open of the ALSA connection to recover from the Host's [PAUSE|STOP] / [RESUME/START] scenarios. It worked fine with your changes from yesterday (and need to retest with your latest changes). I should probably also turn on all of CamillaDSP's logging as well in addition to the ALSA_CDSP and VST3 logs.

It uses some of your inherited code and I felt a little guilty about being your 3rd cousin removed by marriage. I don't feel so bad now after discovering you inherited some of it as well. Somewhere I read something about the sincerest form of flattery ??? :)
 
Last edited:
Hopefully that means you've had more/better responses from them of late than in regards to fixing the loopback notify issue. My limited experience has not been positive with them.
I am sorry for your experience. IMO the notification bug has already been fixed https://github.com/torvalds/linux/commit/168632a495f49f33a18c2d502fc249d7610375e9
If you want to file a bug report I suggest starting with the exact issue that get_avail_min is not working in either the prepare or sw_params callbacks.

If they actually respond you can also ask the general question of what is the point of having hw_param / sw_param callbacks and hooks if the hw_param / sw_params values aren't even readable?

With their general unresponsiveness and my unreliability I'm not going to go down the alsa bug report rabbit hole myself.

I have no problem communicating the issue, just I do not know the details.

Henrik, I noticed one thing while testing to make sure that pause still worked ok. When I use VLC as the player and pause and then resume from pause there is often a glitch in the audio after play resumes. Camilla of course complains about an underrun since there's no way to tell it that it's a pause. Anyway I don't know if the glitches are a plugin problem or a Camilla problem. I don't see anything odd happening counter-wise in the plugin but that's not exactly exhaustive testing. It might be worth testing VLC with loopback instead of the plugin. VLC does not use poll so it's different than many audio players such as aplay. I don't think aplay has a pause function though.
This may be fixed with Henrik's version 1.1 which handles capture/playback stalls. At stall the outdated samples in the device buffer are cleared to avoid a glitch https://github.com/HEnquist/camilladsp/blob/next11/src/alsadevice.rs#L865 https://github.comand /HEnquist/camilladsp/blob/next11/src/alsadevice.rs#L542
Before - a glitch after resume caused by outdated samples is visible:

1645515623670.png


After restarting the device at stall:
1645515703509.png
 
Amended the .yml as per your above post and using plughw:2,0 as you indicated for the output card. However this threw errors..
$ ./camilladsp ~/camilladsp/configs/camilladsp.yml 2022-02-22 00:42:47.873100 INFO [src/bin.rs:711] CamillaDSP version 1.0.0-rc2 2022-02-22 00:42:47.873166 INFO [src/bin.rs:712] Running on linux, x86_64 2022-02-22 00:42:47.887412 ERROR [src/bin.rs:344] Playback error: ALSA function 'snd_pcm_open' failed with error 'EBUSY: Device or resource busy'

Mostly likely pulseaudio has already taken over the card. PA needs to be told to avoid using the card, either via some PA GUI or CLI, e.g. https://askubuntu.com/a/1226710[/ICODE]
 
...

Mentioning Debian 11 it occurs to me I only complied and tested on Debian 10, so it's possible I and the compiler missed some signed/unsigned issues still.
Merged your latest changes and compiled both with gcc and g++.

  • Linux 5.15.0-0.bpo.2-amd64 #1 SMP Debian 5.15.5-2~bpo11+1 (2022-01-02) x86_64 GNU/Linux
  • gcc (Debian 10.2.1-6) 10.2.1 20210110
  • g++ (Debian 10.2.1-6) 10.2.1 20210110

Gcc didn't complain, but g++ did.

A bunch of: goto statements jumping past variable initializations.

A bunch of: (void *) and (cdsp_t *) used interchangeably.

libasound_module_pcm_cdsp.c: In function ‘snd_pcm_sframes_t cdsp_calculate_delay(snd_pcm_ioplug_t*)’:
libasound_module_pcm_cdsp.c:1069:21: error: invalid conversion from ‘void*’ to ‘cdsp_t*’ [-fpermissive]
1069 | cdsp_t *pcm = io->private_data;
| ~~~~^~~~~~~~~~~~
| |
| void*

A couple of int / size_t signed complaints.

libasound_module_pcm_cdsp.c:595:24: warning: comparison of integer expressions of different signedness: ‘int’ and ‘size_t’ {aka ‘long unsigned int’} [-Wsign-compare]
595 | for(int ca = 2; ca < pcm->n_cargs; ca++) {

libasound_module_pcm_cdsp.c:892:20: warning: comparison of integer expressions of different signedness: ‘int’ and ‘size_t’ {aka ‘long unsigned int’} [-Wsign-compare]
892 | for(int f = 0; f < (*pcm)->n_cargs; f++) {
 
Last edited:
I have no problem communicating the issue, just I do not know the details.

Here a simple example of the problem code.
Code:
// This is an ioplug sw_params callback function
static int myplugin_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params) {
  snd_pcm_uframes_t avail_min;
  // Sometime after 1.1.18 the call below stopped working.
  // 1.1.18 => avail_min is returned in &avail_min and err = 0
  // 1.2.x => Large garbage value returned in &avail_main and err = a positive number.
  // Docs say err should be <= 0.  The value returned to err looks like it could actually be the period or maybe the avail_min value
  int err = snd_pcm_sw_params_get_avail_min(params, &avail_min);

  return err;
}

You can also look at the jack plugin in the official alsa github and see how it tries to pull avail_min during the prepare callback. Using that method the snd_pcm_sw_params_get_avail_min call still fails the same way.
 
Merged your latest changes and compiled both with gcc and g++.
Thanks for checking.

The signed/unsigned errors are correct and I have fixed them in a new push. I added -Wextra to the cflags to better catch these issues.

The other errors are specific to C++ which this code is not. None of the uninitialized variables are used after the goto targets so no errors there.

As to the casts of void pointers, googling says the C and C++ standards are different. C does not expect an explicit cast for assignment of void* pointers. C++ does. Even using -pedantic the C compiler is happy w/o the casts. (Now -pedantic -std=c99 whines a lot about the debug macros being called w/o arguments but I'm not going to fix that as it just makes things uglier to have two print macros one with an argument and one without.)
 
I forgot to mention. I noticed I couldn't get it originally to work with the player on Debian 11 due to unresolved symbols after working fine on Debian 10. It turned out to be a linker issue. One of the symbols in lsound had a slightly different name between 10 and 11. If anyone is interested in the specifics, I can dig up the specifics and repost.
I tried aplay on Debian 11 and it seemed happy. Which player are you using?

I am using an 8-channel USB interface between CamillaDSP and an OKTO Research DAC8. I settled on 176.4 sampling rate because that is the highest rate I could get a stable slave-clock to the 3rd Gen Focusrite Scarlett 8i6 mic input for measurement and DRC purposes. I am slave clocking the Scarlett via its S/PDIF input from the DAC8's AES/EBU output as the master clock with a Canare passive AES/EBU to S/PDIF converter. The DAC8 supports up to 192kHz I/O and the Scarlett says it supports 192kHz, but I can't get the Scarlett to maintain stable slave lock at that sampling rate. I had to update a Scarlett ALSA Mixer to add the clock sync indicator, internal/external clock switch control and work with the Gen 3 on Linux since Focusrite doesn't formally support Linux.
Quite a setup. I was hoping you'd found some other gem than the OKTO DAC8 as the world needs more good quality and easily available 8 channel USB DACs.

It uses some of your inherited code and I felt a little guilty about being your 3rd cousin removed by marriage. I don't feel so bad now after discovering you inherited some of it as well. Somewhere I read something about the sincerest form of flattery ??? :)
Inherited code is one of the great things about open source. It lets people modify things to their purposes or build new ones. Shared knowledge helps everyone. bluez_alsa could possibly even benefit from some of the changes I've made if they wanted and if the code bases haven't diverged too much for them to no longer be relevant.

One thing though. Given the heritage and license you should have the bluez_alsa copyright information in your MIT license description.
 
Thanks for checking.

The signed/unsigned errors are correct and I have fixed them in a new push. I added -Wextra to the cflags to better catch these issues.

The other errors are specific to C++ which this code is not. None of the uninitialized variables are used after the goto targets so no errors there.

As to the casts of void pointers, googling says the C and C++ standards are different. C does not expect an explicit cast for assignment of void* pointers. C++ does. Even using -pedantic the C compiler is happy w/o the casts. (Now -pedantic -std=c99 whines a lot about the debug macros being called w/o arguments but I'm not going to fix that as it just makes things uglier to have two print macros one with an argument and one without.)
They are all warnings and still compile/function within their own context.

FWIW, I locally changed the log macros to have an #if/#else/#endif where the #else block redefines the macros to NOOPS (removing the code from runtime) and removes the runtime "if (FLAG > n)" checks in the #if section.

Also added the LINE numbers to the #if section so I could quickly jump to the source by line number.

Current: #define error(fmt, ...) \ do { if(DEBUG > 0){fprintf(stderr,"CDSP Plugin ERROR: "); fprintf(stderr,((fmt)), ##__VA_ARGS__);} } while (0) Modified (not as pretty): #if DEBUG > 0 #define error(fmt, ...) \ do { {fprintf(stderr,"CDSP Plugin %d ERROR: ",__LINE__); fprintf(stderr,((fmt)), ##__VA_ARGS__);} } while (0) #else #define error(fmt, ...) #endif