rcmpd - Controlling MPD (Music Player Daemon) with an IR Remote Control

Table of contents

Introduction

I'm using a headless Raspberry Pi as audio player.

The operating system is Volumio, which is a stripped down Raspbian optimized for playing music, with a nice browser GUI!

Under the hood there is the MPD (Music Player Daemon) working.

Volumio's browser GUI is one of the many possibilities to control MPD.
There are really a lot of client programs out there (I like Cantata the most these days).
But in this case I wanted to control my music player without an additional computer, smartphone or such.
Just a plain old infrared remote control (RC) was my goal - with as many features as possible.

Searching the web I didn't find a client matching my ideas.

So I created one by myself - and rcmpd was born.

rcmpd is written as a bash script with very little requirements
and should work on an original Raspbian too, as well on all other Linuxes.
(For now I've tested it on the above mentioned Raspbian/Volumio only.)

I used bash as programming language to make it as easy as possible for others to understand and modify rcmpd by themselves.

Download

I'm hosting the rcmpd sourcecode on Bitbucket and there is an issue tracker as well.

Since I'm implementing new features every other day the most recent infos are always available there.

For easier recognition I'll try to always log the last commit here:

62[tip]   2fade7bcadab   2016-02-04 15:47 +0100     Fix printing bug

A direct download of the most recent version of rcmpd is always available here (a zip file containing the script rcmpd itself and some documentation files).

Features

Standard functions

Of course there are the usual, obvious commands:

  • Power (shutdown)
  • Mute
  • Volume+/-
  • toggle repeat and random
  • Pause
  • Play/Stop
  • Next/Previous track
  • 1st .. 10th track

And a not so obvious:

  • do something with the current songs title/artist

    Currently it gets saved in a file (appended, to be precise).
    That is intended to remember a nice song for later examination,
    especially useful when listening to radio streams.

    Of course there are more actions thinkable, e.g. mail it somewhere ...

But there is more! Please read on.

Speech output

Inspired by a maker's discussion about a "very simple Raspberry Pi Radio"
I implemented Text-to-speech outputs to get a more comfortable user experience.

There are some informations spoken and it's possible to get some commands "echoed" in words.

I'm using espeak (http://espeak.sourceforge.net) for text-to-speech, but it would be possible to use other software too.
Google's API has much better sound quality, but I wanted to have it working offline.
Both ways are now included and can be switched by setting variable tts_type.
  • speak info: current time
  • speak info: collection (available playlists)
  • speak info: volume and state of "repeat"
  • speak info: playlist
  • speak info: channel/album
  • speak info: current track/song
  • toggle audible commands on/off

Simple Playlist features

Additionally there are the following playlist features:

  • next/previous playlist
  • load playlist "A", "B", "C"
  • skip through all available playlists with the buttons

Compound keys

All of the above functions are reachable with a single button press.

To extend the possibilities I implemented compound keys.

  1. They are started and stopped with the OK button.
  2. Between those two OK's there are the letters A, B, C and D, the digits 0-9 and some more keys allowed.
  3. Every key needs to follow the one before within 5 seconds.

Enhanced Playlist features

  • If a playlist has more than ten entries (reachable via buttons 1-9,0) it's possible to select higher ones with compound keys.

    E.g. entry 27 could be started with:

    OK 2 7 OK
    
  • You can load more playlists directly by combining the letters A, B, C, D with the digits to playlists like "A7", "AC1" or "B126".

  • The list of defined/available playlists and the contents of the current one could be printed on a printer with:

    OK MENU EPG OK
    

    More about printing see below.

Playlist preparation

To make the direct loading of playlists work, the playlists in question have to be prepared a bit:

Using a MPD client on my PC I'm predefining MPD playlists which I would like to manage with the RC with a special naming convention.

Example:

A ~ Various Artists - The ultimate songs
B
B1 -- Angel Hearts - The first album
C24 ~ Alltime favourites
Runaways - Hot!
The lonely boys - Chicago

All the playlists starting with

  • a name consisting only of letters A,B,C,D and optional digits
  • or a prefix of that form, followed by a devider ('~' (a tilde) or '--' (two dashes))

can now be loaded with the RC! (The first four in the example above.)

So the above example playlists can be loaded by:

A

B

OK B 1 OK

OK C 2 4 OK
The two example ones without the special prefix/name can't be loaded directly that way.
But of course they can be reached by skipping to them via Channel+ / Channel-.

Power button and sleep timer

The Power button initiates a "shutown -h now" (that is a power off (on a Raspberry Pi only sort of...)).
Pressing it again, any delayed shutdown gets cancelled.

Using a compound key with Power and then one or more digits, a sleep timer with the given time in minutes is started.

For example set a sleep timer of 30 minutes:

OK POWER 3 0 OK
That means: The system will shut down then.
Anyway: This delayed shutdown can be cancelled with Power again as already mentioned.

Volume control

Additionally to the Vol+/- in steps of 5% the volume can be set to 100% by:

OK VOL+ VOL+ OK

to 50% by:

OK VOL+ VOL- OK
OK VOL- VOL+ OK

and to 0% by:

OK VOL- VOL- OK

Calling external commands

If there are external programs/scripts existing named like rcmpd.A (B,C,D,0-9) they can be called by:

OK MENU A OK

Printing a short summary of keys

A short reference of the possible keys can be printed on a printer with:

OK MENU MENU OK

This is the same list that is shown if rcmpd is called without any parameters.

To increase the WAF (Woman Acceptance Factor) I added those infos in German as well now.

To switch to German help you might edit a config value in the script,
but it's better to control it from outside:

Add a line like the following to your ~/.bashrc file:

export RCMPD_LANGUAGE=DE

To activate it just logoff and login again or type the above in your current shell session.

More about printing

The optional printing features are implemented by producing Postscript output which is converted to PDF and sent to the printer.

The most current output file is stored in /tmp/rcmpd-printout.pdf (configured as variable PRINTOUT in the script).

So it's possible to use the file for other purposes as well.

Here are two example prints, the short manual and playlist infos.

example printout: short manual example printout: playlist infos

(Click to see larger picture.)

Example function assignment on real remote controls

Here the assignments I configured for my IR Remote Controls:

Both can be used in parallel of course.

Pinnacle RC1144201

Pinnacle_RC1144201
Power        shutdown / cancel delayed shutdown / set sleep timer
Mute         mute / unmute
Menu         toggle audible command descriptions on/off / call external scripts / print keys
TV           speak info: current time
EPG          speak info: collection (available playlists) / print playlists
Vol+ Vol-    increase/decrease volume (in 5% steps)
Ch+ Ch-      next/previous playlist
Pinnacle     speak info: volume and state of "repeat"
A  B  C      load playlist "A", "B", "C"
D            speak info: playlist
Back         speak info: channel/album
Loop         toggle "repeat"
Fullscreen   speak info: current track/song
Pause        toggle pause/play
Play  Stop   start, stop playback / stop currently spoken text
Rew  FFwd    seek 30 seconds back/forward
Skip+ Skip-  next/previous track (within playlist)
Record       save current song info (title/artist) in '/home/pi/rcmpd.record'
1-9, 0       1st .. 10th track (within playlist)

OK           start/stop multiple-key commands (build from A,B,C,D,0-9, POWER, MENU, EPG, VOL)

Denon RC-126

http://ziemski.net/rcmpd/Denon_RC-126s.jpg

with only these commands:

KEY_POWER                      shutdown in 1 minute / cancel shutdown / set sleep timer
KEY_VOLUMEUP KEY_VOLUMEDOWN    increase/decrease volume (in 5% steps)
KEY_CHANNELUP=KEY_NEXT         next/previous track (within playlist)
KEY_CHANNELDOWN=KEY_PREVIOUS
KEY_SEARCH=KEY_SCREEN          speak info: current track/song
KEY_MUTE=KEY_PAUSE             toggle pause/play
KEY_MODE=KEY_STOP              stop

Usage

rcmpd is easy to call:

The first one is the normal operation format and the others are for installation/configuration purposes:

rcmpd <command> ...     manages a command, e.g. from an infrared RC buttonpress

rcmpd --checkinstall    checks some aspects of the install (prerequisites)
rcmpd --createlircrc    creates /home/pi/.lircrc if not existing
rcmpd --restartirexec   restarts irexec after changes on .lircrc
rcmpd --showsonginfos   shows the "recorded" infos in '/home/pi/rcmpd.record'
rcmpd --listplaylists   lists all playlists and the contents of current one

rcmpd                   without any parameters this usage info and a short summary of keys is shown
For the commands see in the section Example function assignment on real remote controls.
The installation is described in the installation section.

Hardware requirements

Software requirements

Note

Optional patch for paps

The original paps package (creating Postscript for printing) in version 0.6.8-6 doesn't have a --title option for filling the header on the printed document with own text.

It shows the filename - or the string "stdin" - instead.

Since I really wanted to be able to place variable text in the header I created a patch for that. It's described at http://www.ziemski.net/paps

But of course rcmpd is working with the unpatched paps as well - just without the individual header.

Installation

  1. Save rcmpd into a directory available via $PATH (e.g. in ~/bin).

  2. Make it executable, e.g. with chmod u+x rcmpd

  3. execute rcmpd --checkinstall to do a base installation check

  4. Install-and-configure-LIRC-for-your-RC (see below)

  5. Create an appropriate ~/.lircrc for handling the RC commands

    It needs to match your RC and the commands in rcmpd.
    It's possible to create it manually, but it's easier to use rcmpd --createlircrc.
  6. (Re)start irexec to let it know about the new lircrc: rcmpd --restartirexec

  7. Test it in your shell by rcmpd <command> with <command> being any of the defined commands above.


If all works fine you should make irexec autostart.

That may be done via an entry in /etc/rc.local like this:

su - pi -c "/usr/bin/irexec --daemon /home/pi/.lircrc"

Or if playback should start immediately:

su - pi -c "/usr/bin/irexec --daemon /home/pi/.lircrc ; mpc play"

You should use a "normal" user (here: pi) for that.

Note

Volumio's resetting of /etc/rc.local on every reboot

Another solution is to disable Volumio's "protection" of rc.local. I prefer this method, so that I'm free to edit rc.local again in the future without having to remember some weird location.:

sudo nano +1167 /var/www/inc/player_lib.php

Comment out these 5 lines by adding two slashes to the beginning like this:

//       $a = '/etc/rc.local';
//       $b = '/var/www/_OS_SETTINGS/etc/rc.local';
//       if (md5_file($a) != md5_file($b)) {
//       sysCmd('cp '.$b.' '.$a);
//       }

(from http://volumio.org/forum/volumio-mausberry-switch-t229.html#p2447)

How it works - technically

Here I'll try to describe in easy words how the parts are playing together. More detailed infos are shown in the installation section.

  1. First there is the software LIRC. It knows about

    • the infrared receiver connected to the computer (hardware.conf)
    • the codes the remote control sends (lircd.conf)

    and listens to the IR receiver all the time when started.

    In LIRC's configuration file lircd.conf there are the used remote control(s) defined.

    Shortened example:

    begin remote
    
      name  Pinnacle_RC1144201
      ...
    
          begin codes
              power                    0x6E2D
              menu                     0x6EE7
              mute                     0x6E1E
              stop                     0x6E2B
              play                     0x6ED1
              ...
    

    You can see the name of the RC and some of the known buttons.

  2. LIRC provides - beneath others - a simple program irexec.

    irexec is able to communicate with the above running lircd and gets infos about a pressed button.

    To know what to do with that button info it has a configuration file too: .lircrc.

    That configuration maps got button-presses to actions, for example starting a program.

    In my case I map all buttons to rcmpd - with an appropriate parameter to distinguish them.

    Shortened example:

    begin
        prog   = irexec
        remote = Pinnacle_RC1144201
        button = power
        config = /home/pi/bin/rcmpd power
        repeat = 0
    end
    
    begin
        prog   = irexec
        remote = Pinnacle_RC1144201
        button = pause
        config = /home/pi/bin/rcmpd pause
        repeat = 0
    end
    

    You can see the matching name of the RC and the matching buttons as well.

    So on every button press rcmpd gets called with the appropriate function as parameter.

    To get this working irexec needs to run in background and wait for button infos.

  3. Finally within rcmpd there is a mapping table from "button" to internal function where the commands are executed then:

    #-------------------------------------------------------------
    # The assignments of RC buttons to commands in this program.
    # Here you can do your "setup".
    #-------------------------------------------------------------
    
    MUTE|KEY_MUTE)            cmd_mute ;;
    VOL+|KEY_VOLUMEUP)        cmd_volume_up ;;
    VOL-|KEY_VOLUMEDOWN)      cmd_volume_down ;;
    
    PLAY|KEY_PLAY)            cmd_play ;;
    STOP|KEY_STOP)            cmd_stop ;;
    PAUSE|KEY_PAUSE)          cmd_pause ;;
    LOOP|KEY_MEDIA_REPEAT)    cmd_toggle_repeat ;;
    
    SKIP+|KEY_NEXT)           cmd_next_track ;;
    SKIP-|KEY_PREVIOUS)       cmd_previous_track ;;
    0|1|2|3|4|5|6|7|8|9)      cmd_digit $btn ;;
    KEY_0|KEY_1|KEY_2|KEY_3|KEY_4|KEY_5|KEY_6|KEY_7|KEY_8|KEY_9)  cmd_digit $btn ;;
    CH+|KEY_CHANNELUP)        cmd_next_playlist ;;
    CH-|KEY_CHANNELDOWN)      cmd_previous_playlist ;;
    A|B|C|KEY_A|KEY_B|KEY_C)  cmd_ABC $btn ;;
    
    REC|RECORD|KEY_RECORD)    cmd_record ;;
    
    MENU|KEY_MENU)            cmd_toggle_speech ;;
    
    EPG|KEY_EPG)              cmd_info_collection ;;  # of playlists
    D|KEY_D)                  cmd_info_playlist ;;    # current playlist
    BACK|KEY_BACK)            cmd_info_station ;;     # respective "album"
    FULLSCREEN|KEY_SCREEN)    cmd_info_track ;;
    PINNACLE)                 cmd_info_state ;;
    TV|KEY_TV)                cmd_info_time ;;
    
    POWER|KEY_POWER)          cmd_poweroff ;;
    #-------------------------------------------------------------
    

Some infos regarding LIRC on a Raspberry Pi

Install and configure LIRC for your RC

The following commands need the root authorizations. Easy to get here:

sudo bash

Install the packages:

apt-get install lirc

and do an initial test modul load:

modprobe lirc_rpi

(Note: Sorry, I had a typo here in earlier versions. lircd_rpi was wrong! lirc_rpi is correct.)

Then test the IR remote control:

mode2 -d /dev/lirc0

and press keys and watch the messages in your shell window...

Note: If lirc is already running in the background the above won't work and the following message will happen:

mode2: could not open /dev/lirc0
mode2: default_init(): Device or resource busy

In that case you might want to stop lirc:

/etc/init.d/lirc stop

Now check if there is already a LIRC configuration file for your RC, for example here: http://lirc.sourceforge.net/remotes

If it's not available for your RC: create a lircd.conf yourself (by recording button presses):

cd /etc/lirc
mv lircd.conf elsewhere
irrecord --list-namespace
irrecord -d /dev/lirc0 lircd.conf

Then start lirc:

/etc/init.d/lirc start

and test your RC again:

irw
# or
irw /dev/lircd

==> press keys and watch your shell window ...

Finally you might want to leave the root shell:

exit

Infos about Text-to-speech (TTS) with espeak or Google API