4-channel crossover using Pulseaudio/LADSPA

  • Hi there,

    thanks for all the time and effort put into this project, i hope my first post can give you something back.

    I wanted to use my 4-channel USB-soundcard (Focusrite Saffire 6 USB) to drive a 2.1 speaker system. Having LibreELEC running on a Odroid C2 i used PulseAudio to stream audio to another BananaPi which did the filtering using Richard Taylors rt-plugins hosted on PulseAudio-module module-ladspa-sink.

    Using 2 SBCs seemed overkill so i tried to embed Richards plugins into LibreELEC. The process was quite simple, starting out by setting up the build-environment as described in the Wiki, creating the appropriate package under packages/audio/rt-plugins and the corresponding package.mk file.

    You can checkout my current result on GitHub - chipfunk/LibreELEC.tv at feature/rt-plugins.


    - fix include-path for ladspa.h as its currently fixed for my setup

    Future ideas:

    ATM i have to build the complete image to have the rt-plugins available, maybe i will have the time to make it an optional add-on.

    Please feel free to ask further questions.

  • Hey there chipfunk! Great work!

    I'm in a similar situation right now: I'm using a nanopi as a pulseaudio server to host the excellent DSP LADSPA plugin (GitHub - bmc0/dsp: An audio processing program with an interactive mode.).

    It does pretty much anything and everything a computer audiophile would want: it does crossovers, dynamics processing and even room correction based on either FIR or IIR filters. I'm currently using the FIR Filter to EQ my system. The filter is generated by measuring my in-room frequency and phase response with a calibrated mic and having the excellent DRC software (DRC: Digital Room Correction) compute a correction filter. The result is really great.

    I'll have a look at your github repo. Getting LADSPA filters into LibreELEC is something I have attempted to do before but i always got stuck somewhere. I'm sure I'll learn something new! Thanks!

    EDIT: Just had a look at your repo and I saw that you're working on ButeFIR support. Really cool! How are you going to integrate BruteFIR into the LibreELEC sound stack? I tried to do that before with the snd-aloop kernel module and found out the hard way that it's not available for every target platform (Amlogic, I'm looking at you...). If you'd prefer to use a LADSPA plugin that works within PulseAudio's module-ladspa-sink I really recommend the DSP plugin.

    Edited once, last by ariendj ().

  • Hey ariendj,

    thanks for your interest in this project, your setup sounds exactly like the target i'd like to archieve, very nice :)

    To explain how i try to set things up i added some READMEs to the appropriate branches, please see here for the rt-plugins and here for BruteFIR.

    I'd like to encourage everyone to ask further questions as i will use these to improve the existing documentation.

    Next steps: i think i should convert the packages to installable add-ons first so i dont have to build, flash and install a complete distribution every time i change something.

  • Installable addons would be really great, I'd start testing those ASAP.

    What platform do you use? I'd love to test something out if you can upload a build of yours somewhere. I can test x86/AMD64, Allwinner H3 or Amlogic S905 if you want. I also have a Raspberry Pi 3 somewhere in my office, I just can't seem to find it :D

    EDIT: Found the Pi :)

    I once tried the brutefir/mkfifo and pulseaudio module-pipe-sink/module-pipe-source approach but gave up on that because the latency was too high on the Amlogic S905D box I was working with. On AMD64 it was less but still not great. Maybe you will have more success than me, I might have missed something.

    Like I mentioned, bmc0's dsp LADSPA filter can also replace BruteFIR for convolution and the rt-plugins for crossover in one package.

    Here's what I did on my NanoPi with armbian: First I built the LADSPA plugin, then you can write a config file with all necessairy crossover filters (Butterworth, Linkwitz-Riley and the like) and add a room correction filter to the config. When you then load the dsp filter into pulseaudio you'll have all filtering done in just one step/one LADSPA plugin instance. It's pretty light on CPU load. It runs on a flimsy Allwinner H2+ easily and I think most load does not come from the filtering done but rather from the speex-float-10 resampler I use.

    The convolver used in 'dsp' is the excellent libzita-convolver by Fons Adriaensen. The only difference in handling I noticed is that it uses 32bit floating point precision while BruteFIR can use 64bit. I have never seen anyone deliver actual proof that 64bit is useful at all though.

    Edited once, last by ariendj ().

  • Hey ariendj,

    thanks for the valueable input and your offer to test things.

    I'm still learning how to package addons, yesterday i messed up my build-environment by updating GCC. So it will need some time to setup a build-box based on Ubuntu 16.04 as recommended in the wiki ;) Hope this will give me a more stable foundation to develop.

    I'll keep you updated.

  • Hey there chipfunk!

    I set up a virtual build box that I can take snapshots of. I'm no stranger to messing up the build-env myself :)

    I used it to build your brutefir branch for the 'generic' architecture and that went fine. I have an image that I might get around to testing this sunday.

    What are you using to create filters for BruteFIR? So far I have been using DRC on the command line but I recently came across this:

    GitHub - TheBigW/DRC: Digital Room Correction plugin for rhythmbox

    It's both a plugin for the Rhythmbox music player and a stand-alone application that can use either PORC or DRC to generate impulse response filters. It seems that you can use it to make multiple measurements and use a weighted average to generate the impulse response. I'll be checking that out soon. So far I did not get it to start but that probably has to do with my desktop being KDE and the measurement software being GTK based. I guess I'll just set up a VM and test it on a Gnome based desktop. I'll keep you posted on how that goes. Cheers!

  • Hey ariendj,

    pls do NOT waste time testing the brutefir-branch, as its not building BruteFIR yet (i would be very very suprised :). The branch containing the rt-plugins should build fine, but i see why you want the BruteFIR thing done ;)

    In the meantime i could salvage an old IDE-HDD (took me two days alone because of broken cables and USB-IDE-case) and use it as USB-storage for the build-VM, so now there is slow but enough space to build for Odroid-C2, RPi3 and maybe others. I managed to package FFTW as a dependency of zita-convolver (still ugly, but building), as bmc0/dsp (not yet building ;) relies on it. But i'm not finished, thats why i didn't commit the code by now. Excellent you could setup a build-box, so we can test and build in parallel. I'll try to check in the code as fast as possible, hopefully by wednesday.

    I saw the rhythmbox-plugin too but didn't have time to have a look at it. Pls report back if you got any success on the measurement-process as i didn't evaluated that yet (have to get a decent microphone first). This would be the next step after i got the playback-software up and running.


  • Hey ariendj,

    finally i got the first addon compiled and packaged, it's the rt-plugins by Richard Taylor. I attached the addons for Odroid C2 (audio.rt-plugins-8.2.0-Odroid_C2-aarch64.zip) and RPi2/3 (audio.rt-plugins-8.2.0-RPi2-arm.zip).


    Just install addon from zip-file.


    Before the configuration of ladpspa-plugin-sinks in /storage/.config/autostart.sh pulseaudio has to be informed where to look for the ladspa-plugins. To do so i set the environment-variable LADSPA_PATH for systemd, reload systemd and restart the pulseaudio.service to pick-up the new environment-variable. like so

    # tell pulseaudio to load ladspa-plugins from addon-dir
    systemctl set-environment LADSPA_PATH=$LADSPA_PATH:'/storage/.kodi/addons/audio.rt-plugins/lib/ladspa'
    systemctl daemon-reload
    systemctl restart pulseaudio.service
    # wait for pulseaudio to complete restart before configuring ladspa-filter-sinks
    sleep 5
    # ... pulseaudio config follows below ...

    FFTW and zita-convolver are also nearly done, currently bmc0/dsp and bruteFIR aren't compiling.

    So no much news, but getting there :) cheers

    Edited once, last by chipfunk ().

  • That's some great news! Thanks chipfunk!

    I'll try to build the addon for Generic against the master tree (I'm running milhouse builds because of netflix and the like). If that doesn't work I'll get the Pi out to try your precompiled version.

    Next I'll have a look at writing a package.mk file and building drc-fir for LibreELEC. Seems like it's a low hanging fruit as it only requires a simple 'make' and copying a few files around to get going.

    I might try to build the snapcast addon that's on github while I'm at it. My final goal is to have a LibreELEC system that does FIR filtering on its audio outputs and synchronous multiroom audio steaming to other zones (that also use FIR filters of course). Considering the cost of ARM boards and DAC chips, why not go crazy? ;)

  • I managed to build rt-plugins against the master tree :)

    All that was needed was to edit package.mk line 42 to say


    and then I could build the addon :)

    Edited once, last by ariendj: Edit: no need to hardcode LE version string, we can get it from a variable ().

  • WoW cool! Sorry for my english. And how i may to load DRC FIR file to Libreelec or config parametric equalizer? Please provide step-by-step instructions Sorry for my newbie questions.

    Edited once, last by Magnus ().