GitHub - jjba23/orpheus.el: orpheus.el - the Emacs music player

GitHub

8 min read Original article ↗

https://jointhefreeworld.org/ggg/dist/emacs-lisp.svg https://jointhefreeworld.org/ggg/dist/license-mit.svg

./docs/orpheus-logo.png

orpheus is the singer who could charm stones and rivers; this one charms a music daemon, or mpv, from inside Emacs.

./screenshots/orpheus-demo.gif

The six player themes, the media controls, every tab, four library views, the compact and cover layouts and the Ember and Ice visualizer ramps, recorded reproducibly with maak demo. Stills: Aegean, Nord, Gruvbox, Rosé Pine, Solarized Light, Graphite, cover and compact layouts, and the Ember and Ice ramps.

orpheus.el is a flexible music player for Emacs: a queue, a couple of tabs, a library, playlists, cover art, an equalizer you can shape with the mouse or the keyboard, lyrics that follow the music and a spectrum visualizer, with the keys Emacs fingers already know. MPD, local files, music on another machine and a Spotify account all appear in the same interface, and B switches between them without restarting Emacs.

New here? You do not need to learn everything at once. Pick the backend that matches where your music already lives, install its program, and run M-x orpheus. Press 2 for the files tab, RET to open a folder or play a track, and H whenever you want the map. The glossary explains every word below in plain language.

Everything orpheus does is asynchronous. Replies arrive in process filters and the status is read on a timer, so a slow server, a starting player or a hanging stream never blocks the editor. The SSH backend streams downloads straight to disk, runs a small queue with background prefetch and keeps recent tracks cached, so a slow link does not stop the interface. The list is read when something changed, not on every tick, so a queue of thousands costs nothing while it plays. The interface is text, so it is the same in a terminal, in a graphical frame and over SSH; in a frame that can draw, it adds cover art, an SVG visualizer and a small logo, and in one that cannot, nothing breaks. Six player themes, five visualizer ramps and four layouts are one key away, and the layout is a plain list when you want your own.

Documentation

The full guide lives in docs/. Start with the page that matches what you are doing; every page links back here and to its neighbours.

PageWhat it covers
Feature tourthe tabs, transfer queue, now-playing card, media keys, playlists, equalizer, lyrics and visualizer
How it worksthe backend seam, Mermaid diagrams, formats and the platform matrix
Cross-platform guidewhat works on Linux, macOS and Windows, what falls back, and what still needs a real machine
Using orpheusa working backend, MPD passwords, the keys and the graphical fallbacks
Words and ideasa friendly glossary of backends, queues, tabs, caches and the rest
Configurationevery option, its default and complete examples
BackendsMPD, local files, SSH, Spotify, the backend protocol and platform notes
Troubleshootingwhat to check when the player is silent, a password is rejected or a download stalls
Developmentthe gate, the test suites, the demo and the release

Install

From a checkout

(add-to-list 'load-path "/path/to/orpheus.el")
(require 'orpheus)

With straight.el

(straight-use-package
 '(orpheus :type git :host github :repo "jjba23/orpheus.el"))

With use-package

(use-package orpheus
  :load-path "/path/to/orpheus.el"
  :commands (orpheus orpheus-visualizer)
  :config
  (setq orpheus-backend 'mpd)
  (orpheus-mode-line-mode 1))

The package itself is Emacs Lisp. Each backend calls a program, and which machine that program lives on is the part worth checking:

ProgramWhereNeeded for
emacsthis computerEmacs 29.1 or newer
mpdthe machine running the daemonthe MPD backend
mpvthis computerthe local and SSH backends play through it
ffmpegthis computercovers, lyrics tags, and a disc track fetched as a range
ffmpegthe SSH hostcutting a disc track on the host when it has one
sshthis computerthe SSH backend
sftpthis computerthe SSH backend when the host’s shell cannot run cat
cavathis computerthe visualizer
Spotify appa device of yoursthe Spotify backend: it plays the music, orpheus controls it
yt-dlpthis computervideo links played by the local backend

Cue sheets need no program: a .cue beside an image is read in Emacs, and the local backend also reads the CUESHEET Vorbis comment inside a FLAC file (and falls back to its binary CUESHEET block for track boundaries). Library-wide search indexes those embedded sheets in the background, so a title is found without opening every FLAC on each search. The header line shows the run as indexing cues n/m; browsing a local FLAC reuses the same cache. M-u prunes cache entries for files that are gone or changed, M-U clears the index, and either command drops cached tab rows and covers. The local backend also watches the library, so changes made outside Emacs trigger the same invalidation. A missing ffmpeg on the SSH host does not mean copying the whole image: a track of a FLAC image is fetched as the byte range its seek table names, or estimated from the average bitrate when there is none, and cut here with this computer’s ffmpeg; ffprobe corrects an estimate. Only an image that cannot be planned that way is copied once, and every track of it plays from that copy. orpheus-ssh-split-images turns the range path off.

Audio and video are the common containers mpv opens: MP3, FLAC, Ogg and Opus, M4A and AAC, WAV, AIFF, WMA, ALAC, APE, WavPack, DSD, MIDI and more; MP4, MKV, WebM, AVI, MOV, MPEG and TS, FLV, WMV, VOB and 3GP among video. A video plays its sound only: mpv starts with --no-video. The list is orpheus-local-extensions; MPD uses the formats its daemon supports. How it works has the format table and the platform matrix.

Quick start

A daemon on this machine, reached over its socket:

(require 'orpheus)
(setq orpheus-backend 'mpd)
(setq orpheus-mpd-socket "~/.mpd/socket")
(orpheus)

The local backend needs no daemon:

(setq orpheus-backend 'local)
(setq orpheus-local-directory "~/Music")
(orpheus)                                  ; then 2 for the files tab, RET to play

A Spotify account is driven through its Web API, while Spotify plays on the phone, the desktop app or a small daemon of your choice:

(setq orpheus-backend 'spotify)
(setq orpheus-spotify-client-id "your apps client id")
;; once: M-x orpheus-spotify-login
(orpheus)                                  ; then p for playlists, RET to play

Playback control needs Premium and an active device; the Spotify notes walk through the app, the redirect URI and the sign-in.

Music on another machine is copied over ssh and played by mpv here:

(setq orpheus-backend 'ssh)
(setq orpheus-ssh-host "music.example.org")   ; or "me@music.example.org"
(setq orpheus-ssh-directory "Music")          ; nil starts in the login home
(orpheus)

The complete walkthrough, including MPD passwords, SSH keys and the queue’s behavior, is in Using orpheus. If you are not sure which backend fits, the backend chooser asks the question in plain language. For a quick answer without leaving the player, ? opens the menu and H opens the help buffer.

Why orpheus is built this way

orpheus keeps the interface and the music source apart. The queue, the tabs, the keys and the drawing do not know whether the music comes from a daemon on this machine, a folder of files, or another computer. That separation is what lets one player feel the same everywhere, and what makes a new backend a small, testable piece instead of a rewrite.

The backend is the seam.
The queue, the tabs, the keys and the drawing know nothing about MPD or mpv. They call orpheus-backend-status, orpheus-backend-browse and orpheus-backend-command; a new backend implements those and appears in the same interface, unchanged.
Nothing blocks.
No synchronously read socket and no shell-command-to-string in the path of the interface. MPD replies are parsed as they arrive, mpv speaks JSON over its IPC socket, the ssh backend’s listings and downloads are processes with sentinels, and cava’s frames are read by a filter while you keep typing.
One interface, two worlds.
Plain text, faces and a keymap. A terminal loses pictures and nothing else, and orpheus-ui-plain-ascii loses the Unicode for fonts that do not have it.
Platforms are the player’s problem.
MPD owns its audio output, and mpv picks PipeWire, CoreAudio or WASAPI. orpheus asks for the right one and stays out of the way; only the visualizer needs to know what the system captures with.
MIT, and no dependencies.
Emacs built-ins alone, including the SVG drawing. There is nothing to install for the package itself; the backend programs are tools you install separately.
Tested against real players.
The unit suite runs with no daemon at all (it starts a fake MPD on a loopback port), and the integration suite starts a real MPD and a real mpv and plays through them.

License

MIT. The full text is in LICENSE, and every source file carries an SPDX-License-Identifier: MIT line. History lives in NEWS.org.