Yes I believe you are right. I wasn't sure if this would cause any trouble so I left it at showing a warning message without any further action. It seems to be just fine to run with avail_min < period, so the warning has served it's purpose and can be removed 🙂Maybe the warning check https://github.com/HEnquist/camilla...cc1/src/alsadevice_buffermanager.rs#L100-L105 is not required, setting avail_min < period size seems to make no harm here. But I may have overlooked something and am wrong.
Please bear with me with another question 🙂
tl;dr;: is there a way to bypass camilladsp's main fader for some of the items/input channels in the pipeline? If not, would the upcoming 3.x series provide that feature?
Why am I asking this:
I send an inaudible low freq tone at regular intervals to one of the inputs of the alsa loopback dev used by camillaDSP to prevent my subwoofer from powering off while playing music at a low volume, or to wake-up the sub when needed. (The installation in question uses a master SW volume in the form of a camilladsp volume/loudness effect).
With camilladsp version 1.x, the low freq tone was mixed into the output without any volume effect - ie. it would always play at the same fixed gain regardless of the volume(/loudness) effect I used as a main SW volume. This was straighforward to configure and worked great.
Version 2.x introduced a global volume (definitely a good idea!) but this broke the setup above because when playing music at a low volume, the tone would also play at a low volume, failing to wake the sub up or to keep it on.
I tried to use an aux* fader, but it if I recall correctly they are chained to the main fader. I could have set the main fader to 0dB and used eg. aux1 as my main music volume and aux2 (set to a constant gain) for the low freq tone, but I would have lost the ability to use camilladsp's '-g' startup option and to control the volume with camilladsp-gui (+ I didn't want to go and change the gui's code here and there to use an aux fader rather than 'main').
My current workaround is a bit convoluted: the tone is played through a volume effect controlling aux1, whose volume is dynamically set by the python function that manages camillaDSP's main fader (=my master SW volume), so that the resulting volume would always be the same. For safety I added a limiter effect at the end of the effects chain but the whole thing is more of a hack than a proper solution.
Maybe I've overlooked something? Ideas ?
tl;dr;: is there a way to bypass camilladsp's main fader for some of the items/input channels in the pipeline? If not, would the upcoming 3.x series provide that feature?
Why am I asking this:
I send an inaudible low freq tone at regular intervals to one of the inputs of the alsa loopback dev used by camillaDSP to prevent my subwoofer from powering off while playing music at a low volume, or to wake-up the sub when needed. (The installation in question uses a master SW volume in the form of a camilladsp volume/loudness effect).
With camilladsp version 1.x, the low freq tone was mixed into the output without any volume effect - ie. it would always play at the same fixed gain regardless of the volume(/loudness) effect I used as a main SW volume. This was straighforward to configure and worked great.
Version 2.x introduced a global volume (definitely a good idea!) but this broke the setup above because when playing music at a low volume, the tone would also play at a low volume, failing to wake the sub up or to keep it on.
I tried to use an aux* fader, but it if I recall correctly they are chained to the main fader. I could have set the main fader to 0dB and used eg. aux1 as my main music volume and aux2 (set to a constant gain) for the low freq tone, but I would have lost the ability to use camilladsp's '-g' startup option and to control the volume with camilladsp-gui (+ I didn't want to go and change the gui's code here and there to use an aux fader rather than 'main').
My current workaround is a bit convoluted: the tone is played through a volume effect controlling aux1, whose volume is dynamically set by the python function that manages camillaDSP's main fader (=my master SW volume), so that the resulting volume would always be the same. For safety I added a limiter effect at the end of the effects chain but the whole thing is more of a hack than a proper solution.
Maybe I've overlooked something? Ideas ?
The main fader works the same in 3.0 as in 2.0, and there is no way to let selected channels bypass it. The idea is to keep things as simple as possible for the main fader and to guarantee that it's always enabled, and use the aux faders for everything more complicated.
In 3.0 you will be able to access the aux faders from the gui. They also get their own cli parameters for gain and mute, so you will be able to use the "--gain1" option to set the Aux1 volume etc.
In 3.0 you will be able to access the aux faders from the gui. They also get their own cli parameters for gain and mute, so you will be able to use the "--gain1" option to set the Aux1 volume etc.
Great!In 3.0 you will be able to access the aux faders from the gui. They also get their own cli parameters for gain and mute
Speaking of the main volume as a safety feature, here's a finding that may (or may not 🙂) be of interest for the upcoming 3.x: after stopping camilladsp (sigterm) while some music is playing, I'd get a random* high-pitched tone at max volume until camilladsp is started again. I can see on the card vu-meters (a Motu M4) that a signal is received on the input channels despite camilladsp being stopped, so the issue is most likely with alsa's loopback device. By the way I also hear those high pitched tones when there are underruns.
*: it seems that the frequency and volume of the tone depends on how far from zero the signal is when camilladsp is stopped (so the tone is different on left and right speakers): stopping camilladsp while playing a silent file doesn''t produce any high pitched tone (it probably generates a "zero" signal).
Given that you go to great length to avoid playing stuff at max volume, maybe you'll want to have camilladsp generate a "zero" signal for a couple ms before shutting down. The underruns are another story - given their nature I don't see how this could be dealt with (they're usually very short, so not as much an issue). In my case the issue is minor and has never been concerning - camilladsp has never ever crashed in the middle of a song and my scripts never stop camilladsp when music is playing; so I'd usually encounter this issue when doing tests, in which case I pay attention to lower my amp's volume down beforehand.
Lastly - the right way would be to fix alsa, but that wouldn't solve the problem for distributions (or SoC vendors) shipping older kernels with custom patches for their boards - like in my case. I'll try to do some tests on a PC with the latest kernel and see if the issue is still present - if so I'll file a bug with alsa.
Thank you for your work - I can't say how much I appreciate the time and resources you're contributing to such a great piece of software!
Last edited:
What is your audio chain? How is the loopback involved? There is no such feature in alsa to generate some tones.after stopping camilladsp (sigterm) while some music is playing, I'd get a random* high-pitched tone at max volume until camilladsp is started again. I can see on the card vu-meters (a Motu M4) that a signal is received on the input channels despite camilladsp being stopped, so the issue is most likely with alsa's loopback device. By the way I also hear those high pitched tones when there are underruns.
*: it seems that the frequency and volume of the tone depends on how far from zero the signal is when camilladsp is stopped (so the tone is different on left and right speakers): stopping camilladsp while playing a silent file doesn''t produce any high pitched tone (it probably generates a "zero" signal).
It may look like an issue with your Motu device https://www.motunation.com/forum/viewtopic.php?t=69107 https://gearspace.com/board/audio-s...dio-express-cutting-out-high-pitch-noise.html . Firmware upgrades are mentioned.
I can imagine the USB receiver gets stuck and keeps replaying the last buffered samples - that would explain your observations.
Scratch the loopback - I wasn't fully awake when I replied early this morning. I meant only 'alsa' - sorry.
But you're right.
I'm pretty advanced with linux in general but alsa always had this feeling of black magic - I'd tweak some stuff until it would work without really understanding why it would work and I never really had the time to delve into it. Given my observations I thought that alsa could be keeping the device open in a way that made the M4 output that noise - because as mentioned interrupting camilladsp (or aplay or whatever) when playing a non-zero signal triggers the high pitch noise, while playing silence doesn't. I never really thought about it; your explanation that the USB receiver replaying the last samplesover and over makes sense.
With that said, having camilladsp bring the signal to zero before closing a device could be a nice addition if it's trivial to implement (IMHO - not only because of this problem with the M4, it's not camilladsp's role to work around HW bugs, but in general - it's usually a Good Thing (tm) to avoid abrupt changes).
But you're right.
I'm pretty advanced with linux in general but alsa always had this feeling of black magic - I'd tweak some stuff until it would work without really understanding why it would work and I never really had the time to delve into it. Given my observations I thought that alsa could be keeping the device open in a way that made the M4 output that noise - because as mentioned interrupting camilladsp (or aplay or whatever) when playing a non-zero signal triggers the high pitch noise, while playing silence doesn't. I never really thought about it; your explanation that the USB receiver replaying the last samplesover and over makes sense.
With that said, having camilladsp bring the signal to zero before closing a device could be a nice addition if it's trivial to implement (IMHO - not only because of this problem with the M4, it's not camilladsp's role to work around HW bugs, but in general - it's usually a Good Thing (tm) to avoid abrupt changes).
A firmware issue seems like a likely explanation here. I have a quite new M4 and I haven't noticed anything like this.
Camilladsp stops the stream immediately when shutting down. I don't want to complicate things by generating more samples on shutdown, but a call to snd_pcm_drain could be added to end things more gently.
Camilladsp stops the stream immediately when shutting down. I don't want to complicate things by generating more samples on shutdown, but a call to snd_pcm_drain could be added to end things more gently.
I am not sure it will help. When looking at wireshark capture the USB stream is quite simple:
host: setup request to the playback interface: set altsetting to 1 (or any non-zero altsetting) - meaning start playback with format defined by altsetting 1 (details listed in the stream0 file)
device: success
host: bytestream data, data, data, data....., device just returns successes
host: setup request to the playback interface: set altsetting to 0 - meaning stop playback
device: success
IMO calling snd_pcm_drain will just potentially add a few more data packets to drain the driver buffer. snd_pcm_close() calls snd_pcm_drop() internally which is the sibling of snd_pcm_drain() https://github.com/alsa-project/als...df9fd8240d10b530d9abd/src/pcm/pcm.c#L776-L785
With PCI soundcards, when kernel got stuck during playback, the card would keep re-playing the last alsa buffer samples, as the independent card DMA loop transfer was kept running (the card did not receive any stop command) but CPU ceased to provide new data.
IMO the same issue occurs here. The XMOS in Motu M4 is a standard microcontroller with DMA transfer to its SAI (I2S) interface to allow serving other requests while playing. Re-playing a short DMA buffer will produce high frequencies only. I doubt the host side can do anything to help, apart of sending zeros before stopping.
Maybe looking at wireshark USB packets dump of the CDSP high-pitch termination would help, but I kind of doubt we would see something unusual.
host: setup request to the playback interface: set altsetting to 1 (or any non-zero altsetting) - meaning start playback with format defined by altsetting 1 (details listed in the stream0 file)
device: success
host: bytestream data, data, data, data....., device just returns successes
host: setup request to the playback interface: set altsetting to 0 - meaning stop playback
device: success
IMO calling snd_pcm_drain will just potentially add a few more data packets to drain the driver buffer. snd_pcm_close() calls snd_pcm_drop() internally which is the sibling of snd_pcm_drain() https://github.com/alsa-project/als...df9fd8240d10b530d9abd/src/pcm/pcm.c#L776-L785
With PCI soundcards, when kernel got stuck during playback, the card would keep re-playing the last alsa buffer samples, as the independent card DMA loop transfer was kept running (the card did not receive any stop command) but CPU ceased to provide new data.
IMO the same issue occurs here. The XMOS in Motu M4 is a standard microcontroller with DMA transfer to its SAI (I2S) interface to allow serving other requests while playing. Re-playing a short DMA buffer will produce high frequencies only. I doubt the host side can do anything to help, apart of sending zeros before stopping.
Maybe looking at wireshark USB packets dump of the CDSP high-pitch termination would help, but I kind of doubt we would see something unusual.
I had a look at a wireshark capture with the M4, and yes, that's exactly as you wrote. (fwiw I ran the capture withhost: setup request to the playback interface: set altsetting to 1 (or any non-zero altsetting) - meaning start playback with format defined by altsetting 1 (details listed in the stream0 file)
device: success
host: bytestream data, data, data, data....., device just returns successes
host: setup request to the playback interface: set altsetting to 0 - meaning stop playback
device: success
aplay
playing a tone file).I opened a ticket with motu but it didn't go anywhere: their last reply was "our engineers say you should have a good experience in Class Compliant mode for kernel >=5.11". Ie. they're telling me that my M4 works perfectly. I can't really blame them since they don't officialy support linux but I'll certainly look at other brand in case I build another streamer. Anyway - I won't spam this thread further since it's not related to camilladsp! (I had (wrongly) assumed that camilladsp was to blame - I hadn't done any test with eg. aplay, and it didn't occur to me the issue could be with the M4 since quite a few people use that interface for various builds/purposes on linux without issues ; maybe I got a lemon).
Thank you for your help!
It is definitely a firmware issue. I've seen same issue in my USB transport project on Linux. It was not seen on Windows/MacOS because when audio stream stops, these OS drivers send 'silence' for some time, so USB transport FIFO's get filled with zeros.A firmware issue seems like a likely explanation here. I have a quite new M4 and I haven't noticed anything like this.
Camilladsp stops the stream immediately when shutting down. I don't want to complicate things by generating more samples on shutdown, but a call to snd_pcm_drain could be added to end things more gently.
On Linux, however, this doesn't happen so the FIFO remained non-zero and the device was unaware about stream stop because there were no transfers from USB. The solution to that is to clear the FIFO after sending data thru I2S or stop I2S transmission.
Nice, I really like that you actually did check with wireshark.I had a look at a wireshark capture with the M4, and yes, that's exactly as you wrote. (fwiw I ran the capture withaplay
playing a tone file).
How often do you encounter the issue? With aplay too?
Well, those zeros would be sent by core audio or windows mixer layers. Very likely by pulseaudio/pipewire in linux too. But does actually the UAC2 driver send some extra zeros when using WASAPI exclusive or ASIO, i.e. bypassing the mixer process? That would be quite surprising if the driver itself did that.It was not seen on Windows/MacOS because when audio stream stops, these OS drivers send 'silence' for some time, so USB transport FIFO's get filled with zeros.
The stream stop should be signalled by the host by requesting altsetting 0 for the playback interface - as described and confirmed in the posts above. Did you encounter just plain interrupt of the data packets, without the corresponding "end of stream" control message? If so, what playback chain/software was used in linux?On Linux, however, this doesn't happen so the FIFO remained non-zero and the device was unaware about stream stop because there were no transfers from USB.
Well, you did 99% of the job for me🙂 I just had to run the trace and check the fields you mentioned...Nice, I really like that you actually did check with wireshark
I encounter that every time the M4 stops receiving data, either unexpectedly (buffer underruns) or when aplay or camilladsp exits. I haven't tested with other programs but I'm pretty sure the same will happen whenever the last samples sent to the interface aren't zeroes.How often do you encounter the issue? With aplay too?
FWIW audacity generate tone files that end at zero, so playing such files with aplay doesn't trigger any noise after aplay exits; however, interrupting aplay while it's playing (or using the -d option) triggers the high pitch noise.
[edit - a quick fix for avoiding the noise after stopping camilladsp is to play a short silence file after camilladsp exits. That can be done with a shell script as a wrapper, of if systemd is used to start camilladsp, adding ExecStopPost=play_some_silence in the service definition]
Good point, I'll check what happens with WASAPI/ASIO.Well, those zeros would be sent by core audio or windows mixer layers. Very likely by pulseaudio/pipewire in linux too. But does actually the UAC2 driver send some extra zeros when using WASAPI exclusive or ASIO, i.e. bypassing the mixer process? That would be quite surprising if the driver itself did that.
Yes, I do stop stream and assert mute signal if altset0 is requested, and that was not happening in my experiments with Linux. There were no USB requests at all, just sudden stop of audio data transfers.The stream stop should be signalled by the host by requesting altsetting 0 for the playback interface - as described and confirmed in the posts above.
I did my debug with Android phone and Audio Player PRO app. At that time I had no Linux machine, the issue was found by one of beta-testers of the transport.
Just to make sure - must be WASAPI exclusive or direct ASIO.I'll check what happens with WASAPI/ASIO.
I wonder what playback chain was used. As confirmed with the actual packet capture above, the playback is finished with altset0 control msg in linux. Of course an application could just stop sending samples but I wonder which app would do that as not detecting/ignoring playback xruns would mean the app was broken.that was not happening in my experiments with Linux. There were no USB requests at all, just sudden stop of audio data transfers.
Nevertheless IMO a correct USB device firmware should monitor the buffer/DMA underflow and stop the SAI or wipe the buffer with zeros, since the altset0 control msg can get lost.
Last edited:
Weird, most people seem happy with the M4. Did you update the firmware to the latest? There is one from september last year.I opened a ticket with motu but it didn't go anywhere: their last reply was "our engineers say you should have a good experience in Class Compliant mode for kernel >=5.11". Ie. they're telling me that my M4 works perfectly
https://motu.com/en-us/download/product/410/
Indeed, that's why I initially blamed alsa.Weird, most people seem happy with the M4
Yes, I checked again before posting a few days ago; I even re-flashed the firmware just in case but no luck.Did you update the firmware to the latest?
Update: shortly after my reply above I got an email from the guys at Motu with a test firmware: issue fixed! No idea if my bug report was the cause for the firmware update or if it was already in the works, but either way I'm back to a 5 stars rating for the M4 and Motu 🙂
Thank you guys for your help and pointing to a firmware issue - I wouldn't have pinged Motu otherwise.
Thank you guys for your help and pointing to a firmware issue - I wouldn't have pinged Motu otherwise.
For those that use REW to generate stereo BIQAD filters, here is a script to help inserting REW's stereo biquad file sections into a copy of your config.yml file. It may save you some manual editing sessions.
Hope this helps someone.
This script slices, dices, indents, aggregates and merges 2 stereo REW YAML files into a copy of your CDSP config file in the appropriate 3 sections (aggregate filter definitions, pipeline filter names list for entire left channel and pipeline filter names list for entire right channel).
The script will aggregate the filter definitions for both left and right channel files generated by REW into a single scratch file.
It will extract the left filter names into one scratch file and the right into another scratch file.
It will then create an aggregate output CDSP YAML file containing the original config input file by replacing the following # INSERT_REW_*_HERE comment flags with the contents of the corresponding scratch files to create a new config file with the biquads.
The original config file will remain unscathed (containing no added biquads, just the comment insert here flags).
The temporary scratch files will be deleted.
Finally, it will dump a diff of the SRC and DST files for visual inspection.
USAGE:
Hope this helps someone.
This script slices, dices, indents, aggregates and merges 2 stereo REW YAML files into a copy of your CDSP config file in the appropriate 3 sections (aggregate filter definitions, pipeline filter names list for entire left channel and pipeline filter names list for entire right channel).
The script will aggregate the filter definitions for both left and right channel files generated by REW into a single scratch file.
It will extract the left filter names into one scratch file and the right into another scratch file.
It will then create an aggregate output CDSP YAML file containing the original config input file by replacing the following # INSERT_REW_*_HERE comment flags with the contents of the corresponding scratch files to create a new config file with the biquads.
The original config file will remain unscathed (containing no added biquads, just the comment insert here flags).
The temporary scratch files will be deleted.
Finally, it will dump a diff of the SRC and DST files for visual inspection.
USAGE:
- The YAML filters names are assumed to be "L" and "R" for left and right respectively when generated by REW.
- e.g. L_1, L_2, L_3, .... and R_1, R_2, R_3, ....
- Change the definition of SRC to your CDSP YAML config input file. Include path if not in current directory.
- Change the definition of DST to your CDSP YAML config BIQUAD output file. Include path if not in current directory.
- Change the definition of L_REW_BIQUADS to the name of your REW generated YAML output file for the left channel.
- Change the definition of R_REW_BIQUADS to the name of your REW generated YAML output file for the right channel.
- Add the following line to the filter definition section of your CamillaDSP config file. Comment will not impact the original file.
- # INSERT_REW_BIQUADS_HERE
- Add the following line to the pipeline section listing your entire left channel filter names. Comment will not impact original file.
- # INSERT_REW_LEFT_NAMES_HERE
- Add the following line to the pipeline section listing your entire right channel filter names. Comment will not impact original file.
- # INSERT_REW_RIGHT_NAMES_HERE
Code:
#!/bin/bash
# Change the following 4 definitions to your environment
SRC="config.yml"
DST="config_biquads.yml"
L_REW_BIQUADS="L_FULL.yml"
R_REW_BIQUADS="R_FULL.yml"
# Grab the left filter names
echo "" > L_names
echo "# Left REW filters" >> L_names
echo "" >> L_names
grep "\- L_" ${L_REW_BIQUADS} >> L_names
echo "" >> L_names
# Indent filter names by 2 spaces
sed -i -e 's/\- L_/ - L_/' L_names
# Strip off everything past "pipelines:", including "pipelines:"
sed -E '/^pipeline:$/,$d' ${L_REW_BIQUADS} > L.yml
# Grab the right filter names
echo "" > R_names
echo "# Right REW filters" >> R_names
echo "" >> R_names
grep "\- R_" ${R_REW_BIQUADS} >> R_names
echo "" >> R_names
# Indent filter names by 2 spaces
sed -i -e 's/\- R_/ - R_/' R_names
# Strip off everything past "pipelines:", including "pipelines:"
sed -E '/^pipeline:$/,$d' ${R_REW_BIQUADS} > R.yml
echo "" > BOTH.yml
echo "# [ %< REPLACE HERE" >> BOTH.yml
echo "" >> BOTH.yml
echo "# Left REW Biquads" >> BOTH.yml
echo "" >> BOTH.yml
cat L.yml >> BOTH.yml
echo "" >> BOTH.yml
echo "" >> BOTH.yml
echo "# Right REW Biquads" >> BOTH.yml
echo "" >> BOTH.yml
cat R.yml >> BOTH.yml
echo "" >> BOTH.yml
echo "# REPLACE HERE >% ]" >> BOTH.yml
echo "" >> BOTH.yml
# Remove redundant "filters:"
sed -i -e 's/filters:/ /' BOTH.yml
# Make changes to a copy of the config YAML file
# Replace the following flags with the contents of the temp files
# INSERT_REW_BIQUADS_HERE
# INSERT_REW_LEFT_NAMES_HERE
# INSERT_REW_RIGHT_NAMES_HERE
cp ${SRC} ${DST}
sed -e "s/INSERT_REW_BIQUADS_HERE/$(<BOTH.yml sed -e 's/[\&/]/\\&/g' -e 's/$/\\n/' | tr -d '\n')/g" -i ${DST}
sed -e "s/INSERT_REW_LEFT_NAMES_HERE/$(<L_names sed -e 's/[\&/]/\\&/g' -e 's/$/\\n/' | tr -d '\n')/g" -i ${DST}
sed -e "s/INSERT_REW_RIGHT_NAMES_HERE/$(<R_names sed -e 's/[\&/]/\\&/g' -e 's/$/\\n/' | tr -d '\n')/g" -i ${DST}
# Remove temporary scratch files
rm L_names R_names L.yml R.yml BOTH.yml
diff ${SRC} ${DST}
ls -lt ${SRC} ${DST}
Last edited:
@phofman : in case you're interested I asked the guys at motu what they fixed (as I thought the altsetting param got ignored by the interface) and here's what they replied:
(in my setup channels 3 and 4 are my main speakers; people having their main speakers on channels 1 and 2 with a lowpass on 3/4 for a sub would have been less impacted. The change in IC also explains why Henrik's M4 was OK).Altsetting isn't used for buffer muting due to other cases where the host can fail to maintain a reliable isoc stream without toggling the alternate. The firmware has a watchdog monitoring isoc transactions and is supposed to mute the USB buffers when the more than 2 microframes elapse without any transfers. The code was muting channels 1&2 but not 3&4 (due to an oversight). Some models may not be affected because they do utilize a different IC and the code for that IC was correctly muting both buffers.
- Home
- Source & Line
- PC Based
- CamillaDSP - Cross-platform IIR and FIR engine for crossovers, room correction etc