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

Hi there.

My LMS setup (custom-convert.conf) + Camilla is also working now.

My recordings are done.
The filters are generated.

Now the last stumbling block:

DRC-fir creates .pcm fir-filters.

I just realized that Camilla just accepts .txt.

If I recall correctly I could feed .pcm filters into brutefir.

Obviously Camilla doesn't support it. What's your suggestion of converting the filters
from pcm to txt so that they match the Camilla requirements?

THX.
 
No. No need for plugins. Just a little DIY spirit. ;)

By using custom-convert.conf rules you can apply very flexible all kind of DSP, format conversions and routing to a stream towards a certain client prior to sending it down to the client.

Example:

flc pcm * dc:a6:32:22:5d:30
# F
[sox] -q $FILE$ -t raw -b 32 - | [camilladsp] /etc/camilladsp/configs/client1.yml | [sox] -q -t raw -b 32 -c 2 -L -e signed -r 44100 - -t wavpcm -b 24 -c 2 -

This rule converts a .flac file into a convolved 24bit .wav stream and does it only for the client with above listed MAC.

Camilla gets 32bit in on stdin and delivers 32bit out on stdout. I need to run it through sox twice though to get the required format conversions in place.

Of course you could, or you better should, also use "rate" of sox to resample everything different from 44100. Above is a pretty static setup.

You can take it a step further and write a wrapper script that could do above and on top e.g the sample rate and filter switching for Camilla and could be called like this:

Code:
flc pcm * dc:a6:32:22:5d:30
	# F
	[cdsp] "$FILE$" client1

you just add a script or program that does the job you want it to do. In the example I am calling my own script - a simple bash script I named "cdsp".
 
Hi there.

My LMS setup (custom-convert.conf) + Camilla is also working now.

My recordings are done.
The filters are generated.

Now the last stumbling block:

DRC-fir creates .pcm fir-filters.

I just realized that Camilla just accepts .txt.

If I recall correctly I could feed .pcm filters into brutefir.

Obviously Camilla doesn't support it. What's your suggestion of converting the filters
from pcm to txt so that they match the Camilla requirements?

THX.
CamillaDSP can read raw filters in a bunch of formats. I guess that .pcm is 32-bit float which is supported. The full list is here: GitHub - HEnquist/camilladsp at develop
 
Hi there.

I now got the LMS setup with real filters up'n running.

I do face a serious issue.

There seems to be some kind of start/stop/pause related issue on my LMS-Camilla setup when driven through custom-convert.conf.

Camilla is not running as daemon if started that way. A pipe gets established every time a track playback gets triggered. That's why you see Camilla active
only for a couple of seconds - while running the bulk convolution. There'll be no continuous convolution load. It's basically an offline convolution.

That's different compared to attaching it to squeezelite via stdout (which I also tested and works nicely!) or running inside the Alsa loopback setting.

Anyhow. The issues are that suddenly e.g the playback time stamp jumps ten seconds ahead or the track playback gets simply cut off 10-15s before it ends and the next track gets started right after.
So far I havn't seen any relevant error messages.

Any ideas what else I could look for?
 
Last edited:
AAMOF - I do have it in. ;)

Code:
---
devices:
  samplerate: 44100
  chunksize: 8192
  queuelimit: 1
  capture:
    type: File
    channels: 2
    filename: "/dev/stdin"
    format: S32LE
  playback:
    type: File
    channels: 2
    filename: "/dev/stdout"
    format: S32LE
What happens if you leave out CamillaDSP and just run with the two sox:es?
Have you tried the same pipeline offline to make sure it produces correct wav-files?
 
What happens if you leave out CamillaDSP and just run with the two sox:es?
Have you tried the same pipeline offline to make sure it produces correct wav-files?

I'll try later today.
The pipeline is working as such. Music plays.

*****

I did wonder how to get rid of the 2nd sox to lower the complexity. The issue is that the file header gets lost while channeling the track through Camilla
- at least the way I am doing it right now. The second sox is just in there just to recreate that header.

What would it take to output .wav/PCM

a. channel the header through Camilla in stdin/stdout mode - while feeding a wav (e.g. skip X bytes)
b. let Camilla create the header on stdout
 
Last edited:
I'd like to second the request for a "quiet" option even on stderr. My mpd logs are full of this.

Code:
[2020-10-21T22:32:17Z INFO  camilladsp] Capture finished
[2020-10-21T22:32:17Z INFO  camilladsp] Playback finished
Alright, will be in the next release.


I'll try later today.
The pipeline is working as such. Music plays.

*****

I did wonder how to get rid of the 2nd sox to lower the complexity. The issue is that the file header gets lost while channeling the track through Camilla
- at least the way I am doing it right now. The second sox is just in there just to recreate that header.

What would it take to output .wav/PCM

a. channel the header through Camilla in stdin/stdout mode - while feeding a wav (e.g. skip X bytes)
b. let Camilla create the header on stdout
I checked now and the .wav made by sox in this way has a valid header with the data length set correctly. This means the header was made after it had processed the whole stream, otherwise it wouldn't know the length. So it has to buffer the entire stream before it can send it out, starting with the newly made header. Is this ok for LMS? Then it would not be difficult to make a wrapper for CamillaDSP that analyzes the header, runs the data through camilla, and then adds a new header before passing the result along.
Or is it better to start streaming the data right away. Then the header needs to be made before by calculating what the new length should be. That's easy if there's no resampling. It might also be possible to get away with setting the length to the maximum possible, but that depends on how LMS uses the info.
 
SoX - Sound eXchange / Code /
[dd8b63]
/src/wav.c


Code:
sox -V -r 48000 -n -c 2 -t wav - synth 1 sine 1k gain -1 | pv > out.wav
sox:      SoX v14.4.2

Input File     : '' (null)
Channels       : 1
Sample Rate    : 48000
Precision      : 32-bit

[B]sox WARN wav: Length in output .wav header will be wrong since can't seek to fix it[/B]

Output File    : '-' (wav)
Channels       : 2
Sample Rate    : 48000
Precision      : 32-bit
Sample Encoding: 32-bit Signed Integer PCM
Endian Type    : little
Reverse Nibbles: no
Reverse Bits   : no
Comment        : 'Processed by SoX'
 
Actually LMS doesn't know what the pipe is doing. LMS communicates the original track characteristics towards the client.

It is the client, who has to make sense of the actual data it receives. The client reads the header.

I did some debugging.


Code:
[2020-10-22T09:28:02Z DEBUG camilladsp] Read config file Some("/etc/camilladsp/configs/areos.yml")
/usr/share/lms/Bin/aarch64-linux/sox WARN wav: Length in output .wav header will be wrong since can't seek to fix it
[2020-10-22T09:28:02Z DEBUG camillalib::filters] Read file: /etc/camilladsp/filters/DRC-flt-erb-44100-right.pcm, number of coeffs: 65536
[2020-10-22T09:28:02Z DEBUG camillalib::filters] Read file: /etc/camilladsp/filters/DRC-flt-erb-44100-left.pcm, number of coeffs: 65536
[2020-10-22T09:28:02Z DEBUG camilladsp] Config is valid
[2020-10-22T09:28:02Z DEBUG camilladsp] Wait for config
[2020-10-22T09:28:02Z DEBUG camilladsp] Config ready
[2020-10-22T09:28:02Z DEBUG camillalib::filters] Build new pipeline
[2020-10-22T09:28:02Z DEBUG camillalib::filters] Build from config
[2020-10-22T09:28:02Z DEBUG camilladsp] Playback thread ready to start
[2020-10-22T09:28:02Z DEBUG camilladsp] Capture thread ready to start
[2020-10-22T09:28:02Z DEBUG camillalib::filters] Read file: /etc/camilladsp/filters/DRC-flt-erb-44100-right.pcm, number of coeffs: 65536
[2020-10-22T09:28:02Z DEBUG camillalib::fftconv_fftw] Conv right_fir is using 8 segments
[2020-10-22T09:28:02Z DEBUG camillalib::filters] Build from config
[2020-10-22T09:28:02Z DEBUG camillalib::filters] Read file: /etc/camilladsp/filters/DRC-flt-erb-44100-left.pcm, number of coeffs: 65536
[2020-10-22T09:28:02Z DEBUG camillalib::fftconv_fftw] Conv left_fir is using 8 segments
[2020-10-22T09:28:02Z DEBUG camillalib::processing] build filters, waiting to start processing loop
[2020-10-22T09:28:02Z DEBUG camillalib::filedevice] skipping the first 44 bytes
[2020-10-22T09:28:02Z DEBUG camillalib::filedevice] starting playback loop
[2020-10-22T09:28:02Z DEBUG camillalib::filedevice] starting captureloop
[2020-10-22T09:28:02Z DEBUG camillalib::filedevice] starting captureloop
[2020-10-22T09:28:41Z DEBUG camillalib::filedevice] End of file, read only 696 of 49152 bytes
[2020-10-22T09:28:41Z DEBUG camillalib::filedevice] Reached end of file
[2020-10-22T09:28:41Z INFO  camilladsp] Capture finished
[2020-10-22T09:28:42Z INFO  camilladsp] Playback finished
[2020-10-22T09:28:42Z DEBUG camilladsp] Exiting

The "end of file" message occurs with every track. Different values.

Could it be that the setup of the pipe takes too long and data get lost!?!?
sox throws the data at camilla while camilla is still starting up?!?!

I also noticed that not every track gets cut off several seconds while running down a playlist.

BTW. I changed the pipe btw. Now feeding 24bit .wav, skip the wav 44 header bytes, camilla in/out S24LE3.

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

Code:
---
devices:
  samplerate: 44100
  chunksize: 8192
  queuelimit: 1
  silence_threshold: -60
  silence_timeout: 3.0
  capture:
    type: Stdin
    channels: 2
    format: S24LE3
    skip_bytes: 44
  playback:
    type: Stdout
    channels: 2
    format: S24LE3
 
Last edited:
Hi.

Just tried to compile Camilla git with fftw3. It failed. All errors seem to relate to fftw.
I'll give it another try with rustfft

Code:
  Compiling camilladsp v0.4.0 (/tmp/camilladsp)
error[E0308]: mismatched types
   --> src/fftconv_fftw.rs:119:13
    |
119 |             &mut self.temp_buf,
    |             ^^^^^^^^^^^^^^^^^^ expected slice, found struct `fftw::array::AlignedVec`
    |
    = note: expected mutable reference `&mut [num_complex::Complex<f64>]`
               found mutable reference `&mut fftw::array::AlignedVec<num_complex::Complex<f64>>`

error[E0308]: mismatched types
   --> src/fftconv_fftw.rs:120:13
    |
120 |             &self.input_f[hist_idx],
    |             ^^^^^^^^^^^^^^^^^^^^^^^ expected slice, found struct `fftw::array::AlignedVec`
    |
    = note: expected reference `&[num_complex::Complex<f64>]`
               found reference `&fftw:
 
The "end of file" message occurs with every track. Different values.
This is just a debug message telling how many bytes ended up in the last chunk. The last chunk gets only partly filled, that's fine. It's kept track of so the playback thread can limit the last write to the correct number of samples.


Could it be that the setup of the pipe takes too long and data get lost!?!?
sox throws the data at camilla while camilla is still starting up?!?!

Maybe.. could you save a copy of the processed file with tee or something, to check what was delivered to LMS?


Code:
 ---
devices:
  samplerate: 44100
  chunksize: 8192
  queuelimit: 1
  silence_threshold: -60
  silence_timeout: 3.0
  capture:
    type: Stdin
    channels: 2
    format: S24LE3
    skip_bytes: 44
  playback:
    type: Stdout
    channels: 2
    format: S24LE3
Here I would skip the pausing, could mess things up! Just leave out silence_threshold and silence_timeout.


BTW did you try with just sox | sox, and no camilla in between?


I btw would agree to another inmates feedback for the preference to have the actual system time in the debug log.
Noted. I found an easy way, just need to do it.