Playing Music with Mopidy and Ncmpcpp

12 minute read Published:

Learn. Unlearn. Relearn.
Table of Contents


Maybe you’re stumped as to how to access that massive music collection painlessly, and a have a fear of missing out on the latest mixtapes and radio streams on the internet.


Why use Mopidy-MPD and Ncmpcpp? The answer is the reason we use Linux in the first place; for it’s elegance and configurability. The time spent learning is often richly rewarding in unexpected ways.

MPD stands for Music Player Daemon, which is also the name of the original MPD server project. Mopidy does not depend on the original MPD server, but implements the MPD protocol itself, and is thus compatible with most clients built for the original MPD server ~https://github.com/mopidy/mopidy-mpd

By default Mopidy is a http server, it ships ready to leverage audio content on the web. Think client and daemon. Mopidy-MPD puts the MPD back in MoPiDy and allows us to use one of the many MPD user interfaces to play tunes on our laptop. The beauty of using a Raspberry Pi for this type of deployment, is because it is light on resources, freeing your devices up for other work.


Mopidy is fertile ground for hacking with Python, JavaScript, and JSON-RPC APIs as well as the extension support. Mopidy 3.0 was released in Dec ‘19 just in time for the projects’ 10th anniversary. It was comprehensively restructured, leaving Python 2 behind to be supported by minimum of Python 3.7. This means it can leverage some great new features in gstreamer 1.14. Mopidy’s creator, Stein Magnus Jodal explains the origin story.


Mopidy on a Raspberry Pi is a natural fit for the diminutive device. You can use your phone as a controller with mopidy-mobile or even wire arcade buttons to the GPIO pins with a 16x2 Adafruit LCD display using only pre-built extensions.


My Solar/Wind Powered Raspberry Pi Ex-Grandfather's Clock

Installation

Mopidy and ncmpcpp can be installed on Linux, Mac (with brew) or Windows Subsystem for Linux (WSL2). For a Debian-based distro:

wget -q -O - https://apt.mopidy.com/mopidy.gpg | sudo apt-key add -
sudo wget -q -O /etc/apt/sources.list.d/mopidy.list https://apt.mopidy.com/buster.list
sudo apt update
sudo apt install mopidy ncmpcpp mopidy-mpd mopidy-local mopidy-alsamixer mopidy-internetarchive mopidy-podcast mopidy-podcast-itunes mopidy-somafm mopidy-soundcloud  mopidy-tunein

To avoid port conflicts, remove plain old MPD if it’s installed.

sudo apt remove mpd

We can just type mopidy to run it, however it is generally preferred to run it as a service. My approach is usually to stumble along in the fog of uncertainty, so I was delighted to discover answers to some burning questions laid out in the docs (MacOS users are covered too).


For Debian, run

sudo dpkg-reconfigure mopidy


Package Configuration

For other Linux distros using systemd such as Fedora and Arch

sudo systemctl enable mopidy

This means we can use systemd control commands, handy when applying configuration changes. Running as a service, Mopidy will no longer refer to ~/.config/mopidy/mopidy.conf (it was created if you ran the mopidy command). The service uses a barebones /etc/mopidy/mopidy.conf (created on installation) to add usernames and passwords, and for custom extension settings that will work in concert to override the system defaults.


Configuration Starter File

The following Mopidy subcommand will list out the current configuration values to your terminal, and also warns of any errors.

sudo mopidyctl config

This is what I’ve got in mine


Expand my /etc/mopidy/mopidy.conf
[core]
cache_dir = /var/cache/mopidy
config_dir = /etc/mopidy
data_dir = /var/lib/mopidy

[logging]
config_file = /etc/mopidy/logging.conf
debug_file = /var/log/mopidy/mopidy-debug.log

[local]
media_dir = /home/briain/media/music

[m3u]
playlists_dir = /var/lib/mopidy/playlists

[mpd]
hostname = ::
# Helps toavoid timeout errors for large amounts of files
connection_timeout = 300

[audio]
output = tee name=t t. ! queue ! autoaudiosink t. ! queue ! audioresample ! audioconvert ! audio/x-raw,rate=44100,channels=2,format=S16LE ! wavenc ! filesink location=/tmp/mpd.fifo
## TODO: following will make localhost:5555 
## available as a source of data for the 
## stereo visualizer without the fifo hack.
# output = tee name=t ! queue ! autoaudiosink t.  ! queue ! audio/x-raw,rate=44100,channels=2,format=S16LE ! udpsink host=localhost port=6600
mixer_volume = 70

[file]
media_dirs = /home/briain/media/music
#follow_symlinks = false
#metadata_timeout = 1000

[podcast]
enabled = true
browse_root = /var/lib/mopidy/media/podcasts.opml

[youtube]
#enabled = true
musicapi_enabled = true

#[ytmusic]
#enabled = true

[scrobbler]
#enabled = true
username = *******
password = *******************

[soundcloud]
enabled = true
explore_songs = 45
auth_token = ********************

The config file is only read when Mopidy starts and so you must restart for any configuration change to take effect.

sudo systemctl restart mopidy

An alternate command also works for us Debian users

sudo service mopidy restart

NCurses Music Player Client (Plus Plus)

Ncmpcpp is a rewrite of Ncmpc in C++. It provides new useful features such as support for regular expressions for library searches, extended song format, items filtering, the ability to sort playlists, and a local filesystem browser. It has been my music player of choice for many years. Terminal-based ncurses programs are easy on the eye by setting your ideal keycommands, font-size and colorscheme.

Ncurses stands for new curses and first emerged in 1993. Curses is a terminal control library for Unix-like systems (going back to 1980), enabling the construction of text user interface (TUI) applications. The name is pun on the term “cursor [curser] optimization”. Curses-based software can have a lighter resource footprint and operate on a wider range of systems (both in terms of hardware and software) than their GUI-based counterparts. ~Wikipedia


Example configuration files reside in /usr/share/doc/ncmpcpp/examples and can be copied over. I can share what I’ve got in mine


Expand my ~/.ncmpcpp/config
mpd_music_dir = "/home/user/media/music"
lyrics_directory  = "/home/user/.ncmpcpp/lyrics"
ncmpcpp_directory  = "/home/user/.ncmpcpp"
mpd_host = "localhost"
mpd_port = "6600"
# mpd_connection_timeout = "5"
mpd_crossfade_time = "3"

## Playlist ## 
playlist_disable_highlight_delay = "1"
#playlist_display_mode = "columns"
playlist_display_mode = "classic"
playlist_show_remaining_time = "yes"
browser_display_mode = "columns"
autocenter_mode = "yes"
fancy_scrolling = "yes"
follow_now_playing_lyrics = "yes"
display_screens_numbers_on_start = "yes"
ignore_leading_the = "yes"
lyrics_database = "1"
song_columns_list_format = "(10)[blue]{l} (30)[green]{a} (30)[magenta]{b} (50)[yellow]{t}"
#[global]
colors_enabled = "yes"
enable_window_title = "yes"
external_editor = "nvim"

#main_window_highlight_color = "green"
volume_color = "red"
#progressbar_color = "black"
progressbar_color = "cyan"
statusbar_color = "default"
#statusbar_color = "white"
active_window_border = "red"
alternative_header_first_line_format = "$0$aqqu$/a {$7%a - $9}{$5%t$9}|{$8%f$9} $0$atqq$/a$9"
alternative_header_second_line_format = "{{$6%b$9}{ [$6%y$9]}}|{%D}"
alternative_header_second_line_format = "{{$6%b$9}{ [$6%y$9]}}"
song_list_format = "{$3%n │ $9}{$7%a - $9}{$5%t$9}|{$8%f$9}$R{$6 │ %b$9}{$3 │ %l$9}"
#user_interface = "alternative"
user_interface = "classic"
default_place_to_search_in = "database"

## Visualizer ##

## Fifo may be depreciated but I still use it (shrugs).
## Details in ncmpcpp example conf re: an address of  
## udpsink gstreamer's output instead of fifo
visualizer_fifo_path = "/tmp/mpd.fifo"
visualizer_output_name = "my_fifo"
# Depreciated, will be removed in version .10
visualizer_sync_interval = "30"
# Can be ellipse, wave or spectrum
visualizer_type = "ellipse" (spectrum/wave)
visualizer_in_stereo = "yes"
#visualizer_look = "+|"
#visualizer_look = "●┃"
#visualizer_color = "default"
visualizer_color = 41, 83, 119, 155, 185, 215, 209, 203, 197, 161

## Navigation ##
cyclic_scrolling = "no"
header_text_scrolling = "no"
jump_to_now_playing_song_at_start = "yes"
lines_scrolled = "0"

## Other ##
system_encoding = "utf-8"
regular_expressions = "extended"

## Selected tracks ##
selected_item_prefix = "* "
discard_colors_if_item_is_selected = "yes"

## Seeking ##
incremental_seeking = "yes"
seek_time = "13"

## Visibility ##
header_visibility = "yes"
statusbar_visibility = "yes"
#statusbar_visibility = "no"
titles_visibility = "yes"

[statusbar]
#progressbar_look = "─╼ "
progressbar_look =  "=>-"
#progressbar_elapsed_color = "white"

# Misc
now_playing_prefix = "$b$5"
now_playing_suffix = "$/b$9"
song_status_format = " $2%a $4⟫$3⟫ $8%t $4⟫$3⟫ $5%b "
autocenter_mode = "yes"
centered_cursor = "yes"
display_bitrate = "yes"
follow_now_playing_lyrics = "yes"
ignore_leading_the = "yes"
empty_tag_marker = ""
allow_for_physical_item_deletion = yes
execute_on_song_change = notify-send "Now Playing ♫" "$(mpc current)"

[library]
empty_tag_color = "black"

The program is run from the commandline.

ncmpcpp

Getting Started

Pressing 2 will take you to the browse screen. Press enter to open a directory. Enter will also queue up and play a track if the cursor is on one. Backspace to go to the parent directory. Space will load an entire directory into the current playlist.


The Browse Screen

Help Page

Pressing F1 will show the defaults as well as your customized key commands. Arrow keys and page up/down are the defaults for scrolling/paging.


Ncmpcpp Help Page

Customizing Bindings

Adding keyboard shortcuts, or changing existing ones to be more Vim-like. Change and add keybindings to actions in ~/.ncmpcpp/bindings. The example bindings file documents that you can bind chains of actions and create macros of commands and filters.


Ncmpcpp Key Bindings

Expand my ~/.ncmpcpp/bindings
## Additional to the defaults in example file
def_key "j"
    scroll_down
def_key "k"
    scroll_up
def_key "d"
    page_down
def_key "u"
    page_up
def_key "ctrl-f"
    page_down
def_key "ctrl-b"
    page_up
def_key "n"
    next
def_key "P"
    previous
def_key "space"
    next
def_key "backspace"
    previous
def_key "left"
    seek_backward
def_key "right"
    seek_forward
def_key "H"
    show_playlist
def_key "h"
    jump_to_parent_directory
def_key "h"
    previous_column
def_key "l"
    enter_directory
def_key "l"
    play_item
def_key "l"
    next_column
def_key "l"
    run_action
def_key "ctrl-a"
    add_item_to_playlist
def_key "J"
    select_item
def_key "K"
    select_item
def_key "ctrl-e"
    move_end
def_key "t"
    move_home
def_key "down"
    scroll_down
def_key "up"
    scroll_up
def_key "shift-up"
    move_selected_items_up
def_key "N"
    move_sort_order_down
def_key "shift-down"
    move_selected_items_down
def_key "F"
    apply_filter
def_key "*"
    toggle_visualization_type
def_key "L"
    show_lyrics
def_key "C"
    toggle_playing_song_centering
def_key "+"
    show_clock
def_key "="
    volume_up
    

Global Shortcuts

Set global shortcuts in your desktop settings to run mpc commands from within any application, so you don’t have to change track to change the track. My most used are: toggle play/pause (mpc toggle), skip ahead (mpc seek +7%), change tracks (mpc next) and toggle random mode (mpc random).


The ability to delete a song from the hard drive is critical for shaping a collection. Make the following script executable with chmod u+x delete_song.sh. You can trigger it with a global shortcut. Found on KDE at System Settings -> Shortcuts -> Custom Shortcuts.


Expand delete_song.sh
#!/bin/bash

##TODO: Fine-tune this script for mopidy.
## It was working fine for mpd but mopidy 
## has some other way of aliasing files. 
## I tweaked the sed regex, and it's close to 
## working. Feel free to post a fix in the comments section 
## https://www.digitalneanderthal.com/post/ncmpcpp/
## or email briainodriscoll@gmail.com
song_to_remove=$(mpc | head -n 1)
playlist_pos=$(mpc -f %position% | head -n 1)
## Move the song into ~/.trash 
mv "$(mpc -f %file% | head -n 1 | sed 's/.*\/.\//\//')" ~/.trash
## Better still, delete the song completely
# rm "$(mpc -f %file% | head -n 1 | 's/.*\/.\//\//')"
## Remove the song from playlist
mpc del $playlist_pos
## Write to log file
echo "[`date`] -> --$song_to_remove-- gone to trash..." >> ~/.mpdremove.log

Plugins

Core extensions are available from the system package manager. Dozens of others are available on PyPI and Github. Documentation on Github is often more complete. Somafm, Mixcloud, Internet Archive, Youtube Music and Itunes Podcasts are ready to use out-of-the-box


Aptitude Package Manager

Local Music

Set the location in /etc/mopidy/mopidy.conf

[local]
media_dir = /home/username/media/music

To index your music collection.

sudo mopidyctl local scan

TuneIn

TuneIn has thousands of free stations. Some favourites on a 5V 9” display. Pressing 1 takes you to the playlist screen.


Favorites Playlist

Youtube Music

Youtube Music presents curated playlists (as does the iTunes Podcast directory).

sudo python3 -m pip install Mopidy-YTMusic

Add the following to /etc/mopidy/mopidy.conf

[youtube]
musicapi_enabled = true

Playlist Categories

By default you are connected to YouTube Music as a guest account with several hundred playlists of 50-100 tracks. Connecting to your account will give you even more options.


If the links become unresponsive, flush the cache like so

sudo python3 -m pip install --force-reinstall --no-cache-dir Mopidy-YTMusic

Podcasts

To use our own podcasts.opml file that you have exported from antennapod, gpodder or some other podcast client:

[podcast]
#enabled = true
browse_root = /var/lib/mopidy/media/podcasts.opml

Commented options (lines starting with #) represent the defaults. Uncomment and change to false to remove the option from the Browse page (or else uninstall).

Authentication

Google Play and Spotify require paid accounts (the free version doesn’t work). Others like Soundcloud can be connected via the extensions’ documentation page (you need to be currently signed in). An authorization token will be generated and there are instructions there on how to add it to /etc/mopidy/mopidy.conf


Connecting Soundcloud with MoPiDy

Autoplay

Your music can start as soon as your computer boots. From the docs:

Automatically pick up where you left off and start playing the last track from the position before Mopidy was shut down. It also restores the tracklist options “Consume”, “Random”, “Repeat” and “Single”. It also remembers the volume and if Mopidy was muted. The exact behaviour is configurable, e.g. it is possible to force Mopidy to play a certain track or to start always unmuted.

sudo python3 -m pip install mopidy-autoplay

Search Engine

Searching will trawl through your extensions for tracks, albums, podcasts, mixtapes, streams and live recordings. Pressing 3 will get you there. Scroll your cursor to the relevant field(s), press enter and a text input box will appear at the bottom of the screen, enter. Scroll down to search and press enter. Same goes for reset


Search Screen

Music Visualization

For the visualizer, set the audio output in /etc/mopidy/mopidy.conf

[audio]
output = tee name=t t. ! queue ! autoaudiosink t. ! queue ! audioresample ! audioconvert ! audio/x-raw,rate=44100,channels=2,format=S16LE ! wavenc ! filesink location=/tmp/mpd.fifo
mixer_volume = 70

Configure the colors and layouts in ~/.ncmpcpp/config

#### Visualizer ####
visualizer_fifo_path = "/tmp/mpd.fifo"
visualizer_output_name = "my_fifo"
## visualizer_type can be spectrum, wave, or ellipse
visualizer_type = "ellipse" (spectrum/wave)
visualizer_color = 41, 83, 119, 155, 185, 215, 209, 203, 197, 161


Press 8 for the Visualization screen

Troubleshooting

To save a debug log to file for sharing with others, you can pipe stdout and stderr to a file:

mopidy -vv 2>&1 | tee mopidy.log

The following few commands can also assist with troubleshooting

systemctl status mopidy
sudo mopidyctl deps
sudo journalctl -u mopidy
Expand for random troubleshooting
I ran into problems scanning the local music 
but later discovered that it was because I had 
removed the contents of the original /etc/mopidy/mopidy.conf 
and had replaced it with the contents of i
~/.config/mopidy/mopidy.conf when I changed over 
to running as a service.  Not too swift!

Running `sudo mopidyctl deps` warned that the 
read permission was missing from `/etc/mopidy/mopidy.conf` 
and that it failed to load. Normally the 
[postinstallation script](https://salsa.debian.org/mopidy-team/mopidy/-/blob/debian/master/debian/mopidy.postinst#L12-22) 
sets it up correctly. However, the following command 
is what fixed it for me at the time. N.B. these steps are 
not required on a standard installation, however you 
could run into OS specific problems such as on PiMusicBox 
(plain Mopidy will give you less headaches). 

sudo chown mopidy /etc/mopidy/mopidy.conf

From the [docs](https://docs.mopidy.com/en/latest/running/service/) 
"The Mopidy system service runs as the mopidy user, which is 
automatically created when you install the Mopidy package. 
The mopidy user will need `read access` to any 
local music you want Mopidy to play."

If your having issues with your `read access`, try 
adding the `mopidy` user to your username's group 

`sudo usermod -aG briain mopidy`
`sudo mopidyctl local scan`

If the scan still doesn't work, grant ownership 
of the `audio` group the to the `mopidy` user 

`sudo chown --recursive mopidy:audio /home/username/media/music`


The system is very robust and shouldn’t require much attention beyond committing the keystrokes to muscle memory 🎸 🎶 🕰 🎶 🌃


Support is available on the Discourse forum and Zulip chat.


FYI: Mopidy-MPD is currently looking for a new maintainer.




comments powered by Disqus