Please add "mpd script" as new example script (music player daemon)

Create issue
Issue #3 closed
Martin created an issue

Dear Frank,

is it possible to add a proper "mpd script" which works as follows:

MPD -> pipe output -> MPD script -> Receiver

At the moment, I am using the pipe output of mpd to pipe the raw audio stream to a bash script called "pipehrt" (see mpd.conf):

audio_output {
        type "pipe"
        name "pipehrt"
        command "pipehrt"
}

This script "pipehrt" (in analogy to your "play_writecatloop") now reads the raw audio stream from stdin for passing on this stream to a pipe cascaded with writeloop, catloop and finally playhrt command.

#!/bin/bash

#########################################################################
##  frankl (C) 2015              play_writecatloop
##
##  See README or http://frank_l.bitbucket.org/stereoutils/player.html
##  for explanations.
#########################################################################

CARD="hw:0,0"
EXTRABYTESPLAY=397
VERBOSE=""

#trap "trap - SIGTERM && kill -- -$$ " SIGINT SIGTERM EXIT
#rm -f /dev/shm/bl{1,2,3} /dev/shm/sem.bl{1,2,3}*

input_file="${1:-/dev/stdin}"
cat "$input_file" | \
      writeloop --block-size=1024 --file-size=4096 --shared /bl1 /bl2 /bl3 &

# maybe the start of the background command takes a little time
sleep 0.1

catloop --block-size=1024 --shared /bl1 /bl2 /bl3 | \
      chrt -f 99 playhrt \
           --stdin \
           --device=${CARD} \
           --sample-rate=44100 \
           --sample-format=S16_LE \
           --loops-per-second=1000 \
           --mmap \
           --non-blocking-write \
           ${VERBOSE} \
           --extra-bytes-per-second=${EXTRABYTESPLAY} \
           --hw-buffer=16384

I am really no bash expert, but this approach works. The question is: is it really good script concerning audio quality and overall system overhead? Maybe you could help with this script and add it to your script examples. I am pretty sure that I am not the only person using mpd.

Thank you very much for your help and thanks for these great programs!

Best wishes, Martin

PS: writing the hole pipe sequence into the "command-field" of the pipe output in mpd.conf does not work (maybe because of the writeloop... & catloop... sequence)!

Comments (7)

  1. frank_l repo owner

    Dear Martin,

    Thanks for your suggestion. I have not used mpd (I don't like that it wants to read the music files and only sends the raw audio data to a pipe - this way the sample rate and bit depth cannot be transfered to the receiving program).

    Nevertheless, I can add an example script to the next release, if you can confirm that it works.

    Two comments on the script you propose above:

    (1) The part with 'input_file' allows to read input from stdin or from a file given as argument. But this doesn't sound very sensible to me, because it is unlikely that someone stored raw audio data in a file. Therefore, the script can be simplified to only read from stdin:

    #  this command will read stdin of this script
    writeloop --block-size=1024 --file-size=4096 --shared /bl1 /bl2 /bl3 &
    

    (2) Why did you comment out the two lines with 'trap' and 'rm'. Do they not work? I would leave them uncommented, they ensure a cleanup if the script is killed during operation.

    Best regards, Frank

  2. dimas sky

    I tried the command mpd pipe with parameter substitution format in pipe with a modification of the code MPD. It worked, but after a while there is a failure of the audio stream and the sound disappears.

    command "sox -traw -r$isr -c2 -esi -b$ifor - -traw -efloat -b64 - | volrace -t /tmp/volume | sox -traw -efloat -b64 -c2 -r$isr - -traw -esi -b32 - | chrt -f 80 aplay -fS32_LE -r$isr -c2 -Dplughw:0,0 --disable-resample"

    MPD does resampling. $isr - input samplerate after resampling, $ifor - input format after resampling. Parameters are substituted dynamically. MPD writes volume to the file /tmp/volume in range 0..1.

    Thanks, I'll try and your option.

    I have a question: should be used volrace only for volume control? or Squeezelite volume function for one channel does the same?

    s32_t gain(s32_t gain, s32_t sample) {
            s64_t res = (s64_t)gain * (s64_t)sample;
            if (res > MAX_SCALESAMPLE) res = MAX_SCALESAMPLE;
            if (res < MIN_SCALESAMPLE) res = MIN_SCALESAMPLE;
            return (s32_t) (res >> 16);
    }
    

    gain - volume range 0..65536, sample -32768 ... 32768, s64_t - integer 64bit, s32_t - integer 32bit

  3. frank_l repo owner

    I have a question: should be used volrace only for volume control? or Squeezelite volume function for one channel does the same?

    If you only want volume control and no RACE functionality you can simplify your pipe to not using 'volrace'. A gain function as you show above should be fine instead of volrace.

    BTW: which version of mpd are you talking about in your example? I cannot find anything about parameter substitution in the script for the pipe output in the mpd documentation. Can you post a link to the version of mpd you are using?

  4. dimas sky

    I use custom MPD lastest version 0.18, 0.19 with little mod. Before the opening of the pipe occurs parameter substitution. PipeOutputPlugin.cxx

    ReplaceString(pd->cmd,"$ifor",ifor); //format
    ReplaceString(pd->cmd,"$ich",ich);  //channels
    ReplaceString(pd->cmd,"$isr",isample); //sample rate
    
    pd->fh = popen(pd->cmd.c_str(),"w");
    
  5. dimas sky

    I use your utils with Squeezelite little mod also, great improvement! Internal pipe with "popen" like mpd with occurs $rate substitution. Pipe is read via the parameter file. my pipefile pipe3:

    writeloop --blocksize=4096 --file-size=32768 /tmp/b1 /tmp/b2 /tmp/b3 | catloop --blocksize=4096 /tmp/b1 /tmp/b2 /tmp/b3 | chrt -f 80 playhrt --stdin --device=plughw:0,0 --sample-rate=$rate --sample-format=S32_LE
    

    Squeezelite runs (Max samplerate limited 192K):

    squeezelite -o - -a 32 -b $buffer -n $sqname -r 192000 -j pipe3
    
  6. Log in to comment