#+TITLE: elmpd
#+DESCRIPTION: A tight, async mpd library in Emacs Lisp
#+DATE: <2026-06-19 Fri 14:04>
#+AUTHOR: sp1ff
#+EMAIL: sp1ff@pobox.com
#+AUTODATE: t
#+OPTIONS: toc:nil org-md-headline-style:setext *:t ^:nil

[[https://melpa.org/#/elmpd][file:https://melpa.org/packages/elmpd-badge.svg]]
[[https://stable.melpa.org/#/elmpd][file:https://stable.melpa.org/packages/elmpd-badge.svg]]
[[https://github.com/sp1ff/elmpd/workflows/melpazoid/badge.svg][file:https://github.com/sp1ff/elmpd/workflows/melpazoid/badge.svg]]

* Introduction

[[https://github.com/sp1ff/elmpd][elmpd]] is a tight, asynchronous, ergonomic [[https://www.musicpd.org/][MPD]] client library in Emacs Lisp.
* License

This package is released under the [[https://www.gnu.org/licenses/gpl-3.0.en.html][GPL v3]].
* Prerequisites

Emacs 25.1.
* Installing

The simplest way to install [[https://github.com/sp1ff/elmpd][elmpd]] is from [[https://melpa.org][MELPA]].

You can also install the package manually. Download the .tar file from [[https://github.com/sp1ff/elmpd/releases][Github]] or my personal [[https://www.unwoundstack/distros.html][page]] and say:

#+BEGIN_SRC elisp
  (package-install-file "elmpd-1.0.2.tar")
#+END_SRC

I'm now making GitHub releases that include Autotools source distributions:

#+BEGIN_SRC bash
curl -L --output elmpd-1.0.2.tar.gz https://github.com/sp1ff/elmpd/releases/download/1.0.2/elmpd-1.0.2.tar.gz  
tar xf elmpd-1.0.2.tar.gz && cd elmpd-1.0.2
./configure && make all check
sudo make install
#+END_SRC

And of course, you can just build from source:

#+BEGIN_SRC bash
git clone git@github.com:sp1ff/elmpd.git
cd elmpd
./bootstrap
./configure && make all check
sudo make install
#+END_SRC
* Getting Started

User documentation is provided with the package, and may also be found [[https://unwoundstack.com/doc/elmpd/curr][here]].
* Motivation & Design Philosphy

[[https://github.com/DamienCassou][Damien Cassou]], the author of [[https://github.com/mpdel/mpdel][mpdel]] and [[https://gitea.petton.fr/mpdel/libmpdel][libmpdel]], [[https://github.com/sp1ff/elmpd/issues/1][reached out]] to ask "Why elmpd?" His question prompted me to clarify my thoughts around this project & I've adapted my response here.

I've looked at a few [[https://www.musicpd.org/][MPD]] clients, including [[https://github.com/mpdel/mpdel][mpdel]]. As I fine-tuned my workflow, however, I found myself wanting _less_ functionality: rather than interacting with a fully-featured client, I just wanted to skip to the next song while I was editing code, for example. I customize my mode line heavily, and I wanted just a little bit of logic to add the current track to the mode line & keep it up-to-date. I have written a companion [[https://github.com/sp1ff/mpdpopm][daemon]] to MPD that maintains ratings & play counts; I just needed a little function that would let me rate the current track while I was reading mail, for instance.

My next move was to read through a number of client libraries for inspiration, both in C & Emacs Lisp. Many of them had strong opinions on how one should talk to MPD. Having been programming MPD for a while I had come to appreciate its simplicity (after all, one can program it from bash by simply =echo=-ing  commands to =/dev/tcp/$host/$port=). My experience with async Rust inspired me to see how simple I could make this. =elmpd= exports two primary functions: [[https://unwoundstack.com/doc/elmpd/curr#index-elmpd_002dconnect][elmpd-connect]] & [[https://unwoundstack.com/doc/elmpd/curr#index-elmpd_002dsend][elmpd-send]]. Each connection consumes a socket & optionally a callback-- that's it; no buffer, no transaction queue. Put another way, if other libraries are Gnus (featureful, encourages you to read your e-mail in a certain way), then elmpd is [[https://mailutils.org/][Mailutils]] (small utilities that leave it up to the user to assemble them into something useful).
* Status & Roadmap

The package has been stable for a few years now, so as of  September 2024 I'm calling this "1.0". It's ripe for being used to build up a more caller-friendly API: something like =(play)= instead of

#+BEGIN_SRC elisp
  (let ((conn (elmpd-connect)))
    (elmpd-send conn "play"))
#+END_SRC

I've written a separate package, [[https://github.com/mpdmacs][mpdmacs]], that hopefully does so in a generic way.

I gave a [[https://www.youtube.com/watch?v=PxJDsq2apyo][talk]] on this at [[https://emacsconf.org/][EmacsConf]] in 2022.

Comments, suggestions & bug reports welcome in the [[https://github.com/sp1ff/elmpd/issues][issues]] or at sp1ff@pobox.com.
