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

TNT

Member
Joined 2003
Paid Member
While you are in those territories, why don't add the timestamps to the log so that we can measure delay through Camilla. It would be really nifty (and a unique feature - haven't seen that on others) to have now when I will setup my subs for real using FIR etc. Its really hard to know where to start otherwise.. Pretty please?

:)

//
 
@xorcz: Are you using a very large chunksize? I found a bug that will give a zero delay if chunksize > samplerate, will fix that in the next version.




While you are in those territories, why don't add the timestamps to the log so that we can measure delay through Camilla. It would be really nifty (and a unique feature - haven't seen that on others) to have now when I will setup my subs for real using FIR etc. Its really hard to know where to start otherwise.. Pretty please?

:)

//
There isn't much point, the measurement would be too imprecise to be useful for anything. It works like this, first raw samples for a chunk are read from the capture device. Then they are converted to a chunk in the internal float format, and when doing that it also keeps track of the maximum value. Then it checks if the maximum value was above the threshold. It doesn't check each sample against the threshold, so it doesn't know where in the chunk there was silence. Adding this would make this loop more complicated and slower.

The RMS and peak measurements work in a similar way, always on a full chunk.
 
Great news Henrik, thanks a lot!

I have run into another issue now. If I'm playing back a list of tracks with a variety of sample rates, e.g. Roon radio with a variety of sample rates from 44.1 and 48 KHz to 88.2 and 96 KHz, then my RME Digiface USB automatically changes its sample rate to match the incoming audio stream (as intended). However, given that the playback sample rate in CamillaDSP is manually set in the config file and I don't want to be forced to employ the resampler, I need CamillaDSP to detect the input device sample rate change and set the output device to match it.

I found the following post on StackOverflow that seems to describe what needs to be done:
ios - Distorted sound after sample rate change - Stack Overflow
 
Last edited:
@xorcz: Are you using a very large chunksize? I found a bug that will give a zero delay if chunksize > samplerate, will fix that in the next version.
I kept rePhase default values taps 16384 and FFT length 65536. Is the chunksize the same as taps?


devices:
adjust_period: 10
capture:
channels: 2
device: hw:Loopback,1
format: FLOAT32LE
type: Alsa
capture_samplerate: 44100
chunksize: 16384
enable_rate_adjust: true
enable_resampling: true
playback:
channels: 8
device: hw:1,10,0
format: S32LE
type: Alsa
queuelimit: 100
resampler_type: BalancedAsync
samplerate: 192000
 
Ok I'll try with your values.
Taps usually means the length of the impulse response, but I don't know if that is the case in rePhase. Don't know what FFT length corresponds to.
In Camilladsp you can choose chunksize freely. If it's smaller than the impulse length it will just switch to segmented convolution.
 
What happens now when the rate changes? Is data being fed to CamillaDSP at the new rate?
Yes it is.


CamillaDSP measures the incoming sample rate, and you can read the value on the websocket. Is that changing?
Yes, the "Fireface USB Settings" panel shows that the soundcard locks onto the new incoming sample rate regardless of whether CamillaDSP is running or not. CamillaDSP is able to measure the new sample rate if it's running while the audio stream changes sample rate, i.e. when skipping to a new 176.4 KHz track while the samplerate=44100 and capture_samplerate=96000 (see quote below). However, CamillaDSP is not changing its input and output audio unit sample rates to match the actual sample rate on the soundcard device itself, so you end up with distorted playback. The stackoverflow post linked in my previous reply appears to list the steps needed to handle the transition.

Code:
sundebo@m1 ~ % camilladsp -p 1234 config.yml -vv
Jan 29 21:39:32.857 DEBG Read config file Some("config.yml"), module: camilladsp
Jan 29 21:39:32.857 DEBG Config is valid, module: camilladsp
Jan 29 21:39:32.858 DEBG Start websocket server on 127.0.0.1:1234, module: camillalib::socketserver
Jan 29 21:39:32.858 DEBG Wait for config, module: camilladsp
Jan 29 21:39:32.858 DEBG Config ready, module: camilladsp
Jan 29 21:39:32.858 DEBG Using channels [true, true], module: camilladsp
Jan 29 21:39:32.858 DEBG Build new pipeline, module: camillalib::filters
Jan 29 21:39:32.858 DEBG build filters, waiting to start processing loop, module: camillalib::processing
Jan 29 21:39:32.882 DEBG Opened CPAL playback device Digiface USB (24011413), module: camillalib::cpaldevice
Jan 29 21:39:32.882 DEBG Opened CPAL capture device Digiface USB (24011413), module: camillalib::cpaldevice
Jan 29 21:39:32.882 DEBG Playback thread ready to start, module: camilladsp
Jan 29 21:39:32.882 TRCE Build f32 output stream, module: camillalib::cpaldevice
Jan 29 21:39:32.882 DEBG Capture thread ready to start, module: camilladsp
Jan 29 21:39:32.882 DEBG Both capture and playback ready, release barrier, module: camilladsp
Jan 29 21:39:32.882 TRCE Build f32 input stream, module: camillalib::cpaldevice
Jan 29 21:39:33.535 TRCE f32 output stream ready, module: camillalib::cpaldevice
Jan 29 21:39:33.540 TRCE f32 input stream ready, module: camillalib::cpaldevice
Jan 29 21:39:33.540 DEBG Starting capture loop, module: camillalib::cpaldevice
Jan 29 21:39:33.540 DEBG Starting playback loop, module: camillalib::cpaldevice
Jan 29 21:39:33.559 WARN No data to play, dropping a callback, module: camillalib::cpaldevice
Jan 29 21:39:33.583 WARN No data to play, dropping a callback, module: camillalib::cpaldevice
Jan 29 21:39:34.546 TRCE Measured sample rate is 30550.89572073703 Hz, module: camillalib::cpaldevice
Jan 29 21:39:35.550 TRCE Measured sample rate is 176392.5199562633 Hz, module: camillalib::cpaldevice


Another scenario is the quote below showing the output after starting CamillaDSP with enable_resampling=true and capture_samplerate=176400 while playing audio @ 192 KHz. CamillaDSP plays distorted sound while still correctly measuring the right input sample rate.

Code:
sundebo@m1 ~ % camilladsp -p 1234 config.yml -vv
Jan 29 21:18:30.758 DEBG Read config file Some("config.yml"), module: camilladsp
Jan 29 21:18:30.758 DEBG Config is valid, module: camilladsp
Jan 29 21:18:30.758 DEBG Start websocket server on 127.0.0.1:1234, module: camillalib::socketserver
Jan 29 21:18:30.758 DEBG Wait for config, module: camilladsp
Jan 29 21:18:30.758 DEBG Config ready, module: camilladsp
Jan 29 21:18:30.758 DEBG Using channels [true, true], module: camilladsp
Jan 29 21:18:30.758 DEBG Build new pipeline, module: camillalib::filters
Jan 29 21:18:30.758 DEBG build filters, waiting to start processing loop, module: camillalib::processing
Jan 29 21:18:30.758 DEBG Creating resampler, module: camillalib::cpaldevice
Jan 29 21:18:30.759 DEBG Creating asynchronous resampler with parameters: InterpolationParameters { sinc_len: 128, f_cutoff: 0.92591465, oversampling_factor: 1024, interpolation: Linear, window: Blackman2 }, module: camillalib::audiodevice
Jan 29 21:18:30.780 DEBG Opened CPAL playback device Digiface USB (24011413), module: camillalib::cpaldevice
Jan 29 21:18:30.780 DEBG Opened CPAL capture device Digiface USB (24011413), module: camillalib::cpaldevice
Jan 29 21:18:30.780 DEBG Playback thread ready to start, module: camilladsp
Jan 29 21:18:30.780 DEBG Capture thread ready to start, module: camilladsp
Jan 29 21:18:30.780 DEBG Both capture and playback ready, release barrier, module: camilladsp
Jan 29 21:18:30.780 TRCE Build f32 output stream, module: camillalib::cpaldevice
Jan 29 21:18:30.780 TRCE Build f32 input stream, module: camillalib::cpaldevice
Jan 29 21:18:31.415 TRCE f32 output stream ready, module: camillalib::cpaldevice
Jan 29 21:18:31.426 WARN No data to play, dropping a callback, module: camillalib::cpaldevice
Jan 29 21:18:31.428 TRCE f32 input stream ready, module: camillalib::cpaldevice
Jan 29 21:18:31.428 DEBG Starting capture loop, module: camillalib::cpaldevice
Jan 29 21:18:31.428 DEBG Starting playback loop, module: camillalib::cpaldevice
Jan 29 21:18:31.438 WARN No data to play, dropping a callback, module: camillalib::cpaldevice
Jan 29 21:18:31.449 WARN No data to play, dropping a callback, module: camillalib::cpaldevice
Jan 29 21:18:31.460 WARN No data to play, dropping a callback, module: camillalib::cpaldevice
Jan 29 21:18:31.471 WARN No data to play, dropping a callback, module: camillalib::cpaldevice
Jan 29 21:18:31.476 WARN No data to play, dropping a callback, module: camillalib::cpaldevice
Jan 29 21:18:31.530 WARN No data to play, dropping a callback, module: camillalib::cpaldevice
Jan 29 21:18:32.468 TRCE Measured sample rate is 27910.049476527634 Hz, module: camillalib::cpaldevice
Jan 29 21:18:33.471 TRCE Measured sample rate is 188951.4862883025 Hz, module: camillalib::cpaldevice
Jan 29 21:18:34.471 TRCE Measured sample rate is 191703.32903834837 Hz, module: camillalib::cpaldevice
Jan 29 21:18:35.479 TRCE Measured sample rate is 192382.891015803 Hz, module: camillalib::cpaldevice
Jan 29 21:18:36.479 TRCE Measured sample rate is 191694.60696425877 Hz, module: camillalib::cpaldevice
 
Last edited:

TNT

Member
Joined 2003
Paid Member
Little problem to remember Load / Upload... what do they do now again...? It would be good if the button that says "Apply" used the same lingo as Load / Upload.

Load = Apply? An Upload will just show the config but not activiate it until "Apply"...

If so, Rename Apply -> Load.

Or Load and Load/Apply...

//
 
@Darkless:
This is very good, because it means you can easily solve the rate switching with a python script that monitors the measured capture sample rate. Whenever it changes, it can then let CamillaDSP load a suitable config for the new rate.
Catching the rate changes through CoreAudio would be quicker at detecting them, but it only solves part of the problem. You still have to decide what to do at the new rate. Just switching the sample rate of the pipeline often isn't enough. If you have FIR filters you will want to switch to new filter coeffs for example.



Since I use a library (CPAL) that completely hides the CoreAudio API I can't implement the stuff from the stackoverflow post in CamillaDSP. Instead it would have to go in CPAL, which at the moment doesn't even have any way of forwarding the info. I'm considering to skip that library and use CoreAudio and Wasapi directly. I haven't decided on that yet and it's quite a large amount of work.
 
Little problem to remember Load / Upload... what do they do now again...? It would be good if the button that says "Apply" used the same lingo as Load / Upload.
Load - load a config file into the GUI
Upload - pick a local config file to store in the config folder on the server (meant for when camilladsp runs on some other machine than the one you use to access the gui). This is not very useful yet.

Apply - send the config from the gui to camilladsp.


I'm getting help to make some quite significant improvements to the gui, expect the next version to be a nice big improvement :)
 
@Darkless:
This is very good, because it means you can easily solve the rate switching with a python script that monitors the measured capture sample rate. Whenever it changes, it can then let CamillaDSP load a suitable config for the new rate.
I'm not convinced that monitoring through Python always works, because CamillaDSP doesn't always seem to register the change. To make matters worse, the RME Digiface USB often sends out some nasty noise spikes when the incoming sample rate changes. I really don't want to subject my sensitive (and expensive) treble drivers to potentially damaging noise spikes. As such I believe a proper callback in CoreAudio is needed that can be triggered as soon as the physical device changes its rate. I imagine that muting and stopping the playback until the sample rate has been properly synced would be ideal, but I haven't looked at the code. Once it has been implemented the Python script for monitoring the capture sample rate and loading a suitable config should work just fine.

Catching the rate changes through CoreAudio would be quicker at detecting them, but it only solves part of the problem. You still have to decide what to do at the new rate. Just switching the sample rate of the pipeline often isn't enough. If you have FIR filters you will want to switch to new filter coeffs for example.
I completely agree. In the case of the RME Digiface USB it's even more needed, as the number of device channels depend on the sample rate, i.e. 44.1 and 48 KHz gives you 32 ADAT channels (ignoring the two phono channels), whereas 88.2 and 96 KHz gives you 16 channels and finally 176.4 and 192 KHz gives you 8 channels.
In the first case I need the mixer to send output to ADAT channels 1/2, 9/10, 17/18 and 25/26 for a 4-way setup. If the sample rate changes to e.g. 96 KHz I suddenly need to change my mixer mappings to 1/2, 5/6, 9/10 and 13/14 plus all the associated filters in the pipeline. It's a royal pain having to maintain three configs, but that's how it is.

Since I use a library (CPAL) that completely hides the CoreAudio API I can't implement the stuff from the stackoverflow post in CamillaDSP. Instead it would have to go in CPAL, which at the moment doesn't even have any way of forwarding the info. I'm considering to skip that library and use CoreAudio and Wasapi directly. I haven't decided on that yet and it's quite a large amount of work.
I didn't realise that CPAL is not able to provide meaningful feedback to the caller. If it requires custom patches for CPAL, then that's what must be done. Pity that I don't know my way around Rust. As much as I'd love to add another language to my resume, my IRL situation precludes me from doing that for the time being. I love the pace and direction you're taking CamillaDSP, no easy feat!
 
Last edited:
Hello! I know very little about the intricacies of Linux, I can only generate "brilliant" ideas, I will ask questions, sorry if they are stupid.
1. When will it be possible to use Camillia as an already debugged application with a working graphical interface on an ARM device? Will the opportunity be realized, download an image that can be loaded onto MicroDS in Pi or BBB and enjoy life.
2. How well is Camillia's signal processing? It's no worse than DSP in ROON, HQP, JRIVER and other P (I'm talking about the version for ARM)
3. (Very important IMHO) Is it possible to implement Camilia so that on the ARM device on which it is installed, you can send a stream from any UPnP player, the same BubbleUPnP, and from Camillia, in turn, an already processed signal to another network endpoint capable of output 2-8 channels. For example BBB (BeagleBone Black) with PURE firmware from Pavel Pogodin, which can output a signal via UPnP (MDP), squeezelite and others. Sobsvenno IMHO a bunch when each device does its own thing. Camillia is running on Pi 3 \ 4, she sends already processed DSP channels to the BBB endpoint.
4. Is Camillia's version possible for the BBB?
5. Will the filter pulses generated in Rephase work in Camilli?
6. Is there a time delay setting?

Henrik Thank you for what you are doing. I am especially pleased that you are making a version of Camillia for single-board devices, since there are a lot of programs on x86, and for ARM there is no such software at all, as far as I know.
 
@HenrikEnquist:

It would be nice to either rate limit the "No data to play, dropping a callback" message to once per second or have a way to turn it off completely. I want to be able to see the other debug and trace messages, but this one quickly clutters the screen and/or log files if you pause the playback or hit a track with a different sample rate.