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

I did not mean it should run multithreaded, I just wanted to relate the run time to consumed CPU time - whether just one core or whole CPU was involved. Thanks.
Yes of course, the numbers I gave didn't mean much without that little piece of information :)



Will the accuracy be user configurable?

//
Yes! The question is mostly how, there are quite a few paramters to play with. I think I'll make a few standard profiles like "fast", "balanced", "best" for those who just want it to work, and a completely free mode for those who like to tinker.



Super! What a contribution to linux precision audio processing! And it would be really great if the camilla resampler could perform stereo real-time (online) SRC on a raspberry Pi 4, or even a 3+! Maybe resorting to aforementionned options such as tweaking precision and/or let it run on 2 kernels. I am really eager to make some tests ...
It's possible to try it now!
Clone the repo, and run:
Code:
cargo run --release --example fixedin64 filename_in filename_out rate_in rate_out nbr_channels


example:

cargo run --release --example fixedin64 sine_f64_2ch.raw test.raw 44100 48000 2
There are two examples, one for 32bit float and one for 64. They accept raw files with interleaved float32 and 64 respectively and save the output in the same format as the input.
The resampling parameters aren't exposed as command line options so you have to edit the source code of the example. Look in the 64-bit example. There are a few variateions after line 66.
Code:
let mut resampler = ResamplerFixedIn::<f64>::new(fs_out as f32 / fs_in as f32, 64, 0.95, 160, Interpolation::Nearest, 1024, 2);
You can play with arguments 2-5.

2: sinc length: longer runs slower with steeper rolloff
3: relative cutoff (relative to Nyquist freq). Higher values need a longer sinc length to avoid aliasing.
4: interpolation type (Nearest, Linear or Cubic)


I also saw a mistake now. The last argument is the number of channels, and should to be fixed at 2. Replace that 2 with "channels" to use the value provided on the command line.
 
Have a look at the results of very first experiences with my "torture test" signal along with the new camillaresampler library. In this test, I used the fixedin64 example and ran it first "as is" with a sinc_length=64, and as then a variant with an increased sinc_lenght=512

Sinc lenght 64:
Time_64.png

Sinc lenght 512:
Time_512.png

Sinc lenght 65536 (near-perfect reference):
Time_64K.png

Very promising ...
 

Attachments

  • Time_64.png
    Time_64.png
    19.8 KB · Views: 444
  • Time_512.png
    Time_512.png
    20.1 KB · Views: 451
  • Time_64K.png
    Time_64K.png
    41.4 KB · Views: 440
Some results of some further iterations of sinc length in fixedin64, upsampling from 44100Hz to 96kHz:

sinc length 512, filters down to noise floor (-150dB) < 22050Hz (=Nyquist Frequency!)
sinc length 256, filters down to noise floor (-150dB) @ 22050Hz
sinc length 128 attenuates -50dB @ 22050Hz
sinc length 64 attenuates -20dB @ 22050Hz

Therefore, letting all other parameters of fixedin64 unchanged, a filter lenght of 256 seems the best compromise setting. Values of 64 or 128 instead will in this case more or less violate the Nyquist theorem.
Amplitude.png
 

Attachments

  • Amplitude.png
    Amplitude.png
    28 KB · Views: 387
I have been investigating suitable combinations of parameters and I made a plot of the frequency response for different sinc lengths. Shorter sincs roll off slower, so in order to avoid aliasing I have changed the cutoff frequency for each length. I aimed at getting -140dB ad fs/2 and this led to the formula f_cutoff = 0.5^(16/sinc_length).



I used 64, 128, 256, 512 and 1024 points. The -3dB points end up at approximately (for 44.1kHz input):
64: 18kHz
128: 20kHz
256: 21 kHz
512: 21.5 kHz

1024: 21.8 kHz
See the attached plot for the curves.

sincs.png


The time needed to resample is almost linear with sinc length. 256 points is probably a reasonable value. My Ryzen laptop does a second of stereo audio 44.1kHz -> 96kHz, sinc length of 256 with cubic interpolation in 190 ms.


Switching to linear interpolation drops the time to 95 ms. Then the artefacts grow to about -160dB. Probably still quite ok..


And when using synchronous resampling, the time drops to 55 ms. Then the artefacts are again well below -200dB.



This is all with 64-bit processing. Switching to 32-bit doesn't speed things up on this system. But I would guess that on a raspberry running a 32-bit os it would make a big difference.
 
Resampling is working!


Anyone wants to try it? It would be great if someone could test it on a raspberry. It would also be great with some feedback on the different resampling presets (mostly how much cpu time they consume on different systems).

The readme is updated and I hope it's clear how to enable the resampling. The resampling stuff required some changes to the meaning of some config parameters, so it's not 100% backwards compatible with older config files (although most should work unmodified). For that reason I also bumped the version to 0.1.0.
It's still work in progress. Resampling is working for the Alsa and File capture devices, but not yet for Pulse.

It's in branch "resampling": GitHub - HEnquist/camilladsp at resampling


I also renamed the resampling lib to "rubato", and it lives here now: GitHub - HEnquist/rubato: An asyncronous resampling library written in Rust
("rubato" is a musical term that I think suits quite well here: Tempo rubato - Wikipedia)
If I build a stand-alone resampler around the library some day, that will most likely be named "camillaresampler". Or if somene else want to give that a try, I think it would be a quite nice intro to Rust.. :)
 
RPi will soon get async feedback in the USB-audio gadget Re: usb:gadget:f_uac2: EP OUT is adaptive instead of async - Ruslan Bilovol . If things work out the alsa capture device of the gadget will offer the same PCM Rate Shift alsa control as snd-aloop does (in the first or second patch phase). That will enable using RPi as a smart USB soundcard with embedded camilladsp xover since camilladsp already supports the rate fine-tuning of the capture device. Good timing :)
 
RPi will soon get async feedback in the USB-audio gadget Re: usb:gadget:f_uac2: EP OUT is adaptive instead of async - Ruslan Bilovol . If things work out the alsa capture device of the gadget will offer the same PCM Rate Shift alsa control as snd-aloop does (in the first or second patch phase). That will enable using RPi as a smart USB soundcard with embedded camilladsp xover since camilladsp already supports the rate fine-tuning of the capture device. Good timing :)
Very nice indeed! Will the control have the same name, "PCM rate shift 100000"? If yes it should just work without any changes.
 
The "resampling" branch just got a major update. I haven't quite finished testing it so I'll wait a little before I merge it to "develop". I would really appreciate some feedback!


Among the changes:

- Improved documentation
- PulseAudio capture also supports resampling
- Added S24LE3 format (corresponds to Alsa S24_3LE)
- File capture device can skip a number of bytes at the beginning of a file and then read a limited number of bytes (it can read .wav directly if you know what you are doing)
- Alsa backend rewritten to reduce code duplication (easier to maintain, no functional changes)
- Improved debug output


I also published Rubato to crates.io: https://crates.io/crates/rubato
That means that the full documentation for it is now available here:rubato - Rust
 
I made a simple script to play wav-files directly through CamillaDSP. It's in the "testscripts" folder on branch "resampling".
It analyzes the wav header to extract sample format, and where in the wav file the audio data is stored. It then reads a template config file, and modifies the capture section to point it towards the given wav file. If the file has a different sample rate than the config file, then resampling is enabled.
Last step is that it connects to CamillaDSP via the websocket and uploads the config to make it start playing.


To use it, first start CamillaDSP with the socket server enabled and in "wait" mode:
Code:
camilladsp -p4321 -w
The run the python script to play a wav file:
Code:
python play_wav.py 4321 path/to/some/template/config.yml path/to/file.wav


This works because .wav is such a simple format, just a chunk of raw data with a short header to tell what it is.
 
Quick update. I have now merged the previous develop branch to master, and bumped it to version 0.0.14. The resampling branch has also been merged to develop.


So these are the branches to use now:
- master - v0.0.14 - without resampling support
- develop - v0.1.0 - the latest, with resampling support
 

TNT

Member
Joined 2003
Paid Member
Looking good indeed. Solid work. Attention to detail. Flexible developer, flexible software. Super audio performance. Tidy and orderly development. We love it and I bet this could be *the* new audio processing platform. Not only for the DIYers... Just to be sure - this is all in the public domain? - if so, a very generous gift to the planet. Thank you Henrik!

//
 
Looking good indeed. Solid work. Attention to detail. Flexible developer, flexible software. Super audio performance. Tidy and orderly development. We love it and I bet this could be *the* new audio processing platform. Not only for the DIYers... Just to be sure - this is all in the public domain? - if so, a very generous gift to the planet. Thank you Henrik!

//
Thank you for the nice words!
CamillaDSP is under the GPLv3 license. The license text is pretty long, but in short it's an open source license that allows anyone to use it. You are also allowed to modify it and distribute modified versions, as long as you keep the same license and also distribute the source code.
Summary from github:
Permissions of this strong copyleft license are conditioned on making available complete source code of licensed works and modifications, which include larger works using a licensed work, under the same license. Copyright and license notices must be preserved. Contributors provide an express grant of patent rights.
The Rubato library is instead under the MIT license. This is another open source license that is more permissive. You can basically include the library in projects with different licenses (even closed source). Summary from github:
A short and simple permissive license with conditions only requiring preservation of copyright and license notices. Licensed works, modifications, and larger works may be distributed under different terms and without source code.
 
Henrik.

I fully agree with TNT, this is very good work, thanks man!

At post no. 1 you post this :
..
.
IIR filters (BiQuad)
FIR filters (Convolution via FFT)
Filters can be chained freely
...
..
.

So it's possible to "Pre-EQ" with BiQuad created in e.g REW, and then afterwards make it run through FIR filter with one instance of camilla running.

Keep UP!

Jesper.