moOde with MPD Selective Resample

2020-09-14: More flexible version is available, see MPD soxr selective resample modes .The MPD soxr selective resample modes are part of the upcoming moOde 7.0.0 release. MoOde even provide a nice GUI for it.

Music Player Daemon is a daemon used in a lot of (Raspberry Pi) audio distributions. Including the one that I use; moOde Audio Player. MPD supports a bunch of plugins, including SoxR for high quality resampling. Which can be used for both up and down sampling.

The most common used audio sample rates are based on two ‘base’ clocks; multiplicity of 44.1 kHz or48 kHz. Typical matching sample rates:

  • 44.1 kHz based: 44.1 , 88.2, 176.4, 352.8 kHz
  • 48 kHz based: 48, 96, 192, 384 kHz

Is you resample to a different base clock, for example from 44.1 to 96 kHz, you will get a big performance penalty with SoxR. At least compared with from 48 to 96kHz. It takes twice the number of CPU resource than from 48 to 96 kHz.

In MPD you can configure a target sample rate. Lets say we configure MPD to upsample to 96kHz. This works nice for 48 and 96kHz source, only for 44.1 and 88.2 kHz the outcome is a little bit different. You can image that from 48 to 96 (ratio 2) is a lot easier than 44.1 to 96 (ratio 2.17). You Raspberry Pi agrees and is lot busier with 44.1 to 96kHz. Almost twice the number of CPU resources are used. I don’t dare to say something about the audio quality, I just focus of the used CPU resources.

Wouldn’t it be nice if the 44.1 is just upsample to the nearest round base sample rate? This is what the supplied patch will do.. You just provide the max, as specified in a 48kHz base sample rate and 44.1 based will just match to the closest (but lower) sample rate.

At the end of this articles the results of performance test are shown and includes the commands to reproduce it yourself.

Patch MPD

Please follow the updated instructions concerning patching and installation in https://github.com/bitkeeper/dddac1794build/tree/master/raspberrypi/software for MPD patch and custom settings for Moode MPD !!!

moOde only supports the resample option by using the global audio_output_format setting. Due this the patch will introduce a global setting called selective_44k_resample.

This will not work with Volumio because it doesn’t use the global resample option audio_format option, but the one on the output device. Of course the supplied patch could be changed to also support output devices.

The patch is tested with moOde 6.4.2 and mpd-0.21.20. For building the patch the easiest way is to do it directly on your target. The build instructions below are based moOde build recipe.

pi@moode:~ $ wget http://www.musicpd.org/download/mpd/0.21/mpd-0.21.20.tar.xz
pi@moode:~ $ wget https://www.bitlab.nl/wp-content/uploads/2020/04/mpd_0.21.20_selective_44k_resample.patch
pi@moode:~ $ tar xf mpd-0.21.20.tar.xz
pi@moode:~ $ cd mpd-0.21.20
pi@moode:~ $ patch -b -p1 < ../mpd_0.21.20_selective_44k_resample.patch
pi@moode:~ $ meson . output/release --buildtype=release -Db_ndebug=true
pi@moode:~ $ meson configure \
-Dalsa=enabled \
-Dbzip2=enabled \
-Dcurl=enabled \
-Ddatabase=true \
-Ddsd=true \
-Dffmpeg=enabled \
-Dfaad=enabled \
-Dflac=enabled \
-Dhttpd=true \
-Did3tag=enabled \
-Dlame=enabled \
-Dlibmpdclient=enabled \
-Dmad=enabled \
-Dmpg123=enabled \
-Dpipe=true \
-Drecorder=true \
-Dshout=enabled \
-Dsoundcloud=enabled \
-Dsoxr=enabled \
-Dvorbis=enabled \
-Dwave_encoder=true \
-Dwavpack=enabled \
-Dzeroconf=avahi \
-Dzzip=enabled \
-Dao=disabled \
-Daudiofile=disabled \
-Ddbus=disabled \
-Dexpat=disabled \
-Dfluidsynth=disabled \
-Dgme=disabled \
-Dipv6=disabled \
-Djack=disabled \
-Dlibsamplerate=disabled \
-Dnfs=disabled \
-Doss=disabled \
-Dpulse=disabled \
-Dsidplay=disabled \
-Dsmbclient=disabled \
-Dsndfile=disabled \
-Dsqlite=disabled \
-Dudisks=disabled \
-Dupnp=disabled \
-Dwildmidi=disabled \
output/release
pi@moode:~ $ ninja -C output/release

Especially the latest step will take quite some time. After the build there should be an MPD executable in the ./output/release directory.

Now we have to copy the executable to the location where the system will use it. We have to make sure it isn’t in use, else the file will be locked.

sudo killall worker.php
sudo killall watchdog.sh
sudo rm /run/worker.pid
sudo systemctl restart php7.3-fpm
sudo systemctl restart nginx
sudo systemctl stop mpd
sudo mv  /usr/local/bin/mpd /usr/local/bin/mod.orig
sudo cp output/release/mpd /usr/local/bin
sudo /var/www/command/worker.php

If you are coming from a stock Moode 6.4.2 ( with mpd-0.20.16) you need to regenerate you library, due some changes in the mpd-0.20.21 code.

Usage

To use a MPD build with the selective_44k_resample patch:

  1. Set audio_out_format to a multiplication of 48kHz like 96000:24:2 (Off course you have to make sure the target requested sample rate is supported by your output and/or DAC.).
  2. Set selective_44k_resample is set to yes.

For use with moOde the first one is clear. Open the MPD Configuration page and set the wanted resampling options.

Moode MPD config Sox Resampling configuration

The second one is a little bit harder to do. moOdedoes support small subset of the available MPD settings, let alone new settings. And because moOde generates the configuration for MPD any manual made tweaks are overwritten.

We need to make a small change to MPD configuration generator.

I use myself another patch for moOde. That patch adds the possibility to add additional global and device MPD options by using the moOde web interface. There we can just add the option selective_44k_resample "yes" to the general parameters.

Custom Moode MPD Tweaks

Search in the file /var/www/inc/playerlib.php for the following two line in the function updMpdConf. With Moode 6.4.2 the function starts at line 1521.

$data .= "max_connections \"128\"\n";   
$data .= "\n";

Insert between the two lines a new one with the content below:

$data .= "max_connections \"128\"\n"; 
$data .= "selective_44k_resample \"yes\"\n"; 
$data .= "\n";

Reboot your Pi to make sure the new code is used. After boot go the the mpd configuration page and press save to make sure the mpd configuration is generated.
To be sure you can check if the settings is in the mpd configuration by executing the following command:

cat /etc/mpd.conf| grep selective_44k_resample 
selective_44k_resample "yes"

It should return the setting with yes.

Performance tests

The test are performed with the command line version of sox.

Used test environment:

  • Pi 2B
  • Raspbian Buster Lite 10.2
  • kernel 4.19.97-v7+
  • SoX 14.4.2

Tests are run on a ramdisk. As test file the default audio from moOde is
used. To prevent testing decoder/encoders test files are wave files.

Performed tests:

  • 44.1/16 to 96/24
  • 48/16 to 96/24
  • 44.1/16 to 88.2/24

In the results below it is clearly visible that the resampling from 44.1 to 96 takes twice as more CPU resources that for 88.2 or 48 to 96.

To be able to reproduce the test yourself in the file below all commands to setup and execute the tests are in the attached file:

Test 48/16 to 96/24

pi@moodedev:/mnt/ramdisk $ perf stat sox LRMonoPhase4_48_16.wav -b 24 LRMonoPhase4_96_24.wav rate -v 96000

 Performance counter stats for 'sox LRMonoPhase4_48_16.wav -b 24 LRMonoPhase4_96_24.wav rate -v 96000':

          2,574.54 msec task-clock:u              #    0.999 CPUs utilized
                 0      context-switches:u        #    0.000 K/sec
                 0      cpu-migrations:u          #    0.000 K/sec
               245      page-faults:u             #   95.183 M/sec
     2,169,128,394      cycles:u                  # 842707.224 GHz
     1,492,424,845      instructions:u            #    0.69  insn per cycle
       103,511,129      branches:u                # 40214113.831 M/sec
         2,726,871      branch-misses:u           #    2.63% of all branches

       2.577343598 seconds time elapsed

       2.436878000 seconds user
       0.140396000 seconds sys

Test 44.1/16 to 96/24

pi@moodedev:/mnt/ramdisk $ perf stat sox LRMonoPhase4_44_16.wav -b 24 LRMonoPhase4_96_24.wav rate -v 96000

 Performance counter stats for 'sox LRMonoPhase4_44_16.wav -b 24 LRMonoPhase4_96_24.wav rate -v 96000':

          5,097.92 msec task-clock:u              #    0.999 CPUs utilized
                 0      context-switches:u        #    0.000 K/sec
                 0      cpu-migrations:u          #    0.000 K/sec
               309      page-faults:u             #   60.624 M/sec
     4,385,703,707      cycles:u                  # 860448.049 GHz
     2,983,902,787      instructions:u            #    0.68  insn per cycle
       316,741,603      branches:u                # 62142751.226 M/sec
        10,099,792      branch-misses:u           #    3.19% of all branches

       5.101232776 seconds time elapsed

       4.960521000 seconds user
       0.140014000 seconds sys

Test 44.1/16 to 88.2/24

pi@moodedev=/mnt/ramdisk $ perf stat sox LRMonoPhase4_44_16.wav -b 24 LRMonoPhase4_88_24.wav rate -v 88200

 Performance counter stats for 'sox LRMonoPhase4_44_16.wav -b 24 
 LRMonoPhase4_88_24.wav rate -v 88200'=

      2,385.83 msec task-clock=u       =    0.998 CPUs utilized
             0      context-switches=u =    0.000 K/sec
             0      cpu-migrations=u   =    0.000 K/sec
           243      page-faults=u      =  101.887 M/sec
 1,992,758,822      cycles=u           = 835538.290 GHz
 1,371,449,852      instructions=u     =    0.69  insn per cycle
    95,114,857      branches=u         = 39880443.187 M/sec
     2,507,847      branch-misses=u    =    2.64% of all branches

   2.389982451 seconds time elapsed

   2.248309000 seconds user
   0.139894000 seconds sys

Hifiberry Digi+ Pro with Allo Isolator


For quite some time I’m using the Allo Isolator for galvanic isolation between the Pi and the HifiBerry. Everything was upsampled to 192kHz and works great. No more cracks, deep dark sound.

Only when starting playing with different sample rates (44.1kHz based) MPD hangs. Before using the isolator it did work. If seems that something is wrong.

The HifiBerry Digi+ Pro has two crystals onboard; one for a multiplicity of 48kHz and one for multiplicity of 44.1kHz based sample rates. The crystal selection is done by using GPIO 5 & 6. Only GPIO 5 isn’t isolation by the Allo Isolator.

This can lead to two scenarios:

  • If the power supplies aren’t isolated (for example shared ground), it will work. Only your system isn’t isolated as it should.
  • If the power supplies are really isolated, GPIO 5 becomes floating. In my case this even damaged my crystal.

 The image below illustrate the difference between GPIO6 (pin31) and GPIO5 (pin29).

Isolated vs not Isolated pin

Fixing the isolation

Lets first take a look at the Isolator. In red is shown which pin is isolated by which isolation ICs (Si8630, Si8631 and Si8502). Each pin has a certain fixed role; output(>), input(<) or bidirectional (<>).

Allo Isolator IO Pins vs Isolator Electronics

Also not clear from the Isolator documentation is that the SPI isolating works different from the GPIO isolation; SPI isolation means no connection at all. Yes that is also isolated, but not usable.

For the clock selection we need an unused output pin. Below is an overview of how my system is using the Pi IO header.

Raspberry Pi Io Header usage

GPIO16 (pin 36 ) looks like a good match.

Only the HifiBerry can’t be configured to use a different pin. We could rework the Allo Isolator in such way that GPIO 6 is using isolation electronics from GPIO16 (and disconnect GPIO16 from the Pi).

Steps to reuse the GPIO16 isolation electronics:
– [bottom side] pin 29; cut trace to via
– [bottom side] pin 36; cut connector from the solder pad
– [bottom side] solder wire between pin 29 and pin 36 on the bottom side
– [upper side] solder wire between pin 29 and pin 36 on the bottom side

I choose a different approach, which only requires one electronical modification to the Isolator; break the connection between GPIO5 upper and lower connector of the Allo Isolator. The trick is that we will make software modification so that the HifiBerry software driver will use the already isolated GPIO16.

Steps to take:

  1. Electrical isolate GPIO5 upper and lower connector from the Allo Isolator.
  2. Connect GPIO5 to GPIO16 on the isolated side with a jumper wire.
  3. Create a software mod to use a different GPIO pin.

Isolated GPIO pin 5 from the Pi

First we have to make sure GPIO 5 (pin 29) is electrical isolated. On the bottom of the Isolator there is a via that connects GPIO5 from the bottom connector to the top connector. This via is connected with a very small trace going from to the solder pad of pin 29.

Just cut this trace with a small X-Acto knife or what ever for small knife you have. Probably you need to have some loupe of smartphone to see it clear enough, at least I did. You don’t need to remove the entire trace, just can scarf will do. Don’t forget to measure the connection between the upper and lower connector before and after to see if the cut is good enough. 

Connect GPIO 16 to GPIO 5

Next we have to connect from the Isolator upper connector GPIO 16 (pin 36) to GPIO 5. You can solder a wire between solder pads of pin 36 and pin 29 and you are good to go.
Because my HifiBerry has the additional male header installed, I did have another choice available; Just connect a jumper wire from pin 36 to pin 29 on the HifiBerry upper connector. No soldering required.

Jumper wire for connection between GPIO5 & GPIO16

Do you notice the connector in position P3? You can use this one to feed both the HifiBerry and the Isolator with clean 5V. In this way you can avoid the less available 6.5V for the Isolator. Both the HB and Isolator use own regulators for 3.3V, which what the actual chips are using.

Make the Pi use GPIO 16 for clock selection

Let the Pi HifiBerry driver use an other GPIO for the crystal selection is standard not available. To make this work we need to change the driver overlay a bit.

This involves the steps:

  • create a new overlay that support reconfigure the clock selection GPIO
  • configure the Raspberry Pi to use it.

Create a new overlay

Luckily it isn’t hard to make a new overlay which allow to configure the used pins.
But you need to know a little about using the command line command of Linux. First login open a SSH session, for example with PuTTY.

Or alternative you can download the overlay here and just copy to the overlays directory on the SD card. It is build on Moode 6.4.2 with kernel 4.19.97-v7+ #1293.

  • Install the device tree compiler
sudo apt-get install raspi-gpio device-tree-compiler
  • Download the remap overlay source here or create a file called hifiberry-digi-pro-remap.dts
vi hifiberry-digi-pro-remap-overlay.dts
  • If not downloaded fill the content with:
// Definitions for HiFiBerry Digi Pro clock select remap
/dts-v1/;
/plugin/;

/{
 compatible = "brcm,bcm2835";


 fragment@0 {
  target = <&i2s>;
  __overlay__ {
   status = "okay";
  };
 };

 fragment@1 {
  target = <&i2c1>;
  __overlay__ {
   #address-cells = <1>;
   #size-cells = <0>;
   status = "okay";

   wm8804@3b {
    #sound-dai-cells = <0>;
    compatible = "wlf,wm8804";
    reg = <0x3b>;
    PVDD-supply = <&vdd_3v3_reg>;
    DVDD-supply = <&vdd_3v3_reg>;
    status = "okay";
   };
  };
 };

 fragment@2 {
  target = <&sound>;
  hifiberry_digi_pro: __overlay__ {
   compatible = "hifiberry,hifiberry-digi";
   i2s-controller = <&i2s>;
   status = "okay";
   clock44-gpio = <&gpio 5 0>;
   clock48-gpio = <&gpio 6 0>;
  };
 };

 __overrides__ {
  clock44_gpio_pin = <&hifiberry_digi_pro>,"clock44-gpio:4";
  clock48_gpio_pin = <&hifiberry_digi_pro>,"clock48-gpio:4";
 }; 

};
  • Compile this file with:
dtc -@ -I dts -O dtb -o hifiberry-digi-pro-remap.dtbo hifiberry-digi-pro-remap-overlay.dts
  • Copy it to the correct system location:
sudo cp hifiberry-digi-pro-remap.dtbo /boot/overlays/

Use the new overlay

Steps:

  • Open the file config.txt (/boot/config.txt) in editor.
  • search for the line dtoverlay=hifiberry-digi-pro
  • make it a comment by putting an # before it so it looks like:
#dtoverlay=hifiberry-digi-pro
  • Create a new line just below it with :
dtoverlay=hifiberry-digi-pro-remap,clock44_gpio_pin=16,clock48_gpio_pin=6 
  • Save the file an (re)boot the Pi

If you aren’t familiar with how to edit the file on the Pi with SSH, just remove the SD card an put the card in your normal computer.

If you want to be sure and check if the overlay is correctly loaded else then by playing aa 44.1kHz based file run from the SSH console:

sudo vcdbg log msg |& grep -v HDM

In the output the following lines should appear:

002107.626: dtdebug: Opened overlay file 'overlays/hifiberry-digi-pro-remap.dtbo'
002109.778: brfs: File read: /mfs/sd/overlays/hifiberry-digi-pro-remap.dtbo
002155.779: Loaded overlay 'hifiberry-digi-pro-remap'
002155.842: dtparam: clock44_gpio_pin=16
002156.047: dtdebug: Found override clock44_gpio_pin
002156.100: dtdebug:   override clock44_gpio_pin: cell target clock44-gpio @ offset 4 (size 4)
002156.569: dtparam: clock48_gpio_pin=6
002156.788: dtdebug: Found override clock48_gpio_pin
002156.841: dtdebug:   override clock48_gpio_pin: cell target clock48-gpio @ offset 4 (size 4)

Update 2020-09-14:
In the article DDDAC1794 build is shown how the power supplies are connected. The Isolator isn’t fed with 6.5VDC. I use 2x times 5V(dirty + clean ) for it. The power supply for the Isolator is coming from the 5V connector on top of the Hifiberry. Therefor the extra regulator of the Isolator is bypassed and we can use a more common voltage of 5V.

moOde MPD Tweaks GUI

2020-09-14 The upcoming 7.0.0 release of moOde contains another patch of me, that will make the one below obsolete.

The moOde Audio Player MPD configuration only support a very small subset of the available MPD options. The one that are supported comes with a very nice user interface. Only sometimes I just want to try unsupported or even new MPD options.

Just editing the mpd.conf isn’t an option, because Moode will overwrite the configuration file. You can work around it by modifying the Moode MPD configuration generator. But that isn’t very flexible. This article provide a patch to make experimenting with MPD a little bit easier by using the web interface of Moode.

On the bottom of the MPD configuration page an MPD Tweaks section is added.

When enabled two text input boxes are shown:

One for general parameters and one for the default output device. It doesn’t provide a very rich interface, but it beats changing the MPD configuration generator by hand. Multiple options can be set separated by ‘;’.

When the tweaks are disabled, the settings are still kept in the database only it isn’t used. This makes it easier switch on and off the settings.

Any parameter added to the MPD Tweaks General or Device parameters will override any parameter set by Moode it self.

In the final generated MPD.conf it is shown which parameters are coming from the MPD Tweaks settings:

Install the MDP Tweaks Patch

wget https://www.bitlab.nl/wp-content/uploads/2020/04/moode_mpd_tweaks.patch
wget https://www.bitlab.nl/wp-content/uploads/2020/04/moode_mpd_tweaks.sql
cd /var/www
sudo patch -b -p2 < /home/pi/moode_mpd_tweaks.patch
sqlite3 /var/local/www/db/moode-sqlite3.db < /home/pi/moode_mpd_tweaks.sql
sudo systemctl restart php7.3-fpm

Or if you want to download the patches yourself:

All due the patch is installed, it is still hidden from the user. We need to unlock it by setting a field in the database like:

$ sqlite3 /var/local/www/db/moode-sqlite3.db 'UPDATE cfg_mpd  SET value="1" where param="mpd_tweaks_unlock";'

Usage

Go to the MPD configure page and on the bottom you will find the MPD tweak. Default it is disabled.

To enabled it:

  • change the toggle button to on
  • press the set button next to it

Now the additional text input for general and device parameters should be present:

Enter the configuration parameters separated by “;”. See the original MPD documentation for the available parameters.

For example adding log_level "verbose" general parameters adds message to the /var/log/mp/log file.