How do I make a Linux/ALSA loudspeaker crossover DSP?

Thanks.

Why default ctl to hw:2 while default pcm to hw:0+hw:1? Did your card IDs stay constant? It would be better to use card names, plus renaming identical USB devices with udev rules configured for the particular USB port.

I am afraid you will have to troubleshoot your alsa config step by step, using an extra pcm device in each step, in order to find the failing pcm device config.
 
Thanks.
Why default ctl to hw:2 while default pcm to hw:0+hw:1? Did your card IDs stay constant? It would be better to use card names, plus renaming identical USB devices with udev rules configured for the particular USB port.
I am afraid you will have to troubleshoot your alsa config step by step, using an extra pcm device in each step, in order to find the failing pcm device config.
ctl set to 2 because the two amps (hw 0 and 1) have no ctl available to alsa.

Just started that before being rudely interrupted by obligatory New Year celebrations (yes, I'm married!)

Thanks for having a look.

Andy
 
Interim report:
the problem is in type multi; removing all but that still produces the error; changing to plughw for the two amps changes the error message.
Will try using different outputs in an attempt to discover whether the problem is the amps, or the software.
The change in behavior started with Buster.
 
Unfortunately the error message "aplay: pcm_params.c:170: snd1_pcm_hw_param_get_min: Assertion `!snd_interval_empty(i)' failed" does not say what hw param has the empty interval (buffer size, period size, samplerates, etc.). Would perhaps verbose output of aplay (-v) tell more?
 
Member
Joined 2007
Paid Member
For debugging in ALSA, here are links that I have found useful in the past - not always for precise answers, but sometimes to realize alternate strategies.

https://www.alsa-project.org/alsa-doc/alsa-lib/index.html
...and particularly within the above link:
https://www.alsa-project.org/alsa-doc/alsa-lib/pcm_plugins.html
The above is a definitive description of the various types of plugs, their allowed variables and syntax, and their defaults.

https://wiki.archlinux.org/title/Advanced_Linux_Sound_Architecture#Unmute_5.1.2F7.1_sound
All the best in this hopeful new year,

Frank
 
Would perhaps verbose output of aplay (-v) tell more?
Sadly, nothing so helpful.
Here it is:

rab@raspberrypiS:~ $ aplay -v ~/Music/RVWSy2.wav
Playing WAVE '/home/rab/Music/RVWSy2.wav' : Signed 24 bit Little Endian in 3bytes, Rate 96000 Hz, Stereo
aplay: pcm_params.c:170: snd1_pcm_hw_param_get_min: Assertion `!snd_interval_empty(i)' failed.
Aborted by signal Aborted...
rab@raspberrypiS:~ $


This file will play successfully direct to the amp. with no conversion:

rab@raspberrypiS:~ $ aplay -D hw:1,0 -v ~/Music/RVWSy2.wav
Playing WAVE '/home/rab/Music/RVWSy2.wav' : Signed 24 bit Little Endian in 3bytes, Rate 96000 Hz, Stereo
Hardware PCM card 1 'Sabaj A4 AMP' device 0 subdevice 0
Its setup is:
stream : PLAYBACK
access : RW_INTERLEAVED
format : S24_3LE
subformat : STD
channels : 2
rate : 96000
exact rate : 96000 (96000/1)
msbits : 24
buffer_size : 48000
period_size : 12000
period_time : 125000
tstamp_mode : NONE
tstamp_type : MONOTONIC
period_step : 1
avail_min : 12000
period_event : 0
start_threshold : 48000
stop_threshold : 48000
silence_threshold: 0
silence_size : 0
boundary : 1572864000
appl_ptr : 0
hw_ptr : 0
rab@raspberrypiS:~ $
 
Ran a test with different playback devices - the Cirrus sound card on the GPIO pins outputting to SPDIF to one amp, and an ancient cheap usb sound card also converting to SPDIF to the other. Worked perfectly, so must conclude that the Pi4 hardware communicates to the amps in a subtly different way.

Bullseye worked on the Pi3, but the Pi3 did not have the power to run alsaloop fast enough under Bullseye to maintain lip sync. The amps were receiving the stream at its original rate - the tiny screen shows the rate it's being fed.

A little more thinking time needed on the software side before either: putting the Pi3 back to work until it fails; or buying some hardware.

I seem to recall Charlie telling us about a way to use two ?three? Pis using ethernet to communicate the audio stream. He got a bit of flac for I believe.
 
Member
Joined 2007
Paid Member
Bullseye worked on the Pi3, but the Pi3 did not have the power to run alsaloop fast enough under Bullseye to maintain lip sync. The amps were receiving the stream at its original rate - the tiny screen shows the rate it's being fed.

A little more thinking time needed on the software side before either: putting the Pi3 back to work until it fails; or buying some hardware.
Interesting. How can you be sure the all of the channels are synchronized?

I do NOT have a kernel level knowledge of Linux, but a reliable kernel hacker told me that the RPi device tree only supports a single PCM serial audio stream (or L & R channels in the case of I2S). I have never attempted on an RPi what you are trying.

I see that your ALSA config file in post #17 contains 39 filters in one plug (if I'm not mistaken)? That in itself would crash the output from the single-core BBB on which my crossover runs. I limit the plug filter count to 8, run in parallel, adding 1098s to channels that are untouched. ...worked better for me... So a humble suggestion would be to test while running only one obvious filter per channel JIC the complex chain is causing under-runs.

F
 
The error hits before aplay can even print PCM device configs in the verbose mode.

Every PCM device has a set of parameters (hw_params), some of which (buffer size, period size) are defined in ranges (intervals). When chaining the configured devices, alsa-lib computes intersection of the intervals defined by the slave PCMs, eventually modifies it and reports as new interval for the given device to its parent/master device. When the intersected interval is empty, alsa cannot proceed and throws the error.

Unfortunately there are no debug lines in that part of the source code, troubleshooting requires installing debugging symbol packages and debugging with gdb:

Code:
sudo aptitude install alsa-utils-dbgsym libasound2-dbgsym gdb
gdb /usr/bin/aplay
 --------- in gdb enter gdb commands:
set args -d yourdevice /home/pi/some.wav    <---- type your aplay params behind the word "args", no bash shortcuts (~ etc).
break pcm_params.c:170  <--- gdb will offer finding the file when dynamic libraries are loaded, answer y
run

Now gdb will run aplay with the params and stop at the line with your error message. Type bt (backtrace) and gdb will print funtion call stack with line numbers. Copy the output here.

Just a note - your two USB devices are almost certainly async (being XMOS based), having independent clocks. The multi plugin will hit buffer under/overrun anyway, eventually.
 
Last edited:
Frank,
thanks again for the suggestions. I wondered whether it would be useful to split the two sides into separate asound files, if only to test a different way to address the two amps. I'll have a good look at your asound in earlier posts and look at the links you gave to try to understand run in parallel, adding 1098s to channels that are untouched. Please don't feel any need to be humble; I've never worked at operating system level; the nearest I got was a bit of IBM assembler in the 1960s, and analyzing core dumps; COBOL was good enough even then to tell you where your carefully crafted code was rubbish! That's what you got back then when you paid lots of money.

phofman,
now that I know that type multi is the sticking point, I shall, as you suggested, create some simple asound files to see which bits will work.

Happy New Year to all, belatedly,
Andy
 
Member
Joined 2007
Paid Member
Andy,
I didn't post my complete asound.conf file. My approach to DSP has been to manage equalization at the 2-channel level using multiple plugs. In this way I can mix various filters and change between/among them simply by re-specifying the starting ALSA input plug for the player (the '-o' option in squeezelite). ...and the commands to choose among the DSP options are built into buttons within my system remote control. All the EQ profiles then 'drain' into the crossover plugs, which expand to 8 channels and finally exit ALSA after re-ordering to arrive at the correct location in the (6-channel) DAC.

I run some very high resolution midrange drivers from nice balanced amps. The midranges typically require twice as many filter instances - upper and lower. I can clearly hear that the more Alsa processing the signals get, the poorer the sound quality. So a first principle has become efficiency in the filter chain. My current direction is to implement FIR filters within the LADSPA wrappers in hopes of clearing up some of the sonic artifacts. Unfortunately, there is a great deal of competition for the time needed to execute, experiment, and tweak.
 
The error hits before aplay can even print PCM device configs in the verbose mode.
Now gdb will run aplay with the params and stop at the line with your error message. Type bt (backtrace) and gdb will print funtion call stack with line numbers. Copy the output here.
Just a note - your two USB devices are almost certainly async (being XMOS based), having independent clocks. The multi plugin will hit buffer under/overrun anyway, eventually.
attached is the output from dbg.
Before running this I checked that the wav file plays direct to one amp, then ran aplay to check the error code - which seems to have changed from last time!
If I continue, it produces yet another slightly different breakpoint. But one is enough for now.
Hope you can see what's happening.
Thanks,
Andy
 

Attachments

  • ALSA_failure_1.txt
    4.1 KB · Views: 54
Frank,

you have obviously been able to wrestle ALSA far more successfully than I have.
I looked at using Charlie's FIR filters, then realised that FIR embeds the rate in the filter. Fine for the TV, which is always 48000, but a problem for 441000 and 96000 when playing music. Also, no sonic artifacts even on the Pi3.

Giving myself a break by listening via the uneven setup that does work despite the evil pulseaudio deamon running. Surprisingly good quality. Not sure whether I am imagining a slight delay on the USB compared to the Cirrus GPIO card.

Wish I didn't have so much time; my out-of-the-house activities are curtailed by you-know-what.

Andy
 
Member
Joined 2007
Paid Member
Frank,

you have obviously been able to wrestle ALSA far more successfully than I have.
I looked at using Charlie's FIR filters, then realised that FIR embeds the rate in the filter. Fine for the TV, which is always 48000, but a problem for 441000 and 96000 when playing music. Also, no sonic artifacts even on the Pi3.

Giving myself a break by listening via the uneven setup that does work despite the evil pulseaudio deamon running. Surprisingly good quality. Not sure whether I am imagining a slight delay on the USB compared to the Cirrus GPIO card.

Wish I didn't have so much time; my out-of-the-house activities are curtailed by you-know-what.

Andy
You are right that the FIR option is frequency constrained. My plan is to optimize for 44.1 and 48 kHz to see what can be accomplished. Based on those results will move on to 88/96. If those filters are ok in terms of precision and speed, then I would consider down-sampling any source material at 176/192 or above because bit depth matters more than frequency up there. A simple subroutine in my Python system control code could swap the filter sets based on sample rate of the recording. Plus, I might consider trying the BBB-AI, which has 3 times the CPU grunt but could find me wrangling kernel code. In other words, I’m looking at a black hole for time in the midst of a whole-house remodeling job! 😜
 
Member
Joined 2007
Paid Member
Perhaps use a ‘rate’ variable in the Alsa chain to up-sample 44.1 to a multiple of 48? Not sure, but it sounds like the Asus Ubuntu kernel isnt setup for redbook. Can’t research that atm…. If upsampling works then perhaps a different Debian version would iron out the problem to avoid resampling. I like dietPi - no idea if it would fix the problem.