Pulseaudio Crossover Rack - multi-way crossover design & implementation with linux

A smartphone app would be great. The Marantz smartphone app for Audyssey caught my attention, but it doesn't work with my Marantz model.

I guess the app would need to be able to access and modify the configuration files of paxoverrack.

Well, there are two different approaches here:

a) build the filter structure in the main GUI and have an app that can change parameters.
b) make the app do everything the GUI can now do, including building the filter chain.

a) is relatively easy to do, just a bunch of sliders and text input fields and a very simple REST API for querying available parameters and sending back changed values.

b) is a totally different beast and will be very challenging, especially if you want to have the kind of UI quality I provided with the existing UI (which I'm quite proud of to be honest).

A lot of thinking a programming time has to be spent on good UI/UX design! That said, I will probably never code up an app for this. It's just too much hasssle. And there's the people who then want to have a f**cking iOS app too, not understanding that this doubles the amount of work again... All in all not likely to happen at all.

But: Why not use vnc or remote desktop for this? I use x11vnc to serve the desktop of my HTPC, even on a oneplus one with its 5.5" screen I can use it pretty comfortably to change parameters of filters on the fly. And you have to ask yourself how often you might want to do that... If the filters are set up correctly you will probably never touch them again.

So, if someone wants to give it a try to come up with an app I will give them my advice and help, especially with regards to implementing a remote control API, but don't expect the app to be delivered by me.
 
1) I think it is Raspbian Stretch
2) I used your Repo in the second try
3) You will need a HDMI 7.1 Pulseaudio config, I do not think that this is automatically generated.

For me this was just a Test. I think your Software is fantastic for people who need a graphical Playground. My Brutefir Convolver is running headless with a Hifiberry digi I/O as Input and 4 Channel Output on HDMI straight into my AVR.

Brutefir is doing roomcorrection and crossover for my FAST system.

I can change roomcorrection Filters with LIRC, the Crossover section is allways the same.

OK, maybe this would be interesting for others then: On linux mint MATE i can use the mate-colume-control application to change the output config for the soundcards, i.e. stereo/2.1/4.1/5.1 etc... maybe pavucontrol can do the same on Raspbian? Would be interesting to know but I have no means of testing this here (don't have a RPi, don't have a TV that announces multichannel for HDMI nor a HDMI extractor card). If someone wants to sponsor one of each to improve development for RPi, feel free... :D:D:D
 
Member
Joined 2008
Paid Member
My 3D printer guy had some problems with head hitting the print, first one around half abd second one at 80 %. He printed and glued the rest, did some filling and sanding and here is the result. The second one will be printed in two pieces from the beginning.
 

Attachments

  • AF907618-C931-4EC6-B2CD-1581029D95A8.jpeg
    AF907618-C931-4EC6-B2CD-1581029D95A8.jpeg
    133.6 KB · Views: 150
Please don't take this as an insult, but the most challenging aspect there sounds like finding a DAC supporting 16 output channels :)

A pro-model of some sort?

I just thought I would comment that a solution that can deliver 16 output channels is to pair a pro-audio audio interface with 8 analog output with an ADAT ADDA unit. For example: Presonus 1818vsl plus Behringer ADA8200.
 
That sounds more plausible. I have seen other programs storing IR coefficients as *.wav files. Why not simply text files?
I don't see any advantage to using *.wav over text, other than file-size, and that is a complete non sequitur for this domain.

That one is simple to answer: there are ready made C libraries for reading wav files into float arrays, not so much for text files. So I will use wav files.

What happens on the GUI side where the user can load impulse responses is a completely different thing.
a) python can much more easily parse text files.
b) I will have to store the IR in the .paxor file anyways to be able to extract phase and amplitude response for displaying etc.
c) I will have to double check that the IR fits certain criteria (IR length, format correct etc.) - all the things you would expect from a modern GUI program that is intended to be used by end users...

It's a series of significant leaps, conceptually, from simple convolution, to streaming overlap-add/overlap-save, to streaming partitioned convolution. But, you will need FFTW at each step along way (unless you plan on starting with convolution in the time domain).

The FFTW wisdom files are something I would consider dead last, if at all.

Actually I do plan to implement convolution in the time domain first. If I read the brutefir code correctly and if I remember correctly brutefir has the same fallback convolution algorithms implemented. Taking it one step at a time has always proven to be very useful when developing something completely from scratch, as I will probably have to do here...

Of course FFTW wisdom files should be the least concern, but in the end the "magic" of a good UX has to deal with such seemingly unimportant details.

That said, where can I have a look at your FIR algorithms? Still willing to share the code? And of course willing to re-release parts of it under the BSD three clause licence?

To be fair, LADPSA is the only choice if you want to make use of the various IIR libraries floating around and integrate with Pulseaudio.

I never used any of the filtering libraries "floating around" because for real time parametrization I needed a shared memory API anyway, so all of my LADSPA plugins were developed according the audio eq cookbook and the 3rd order filter formulas were developed "by hand" with a bit of sweat and on the other hand a lot of things learned. :D
 
Well, there are two different approaches here:

a) build the filter structure in the main GUI and have an app that can change parameters.
b) make the app do everything the GUI can now do, including building the filter chain.

a) is relatively easy to do, just a bunch of sliders and text input fields and a very simple REST API for querying available parameters and sending back changed values.

b) is a totally different beast and will be very challenging, especially if you want to have the kind of UI quality I provided with the existing UI (which I'm quite proud of to be honest).

A lot of thinking a programming time has to be spent on good UI/UX design! That said, I will probably never code up an app for this. It's just too much hasssle. And there's the people who then want to have a f**cking iOS app too, not understanding that this doubles the amount of work again... All in all not likely to happen at all.

But: Why not use vnc or remote desktop for this? I use x11vnc to serve the desktop of my HTPC, even on a oneplus one with its 5.5" screen I can use it pretty comfortably to change parameters of filters on the fly. And you have to ask yourself how often you might want to do that... If the filters are set up correctly you will probably never touch them again.

So, if someone wants to give it a try to come up with an app I will give them my advice and help, especially with regards to implementing a remote control API, but don't expect the app to be delivered by me.

This is one reason why I eschewed a GUI interface for text files for all settings my own audio DSP processing application. That way any device on the LAN that can SSH into the box running the DSP can change any setting on demand. Easy-peasey. Well, the other reason is I have no clue how to do build a GUI interface! Have to admit that one, I guess...
 
This is one reason why I eschewed a GUI interface for text files for all settings my own audio DSP processing application. That way any device on the LAN that can SSH into the box running the DSP can change any setting on demand. Easy-peasey. Well, the other reason is I have no clue how to do build a GUI interface! Have to admit that one, I guess...

Easy-peasy... Many people will disagree. :)

A GUI is more or less a separate thing from the underlying software. If you would add a GUI to your dsp stuff, you would still be able to SSH as you do now.
 
Easy-peasy... Many people will disagree. :)

A GUI is more or less a separate thing from the underlying software. If you would add a GUI to your dsp stuff, you would still be able to SSH as you do now.

Actually you couldn't be more correct. In the end the only thing that is left behind by pulseaudio-crossover-rack is one config file with all the filters and their config (~/.config/default.pa). Easy to change with a text editor if you really wanted to.

But of course the GUI provides so much more. And even being some kind of hacker myself, I would not want to build a three way active crossover with delays, EQs etc in a text file. Way too much room for simple mistakes. That's why I wanted a GUI for myself and hence I built one.

BTW: This is one of the additional reasons I want to encapsulate FIR filters into a LADSPA plugin: You then don't need any convolution engine like brutefir running in the background, everything can be spun up by pulseaudio itself from that one text config file. Which IMHO is very important, you wouldn't want to start the GUI and load your crossover setup each time after a reboot, would you?
 
That one is simple to answer: there are ready made C libraries for reading wav files into float arrays, not so much for text files. So I will use wav files.

Nothing for handling text files? You've looked at the libc api before right ;)?

Maybe it's personal preference, but I would prefer to code something so simple myself, rather than maintain a dependency just for that. But, to each their own.

Actually I do plan to implement convolution in the time domain first. If I read the brutefir code correctly and if I remember correctly brutefir has the same fallback convolution algorithms implemented. Taking it one step at a time has always proven to be very useful when developing something completely from scratch, as I will probably have to do here...

BruteFIR (or any other conv engine) would quickly fall on its face trying to do any serious convolution in the time-domain - the efficiency crossover point for direct vs spectral convolution happens for quite small block sizes (~32 points, IIRC). I understand this aspect is strictly for learning, but still...

That said, where can I have a look at your FIR algorithms? Still willing to share the code? And of course willing to re-release parts of it under the BSD three clause licence?

As I said, happy to share things when it's comfortable for me to do so.
No idea about licensing yet, but yes, BSD, LGPL, or MIT seem apropos.

As for my "FIR algorithms", I don't understand what you're referring to. My software does not provide filter synthesis tools.

If you're asking about convolution algorithms, there is a lot of material available on overlap-add and partitioned convolution techniques. I could provide some links for that sort of thing if you're interested.

I never used any of the filtering libraries "floating around" because for real time parametrization I needed a shared memory API anyway, so all of my LADSPA plugins were developed according the audio eq cookbook and the 3rd order filter formulas were developed "by hand" with a bit of sweat and on the other hand a lot of things learned. :D

That's fair.
 
BruteFIR (or any other conv engine) would quickly fall on its face trying to do any serious convolution in the time-domain - the efficiency crossover point for direct vs spectral convolution happens for quite small block sizes (~32 points, IIRC). I understand this aspect is strictly for learning, but still...

OK, I understand - not worth the effort. Well, if I could I would just use convolver algorithm xyz... N samples in + Impulse response in -> N samples out. But I did a lot of research now and can't seem to find anything ready made that I could just wrap in a LADSPA plugin and just do the "housekeeping" like loading IRs from file etc.

As I said, happy to share things when it's comfortable for me to do so.
No idea about licensing yet, but yes, BSD, LGPL, or MIT seem apropos.

As for my "FIR algorithms", I don't understand what you're referring to. My software does not provide filter synthesis tools.

If you're asking about convolution algorithms, there is a lot of material available on overlap-add and partitioned convolution techniques. I could provide some links for that sort of thing if you're interested.

I meant the convolution algorithms. Well, by the time you feel comfortable sharing, please do so. You can always drop me a PM if you don't want to make your code public just yet, I feel I always learn better from real world examples and code. That said, please also point me to the material you're talking about... Thanks!
 
Well, there are two different approaches here:

a) build the filter structure in the main GUI and have an app that can change parameters.
b) make the app do everything the GUI can now do, including building the filter chain.

a) is relatively easy to do, just a bunch of sliders and text input fields and a very simple REST API for querying available parameters and sending back changed values.

b) is a totally different beast and will be very challenging, especially if you want to have the kind of UI quality I provided with the existing UI (which I'm quite proud of to be honest).

A lot of thinking a programming time has to be spent on good UI/UX design! That said, I will probably never code up an app for this. It's just too much hasssle. And there's the people who then want to have a f**cking iOS app too, not understanding that this doubles the amount of work again... All in all not likely to happen at all.

But: Why not use vnc or remote desktop for this? I use x11vnc to serve the desktop of my HTPC, even on a oneplus one with its 5.5" screen I can use it pretty comfortably to change parameters of filters on the fly. And you have to ask yourself how often you might want to do that... If the filters are set up correctly you will probably never touch them again.

So, if someone wants to give it a try to come up with an app I will give them my advice and help, especially with regards to implementing a remote control API, but don't expect the app to be delivered by me.
I understand the frustration, so here is another idea.

Why don't you use it with some kind of simple webserver or direct http requests (than a server isn't even really needed)?
I used this many times in escape room solutions with RaspB Pies.
That way you only have to develop a simple web page with some sliders/knobs and you're already basically done.
 
Well, if it's so simple - why don't you do it? ;)

To be clear: to serve HTTP request, you always need some kind of server. This requirement is not hard to fulfill, there's even a threaded http server class in python 3.7. But you have to define signals and slots in QT for all the http server callbacks because you are not allowed to block the QT main thread and also not allowed to access QT member data from outside the QT main thread. That's the backend side.

On the frontend side you need a fair bit of (JS/jquery/whatever) code for the UI to be interactive, you need AJAX callbacks to the http server etc. Not to mention that it should be modern, responsive UI design using bootstrap or similar to be useable with any device. The more I think of it, I would probably break the server for the frontend side of things out into maybe a pyramid project because then routing the requests is way more structured. Setting up a pyramid stack also takes time though.

All in all for just the parameter changing version I would predict somewhere around 20-30 hours at least. Most of times you simply double expected man hours to be somewhat near realistic :D And I was only talking about the "slim version" which cannot modify the signal routing of the crossover, i.e. delete/insert/connect filters. That would add a completely new level of complexity and thus man hours!

There's simply too much else going on in the background which I deem way more important ATM (measurement support is still cooking - more on that probably soon, and recently FIR support has made it at least into the serious research phase)...
 
...even being some kind of hacker myself, I would not want to build a three way active crossover with delays, EQs etc in a text file. Way too much room for simple mistakes. That's why I wanted a GUI for myself and hence I built one.

Actually, to define via text file all the filters for a 3-way crossover like you describe above is a piece of cake. I do it all the time, like this:
ROUTE 1 (start, end)
filter1 definition
filter2 definition
filter3 definition
etc.
END ROUTE 1
Each route connects an input or source (start) to an output or sink (end) and the processing done to the audio taking that route is the list of filters given.

What is much more time consuming and elaborate, and that must be done graphically, is the modeling of the loudspeaker system (e.g. based multiple measurements) followed by the development of the crossover. This is best done in special software that is designed explicitly for that purpose. A GUI interface for setting filters is nothing like that at all. It's more like a pro-audio crossover with GUI interface. That's fine in that role, but that is not what a serious DIY loudspeaker builder would use. Instead it would be only for the last step, where the fully developed crossover filters are transferred to the hardware or software that then implements them.
 
Last edited:
That one is simple to answer: there are ready made C libraries for reading wav files into float arrays, not so much for text files. So I will use wav files.

I have thought more about this aspect (wav container for IR coefficients), and came to the conclusion that a) I was wrong, and b) it is all about the metadata. Note, one could similarly use a flac container for this matter.

In much of DSP, the fundamental property is sampling frequency. Filter performance is all relative to the sampling frequency they were designed for - eg: a lowpass FIR filter designed with a corner frequency of 300Hz for 44.1kHz sampling frequency will, for a 96kHz input, have that corner frequency shifted to 300Hz * 96/44.1 = 653Hz. Others aspects of the filter will also differ at different sampling rates.

So, what is the designer of a convolution engine to do, given that filters designed for one sampling frequency will have (very) different behavior as a function of that parameter?

Some options:

  1. Normalize the sampling frequency of all input to some common value (say, resample everything to 48kHz). This requires integration of a resampler (libsoxr, src, etc), and will have a performance impact.
  2. Require users to synthesize filters for each different "common" sampling frequency (44.1, 48, 96kHz, etc) they will use. The framework can chose what filter to use based on the rate of the input and that carried by a filter's metadata.
  3. Require that filters be specified not by their IR coefficients, but by their features on an absolute scale in the frequency domain. eg: "an LPF with a corner frequency of 300Hz and stopband of -96dB". This approach obviously requires the DSP framework designer to get into the business of filter synthesis. Given an arbitrary magnitude spectrum for a filter, it's relative straightforward to synthesize the FIR coefficients.
  4. Translate a given set of IR coefficients for a filter at one sampling frequency into another set of coefficients for a different frequency. I have not found a way to reliably do this. From my limited research, no one else has either.

I believe BruteFIR uses 2) (IIRC?!?), but I would advocate for 1), and that is the direction I am leaning. Clearly Pulseaudio may have something to offer on this front. I got side-tracked (squirrel!) a while ago with resampling when I first realized the impact of this minor conundrum. I went so far as implementing my own just to make sure I understood where the sharp edges were. In practice, I would likely use libsoxr.
 
Actually, to define via text file all the filters for a 3-way crossover like you describe above is a piece of cake. I do it all the time, like this:
ROUTE 1 (start, end)
filter1 definition
filter2 definition
filter3 definition
etc.
END ROUTE 1
Each route connects an input or source (start) to an output or sink (end) and the processing done to the audio taking that route is the list of filters given.

What is much more time consuming and elaborate, and that must be done graphically, is the modeling of the loudspeaker system (e.g. based multiple measurements) followed by the development of the crossover. This is best done in special software that is designed explicitly for that purpose. A GUI interface for setting filters is nothing like that at all. It's more like a pro-audio crossover with GUI interface. That's fine in that role, but that is not what a serious DIY loudspeaker builder would use. Instead it would be only for the last step, where the fully developed crossover filters are transferred to the hardware or software that then implements them.

Let's end that textfile vs GUI discussion here, to each their own ;)

Regarding the development process: pulseaudio-crossover-rack can already overlay filter functions and .FRD (frequency response measurement) files for that purpose. Probably nobody ever tried that yet, because I never got any feedback on that matter.

This will be much improved upon from a user experience perspective once the program can handle the measurements itself. Basic delay and frequency/amplitude/phase/impulse response measurements are already working but it still needs some work to have proper integration with .paxor files (for storing measurement IRs) and to pass my quality checks :D
 
I agree with Jürgen. Going from GUI program where all the functional code runs in GUI callbacks to a CLI/web server operated by web requests means complete rewrite.

As of web UI and python - I like GitHub - dddomodossola/remi: Python REMote Interface library. Platform independent. In about 100 Kbytes, perfect for your diet. - programmed as regular UI components.

Interesting. For having some sliders and text inputs probably useable.

Plus let's not forget python is quite difficult to refactor due to its loose type system. Refactoring a program in Java would be WAY easier (but still a major task).

That is actually at least partly a myth. I use PyCharm as IDE which has a lot of refactoring functionality. Also python3 supports type hints which makes the guesswork for the IDE much easier.
 
I have thought more about this aspect (wav container for IR coefficients), and came to the conclusion that a) I was wrong, and b) it is all about the metadata. Note, one could similarly use a flac container for this matter.

In much of DSP, the fundamental property is sampling frequency. Filter performance is all relative to the sampling frequency they were designed for - eg: a lowpass FIR filter designed with a corner frequency of 300Hz for 44.1kHz sampling frequency will, for a 96kHz input, have that corner frequency shifted to 300Hz * 96/44.1 = 653Hz. Others aspects of the filter will also differ at different sampling rates.

So, what is the designer of a convolution engine to do, given that filters designed for one sampling frequency will have (very) different behavior as a function of that parameter?

Some options:

  1. Normalize the sampling frequency of all input to some common value (say, resample everything to 48kHz). This requires integration of a resampler (libsoxr, src, etc), and will have a performance impact.
  2. Require users to synthesize filters for each different "common" sampling frequency (44.1, 48, 96kHz, etc) they will use. The framework can chose what filter to use based on the rate of the input and that carried by a filter's metadata.
  3. Require that filters be specified not by their IR coefficients, but by their features on an absolute scale in the frequency domain. eg: "an LPF with a corner frequency of 300Hz and stopband of -96dB". This approach obviously requires the DSP framework designer to get into the business of filter synthesis. Given an arbitrary magnitude spectrum for a filter, it's relative straightforward to synthesize the FIR coefficients.
  4. Translate a given set of IR coefficients for a filter at one sampling frequency into another set of coefficients for a different frequency. I have not found a way to reliably do this. From my limited research, no one else has either.

I believe BruteFIR uses 2) (IIRC?!?), but I would advocate for 1), and that is the direction I am leaning. Clearly Pulseaudio may have something to offer on this front. I got side-tracked (squirrel!) a while ago with resampling when I first realized the impact of this minor conundrum. I went so far as implementing my own just to make sure I understood where the sharp edges were. In practice, I would likely use libsoxr.

I though about this as well already.

3) is out of the scope, at least at the moment. This opens a whole new can of worms and I don't feel confident enough to tackle this at the moment!

2) is a viable option, one more reason why I preferred wav files. They "know" their intended sample rate and the GUI can match that to the sample rate that pulseaudio is currently running at. If there's a mismatch the GUI can inform the user about that and even offer to resample the IR with soxr which then would lead into option 4).

I briefly looked at rePhase as my filter design tool of choice. The .txt files it generates don't have any metadata at all, wav files do have at least the sampling frequency.

Btw. on more question: Why does rePhase need the FFT length? I thought that would have no impact on the IR?! Please enlighten me :)

PS: Should we open a new thread for the FIR filter/convolver implementation stuff?