Yes of course, the numbers I gave didn't mean much without that little piece of information 🙂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! 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.Will the accuracy be user configurable?
//
It's possible to try it now!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 ...
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
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);
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 ...
Sinc lenght 64:
Time_64.png
Sinc lenght 512:
Time_512.png
Sinc lenght 65536 (near-perfect reference):
Time_64K.png
Very promising ...
Attachments
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
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
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.

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.
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.

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.. 🙂
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 🙂
Very nice indeed! Will the control have the same name, "PCM rate shift 100000"? If yes it should just work without any changes.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 🙂
Last edited by a moderator:
Very nice indeed! Will the control have the same name, "PCM rate shift 100000"? If yes it should just work without any changes.
When such control is added, IMO it would be unreasonable to name it differently, breaking compatibility with existing projects.
There is a typo in my previous post. In all the plots the resampling was done to 96kHz, not 48. Maybe some mod could help me to edit?
Here are some curves showing the high-frequency roll-off of the different presets. The y-scale is in dB.
Zoomed in:
View attachment 839070
Zoomed out:
View attachment 839071
How about ripple? Can you make the whole y-axis as shown, span 1 dB and focus on 1-25 khz?
DC filtering?
//
There is a typo in my previous post. In all the plots the resampling was done to 96kHz, not 48. Maybe some mod could help me to edit?

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
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:
The run the python script to play a wav file:
This works because .wav is such a simple format, just a chunk of raw data with a short header to tell what it is.
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
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
So these are the branches to use now:
- master - v0.0.14 - without resampling support
- develop - v0.1.0 - the latest, with resampling support
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!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!
//
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:
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: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.
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 :
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.
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.
- Home
- Source & Line
- PC Based
- CamillaDSP - Cross-platform IIR and FIR engine for crossovers, room correction etc