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

Multiplying biquad sets for different Fs seem to be a tedious work. Is there any chance of automation once say a set is done for 44,1? Maybe it's not possible within Camilla?

//

Code:
//Convert biquad coefficients for 44.1kHz to selected fs using BLT (won't work for tweaked 
//ones):

// z-plane to s-plane
d0 = b0 + b1 + b2;
d1 = 2.0 * (b0 - b2);
d2 = b0 - b1 + b2;
c0 = 1.0 + a1 + a2;
c1 = 2.0 * (1.0 - a2);
c2 = 1.0 - a1 + a2;

r = fs/44100; // scaling 

// s-plane to z-plane (BLT)
invc = 1.0/(c0 + r * (c1 + r * c2));
b0 = (d0 + r * (d1 + r * d2)) * invc;
b1 = 2.0 * (d0 - r^2 * d2) * invc;
b2 = (d0 - r*(d1 - r * d2)) * invc;
a1 = 2.0 * (c0 - r^2 * c2) * invc;
a2 = (c0 - r * (c1 - r * c2)) * invc;
 
Last edited:
Multiplying biquad sets for different Fs seem to be a tedious work. Is there any chance of automation once say a set is done for 44,1? Maybe it's not possible within Camilla?

//
If you can use the built in filter types, then the coefficient are calculated automatically for the active sample rate. If you can't, then is there maybe a filter type I'm missing? I't pretty simple to add more, as long as there are some equations to get the biquad coeffs.
 
Henrik, when you said before you can add as many filters as you like does that mean you can add one convolver filter after another or chained with PEQ or biquads inbetween?

I think this is what Jesper wants to do, run two convolution filters chained together one after the other
This is possible! You can add any filters you want, in any order you want.

So yes you could have a pipeline consisting of a FIR prefilter, then some BiQuads, followed by another FIR, and at the end some final tweaking with more BiQuads.

You can also mix filtering and mixer steps freely.
 
This is possible! You can add any filters you want, in any order you want.

So yes you could have a pipeline consisting of a FIR prefilter, then some BiQuads, followed by another FIR, and at the end some final tweaking with more BiQuads.

You can also mix filtering and mixer steps freely.

:yes: ... Henrik it's perfect...

I will try this out very soon; i didn't think it was possible to have more than one pair of fir's (i don't know why i was thinking that ?), that's the reason i was using BiQuads as prefilter, but it's more easy for me to make fir's for that!

fluid is along with others a very big help for me in my learning progress about DSP, everyone is so helpfull at these forum's, thanks all :grouphug:

Ohh something Henrik, i was told that a lot of convolvers do have some "normalize" function, is it something worth consider as a future option perhaps?

I did come a very long way now. I now have a functional streamer/player, which is capable of switching .yml filters (switching samplerates from 44100 to 192000) on the fly through the websocket and my hacked squeezelite player.

Jesper.
 
Ohh something Henrik, i was told that a lot of convolvers do have some "normalize" function, is it something worth consider as a future option perhaps?

I did come a very long way now. I now have a functional streamer/player, which is capable of switching .yml filters (switching samplerates from 44100 to 192000) on the fly through the websocket and my hacked squeezelite player.

Jesper.
I think that (and please correct me if I'm wrong) normalization is used for reverb filters and such, when you don't want the loudness to change when you enable/disable a filter. I don't think this is very useful here, feels like there is a very big risk of causing lots of clipping. But sure, if someone brings a good argument to include it I'll consider it :)

Really neat that you got the rate switching working. Bra jobbat / godt arbejde!! I think this could be interesting for many people.
Did you get any feeling for if your changes to squeezelite have any chance of becoming standard features?
 
Jriver has it in it's convolution engine and it allows to not be concerned over the level of the impulse filter being too low or too high, so it actually prevents clipping in their implementation.

Jrivers use is targeted at speaker tuning not reverb. I find it very useful :)

attachment.php
 

Attachments

  • Jriver Conv.jpg
    Jriver Conv.jpg
    48.6 KB · Views: 1,062
WARNING off topic, sry.

Really neat that you got the rate switching working. Bra jobbat / godt arbejde!! I think this could be interesting for many people.
Did you get any feeling for if your changes to squeezelite have any chance of becoming standard features?

Allright, my "hack" is working eventhrough the start parameters on squeezelite has to be tweaked for it to do "clicks and pops" as little as possible when samplerate is switching :)

I was looking in the sourcecode for squeezelite and it tells me i can do whatever i like so i put my work here for someone else to try it, and perhaps modify it to be right! (My hack is not coded the right way, but it's just working for me :eek:)

Code:
 *  Squeezelite - lightweight headless squeezebox emulator
 *
 *  (c) Adrian Smith 2012-2015, [email]triode1@btinternet.com[/email]
 *      Ralph Irving 2015-2017, [email]ralph_irving@hotmail.com[/email]
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Additions (c) Paul Hermann, 2015-2017 under the same license terms
 *   -Control of Raspberry pi GPIO for amplifier power
 *   -Launch script on power status change from LMS

The version i was compiling is Squeezelite v1.9.7-1218
I changed some in output_alsa.c, and set the Makefile.rpi so that it would compile proberly.

Code:
	/*
	*	CamillaDSP engine integration START
	*/

	LOG_INFO("Player detected sample rate change ! %u", sample_rate);

	UNLOCK;

	if(sample_rate == 44100) system("python3 /home/tc/DSP_Engine/filters/exec_44100.py");
        if(sample_rate == 96000) system("python3 /home/tc/DSP_Engine/filters/exec_96000.py");
	if(sample_rate == 48000) system("python3 /home/tc/DSP_Engine/filters/exec_48000.py");
	if(sample_rate == 88200) system("python3 /home/tc/DSP_Engine/filters/exec_88200.py");
	if(sample_rate == 176400) system("python3 /home/tc/DSP_Engine/filters/exec_176400.py");
	if(sample_rate == 192000) system("python3 /home/tc/DSP_Engine/filters/exec_192000.py");
	if(sample_rate == 352800) system("python3 /home/tc/DSP_Engine/filters/exec_352800.py");
	if(sample_rate == 384000) system("python3 /home/tc/DSP_Engine/filters/exec_384000.py");


	LOG_INFO("Sample rate filter changed ! %u", sample_rate);

	/*
	*	CamillaDSP engine integration STOP
	*/

And close to the end i also changed the "dual" opening of alsa, i just put in an "!" in the code.
Code:
			// FIXME - some alsa hardware requires opening twice for a new sample rate to work
			// this is a workaround which should be removed
			if (!alsa.reopen) {
#if DSD
				alsa_open(output.device, output.current_sample_rate, output.buffer, output.period, output.outfmt);
#else
				alsa_open(output.device, output.current_sample_rate, output.buffer, output.period);
#endif
			}

The OS distribution i use is piCoreplayer on my RPI4, and python 3 has to be installed for it to work. The piCoreplayer is based on TinyCore Linux, which load everything in RAM at boot; so plugging the wallswitch when it's running don't harm anything because the SD card is not used after booting is done!!!.

I attached the files here i use, including the compiled squeezelite which runs on RPI4.

I will make a post at the slimserver forum, where squeezelite/piCoreplayer lives and link to this post.
LINK is here :: Digital signal processing is possible with piCoreplayer & squeezelite

Please feel free to delete/remove or burn whatever this post :)

Jesper.
 

Attachments

  • Hacked_squeezelite.zip
    74.3 KB · Views: 74
Last edited:
Jesper, please would you consider forking the squeezelite repo on github GitHub - ralph-irving/squeezelite: Lightweight headless squeezebox player for Logitech Media Server and pushing your patch? That way everyone could use it easily and see the changes. Thanks for considering.

Thanks Phofman, i know but my code is not right at all for this. -Therefore i linked my post here to slimserver forum where a lot of coders live; hoping that someone there would do it the right way; sry.. i'am not capable of coding it the right way.

Hope you understand.

Jesper.
 
According to the Jriver wiki you are right, that is not what I thought it did at all :eek:

Seem's to cure my "problem" :)

With none gain corrected filter :

2020-05-24T06:57:07Z WARN camilladsp::conversions] Clipping detected, 100 samples clipped, peak 136.72538361247942%
[2020-05-24T06:57:07Z DEBUG camilladsp::alsadevice] Current buffer level 2018, set capture rate to 99.993744%
[2020-05-24T06:57:07Z DEBUG camilladsp] SetSpeed message reveiced
[2020-05-24T06:57:07Z WARN camilladsp::conversions] Clipping detected, 32 samples clipped, peak 122.46925747955886%
[2020-05-24T06:57:07Z WARN camilladsp::conversions] Clipping detected, 1 samples clipped, peak 100.63506757672964%
[2020-05-24T06:57:08Z WARN camilladsp::conversions] Clipping detected, 13 samples clipped, peak 114.16722247695161%

Adding this to pipeline cured the clipping :

clipgain_L:
type: Gain
parameters:
gain: -6.0
inverted: false

clipgain_R:
type: Gain
parameters:
gain: -6.0
inverted: false

No clipping anymore :

2020-05-24T06:59:32Z DEBUG camilladsp::alsadevice] Current buffer level 2034, set capture rate to 99.997086%
[2020-05-24T06:59:32Z DEBUG camilladsp] SetSpeed message reveiced
[2020-05-24T06:59:37Z DEBUG camilladsp::alsadevice] Current buffer level 2047, set capture rate to 99.999794%
[2020-05-24T06:59:37Z DEBUG camilladsp] SetSpeed message reveiced
[2020-05-24T06:59:42Z DEBUG camilladsp::alsadevice] Current buffer level 2026, set capture rate to 99.995415%

Jesper.
 
Hello..

I'am running CamillaDSP 0.0.13 on my laptop for some test's now.
(Same issues on my RPI's)

I recently discovered that when i run .bin files in my pipeline the filter are working.
(generated in rePhase)
L_prefir:
type: Conv
parameters:
type: File
filename: /home/lykke/home/Pre_filter/44100/L_red_RP_44100.bin
format: FLOAT32LE

R_prefir:
type: Conv
parameters:
type: File
filename: /home/lykke/home/Pre_filter/44100/R_red_RP_44100.bin
format: FLOAT32LE
But when i run the same files, but in .wav (also generated in rePhase) i got this error:
Code:
lykke@Lykkedk:~/home$ camilladsp -v /home/lykke/home/test_Red_44100.yml
[2020-05-27T19:36:43Z DEBUG camilladsp] Read config file Some("/home/lykke/home/test_Red_44100.yml")
[2020-05-27T19:36:43Z DEBUG camilladsp::filters] Read file: /home/lykke/home/Pre_filter/44100/L_red_RP_44100.wav, number of coeffs: 16433
[2020-05-27T19:36:43Z DEBUG camilladsp::filters] Read file: /home/lykke/home/Pre_filter/44100/R_red_RP_44100.wav, number of coeffs: 16433
[2020-05-27T19:36:43Z DEBUG camilladsp] Config is valid
[2020-05-27T19:36:43Z DEBUG camilladsp] Wait for config
[2020-05-27T19:36:43Z DEBUG camilladsp] Config ready
[2020-05-27T19:36:43Z DEBUG camilladsp::filters] Build new pipeline
[2020-05-27T19:36:43Z DEBUG camilladsp::filters] Build from config
[2020-05-27T19:36:43Z DEBUG camilladsp::filters] Read file: /home/lykke/home/Pre_filter/44100/L_red_RP_44100.wav, number of coeffs: 16433
[2020-05-27T19:36:43Z DEBUG camilladsp::alsadevice] Opened audio output "camilla_in" with parameters: HwParams { channels: Ok(2), rate: "Ok(44100) Hz", format: Ok(S16LE), access: Ok(RWInterleaved), period_size: "Ok(512) frames", buffer_size: "Ok(8192) frames" }, SwParams(avail_min: Ok(512) frames, start_threshold: Ok(3584) frames, stop_threshold: Ok(8192) frames)
[2020-05-27T19:36:43Z DEBUG camilladsp] Capture thread ready to start
[2020-05-27T19:36:43Z DEBUG camilladsp::alsadevice] Opened audio output "sound_out" with parameters: HwParams { channels: Ok(2), rate: "Ok(44100) Hz", format: Ok(S16LE), access: Ok(RWInterleaved), period_size: "Ok(512) frames", buffer_size: "Ok(8192) frames" }, SwParams(avail_min: Ok(512) frames, start_threshold: Ok(3584) frames, stop_threshold: Ok(8192) frames)
[2020-05-27T19:36:43Z DEBUG camilladsp] Playback thread ready to start
[2020-05-27T19:36:44Z DEBUG camilladsp::fftconv_fftw] Conv L_prefir is using 5 segments
[2020-05-27T19:36:44Z DEBUG camilladsp::filters] Build from config
[2020-05-27T19:36:44Z DEBUG camilladsp::filters] Read file: /home/lykke/home/Pre_filter/44100/R_red_RP_44100.wav, number of coeffs: 16433
[2020-05-27T19:36:44Z DEBUG camilladsp::fftconv_fftw] Conv R_prefir is using 5 segments
[2020-05-27T19:36:44Z DEBUG camilladsp::filters] Build from config
[2020-05-27T19:36:44Z DEBUG camilladsp::filters] Build from config
[2020-05-27T19:36:44Z DEBUG camilladsp::processing] build filters, waiting to start processing loop
[2020-05-27T19:36:44Z DEBUG camilladsp::alsadevice] Starting playback loop
[2020-05-27T19:36:44Z DEBUG camilladsp::alsadevice] Starting captureloop
[2020-05-27T19:36:44Z INFO  camilladsp::alsadevice] Capture device supports rate adjust
[2020-05-27T19:36:44Z DEBUG camilladsp::conversions] bad float NaN
[2020-05-27T19:36:44Z DEBUG camilladsp::conversions] bad float NaN
[2020-05-27T19:36:44Z DEBUG camilladsp::conversions] bad float NaN
[2020-05-27T19:36:44Z DEBUG camilladsp::conversions] bad float NaN
[2020-05-27T19:36:44Z DEBUG camilladsp::conversions] bad float NaN

Strangewavs

I have no clue what's wrong with the .wav's ?
I tried everything with no luck, i think i am doing something wrong?

Does anyone care to look at them .wav's ?

Jesper.
 
Wav format is not supported for filter coefficents! Use raw format (.bin or .dbl) instead. There is most likely nothing wrong with the wav files themselves, but it's not supposed to work :).


I have been thinking about adding support for wav, but I'm leaning towards not doing it. To make it work reliably I need to parse the header properly. The data can be in many different formats, and there is often more tags with metadata after the fixed 44-byte header. Just skipping the first 44 bytes will only work sometimes.
 
Wav format is not supported for filter coefficents! Use raw format (.bin or .dbl) instead. There is most likely nothing wrong with the wav files themselves, but it's not supposed to work :).


I have been thinking about adding support for wav, but I'm leaning towards not doing it. To make it work reliably I need to parse the header properly. The data can be in many different formats, and there is often more tags with metadata after the fixed 44-byte header. Just skipping the first 44 bytes will only work sometimes.

Yep...:) ... I got it Henrik! :D
I learned a lot about converting stuff with this "issue"
It's like that when one invents it's own problems :)

Jesper.
 
CamillaDSP on Rasperry 3B+

Hello, Rasperians,
I have now installed CamillaDSP on a Raspberry 3b+. My configuration is as follows: Hifiberry DigiIO+ HAT for the digital input and as output the HDMI output of the Raspi. I only use FIR filters, which I create with the software ((acourate)) from audiovero. For my 2 way Ripol speakers the crossover and correction is done (2 to 4 channel). Here the Camilla messages:
Code:
pi@musicpi:~ $ /home/pi/.cargo/bin/camilladsp -v /home/pi/2fir4.yaml 
[2020-06-07T16:13:22Z DEBUG camilladsp] Read config file Some("/home/pi/2fir4.yaml")
[2020-06-07T16:13:22Z DEBUG camilladsp::filters] Read file: /media/pi/BRUTEFIR21/filter/UB/Cor1L48.dbl, number of coeffs: 65536
[2020-06-07T16:13:22Z DEBUG camilladsp::filters] Read file: /media/pi/BRUTEFIR21/filter/UB/Cor2L48.dbl, number of coeffs: 65536
[2020-06-07T16:13:22Z DEBUG camilladsp::filters] Read file: /media/pi/BRUTEFIR21/filter/UB/Cor1R48.dbl, number of coeffs: 65536
[2020-06-07T16:13:22Z DEBUG camilladsp::filters] Read file: /media/pi/BRUTEFIR21/filter/UB/Cor2R48.dbl, number of coeffs: 65536
[2020-06-07T16:13:22Z DEBUG camilladsp] Config is valid
[2020-06-07T16:13:22Z DEBUG camilladsp] Wait for config
[2020-06-07T16:13:22Z DEBUG camilladsp] Config ready
[2020-06-07T16:13:22Z DEBUG camilladsp::filters] Build new pipeline
[2020-06-07T16:13:22Z DEBUG camilladsp::filters] Build from config
[2020-06-07T16:13:22Z DEBUG camilladsp::filters] Read file: /media/pi/BRUTEFIR21/filter/UB/Cor1L48.dbl, number of coeffs: 65536
[2020-06-07T16:13:22Z DEBUG camilladsp::alsadevice] Opened audio output "hw:1,1" with parameters: HwParams { channels: Ok(4), rate: "Ok(48000) Hz", format: Ok(S16LE), access: Ok(RWInterleaved), period_size: "Ok(960) frames", buffer_size: "Ok(15360) frames" }, SwParams(avail_min: Ok(960) frames, start_threshold: Ok(6720) frames, stop_threshold: Ok(15360) frames)
[2020-06-07T16:13:22Z DEBUG camilladsp] Playback thread ready to start
[2020-06-07T16:13:22Z DEBUG camilladsp::alsadevice] Opened audio output "hw:2,0" with parameters: HwParams { channels: Ok(2), rate: "Ok(48000) Hz", format: Ok(S16LE), access: Ok(RWInterleaved), period_size: "Ok(960) frames", buffer_size: "Ok(15360) frames" }, SwParams(avail_min: Ok(960) frames, start_threshold: Ok(6720) frames, stop_threshold: Ok(15360) frames)
[2020-06-07T16:13:22Z DEBUG camilladsp] Capture thread ready to start
[2020-06-07T16:13:23Z DEBUG camilladsp::fftconv_fftw] Conv left_low is using 9 segments
[2020-06-07T16:13:23Z DEBUG camilladsp::filters] Build from config
[2020-06-07T16:13:23Z DEBUG camilladsp::filters] Read file: /media/pi/BRUTEFIR21/filter/UB/Cor2L48.dbl, number of coeffs: 65536
[2020-06-07T16:13:23Z DEBUG camilladsp::fftconv_fftw] Conv left_high is using 9 segments
[2020-06-07T16:13:23Z DEBUG camilladsp::filters] Build from config
[2020-06-07T16:13:23Z DEBUG camilladsp::filters] Read file: /media/pi/BRUTEFIR21/filter/UB/Cor1R48.dbl, number of coeffs: 65536
[2020-06-07T16:13:23Z DEBUG camilladsp::fftconv_fftw] Conv right_low is using 9 segments
[2020-06-07T16:13:23Z DEBUG camilladsp::filters] Build from config
[2020-06-07T16:13:23Z DEBUG camilladsp::filters] Read file: /media/pi/BRUTEFIR21/filter/UB/Cor2R48.dbl, number of coeffs: 65536
[2020-06-07T16:13:23Z DEBUG camilladsp::fftconv_fftw] Conv right_high is using 9 segments
[2020-06-07T16:13:23Z DEBUG camilladsp::processing] build filters, waiting to start processing loop
[2020-06-07T16:13:23Z DEBUG camilladsp::alsadevice] Starting playback loop
[2020-06-07T16:13:23Z DEBUG camilladsp::alsadevice] Starting captureloop
[2020-06-07T16:13:24Z WARN  camilladsp::alsadevice] Prepare playback


This is going very well without any dropouts or crackles :D . The CPU load is about 6%.

If I output eight channels it also runs very well, but the following messages are displayed, which don't appear with four channels.

Code:
[2020-06-07T15:42:28Z DEBUG camilladsp::alsadevice] Current buffer level 2536, set capture rate to 100.12709%
[2020-06-07T15:42:28Z DEBUG camilladsp] SetSpeed message reveiced
[2020-06-07T15:42:32Z DEBUG camilladsp::alsadevice] Current buffer level 2534, set capture rate to 100.126564%
[2020-06-07T15:42:32Z DEBUG camilladsp] SetSpeed message reveiced
[2020-06-07T15:42:36Z DEBUG camilladsp::alsadevice] Current buffer level 2530, set capture rate to 100.12552%
[2020-06-07T15:42:36Z DEBUG camilladsp] SetSpeed message reveiced
[2020-06-07T15:42:40Z DEBUG camilladsp::alsadevice] Current buffer level 2481, set capture rate to 100.11276%
[2020-06-07T15:42:40Z DEBUG camilladsp] SetSpeed message reveiced
........
As multichannelDAC and amplifier I use a Pioneer AV 5.1 receiver, or the HDMI DAC Envolve II 4K and a four/eight channel power amp. If the AV receiver cannot handle LPCM, the Alsa A52 plugin allows AC3 encoding up to 5.1 but this is only enough for up to four channels, as the .x channels can only be used as sub output.

Roland
 
...

Code:
	/*
	*	CamillaDSP engine integration START
	*/

	LOG_INFO("Player detected sample rate change ! %u", sample_rate);

	UNLOCK;

	if(sample_rate == 44100) system("python3 /home/tc/DSP_Engine/filters/exec_44100.py");
        if(sample_rate == 96000) system("python3 /home/tc/DSP_Engine/filters/exec_96000.py");
	if(sample_rate == 48000) system("python3 /home/tc/DSP_Engine/filters/exec_48000.py");
	if(sample_rate == 88200) system("python3 /home/tc/DSP_Engine/filters/exec_88200.py");
	if(sample_rate == 176400) system("python3 /home/tc/DSP_Engine/filters/exec_176400.py");
	if(sample_rate == 192000) system("python3 /home/tc/DSP_Engine/filters/exec_192000.py");
	if(sample_rate == 352800) system("python3 /home/tc/DSP_Engine/filters/exec_352800.py");
	if(sample_rate == 384000) system("python3 /home/tc/DSP_Engine/filters/exec_384000.py");


	LOG_INFO("Sample rate filter changed ! %u", sample_rate);

	/*
	*	CamillaDSP engine integration STOP
	*/

...

In case of static filters, one could also make one IIR filter with coefficients suitable for all those common sample rates. Here's an example (Linkwitz-Riley Crossfeed using 1st order filters):

Code:
function [b, a] = LinkwiztRileyCrossfeed_HSF1(x)
b(1) = 8.92486106577848E-39*x^7 - 1.23294609205113E-32*x^6 + 6.90481427610453E-27*x^5 - 2.03708367949616E-21*x^4 + 3.45581026357451E-16*x^3 - 3.44913669956660E-11*x^2 + 4.56707825960187E-04*x + 1.06218214714401E+00;
b(2) = -8.92486106186911E-39*x^7 + 1.23294609153202E-32*x^6 - 6.90481427335710E-27*x^5 + 2.03708367874968E-21*x^4 - 3.45581026245418E-16*x^3 + 3.44913669864111E-11*x^2- 4.56707825959798E-04*x + 1.18185476145362E+00;
a(1) = 1.12357343915144E-38*x^7 - 1.55218716653502E-32*x^6 + 8.69264615528866E-27*x^5 - 2.56453640990810E-21*x^4 + 4.35060735892690E-16*x^3 - 4.34220583966637E-11*x^2+ 5.74961087866485E-04*x + 1.04668900667368E+00;
a(2) = -1.12357343917162E-38*x^7 + 1.55218716656155E-32*x^6 - 8.69264615542657E-27*x^5+ 2.56453640994445E-21*x^4 - 4.35060735897871E-16*x^3 + 4.34220583970547E-11*x^2 - 5.74961087866498E-04*x + 1.19734790193039E+00;

Code:
function [b, a] = LinkwiztRileyCrossfeed_LPF1(x)
b(1) = -3.73347936059962E-38*x^7 + 5.15879461936065E-32*x^6 - 2.88994018251960E-26*x^5 + 8.52985718947504E-21*x^4 - 1.44803393019973E-15*x^3 + 1.44677547605219E-10*x^2 - 8.31737045233532E-06*x + 2.52213714392960E-01;
b(2) = -3.73347936059962E-38*x^7 + 5.15879461936065E-32*x^6 - 2.88994018251960E-26*x^5+ 8.52985718947504E-21*x^4 - 1.44803393019973E-15*x^3 + 1.44677547605219E-10*x^2 - 8.31737045233532E-06*x + 2.52213714392960E-01;
a(1) = -4.32331264486865E-38*x^7 + 5.98574666256680E-32*x^6 - 3.36300126624330E-26*x^5+ 9.96980705947461E-21*x^4 - 1.70404536083758E-15*x^3 + 1.72154874571558E-10*x^2 - 1.00923085954559E-05*x + 2.31848477835107E+00;
a(2) = -6.23656164833149E-38*x^7 + 8.60552796982759E-32*x^6 - 4.81098393488902E-26*x^5+ 1.41562723854473E-20*x^4 - 2.39161308489201E-15*x^3 + 2.37055025416788E-10*x^2 - 1.34327675984916E-05*x - 1.60511666732906E+00;

where x = sample rate (fs).
Above polynomials returns exact (R^2=1) coefficients but, if the accuracy isn't important, most of those (above) original coefficients for each sample rate can be restored by using simple linear interpolation (a*x+c) with R^2 = ~ 0.99999999. NOTE, you may need to swap a and b coefficients to get proper response!
 
Last edited:
Hi rolli!
Thank you very much for the feedback!
Nice to see that using hdmi and an AV receiver works well. I think this is the most convenient way to set up an active crossover, with a reliable multi-channel volume control.

The debug output with current buffer level/ SetSpeed look perfectly normal. They just mean that it's adjusting the speed of the loopback device to keep capture and playback in sync. It's a bit strange that you don't get them with 4 channels. Are all the other settings the same?

What do you use for volume control with the Evolve DAC?
 
When I'm anyway here I can give a little update on what I'm up to since I haven't written anything in a while. The next version will have a much faster resampler. The asynchronous mode will be about a factor 2-3 faster, compared to the version in the develop branch. This is from optimizing the code.

For synchronous resampling the difference is even larger. I'm working on a "proper" synchronous resampler using FFT. This gives the same quality but is more efficient. Compared to develop, my very preliminary test version is almost a factor 10 faster. This turned out to take much longer than I expected, partly because I ended up on various side tracks. I tried a different FFT library (also written in Rust) that was supposed to be faster but turned out to be much slower in some cases. I also implemented the algorithm from this TI application report to speed up processing: http://www.ti.com/lit/an/spra291/spra291.pdf?ts=1591555286316
I got it working in the end, but there are typos in a few of the important equations that made it much more difficult than it should have been. I reported this to TI, but they think the report is too old and most likely they won't fix it.