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

How to play directly to ALSA loopback with started Camilla?

aplay -c2 -fS32_LE -r96000 -D"hw:Loopback,1" --buffer-size=2048 --period-size=1024 note96_2ch.wav

Playing WAVE 'note96_2ch.wav' : Signed 32 bit Little Endian, Rate 96000 Hz, Stereo


makes no sound, Camilla does not see any signal (Signal range: -1000).
If Camilla is capturing from Loopback,1, then you should let aplay output to Loopback,0:
Code:
aplay -c2 -fS32_LE -r96000 -D"hw:Loopback,0" --buffer-size=2048 --period-size=1024 note96_2ch.wav
 
Yes it would be possible to use a minimum phase interpolation filter. For the same steepness is has the same amount of ringing as the sinc, but puts all of it after the impulse. I didn't add this (yet) to the resampler as I didn't see a large enough need for it to motivate the extra complexity.

Sorry to ponder on this topic still.
When i look at GitHub - HEnquist/camilladsp: A flexible linux IIR and FIR engine for crossovers, room correction etc. it reads like no sinc is involved for synchronous resampling (FFT/IFFT), but when i look at the rubato code it says:
Code:
/// The resampling is done by FFT:ing the input data. The spectrum is then extended or
/// truncated as well as multiplied with an antialiasing filter
/// before it's inverse transformed to get the resampled waveforms.
:
:
filter_t[n] = sinc[0][n] / (fft_size_in as $ft);
So I see always sinc....
 
But also see that for someone that manages coding in rust, it is quite simple to make a program with rubato that takes a FIR filter and resamples it with synchronous resampling to all the common samplerates.
The resampled FIR filter will allways be a few samples longer as i understand (sinc)? So a litte "irritating" when original filter is 2^n length.
 
The solution to the 2^n anoyance is maybe to generate a FIR filter that is, lets say, 256 samples shorter than 2^n and force resampler to be fixed length out and length is 2^n. And also resample original filter to original samplerate. (lose some HF, but guess original filter will be at least 192kHz samplerate)
 
Last edited:
Sorry to ponder on this topic still.
When i look at GitHub - HEnquist/camilladsp: A flexible linux IIR and FIR engine for crossovers, room correction etc. it reads like no sinc is involved for synchronous resampling (FFT/IFFT), but when i look at the rubato code it says:
Code:
/// The resampling is done by FFT:ing the input data. The spectrum is then extended or 
/// truncated as well as multiplied with an antialiasing filter 
/// before it's inverse transformed to get the resampled waveforms. 
: 
: 
filter_t[n] = sinc[0][n] / (fft_size_in as $ft);
So I see always sinc....
The sinc is just the impulse response of a brickwall filter. For an infinitely sharp brickwall filter, the impulse response is the infinite sinc function. If I didn't explicitly make a filter in the synchronous resampler, the resampling would anyway act as a brickwall filter and generate such an infinitely long sinc. Infinitely long functions are not that great to work with in practice for many reasons. So instead you use windowed sinc filters, which aren't as steep but limit the length of the pre-and post-ringing. That's why you see a sinc filter also in the synchronous resampler.

But also see that for someone that manages coding in rust, it is quite simple to make a program with rubato that takes a FIR filter and resamples it with synchronous resampling to all the common samplerates.
The resampled FIR filter will allways be a few samples longer as i understand (sinc)? So a litte "irritating" when original filter is 2^n length.
Yes it would be quite easy to write such a program. The examples in the rubato repo would be a good starting point. It should also be possible to use sox, with a simple bash script to resample to all the desired rates.

The solution to the 2^n anoyance is maybe to generate a FIR filter that is, lets say, 256 samples shorter than 2^n and force resampler to be fixed length out and length is 2^n. And also resample original filter to original samplerate. (lose some HF, but guess original filter will be at least 192kHz samplerate)

Fixed filter length i time. I give up on 44.1, 88,2, 176,4 to 48,96 or 192 or vice versa
It doesn't matter so much what the filter length is, the convolution will anyway be done in chunks of a fixed size. If the length is more than one chunksize, it will just switch to segmented convolution with as many segments as needed.
 
If Camilla is capturing from Loopback,1, then you should let aplay output to Loopback,0:
Code:
aplay -c2 -fS32_LE -r96000 -D"hw:Loopback,0" --buffer-size=2048 --period-size=1024 note96_2ch.wav


I chose the easier way and changed OS to Fedora 33 Cinnamon. It is working fine with chunksize 4096 and there are no pops. I tried also Linuxmint 20, but it was the same as Ubuntu 18.04, no chunksize above 2048. I briefly tried 5.8 kernel instead of stock 5.4, but it has more dependencies. So now I will change to Pulse without the Alsa loopback.
 
Hi,


I have been using camillagui on an RPI and notices a few things.

I am not able to enter negative values for a gain filter via the gui. The negative character does not seem to be accepted. I have tried safari and firefox.


I use two config files, one with FIR filters and one with IIR. Both run fine and pass the config check. Ploting of the filters via the gui works for the configuration with IIR but not for the FIR configuration. With the FIR config, a blank window opens for any of the filters.



Christian
 
I chose the easier way and changed OS to Fedora 33 Cinnamon. It is working fine with chunksize 4096 and there are no pops. I tried also Linuxmint 20, but it was the same as Ubuntu 18.04, no chunksize above 2048. I briefly tried 5.8 kernel instead of stock 5.4, but it has more dependencies. So now I will change to Pulse without the Alsa loopback.
Great that you got it working!
I get lower cpu usage if I use pulse alsa-sink -> alsa loopback -> camilla, than if I do pulse null-sink -> camilla. I haven't investigated properly yet, but I suspect Pulse is doing some resampling in the background. The null-sink also doesn't support setting the rate, so the resampler must be used for rate adjust.

Summary: I recommend using the alsa-sink!

There is also a pipe-sink in pulse that I didn't try yet. It could perhaps be useful.
 
I am not able to enter negative values for a gain filter via the gui. The negative character does not seem to be accepted. I have tried safari and firefox.

I use two config files, one with FIR filters and one with IIR. Both run fine and pass the config check. Ploting of the filters via the gui works for the configuration with IIR but not for the FIR configuration. With the FIR config, a blank window opens for any of the filters.
I'm aware of the problem with negative values! As a workaround it should work if you first type the number without the minus sign, and then add the sign. I'll fix it in the next release.

The FIR plotting problem could have many causes. Do you get any meaningful errors messages from the backend?
Are you putting the full path or a relative path to the coeff files?
If you have relative path, try with the full path instead. That usually causes less problems.
 
So. I did another test.

Not the sox2sox test. ;)

Instead of feeding wav into the pipe towards squeeezelite. I know feed stream flacs.

Code:
SOXOUTFT="-t flac -C 0 -b 24 -c 2"

$SOX -q "$track" -t wavpcm -b 24 - | $CAMILLA -v $camconfig | $SOX -q -t raw -b 24 -c 2 -L -e sign -r $newrate - $SOXOUTFT -

That still shows the jumps on time stamps (not always) in the beginning, but somehow LMS seems to be able to resync the "playback time stamps" between LMS and squeezelite.

Bottom line. That's at least working so far. Good. :D

Obviously the primary issue is not yet solved.


I read about your attempts of integrating camilla in LMS. Have you manager to make It work with output from stdin (I flag) instead of input from file (F flag) in a more decent way compared to what I've done?
In particular the only way I found Is to pipe before camilla sox upsampling at a fixed frequency and then feeding the raw to camilla.
This can be avoided with file input since you have the full path as $FILE and you can read the file infos.
I'm trying to find some ideas if it Is possibile to determine bit depth and sample rate of the file received from pipe (necessary with streaming services in lms, like tidal or qobuz).
 
This is what I am getting as message:


plotcamillaconf /media/diskstation/chris/camilladsp/configs/FIRversionC.yml
Traceback (most recent call last):
File "/home/pi/.local/bin/plotcamillaconf", line 8, in <module>
sys.exit(main())
File "/home/pi/.local/lib/python3.7/site-packages/camilladsp_plot/plotcamillaconf.py", line 15, in main
plot_filters(conf)
File "/home/pi/.local/lib/python3.7/site-packages/camilladsp_plot/plot_filters.py", line 58, in plot_filters
plot_filter(fconf, samplerate=srate, name=filter)
File "/home/pi/.local/lib/python3.7/site-packages/camilladsp_plot/plot_filters.py", line 33, in plot_filter
currfilt = Conv(filterconf['parameters'], samplerate)
File "/home/pi/.local/lib/python3.7/site-packages/camilladsp_plot/filter_eval.py", line 44, in __init__
values = self._read_coeffs(conf)
File "/home/pi/.local/lib/python3.7/site-packages/camilladsp_plot/filter_eval.py", line 65, in _read_coeffs
values = self._read_binary_coeffs(fname, conf["format"], skip_nbr, read_nbr)
File "/home/pi/.local/lib/python3.7/site-packages/camilladsp_plot/filter_eval.py", line 84, in _read_binary_coeffs
np.fromfile(fname, offset=skip_bytes, count=count, dtype=datatype)
TypeError: 'offset' is an invalid keyword argument for fromfile()
 
I read about your attempts of integrating camilla in LMS. Have you manager to make It work with output from stdin (I flag) instead of input from file (F flag) in a more decent way compared to what I've done?
In particular the only way I found Is to pipe before camilla sox upsampling at a fixed frequency and then feeding the raw to camilla.
This can be avoided with file input since you have the full path as $FILE and you can read the file infos.
I'm trying to find some ideas if it Is possibile to determine bit depth and sample rate of the file received from pipe (necessary with streaming services in lms, like tidal or qobuz).
You could maybe do something like what I did in the script here: https://www.diyaudio.com/forums/pc-...rossovers-correction-etc-105.html#post6372438
You could read the the header from the pipe, analyze it to find out the parameters (based on this perhaps:camilladsp/analyze_wav.py at master * HEnquist/camilladsp * GitHub), and then connect stdin of the script to stdin of camilladsp.


This is what I am getting as message:


plotcamillaconf /media/diskstation/chris/camilladsp/configs/FIRversionC.yml
Traceback (most recent call last):
File "/home/pi/.local/bin/plotcamillaconf", line 8, in <module>
sys.exit(main())
File "/home/pi/.local/lib/python3.7/site-packages/camilladsp_plot/plotcamillaconf.py", line 15, in main
plot_filters(conf)
File "/home/pi/.local/lib/python3.7/site-packages/camilladsp_plot/plot_filters.py", line 58, in plot_filters
plot_filter(fconf, samplerate=srate, name=filter)
File "/home/pi/.local/lib/python3.7/site-packages/camilladsp_plot/plot_filters.py", line 33, in plot_filter
currfilt = Conv(filterconf['parameters'], samplerate)
File "/home/pi/.local/lib/python3.7/site-packages/camilladsp_plot/filter_eval.py", line 44, in __init__
values = self._read_coeffs(conf)
File "/home/pi/.local/lib/python3.7/site-packages/camilladsp_plot/filter_eval.py", line 65, in _read_coeffs
values = self._read_binary_coeffs(fname, conf["format"], skip_nbr, read_nbr)
File "/home/pi/.local/lib/python3.7/site-packages/camilladsp_plot/filter_eval.py", line 84, in _read_binary_coeffs
np.fromfile(fname, offset=skip_bytes, count=count, dtype=datatype)
TypeError: 'offset' is an invalid keyword argument for fromfile()
Ok! Yu probably have a numpy version older than 1.17. But don't bother updating, the next version won't use numpy at all :)
 
Thanks for the Hint. I've already made a Java "wrapper" that includes all the sox|Camilla|sox logic, including input/output from pipes and dynamic generation of temporary config files for camilla, the last missing step was to better manage input from pipes. I'll implement the header parsing of wav files and I'll make some tests... Thanks again for the idea
 
Summary: I recommend using the alsa-sink!
I am just curious, how did you setup the chain - where do you resample and what formats.
Currently I keep this PA daemon's configuration
default-sample-format = float32le
default-sample-rate = 192000
avoid-resampling = false
resample-method = speex-float-10

from Pulseaudio Crossover Rack - Online Help

So format of the PA sink is float32 so I changed asound.conf to the same rate and format.

And then CamillaDSP config (modified camilladsp-config/alsaconfig.yml at master * HEnquist/camilladsp-config * GitHub) sure the same rate, capture format also, playback device can S322LE.
 
@Henrik...

Well i was storking your'e github and i see that you have a numpyless development in the github :)

Looking forward to see when it's eventually done.
You also mentioned some time ago, that you are developing a plugin without matplotlib also, is this part of this development (not to rush you at all, just curious) :up:

Good day out there.

Jesper.
 

Attachments

  • Numpy_less.PNG
    Numpy_less.PNG
    32.6 KB · Views: 157