emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/emms e102891 4/4: move all files to top-level


From: Yoni Rabkin
Subject: [elpa] externals/emms e102891 4/4: move all files to top-level
Date: Sun, 7 Jun 2020 22:02:35 -0400 (EDT)

branch: externals/emms
commit e102891fb3bbb3fec134b5c678a0dd2306b9beaf
Author: Yoni Rabkin <yoni@rabkins.net>
Commit: Yoni Rabkin <yoni@rabkins.net>

    move all files to top-level
---
 Makefile                                           |   41 +-
 doc/developer-release.txt                          |    2 +-
 emms-auto.el                                       |  562 +++++++
 lisp/emms-auto.in => emms-auto.in                  |    0
 lisp/emms-bookmarks.el => emms-bookmarks.el        |    0
 lisp/emms-browser.el => emms-browser.el            |    0
 lisp/emms-cache.el => emms-cache.el                |    0
 lisp/emms-compat.el => emms-compat.el              |    0
 lisp/emms-cue.el => emms-cue.el                    |    0
 lisp/emms-history.el => emms-history.el            |    0
 lisp/emms-i18n.el => emms-i18n.el                  |    0
 lisp/emms-info-libtag.el => emms-info-libtag.el    |    0
 .../emms-info-metaflac.el => emms-info-metaflac.el |    0
 lisp/emms-info-mp3info.el => emms-info-mp3info.el  |    0
 lisp/emms-info-ogginfo.el => emms-info-ogginfo.el  |    0
 .../emms-info-opusinfo.el => emms-info-opusinfo.el |    0
 lisp/emms-info-tinytag.el => emms-info-tinytag.el  |    0
 lisp/emms-info.el => emms-info.el                  |    0
 lisp/emms-last-played.el => emms-last-played.el    |    0
 ...brefm-scrobbler.el => emms-librefm-scrobbler.el |    0
 ...mms-librefm-stream.el => emms-librefm-stream.el |    0
 lisp/emms-lyrics.el => emms-lyrics.el              |    0
 lisp/emms-maint.el => emms-maint.el                |    0
 lisp/emms-mark.el => emms-mark.el                  |    0
 ...taplaylist-mode.el => emms-metaplaylist-mode.el |    0
 ...mms-mode-line-icon.el => emms-mode-line-icon.el |    0
 lisp/emms-mode-line.el => emms-mode-line.el        |    0
 lisp/emms-player-mpd.el => emms-player-mpd.el      |    0
 ...pg321-remote.el => emms-player-mpg321-remote.el |    0
 ...mms-player-mplayer.el => emms-player-mplayer.el |    0
 lisp/emms-player-mpv.el => emms-player-mpv.el      |    0
 .../emms-player-simple.el => emms-player-simple.el |    0
 lisp/emms-player-vlc.el => emms-player-vlc.el      |    0
 lisp/emms-player-xine.el => emms-player-xine.el    |    0
 lisp/emms-playing-time.el => emms-playing-time.el  |    0
 ...mms-playlist-limit.el => emms-playlist-limit.el |    0
 .../emms-playlist-mode.el => emms-playlist-mode.el |    0
 .../emms-playlist-sort.el => emms-playlist-sort.el |    0
 lisp/emms-score.el => emms-score.el                |    0
 lisp/emms-setup.el => emms-setup.el                |    0
 lisp/emms-show-all.el => emms-show-all.el          |    0
 lisp/emms-source-file.el => emms-source-file.el    |    0
 ...s-source-playlist.el => emms-source-playlist.el |    0
 lisp/emms-stream-info.el => emms-stream-info.el    |    0
 lisp/emms-streams.el => emms-streams.el            |    0
 lisp/emms-tag-editor.el => emms-tag-editor.el      |    0
 lisp/emms-url.el => emms-url.el                    |    0
 .../emms-volume-amixer.el => emms-volume-amixer.el |    0
 ...s-volume-mixerctl.el => emms-volume-mixerctl.el |    0
 lisp/emms-volume-pulse.el => emms-volume-pulse.el  |    0
 lisp/emms-volume.el => emms-volume.el              |    0
 emms.el                                            | 1528 ++++++++++++++++++-
 lisp/jack.el => jack.el                            |    0
 lisp/later-do.el => later-do.el                    |    0
 lisp/Makefile                                      |   28 -
 lisp/emms.el                                       | 1539 --------------------
 56 files changed, 2107 insertions(+), 1593 deletions(-)

diff --git a/Makefile b/Makefile
index 5e5dfc6..698d3b5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,14 @@
 GZIP=gzip
 MAN1PAGES=emms-print-metadata.1
 DOCDIR=doc/
-LISPDIR=lisp
 SRCDIR=src
+SITEFLAG=--no-site-file
+EMACS=emacs
 
-ALLSOURCE=$(wildcard $(LISPDIR)/*.el)
-ALLCOMPILED=$(wildcard $(LISPDIR)/*.elc)
+ALLSOURCE=$(wildcard *.el)
+SOURCE=$(filter-out $(SPECIAL),$(ALLSOURCE))
+TARGET=$(patsubst %.el,%.elc,$(SOURCE))
+ALLCOMPILED=$(wildcard *.elc)
 
 DESTDIR=
 PREFIX=$(DESTDIR)/usr/local
@@ -20,17 +23,25 @@ INSTALLINFO = /usr/bin/install-info --info-dir=$(INFODIR)
 CHANGELOG_CMD = git log --pretty=medium --no-merges
 
 # The currently released version of EMMS
-VERSION=5.4
+VERSION=5.41
 
-.PHONY: all install lisp docs deb-install clean
+.PHONY: all install docs clean
 .PRECIOUS: %.elc
-all: lisp docs
-
-autoloads:
-       $(MAKE) -C $(LISPDIR) emms-auto.el
-
-lisp:
-       $(MAKE) -C $(LISPDIR)
+all: emms-auto.el $(TARGET) docs
+
+emms-auto.el: emms-auto.in $(SOURCE)
+       cp emms-auto.in emms-auto.el
+       -rm -f emms-auto.elc
+       @$(EMACS) -q $(SITEFLAG) -batch \
+               -l emms-maint.el \
+               -l emms-auto.el \
+               -f emms-generate-autoloads \
+               $(shell pwd)/emms-auto.el .
+
+%.elc: %.el
+       @$(EMACS) -q $(SITEFLAG) -batch \
+               -l emms-maint.el \
+               -f batch-byte-compile $<
 
 docs:
        $(MAKE) -C $(DOCDIR)
@@ -70,13 +81,13 @@ ChangeLog:
 
 clean:
        -rm -f *~ $(DOCDIR)emms.info $(DOCDIR)emms.html 
$(SRCDIR)/emms-print-metadata
-       $(MAKE) -C $(LISPDIR) clean
+       -rm -f *~ *.elc emms-auto.el
 
-dist: clean autoloads
+dist: clean emms-auto.el
        git archive --format=tar --prefix=emms-$(VERSION)/ HEAD | \
          (cd .. && tar xf -)
        rm -f ../emms-$(VERSION)/.gitignore
-       cp lisp/emms-auto.el ../emms-$(VERSION)/lisp
+       cp emms-auto.el ../emms-$(VERSION)
        $(CHANGELOG_CMD) > ../emms-$(VERSION)/ChangeLog
 
 release: dist
diff --git a/doc/developer-release.txt b/doc/developer-release.txt
index 4453a6a..65fc8ab 100644
--- a/doc/developer-release.txt
+++ b/doc/developer-release.txt
@@ -1,7 +1,7 @@
 This file tries to list the things people have to do before they do a
 release.
 
-*  Increase the version number in emms.el (variable, elpa header), Makefile, 
and emms-elpa.el
+*  Increase the version number in emms.el (variable, elpa header), Makefile
 
 *  Update NEWS
 
diff --git a/emms-auto.el b/emms-auto.el
new file mode 100644
index 0000000..2ee5831
--- /dev/null
+++ b/emms-auto.el
@@ -0,0 +1,562 @@
+;;; -*-emacs-lisp-*-
+
+(defvar generated-autoload-file)
+(defvar command-line-args-left)
+(defun emms-generate-autoloads ()
+  (interactive)
+  (require 'autoload)
+  (setq generated-autoload-file (car command-line-args-left))
+  (setq command-line-args-left (cdr command-line-args-left))
+  (batch-update-autoloads))
+
+(add-to-list 'load-path (directory-file-name
+                        (or (file-name-directory load-file-name)
+                            (car load-path))))
+
+(provide 'emms-auto)
+;;; Generated autoloads follow (made by autoload.el).
+
+;;;### (autoloads nil "emms" "emms.el" (0 0 0 0))
+;;; Generated autoloads from emms.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms" '("define-emms-" "emms-" "with-current-emms-playlist")))
+
+;;;***
+
+;;;### (autoloads nil "emms-browser" "emms-browser.el" (0 0 0 0))
+;;; Generated autoloads from emms-browser.el
+
+(autoload 'emms-browser "emms-browser" "\
+Launch or switch to the EMMS Browser." t nil)
+
+(autoload 'emms-smart-browse "emms-browser" "\
+Display browser and playlist.
+Toggle between selecting browser, playlist or hiding both. Tries
+to behave sanely if the user has manually changed the window
+configuration." t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-browser" '("case-fold-string" "emms-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-cache" "emms-cache.el" (0 0 0 0))
+;;; Generated autoloads from emms-cache.el
+
+(autoload 'emms-cache-enable "emms-cache" "\
+Enable caching of Emms track data." t nil)
+
+(autoload 'emms-cache-disable "emms-cache" "\
+Disable caching of Emms track data." t nil)
+
+(autoload 'emms-cache-toggle "emms-cache" "\
+Toggle caching of Emms track data." t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-cache" '("emms-cache")))
+
+;;;***
+
+;;;### (autoloads nil "emms-compat" "emms-compat.el" (0 0 0 0))
+;;; Generated autoloads from emms-compat.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-compat" '("emms-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-cue" "emms-cue.el" (0 0 0 0))
+;;; Generated autoloads from emms-cue.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-cue" '("emms-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-history" "emms-history.el" (0 0 0 0))
+;;; Generated autoloads from emms-history.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-history" '("emms-history-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-i18n" "emms-i18n.el" (0 0 0 0))
+;;; Generated autoloads from emms-i18n.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-i18n" '("emms-i18n-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-info" "emms-info.el" (0 0 0 0))
+;;; Generated autoloads from emms-info.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-info" '("emms-info-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-info-libtag" "emms-info-libtag.el" (0
+;;;;;;  0 0 0))
+;;; Generated autoloads from emms-info-libtag.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-info-libtag" '("emms-info-libtag")))
+
+;;;***
+
+;;;### (autoloads nil "emms-info-metaflac" "emms-info-metaflac.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-info-metaflac.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-info-metaflac" '("emms-info-metaflac")))
+
+;;;***
+
+;;;### (autoloads nil "emms-info-mp3info" "emms-info-mp3info.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-info-mp3info.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-info-mp3info" '("emms-info-mp3")))
+
+;;;***
+
+;;;### (autoloads nil "emms-info-ogginfo" "emms-info-ogginfo.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-info-ogginfo.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-info-ogginfo" '("emms-info-ogginfo")))
+
+;;;***
+
+;;;### (autoloads nil "emms-info-opusinfo" "emms-info-opusinfo.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-info-opusinfo.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-info-opusinfo" '("emms-info-opusinfo")))
+
+;;;***
+
+;;;### (autoloads nil "emms-info-tinytag" "emms-info-tinytag.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-info-tinytag.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-info-tinytag" '("emms-info-tinytag")))
+
+;;;***
+
+;;;### (autoloads nil "emms-last-played" "emms-last-played.el" (0
+;;;;;;  0 0 0))
+;;; Generated autoloads from emms-last-played.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-last-played" '("emms-last-played-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-librefm-scrobbler" "emms-librefm-scrobbler.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-librefm-scrobbler.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-librefm-scrobbler" '("emms-librefm-scrobbler-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-librefm-stream" "emms-librefm-stream.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-librefm-stream.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-librefm-stream" '("emms-librefm-stream")))
+
+;;;***
+
+;;;### (autoloads nil "emms-lyrics" "emms-lyrics.el" (0 0 0 0))
+;;; Generated autoloads from emms-lyrics.el
+
+(autoload 'emms-lyrics-enable "emms-lyrics" "\
+Enable displaying emms lyrics." t nil)
+
+(autoload 'emms-lyrics-disable "emms-lyrics" "\
+Disable displaying emms lyrics." t nil)
+
+(autoload 'emms-lyrics-toggle "emms-lyrics" "\
+Toggle displaying emms lyrics." t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-lyrics" '("emms-lyrics")))
+
+;;;***
+
+;;;### (autoloads nil "emms-mark" "emms-mark.el" (0 0 0 0))
+;;; Generated autoloads from emms-mark.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-mark" '("emms-mark-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-metaplaylist-mode" "emms-metaplaylist-mode.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-metaplaylist-mode.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-metaplaylist-mode" '("emms-metaplaylist-mode")))
+
+;;;***
+
+;;;### (autoloads nil "emms-mode-line" "emms-mode-line.el" (0 0 0
+;;;;;;  0))
+;;; Generated autoloads from emms-mode-line.el
+
+(autoload 'emms-mode-line-enable "emms-mode-line" "\
+Turn on `emms-mode-line'." t nil)
+
+(autoload 'emms-mode-line-disable "emms-mode-line" "\
+Turn off `emms-mode-line'." t nil)
+
+(autoload 'emms-mode-line-toggle "emms-mode-line" "\
+Toggle `emms-mode-line'." t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-mode-line" '("emms-mode-line")))
+
+;;;***
+
+;;;### (autoloads nil "emms-mode-line-icon" "emms-mode-line-icon.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-mode-line-icon.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-mode-line-icon" '("emms-mode-line-icon-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-player-mpd" "emms-player-mpd.el" (0 0
+;;;;;;  0 0))
+;;; Generated autoloads from emms-player-mpd.el
+
+(autoload 'emms-player-mpd-clear "emms-player-mpd" "\
+Clear the MusicPD playlist." t nil)
+
+(autoload 'emms-player-mpd-connect "emms-player-mpd" "\
+Connect to MusicPD and retrieve its current playlist.
+
+Afterward, the status of MusicPD will be tracked.
+
+This also has the effect of changing the current EMMS playlist to
+be the same as the current MusicPD playlist.  Thus, this
+function is useful to call if the contents of the EMMS playlist
+buffer get out-of-sync for some reason." t nil)
+
+(autoload 'emms-player-mpd-show "emms-player-mpd" "\
+Describe the current EMMS track in the minibuffer.
+
+If INSERTP is non-nil, insert the description into the current
+buffer instead.
+
+If CALLBACK is a function, call it with the current buffer and
+description as arguments instead of displaying the description or
+inserting it.
+
+This function uses `emms-show-format' to format the current track.
+It differs from `emms-show' in that it asks MusicPD for the current track,
+rather than EMMS.
+
+\(fn &optional INSERTP CALLBACK)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-player-mpd" '("emms-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-player-mpg321-remote" 
"emms-player-mpg321-remote.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-player-mpg321-remote.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-player-mpg321-remote" '("emms-player-mpg321-remote")))
+
+;;;***
+
+;;;### (autoloads nil "emms-player-mplayer" "emms-player-mplayer.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-player-mplayer.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-player-mplayer" '("emms-player-mplayer-" "mplayer")))
+
+;;;***
+
+;;;### (autoloads nil "emms-player-mpv" "emms-player-mpv.el" (0 0
+;;;;;;  0 0))
+;;; Generated autoloads from emms-player-mpv.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-player-mpv" '("emms-player-mpv")))
+
+;;;***
+
+;;;### (autoloads nil "emms-player-simple" "emms-player-simple.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-player-simple.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-player-simple" '("alsaplayer" "define-emms-simple-player" "emms-player-" 
"fluidsynth" "mikmod" "mpg321" "ogg123" "playsound" "speexdec" "timidity")))
+
+;;;***
+
+;;;### (autoloads nil "emms-player-vlc" "emms-player-vlc.el" (0 0
+;;;;;;  0 0))
+;;; Generated autoloads from emms-player-vlc.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-player-vlc" '("emms-player-vlc-" "vlc")))
+
+;;;***
+
+;;;### (autoloads nil "emms-player-xine" "emms-player-xine.el" (0
+;;;;;;  0 0 0))
+;;; Generated autoloads from emms-player-xine.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-player-xine" '("emms-" "xine")))
+
+;;;***
+
+;;;### (autoloads nil "emms-playing-time" "emms-playing-time.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-playing-time.el
+
+(autoload 'emms-playing-time-enable-display "emms-playing-time" "\
+Display playing time on mode line." t nil)
+
+(autoload 'emms-playing-time-disable-display "emms-playing-time" "\
+Remove playing time from mode line." t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-playing-time" '("emms-playing-time")))
+
+;;;***
+
+;;;### (autoloads nil "emms-playlist-limit" "emms-playlist-limit.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-playlist-limit.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-playlist-limit" '("define-emms-playlist-limit" "emms-playlist-limit-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-playlist-mode" "emms-playlist-mode.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-playlist-mode.el
+
+(autoload 'emms-playlist-mode "emms-playlist-mode" "\
+A major mode for Emms playlists.
+\\{emms-playlist-mode-map}" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-playlist-mode" '("emms")))
+
+;;;***
+
+;;;### (autoloads nil "emms-playlist-sort" "emms-playlist-sort.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-playlist-sort.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-playlist-sort" '("define-emms-playlist-sort" "emms-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-score" "emms-score.el" (0 0 0 0))
+;;; Generated autoloads from emms-score.el
+
+(autoload 'emms-score-enable "emms-score" "\
+Turn on emms-score." t nil)
+
+(autoload 'emms-score-disable "emms-score" "\
+Turn off emms-score." t nil)
+
+(autoload 'emms-score-toggle "emms-score" "\
+Toggle emms-score." t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-score" '("emms-score")))
+
+;;;***
+
+;;;### (autoloads nil "emms-setup" "emms-setup.el" (0 0 0 0))
+;;; Generated autoloads from emms-setup.el
+
+(autoload 'emms-minimalistic "emms-setup" "\
+An Emms setup script.
+Invisible playlists and all the basics for playing media." nil nil)
+
+(autoload 'emms-all "emms-setup" "\
+An Emms setup script.
+Everything included in the `emms-minimalistic' setup and adds all
+the stable features which come with the Emms distribution." nil nil)
+
+(autoload 'emms-default-players "emms-setup" "\
+Set `emms-player-list' to `emms-setup-default-player-list'." nil nil)
+
+(autoload 'emms-devel "emms-setup" nil nil nil)
+
+(autoload 'emms-standard "emms-setup" nil nil nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-setup" '("emms-setup-default-player-list")))
+
+;;;***
+
+;;;### (autoloads nil "emms-show-all" "emms-show-all.el" (0 0 0 0))
+;;; Generated autoloads from emms-show-all.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-show-all" '("emms-show-all")))
+
+;;;***
+
+;;;### (autoloads nil "emms-source-file" "emms-source-file.el" (0
+;;;;;;  0 0 0))
+;;; Generated autoloads from emms-source-file.el
+ (autoload 'emms-play-file "emms-source-file" nil t)
+ (autoload 'emms-add-file "emms-source-file" nil t)
+ (autoload 'emms-play-directory "emms-source-file" nil t)
+ (autoload 'emms-add-directory "emms-source-file" nil t)
+ (autoload 'emms-play-directory-tree "emms-source-file" nil t)
+ (autoload 'emms-add-directory-tree "emms-source-file" nil t)
+ (autoload 'emms-play-find "emms-source-file" nil t)
+ (autoload 'emms-add-find "emms-source-file" nil t)
+ (autoload 'emms-play-dired "emms-source-file" nil t)
+ (autoload 'emms-add-dired "emms-source-file" nil t)
+
+(autoload 'emms-source-file-directory-tree "emms-source-file" "\
+Return a list of all files under DIR that match REGEX.
+This function uses `emms-source-file-directory-tree-function'.
+
+\(fn DIR REGEX)" nil nil)
+
+(autoload 'emms-source-file-regex "emms-source-file" "\
+Return a regexp that matches everything any player (that supports
+files) can play." nil nil)
+
+(autoload 'emms-locate "emms-source-file" "\
+Search for REGEXP and display the results in a locate buffer
+
+\(fn REGEXP)" t nil)
+ (autoload 'emms-play-url "emms-source-file" nil t)
+ (autoload 'emms-add-url "emms-source-file" nil t)
+ (autoload 'emms-play-streamlist "emms-source-file" nil t)
+ (autoload 'emms-add-streamlist "emms-source-file" nil t)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-source-file" '("dire" "emms-" "file" "find" "streamlist" "url")))
+
+;;;***
+
+;;;### (autoloads nil "emms-source-playlist" "emms-source-playlist.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-source-playlist.el
+ (autoload 'emms-play-playlist "emms-source-playlist" nil t)
+ (autoload 'emms-add-playlist "emms-source-playlist" nil t)
+ (autoload 'emms-play-native-playlist "emms-source-playlist" nil t)
+ (autoload 'emms-add-native-playlist "emms-source-playlist" nil t)
+ (autoload 'emms-play-m3u-playlist "emms-source-playlist" nil t)
+ (autoload 'emms-add-m3u-playlist "emms-source-playlist" nil t)
+ (autoload 'emms-play-pls-playlist "emms-source-playlist" nil t)
+ (autoload 'emms-add-pls-playlist "emms-source-playlist" nil t)
+ (autoload 'emms-play-playlist-file "emms-source-playlist" nil t)
+ (autoload 'emms-add-playlist-file "emms-source-playlist" nil t)
+ (autoload 'emms-play-playlist-directory
+          "emms-source-playlist" nil t)
+ (autoload 'emms-add-playlist-directory
+          "emms-source-playlist" nil t)
+ (autoload 'emms-play-playlist-directory-tree
+          "emms-source-playlist" nil t)
+ (autoload 'emms-add-playlist-directory-tree
+          "emms-source-file" nil t)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-source-playlist" '("emms-" "m3u-playlist" "native-playlist" "playlist" 
"pls-playlist")))
+
+;;;***
+
+;;;### (autoloads nil "emms-streams" "emms-streams.el" (0 0 0 0))
+;;; Generated autoloads from emms-streams.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-streams" '("emms-streams")))
+
+;;;***
+
+;;;### (autoloads nil "emms-tag-editor" "emms-tag-editor.el" (0 0
+;;;;;;  0 0))
+;;; Generated autoloads from emms-tag-editor.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-tag-editor" '("emms-tag-editor-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-url" "emms-url.el" (0 0 0 0))
+;;; Generated autoloads from emms-url.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-url" '("emms-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-volume" "emms-volume.el" (0 0 0 0))
+;;; Generated autoloads from emms-volume.el
+
+(autoload 'emms-volume-raise "emms-volume" "\
+Raise the speaker volume." t nil)
+
+(autoload 'emms-volume-lower "emms-volume" "\
+Lower the speaker volume." t nil)
+
+(autoload 'emms-volume-mode-plus "emms-volume" "\
+Raise volume and enable or extend the `emms-volume-minor-mode' timeout." t nil)
+
+(autoload 'emms-volume-mode-minus "emms-volume" "\
+Lower volume and enable or extend the `emms-volume-minor-mode' timeout." t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-volume" '("emms-volume-")))
+
+;;;***
+
+;;;### (autoloads nil "emms-volume-amixer" "emms-volume-amixer.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-volume-amixer.el
+
+(autoload 'emms-volume-amixer-change "emms-volume-amixer" "\
+Change amixer master volume by AMOUNT.
+
+\(fn AMOUNT)" nil nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-volume-amixer" '("emms-volume-amixer-c")))
+
+;;;***
+
+;;;### (autoloads nil "emms-volume-mixerctl" "emms-volume-mixerctl.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-volume-mixerctl.el
+
+(autoload 'emms-volume-mixerctl-change "emms-volume-mixerctl" "\
+Change mixerctl master volume by AMOUNT.
+
+\(fn AMOUNT)" nil nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-volume-mixerctl" '("emms-volume-mixerctl-c")))
+
+;;;***
+
+;;;### (autoloads nil "emms-volume-pulse" "emms-volume-pulse.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from emms-volume-pulse.el
+
+(autoload 'emms-volume-pulse-change "emms-volume-pulse" "\
+Change PulseAudio volume by AMOUNT.
+
+\(fn AMOUNT)" nil nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-volume-pulse" '("emms-volume-")))
+
+;;;***
+
+;;;### (autoloads nil "jack" "jack.el" (0 0 0 0))
+;;; Generated autoloads from jack.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"jack" '("jack-")))
+
+;;;***
+
+;;;### (autoloads nil "later-do" "later-do.el" (0 0 0 0))
+;;; Generated autoloads from later-do.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"later-do" '("later-do")))
+
+;;;***
+
+;;;### (autoloads nil nil ("emms-maint.el" "emms-stream-info.el")
+;;;;;;  (0 0 0 0))
+
+;;;***
+
+;;;### (autoloads nil "emms-bookmarks" "emms-bookmarks.el" (0 0 0
+;;;;;;  0))
+;;; Generated autoloads from emms-bookmarks.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes 
"emms-bookmarks" '("emms-bookmarks-")))
+
+;;;***
diff --git a/lisp/emms-auto.in b/emms-auto.in
similarity index 100%
rename from lisp/emms-auto.in
rename to emms-auto.in
diff --git a/lisp/emms-bookmarks.el b/emms-bookmarks.el
similarity index 100%
rename from lisp/emms-bookmarks.el
rename to emms-bookmarks.el
diff --git a/lisp/emms-browser.el b/emms-browser.el
similarity index 100%
rename from lisp/emms-browser.el
rename to emms-browser.el
diff --git a/lisp/emms-cache.el b/emms-cache.el
similarity index 100%
rename from lisp/emms-cache.el
rename to emms-cache.el
diff --git a/lisp/emms-compat.el b/emms-compat.el
similarity index 100%
rename from lisp/emms-compat.el
rename to emms-compat.el
diff --git a/lisp/emms-cue.el b/emms-cue.el
similarity index 100%
rename from lisp/emms-cue.el
rename to emms-cue.el
diff --git a/lisp/emms-history.el b/emms-history.el
similarity index 100%
rename from lisp/emms-history.el
rename to emms-history.el
diff --git a/lisp/emms-i18n.el b/emms-i18n.el
similarity index 100%
rename from lisp/emms-i18n.el
rename to emms-i18n.el
diff --git a/lisp/emms-info-libtag.el b/emms-info-libtag.el
similarity index 100%
rename from lisp/emms-info-libtag.el
rename to emms-info-libtag.el
diff --git a/lisp/emms-info-metaflac.el b/emms-info-metaflac.el
similarity index 100%
rename from lisp/emms-info-metaflac.el
rename to emms-info-metaflac.el
diff --git a/lisp/emms-info-mp3info.el b/emms-info-mp3info.el
similarity index 100%
rename from lisp/emms-info-mp3info.el
rename to emms-info-mp3info.el
diff --git a/lisp/emms-info-ogginfo.el b/emms-info-ogginfo.el
similarity index 100%
rename from lisp/emms-info-ogginfo.el
rename to emms-info-ogginfo.el
diff --git a/lisp/emms-info-opusinfo.el b/emms-info-opusinfo.el
similarity index 100%
rename from lisp/emms-info-opusinfo.el
rename to emms-info-opusinfo.el
diff --git a/lisp/emms-info-tinytag.el b/emms-info-tinytag.el
similarity index 100%
rename from lisp/emms-info-tinytag.el
rename to emms-info-tinytag.el
diff --git a/lisp/emms-info.el b/emms-info.el
similarity index 100%
rename from lisp/emms-info.el
rename to emms-info.el
diff --git a/lisp/emms-last-played.el b/emms-last-played.el
similarity index 100%
rename from lisp/emms-last-played.el
rename to emms-last-played.el
diff --git a/lisp/emms-librefm-scrobbler.el b/emms-librefm-scrobbler.el
similarity index 100%
rename from lisp/emms-librefm-scrobbler.el
rename to emms-librefm-scrobbler.el
diff --git a/lisp/emms-librefm-stream.el b/emms-librefm-stream.el
similarity index 100%
rename from lisp/emms-librefm-stream.el
rename to emms-librefm-stream.el
diff --git a/lisp/emms-lyrics.el b/emms-lyrics.el
similarity index 100%
rename from lisp/emms-lyrics.el
rename to emms-lyrics.el
diff --git a/lisp/emms-maint.el b/emms-maint.el
similarity index 100%
rename from lisp/emms-maint.el
rename to emms-maint.el
diff --git a/lisp/emms-mark.el b/emms-mark.el
similarity index 100%
rename from lisp/emms-mark.el
rename to emms-mark.el
diff --git a/lisp/emms-metaplaylist-mode.el b/emms-metaplaylist-mode.el
similarity index 100%
rename from lisp/emms-metaplaylist-mode.el
rename to emms-metaplaylist-mode.el
diff --git a/lisp/emms-mode-line-icon.el b/emms-mode-line-icon.el
similarity index 100%
rename from lisp/emms-mode-line-icon.el
rename to emms-mode-line-icon.el
diff --git a/lisp/emms-mode-line.el b/emms-mode-line.el
similarity index 100%
rename from lisp/emms-mode-line.el
rename to emms-mode-line.el
diff --git a/lisp/emms-player-mpd.el b/emms-player-mpd.el
similarity index 100%
rename from lisp/emms-player-mpd.el
rename to emms-player-mpd.el
diff --git a/lisp/emms-player-mpg321-remote.el b/emms-player-mpg321-remote.el
similarity index 100%
rename from lisp/emms-player-mpg321-remote.el
rename to emms-player-mpg321-remote.el
diff --git a/lisp/emms-player-mplayer.el b/emms-player-mplayer.el
similarity index 100%
rename from lisp/emms-player-mplayer.el
rename to emms-player-mplayer.el
diff --git a/lisp/emms-player-mpv.el b/emms-player-mpv.el
similarity index 100%
rename from lisp/emms-player-mpv.el
rename to emms-player-mpv.el
diff --git a/lisp/emms-player-simple.el b/emms-player-simple.el
similarity index 100%
rename from lisp/emms-player-simple.el
rename to emms-player-simple.el
diff --git a/lisp/emms-player-vlc.el b/emms-player-vlc.el
similarity index 100%
rename from lisp/emms-player-vlc.el
rename to emms-player-vlc.el
diff --git a/lisp/emms-player-xine.el b/emms-player-xine.el
similarity index 100%
rename from lisp/emms-player-xine.el
rename to emms-player-xine.el
diff --git a/lisp/emms-playing-time.el b/emms-playing-time.el
similarity index 100%
rename from lisp/emms-playing-time.el
rename to emms-playing-time.el
diff --git a/lisp/emms-playlist-limit.el b/emms-playlist-limit.el
similarity index 100%
rename from lisp/emms-playlist-limit.el
rename to emms-playlist-limit.el
diff --git a/lisp/emms-playlist-mode.el b/emms-playlist-mode.el
similarity index 100%
rename from lisp/emms-playlist-mode.el
rename to emms-playlist-mode.el
diff --git a/lisp/emms-playlist-sort.el b/emms-playlist-sort.el
similarity index 100%
rename from lisp/emms-playlist-sort.el
rename to emms-playlist-sort.el
diff --git a/lisp/emms-score.el b/emms-score.el
similarity index 100%
rename from lisp/emms-score.el
rename to emms-score.el
diff --git a/lisp/emms-setup.el b/emms-setup.el
similarity index 100%
rename from lisp/emms-setup.el
rename to emms-setup.el
diff --git a/lisp/emms-show-all.el b/emms-show-all.el
similarity index 100%
rename from lisp/emms-show-all.el
rename to emms-show-all.el
diff --git a/lisp/emms-source-file.el b/emms-source-file.el
similarity index 100%
rename from lisp/emms-source-file.el
rename to emms-source-file.el
diff --git a/lisp/emms-source-playlist.el b/emms-source-playlist.el
similarity index 100%
rename from lisp/emms-source-playlist.el
rename to emms-source-playlist.el
diff --git a/lisp/emms-stream-info.el b/emms-stream-info.el
similarity index 100%
rename from lisp/emms-stream-info.el
rename to emms-stream-info.el
diff --git a/lisp/emms-streams.el b/emms-streams.el
similarity index 100%
rename from lisp/emms-streams.el
rename to emms-streams.el
diff --git a/lisp/emms-tag-editor.el b/emms-tag-editor.el
similarity index 100%
rename from lisp/emms-tag-editor.el
rename to emms-tag-editor.el
diff --git a/lisp/emms-url.el b/emms-url.el
similarity index 100%
rename from lisp/emms-url.el
rename to emms-url.el
diff --git a/lisp/emms-volume-amixer.el b/emms-volume-amixer.el
similarity index 100%
rename from lisp/emms-volume-amixer.el
rename to emms-volume-amixer.el
diff --git a/lisp/emms-volume-mixerctl.el b/emms-volume-mixerctl.el
similarity index 100%
rename from lisp/emms-volume-mixerctl.el
rename to emms-volume-mixerctl.el
diff --git a/lisp/emms-volume-pulse.el b/emms-volume-pulse.el
similarity index 100%
rename from lisp/emms-volume-pulse.el
rename to emms-volume-pulse.el
diff --git a/lisp/emms-volume.el b/emms-volume.el
similarity index 100%
rename from lisp/emms-volume.el
rename to emms-volume.el
diff --git a/emms.el b/emms.el
index e43457e..1f49e73 100644
--- a/emms.el
+++ b/emms.el
@@ -5,7 +5,7 @@
 
 ;; Author: Jorgen Schäfer <forcer@forcix.cx>, the Emms developers (see AUTHORS 
file)
 ;; Maintainer: Yoni Rabkin <yrk@gnu.org>
-;; Version: 5.4
+;; Version: 5.41
 ;; Keywords: emms, mp3, ogg, flac, music, mpeg, video, multimedia
 ;; Package-Type: multi
 ;; Package-Requires: ((cl-lib "0.5"))
@@ -13,20 +13,1528 @@
 
 ;; This file is part of EMMS.
 
-;; EMMS is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
+;; EMMS is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
 
-;; EMMS is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
+;; EMMS is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
+;; This is the very core of EMMS.  It provides ways to play a track
+;; using `emms-start', to go through the playlist using the commands
+;; `emms-next' and `emms-previous', to stop the playback using
+;; `emms-stop', and to see what's currently playing using `emms-show'.
 
-;;; emms.el ends here.
+;; But in itself, this core is useless, because it doesn't know how to
+;; play any tracks --- you need players for this.  In fact, it doesn't
+;; even know how to find any tracks to consider playing --- for this,
+;; you need sources.
+
+;; A sample configuration is offered in emms-setup.el, and the
+;; Friendly Manual in the doc/ directory is both detailed, and kept up
+;; to date.
+
+
+;;; Code:
+
+(defvar emms-version "5.41"
+  "EMMS version string.")
+
+
+;;; User Customization
+
+(defgroup emms nil
+  "*The Emacs Multimedia System."
+  :prefix "emms-"
+  :group 'multimedia
+  :group 'applications)
+
+(defgroup emms-player nil
+  "*Track players for EMMS."
+  :prefix "emms-player-"
+  :group 'emms)
+
+(defgroup emms-source nil
+  "*Track sources for EMMS."
+  :prefix "emms-source-"
+  :group 'emms)
+
+(defcustom emms-player-list nil
+  "*List of players that EMMS can use.  You need to set this!"
+  :group 'emms
+  :type '(repeat (symbol :tag "Player")))
+
+(defcustom emms-show-format "Currently playing: %s"
+  "*The format to use for `emms-show'.
+Any \"%s\" is replaced by what `emms-track-description-function' returns
+for the currently playing track."
+  :group 'emms
+  :type 'string)
+
+(defcustom emms-repeat-playlist nil
+  "*Non-nil if the EMMS playlist should automatically repeat.
+If nil, playback will stop when the last track finishes playing.
+If non-nil, EMMS will wrap back to the first track when that happens."
+  :group 'emms
+  :type 'boolean)
+
+(defcustom emms-random-playlist nil
+  "*Non-nil means that tracks are played randomly. If nil, tracks
+are played sequentially."
+  :group 'emms
+  :type 'boolean)
+
+(defcustom emms-repeat-track nil
+  "Non-nil, playback will repeat current track.  If nil, EMMS will play
+track by track normally."
+  :group 'emms
+  :type 'boolean)
+
+(defvar-local emms-single-track nil
+  "Non-nil, play the current track and then stop.")
+
+(defcustom emms-completing-read-function
+  (if (and (boundp 'ido-mode)
+           ido-mode)
+      'ido-completing-read
+    'completing-read)
+  "Function to call when prompting user to choose between a list of options.
+This should take the same arguments as `completing-read'.  Some
+possible values are `completing-read' and `ido-completing-read'.
+Note that you must set `ido-mode' if using
+`ido-completing-read'."
+  :group 'emms
+  :type 'function)
+
+(defcustom emms-track-description-function 'emms-track-simple-description
+  "*Function for describing an EMMS track in a user-friendly way."
+  :group 'emms
+  :type 'function)
+
+(defcustom emms-player-delay 0
+  "The delay to pause after a player finished.
+This is a floating-point number of seconds.  This is necessary
+for some platforms where it takes a bit to free the audio device
+after a player has finished.  If EMMS is skipping songs, increase
+this number."
+  :type 'number
+  :group 'emms)
+
+(defcustom emms-playlist-shuffle-function 'emms-playlist-simple-shuffle
+  "*The function to use for shuffling the playlist."
+  :type 'function
+  :group 'emms)
+
+(defcustom emms-playlist-sort-function 'emms-playlist-simple-sort
+  "*The function to use for sorting the playlist."
+  :type 'function
+  :group 'emms)
+
+(defcustom emms-playlist-uniq-function 'emms-playlist-simple-uniq
+  "*The function to use for removing duplicate tracks in the playlist."
+  :type 'function
+  :group 'emms)
+
+(defcustom emms-sort-lessp-function 'emms-sort-track-name-less-p
+  "*Function for comparing two EMMS tracks.
+The function should return non-nil if and only if the first track
+sorts before the second (see `sort')."
+  :group 'emms
+  :type 'function)
+
+(defcustom emms-playlist-buffer-name " *EMMS Playlist*"
+  "*The default name of the EMMS playlist buffer."
+  :type 'string
+  :group 'emms)
+
+(defcustom emms-playlist-default-major-mode 'emms-playlist-mode
+  "*The default major mode for EMMS playlist."
+  :type 'function
+  :group 'emms)
+
+(defcustom emms-playlist-insert-track-function 
'emms-playlist-simple-insert-track
+  "*A function to insert a track into the playlist buffer."
+  :group 'emms
+  :type 'function)
+(make-variable-buffer-local 'emms-playlist-insert-track-function)
+
+(defcustom emms-playlist-update-track-function 
'emms-playlist-simple-update-track
+  "*A function to update the track at point.
+This is called when the track information changed.  This also
+shouldn't assume that the track has been inserted before."
+  :group 'emms
+  :type 'function)
+(make-variable-buffer-local 'emms-playlist-insert-track-function)
+
+(defcustom emms-playlist-delete-track-function 
'emms-playlist-simple-delete-track
+  "*A function to delete the track at point in the playlist buffer."
+  :group 'emms
+  :type 'function)
+(make-variable-buffer-local 'emms-playlist-delete-track-function)
+
+(defcustom emms-ok-track-function 'emms-default-ok-track-function
+  "*Function returns true if we shouldn't skip this track."
+  :group 'emms
+  :type 'function)
+
+(defcustom emms-playlist-source-inserted-hook nil
+  "*Hook run when a source got inserted into the playlist.
+The buffer is narrowed to the new tracks."
+  :type 'hook
+  :group 'emms)
+
+(defcustom emms-playlist-selection-changed-hook nil
+  "*Hook run after another track is selected in the EMMS playlist."
+  :group 'emms
+  :type 'hook)
+
+(defcustom emms-playlist-cleared-hook nil
+  "*Hook run after the current EMMS playlist is cleared.
+This happens both when the playlist is cleared and when a new
+buffer is created for it."
+  :group 'emms
+  :type 'hook)
+
+(defcustom emms-track-initialize-functions nil
+  "*List of functions to call for each new EMMS track.
+This can be used to initialize tracks with various info."
+  :group 'emms
+  :type 'hook)
+
+(defcustom emms-track-info-filters nil
+  "*List of functions to call when a track changes data, before updating
+the display.
+These functions are passed the track as an argument."
+  :group 'emms
+  :type 'hook)
+
+(defcustom emms-track-updated-functions nil
+  "*List of functions to call when a track changes data, after updating
+the display.
+These functions are passed the track as an argument."
+  :group 'emms
+  :type 'hook)
+
+(defcustom emms-player-started-hook nil
+  "*Hook run when an EMMS player starts playing."
+  :group 'emms
+  :type 'hook
+  :options '(emms-show))
+
+(defcustom emms-player-stopped-hook nil
+  "*Hook run when an EMMS player is stopped by the user.
+See `emms-player-finished-hook'."
+  :group 'emms
+  :type 'hook)
+
+(defcustom emms-player-finished-hook nil
+  "*Hook run when an EMMS player finishes playing a track.
+Please pay attention to the differences between
+`emms-player-finished-hook' and `emms-player-stopped-hook'.  The
+former is called only when the player actually finishes playing a
+track; the latter, only when the player is stopped
+interactively."
+  :group 'emms
+  :type 'hook)
+
+(defcustom emms-player-next-function 'emms-next-noerror
+  "*A function run when EMMS thinks the next song should be played."
+  :group 'emms
+  :type 'function
+  :options '(emms-next-noerror
+             emms-random))
+
+(defcustom emms-player-paused-hook nil
+  "*Hook run when a player is paused or resumed.
+Use `emms-player-paused-p' to find the current state."
+  :group 'emms
+  :type 'hook)
+
+(defcustom emms-seek-seconds 10
+  "The number of seconds to seek forward or backward when seeking."
+  :group 'emms
+  :type 'number)
+
+(defcustom emms-player-seeked-functions nil
+  "*Functions called when a player is seeking.
+The functions are called with a single argument, the amount of
+seconds the player did seek."
+  :group 'emms
+  :type 'hook)
+
+(defcustom emms-player-time-set-functions nil
+  "*Functions called when a player is setting the elapsed time of a track.
+The functions are called with a single argument, the time elapsed
+since the beginning of the current track."
+  :group 'emms
+  :type 'hook)
+
+(defcustom emms-cache-get-function nil
+  "A function to retrieve a track entry from the cache.
+This is called with two arguments, the type and the name."
+  :group 'emms
+  :type 'function)
+
+(defcustom emms-cache-set-function nil
+  "A function to add/set a track entry from the cache.
+This is called with three arguments: the type of the track, the
+name of the track, and the track itself."
+  :group 'emms
+  :type 'function)
+
+(defcustom emms-cache-modified-function nil
+  "A function to be called when a track is modified.
+The modified track is passed as the argument to this function."
+  :group 'emms
+  :type 'function)
+
+(defcustom emms-directory (expand-file-name "emms" user-emacs-directory)
+  "*Directory variable from which all other emms file variables are derived."
+  :group 'emms
+  :type 'string)
+
+(defvar emms-player-playing-p nil
+  "The currently playing EMMS player, or nil.")
+
+(defvar emms-player-paused-p nil
+  "Whether the current player is paused or not.")
+
+(defvar emms-source-old-buffer nil
+  "The active buffer before a source was invoked.
+This can be used if the source depends on the current buffer not
+being the playlist buffer.")
+
+(defvar emms-playlist-buffer nil
+  "The current playlist buffer, if any.")
+
+
+;;; Macros
+
+;;; These need to be at the top of the file so that compilation works.
+
+(defmacro with-current-emms-playlist (&rest body)
+  "Run BODY with the current buffer being the current playlist buffer.
+This also disables any read-onliness of the current buffer."
+  `(progn
+     (when (or (not emms-playlist-buffer)
+               (not (buffer-live-p emms-playlist-buffer)))
+       (emms-playlist-current-clear))
+     (let ((emms-source-old-buffer (or emms-source-old-buffer
+                                       (current-buffer))))
+       (with-current-buffer emms-playlist-buffer
+        (let ((inhibit-read-only t))
+          ,@body)))))
+(put 'with-current-emms-playlist 'lisp-indent-function 0)
+(put 'with-current-emms-playlist 'edebug-form-spec '(body))
+
+(defmacro emms-with-inhibit-read-only-t (&rest body)
+  "Simple wrapper around `inhibit-read-only'."
+  `(let ((inhibit-read-only t))
+     ,@body))
+(put 'emms-with-inhibit-read-only-t 'edebug-form-spec '(body))
+
+(defmacro emms-with-widened-buffer (&rest body)
+  `(save-restriction
+     (widen)
+     ,@body))
+(put 'emms-with-widened-buffer 'edebug-form-spec '(body))
+
+(defmacro emms-walk-tracks (&rest body)
+  "Execute BODY for each track in the current buffer, starting at point.
+Point will be placed at the beginning of the track before
+executing BODY.
+
+Point will not be restored afterward."
+  (let ((donep (make-symbol "donep")))
+    `(let ((,donep nil))
+       ;; skip to first track if not on one
+       (unless (emms-playlist-track-at (point))
+         (condition-case nil
+             (emms-playlist-next)
+           (error
+            (setq ,donep t))))
+       ;; walk tracks
+       (while (not ,donep)
+         ,@body
+         (condition-case nil
+             (emms-playlist-next)
+           (error
+            (setq ,donep t)))))))
+(put 'emms-walk-tracks 'lisp-indent-function 0)
+(put 'emms-walk-tracks 'edebug-form-spec '(body))
+
+(defvar emms-player-base-format-list
+  '("ogg" "mp3" "wav" "mpg" "mpeg" "wmv" "wma"
+    "mov" "avi" "divx" "ogm" "ogv" "asf" "mkv"
+    "rm" "rmvb" "mp4" "flac" "vob" "m4a" "ape"
+    "flv" "webm" "aif")
+  "A list of common formats which player definitions can use.")
+
+
+;;; User Interface
+
+(defun emms-start ()
+  "Start playing the current track in the EMMS playlist."
+  (interactive)
+  (unless emms-player-playing-p
+    (emms-player-start (emms-playlist-current-selected-track))))
+
+(defun emms-stop ()
+  "Stop any current EMMS playback."
+  (interactive)
+  (when emms-player-playing-p
+    (emms-player-stop)))
+
+(defun emms-next ()
+  "Start playing the next track in the EMMS playlist.
+This might behave funny if called from `emms-player-next-function',
+so use `emms-next-noerror' in that case."
+  (interactive)
+  (when emms-player-playing-p
+    (emms-stop))
+  (emms-playlist-current-select-next)
+  (emms-start))
+
+(defun emms-next-noerror ()
+  "Start playing the next track in the EMMS playlist.
+Unlike `emms-next', this function doesn't signal an error when called
+at the end of the playlist.
+This function should only be called when no player is playing.
+This is a good function to put in `emms-player-next-function'."
+  (interactive)
+  (when emms-player-playing-p
+    (error "A track is already being played"))
+  (cond (emms-repeat-track
+        (emms-start))
+       (emms-single-track              ; buffer local
+        (emms-stop))
+       ;; attempt to play the next track but ignore errors
+       ((condition-case nil
+             (progn
+               (emms-playlist-current-select-next)
+               t)
+           (error nil))
+        (if (funcall emms-ok-track-function
+                     (emms-playlist-current-selected-track))
+            (emms-start)
+          (emms-next-noerror)))
+        (t
+        (message "No next track in playlist"))))
+
+(defun emms-previous ()
+  "Start playing the previous track in the EMMS playlist."
+  (interactive)
+  (when emms-player-playing-p
+    (emms-stop))
+  (emms-playlist-current-select-previous)
+  (emms-start))
+
+(defun emms-random ()
+  "Jump to a random track."
+  (interactive)
+  (when emms-player-playing-p
+    (emms-stop))
+  (emms-playlist-current-select-random)
+  (emms-start))
+
+(defun emms-pause ()
+  "Pause the current player.
+If player hasn't started, then start it now."
+  (interactive)
+  (if emms-player-playing-p
+      (emms-player-pause)
+    (emms-start)))
+
+(defun emms-seek (seconds)
+  "Seek the current player SECONDS seconds.
+This can be a floating point number for sub-second fractions.
+It can also be negative to seek backwards."
+  (interactive "nSeconds to seek: ")
+  (emms-ensure-player-playing-p)
+  (emms-player-seek seconds))
+
+(defun emms-seek-to (seconds)
+  "Seek the current player to SECONDS seconds.
+This can be a floating point number for sub-second fractions.
+It can also be negative to seek backwards."
+  (interactive "nSeconds to seek to: ")
+  (emms-ensure-player-playing-p)
+  (emms-player-seek-to seconds))
+
+(defun emms-seek-forward ()
+  "Seek ten seconds forward."
+  (interactive)
+  (when emms-player-playing-p
+    (emms-player-seek emms-seek-seconds)))
+
+(defun emms-seek-backward ()
+  "Seek ten seconds backward."
+  (interactive)
+  (when emms-player-playing-p
+    (emms-player-seek (- emms-seek-seconds))))
+
+(defun emms-show (&optional insertp)
+  "Describe the current EMMS track in the minibuffer.
+If INSERTP is non-nil, insert the description into the current buffer instead.
+This function uses `emms-show-format' to format the current track."
+  (interactive "P")
+  (let ((string (if emms-player-playing-p
+                    (format emms-show-format
+                            (emms-track-description
+                             (emms-playlist-current-selected-track)))
+                  "Nothing playing right now")))
+    (if insertp
+        (insert string)
+      (message "%s" string))))
+
+(defun emms-shuffle ()
+  "Shuffle the current playlist.
+This uses `emms-playlist-shuffle-function'."
+  (interactive)
+  (with-current-emms-playlist
+    (save-excursion
+      (funcall emms-playlist-shuffle-function))))
+
+(defun emms-sort ()
+  "Sort the current playlist.
+This uses `emms-playlist-sort-function'."
+  (interactive)
+  (with-current-emms-playlist
+    (save-excursion
+      (funcall emms-playlist-sort-function))))
+
+(defun emms-uniq ()
+  "Remove duplicates from the current playlist.
+This uses `emms-playlist-uniq-function'."
+  (interactive)
+  (with-current-emms-playlist
+    (save-excursion
+      (funcall emms-playlist-uniq-function))))
+
+(defun emms-toggle-single-track ()
+  "Toggle if Emms plays a single track and stops."
+  (interactive)
+  (with-current-emms-playlist
+    (cond (emms-single-track
+          (setq emms-single-track nil)
+          (message "single track mode disabled for %s"
+                   (buffer-name)))
+         (t (setq emms-single-track t)
+            (message "single track mode enabled for %s"
+                   (buffer-name))))))
+
+(defun emms-toggle-random-playlist ()
+  "Toggle whether emms plays the tracks randomly or sequentially.
+See `emms-random-playlist'."
+  (interactive)
+  (setq emms-random-playlist (not emms-random-playlist))
+  (if emms-random-playlist
+      (progn (setq emms-player-next-function 'emms-random)
+             (message "Will play the tracks randomly."))
+    (setq emms-player-next-function 'emms-next-noerror)
+    (message "Will play the tracks sequentially.")))
+
+(defun emms-toggle-repeat-playlist ()
+  "Toggle whether emms repeats the playlist after it is done.
+See `emms-repeat-playlist'."
+  (interactive)
+  (setq emms-repeat-playlist (not emms-repeat-playlist))
+  (if emms-repeat-playlist
+      (message "Will repeat the playlist after it is done.")
+    (message "Will stop after the playlist is over.")))
+
+(defun emms-toggle-repeat-track ()
+  "Toggle whether emms repeats the current track.
+See `emms-repeat-track'."
+  (interactive)
+  (setq emms-repeat-track (not emms-repeat-track))
+  (if emms-repeat-track
+      (message "Will repeat the current track.")
+    (message "Will advance to the next track after this one.")))
+
+(defun emms-sort-track-name-less-p (a b)
+  "Return non-nil if the track name of A sorts before B."
+  (string< (emms-track-name a)
+           (emms-track-name b)))
+
+(defun emms-ensure-player-playing-p ()
+  "Raise an error if no player is playing right now."
+  (when (not emms-player-playing-p)
+    (error "No EMMS player playing right now")))
+
+(defun emms-completing-read (&rest args)
+  "Read a string in the minibuffer, with completion.
+Set `emms-completing-read' to determine which function to use.
+
+See `completing-read' for a description of ARGS."
+  (apply emms-completing-read-function args))
+
+(defun emms-display-modes ()
+  "Display the current EMMS play modes."
+  (interactive)
+  (with-current-emms-playlist
+    (message
+     "repeat playlist: %s, repeat track: %s, random: %s, single %s"
+     (if emms-repeat-playlist "yes" "no")
+     (if emms-repeat-track "yes" "no")
+     (if emms-random-playlist "yes" "no")
+     (if emms-single-track "yes" "no"))))
+
+
+;;; Compatibility functions
+
+(require 'emms-compat)
+
+
+;;; Utility functions
+
+(defun emms-insert-file-contents (filename &optional visit)
+  "Insert the contents of file FILENAME after point.
+Do character code conversion and end-of-line conversion, but none
+of the other unnecessary things like format decoding or
+`find-file-hook'.
+
+If VISIT is non-nil, the buffer's visited filename
+and last save file modtime are set, and it is marked unmodified.
+If visiting and the file does not exist, visiting is completed
+before the error is signaled."
+  (let ((format-alist nil)
+        (after-insert-file-functions nil)
+        (inhibit-file-name-handlers
+         (append '(jka-compr-handler image-file-handler epa-file-handler)
+                 inhibit-file-name-handlers))
+        (inhibit-file-name-operation 'insert-file-contents))
+    (insert-file-contents filename visit)))
+
+
+;;; Dictionaries
+
+;; This is a simple helper data structure, used by both players
+;; and tracks.
+
+(defsubst emms-dictionary (name)
+  "Create a new dictionary of type NAME."
+  (list name))
+
+(defsubst emms-dictionary-type (dict)
+  "Return the type of the dictionary DICT."
+  (car dict))
+
+(defun emms-dictionary-get (dict name &optional default)
+  "Return the value of NAME in DICT."
+  (let ((item (assq name (cdr dict))))
+    (if item
+        (cdr item)
+      default)))
+
+(defun emms-dictionary-set (dict name value)
+  "Set the value of NAME in DICT to VALUE."
+  (let ((item (assq name (cdr dict))))
+    (if item
+        (setcdr item value)
+      (setcdr dict (append (cdr dict)
+                           (list (cons name value))))))
+  dict)
+
+
+;;; Tracks
+
+;; This is a simple datatype to store track information.
+;; Each track consists of a type (a symbol) and a name (a string).
+;; In addition, each track has an associated dictionary of information.
+
+(defun emms-track (type name)
+  "Create an EMMS track with type TYPE and name NAME."
+  (let ((track (when emms-cache-get-function
+                 (funcall emms-cache-get-function type name))))
+    (when (not track)
+      (setq track (emms-dictionary '*track*))
+      ;; Prevent the cache from being called for these two sets
+      (let ((emms-cache-modified-function nil))
+        (emms-track-set track 'type type)
+        (emms-track-set track 'name name))
+      (when emms-cache-set-function
+        (funcall emms-cache-set-function type name track)))
+    ;; run any hooks regardless of a cache hit, as the entry may be
+    ;; old
+    (run-hook-with-args 'emms-track-initialize-functions track)
+    track))
+
+(defun emms-track-p (obj)
+  "True if OBJ is an emms track."
+  (and (listp obj)
+       (eq (car obj) '*track*)))
+
+(defun emms-track-type (track)
+  "Return the type of TRACK."
+  (emms-track-get track 'type))
+
+(defun emms-track-name (track)
+  "Return the name of TRACK."
+  (emms-track-get track 'name))
+
+(defun emms-track-get (track name &optional default)
+  "Return the value of NAME for TRACK.
+If there is no value, return DEFAULT (or nil, if not given)."
+  (emms-dictionary-get track name default))
+
+(defun emms-track-set (track name value)
+  "Set the value of NAME for TRACK to VALUE."
+  (emms-dictionary-set track name value)
+  (when emms-cache-modified-function
+    (funcall emms-cache-modified-function track)))
+
+(defun emms-track-description (track)
+  "Return a description of TRACK.
+This function uses the global value for
+`emms-track-description-function', rather than anything the
+current mode might have set.
+
+Use `emms-track-force-description' instead if you need to insert
+a description into a playlist buffer."
+  (funcall (default-value 'emms-track-description-function) track))
+
+(defun emms-track-updated (track)
+  "Information in TRACK got updated."
+  (run-hook-with-args 'emms-track-info-filters track)
+  (emms-playlist-track-updated track)
+  (run-hook-with-args 'emms-track-updated-functions track))
+
+(defun emms-track-simple-description (track)
+  "Simple function to give a user-readable description of a track.
+If it's a file track, just return the file name.  Otherwise,
+return the type and the name with a colon in between.
+Hex-encoded characters in URLs are replaced by the decoded
+character."
+  (let ((type (emms-track-type track)))
+    (cond ((eq 'file type)
+           (emms-track-name track))
+          ((eq 'url type)
+           (emms-format-url-track-name (emms-track-name track)))
+          (t (concat (symbol-name type)
+                     ": " (emms-track-name track))))))
+
+(defun emms-format-url-track-name (name)
+  "Format URL track name for better readability."
+  (url-unhex-string name))
+
+(defun emms-track-force-description (track)
+  "Always return text that describes TRACK.
+This is used when inserting a description into a buffer.
+
+The reason for this is that if no text was returned (i.e. the
+user defined a track function that returned nil or the empty
+string), a confusing error message would result."
+  (let ((desc (funcall emms-track-description-function track)))
+    (if (and (stringp desc) (not (string= desc "")))
+        desc
+      (emms-track-simple-description track))))
+
+(defun emms-track-get-year (track)
+  "Get year of TRACK for display.
+There is the separation between the 'release date' and the
+'original date'.  This difference matters e.g. for
+re-releases (anniversaries and such) where the release date is
+more recent than the original release date.  In such cases the
+user probably wants the original release date so this is what we
+show."
+  (or
+   (emms-format-date-to-year (emms-track-get track 'info-date))
+   (emms-format-date-to-year (emms-track-get track 'info-originaldate))
+   (emms-track-get track 'info-year)
+   (emms-track-get track 'info-originalyear)))
+
+(defun emms-format-date-to-year (date)
+  "Try to extract year part from DATE.
+Return nil if the year cannot be extracted."
+  (when date
+    (let ((year (nth 5 (parse-time-string date))))
+      (if year (number-to-string year)
+        (when (string-match "^[ \t]*\\([0-9]\\{4\\}\\)" date)
+          (match-string 1 date))))))
+
+
+;;; The Playlist
+
+;; Playlists are stored in buffers.  The current playlist buffer is
+;; remembered in the `emms-playlist' variable.  The buffer consists of
+;; any kind of data.  Strings of text with a `emms-track' property are
+;; the tracks in the buffer.
+
+(defvar emms-playlist-buffers nil
+  "The list of EMMS playlist buffers.
+You should use the `emms-playlist-buffer-list' function to
+retrieve a current list of EMMS buffers.  Never use this variable
+for that purpose.")
+
+(defvar emms-playlist-selected-marker nil
+  "The marker for the currently selected track.")
+(make-variable-buffer-local 'emms-playlist-selected-marker)
+
+(defvar emms-playlist-buffer-p nil
+  "Non-nil if the current buffer is an EMMS playlist.")
+(make-variable-buffer-local 'emms-playlist-buffer-p)
+
+(defun emms-playlist-ensure-playlist-buffer ()
+  "Throw an error if we're not in a playlist-buffer."
+  (when (not emms-playlist-buffer-p)
+    (error "Not an EMMS playlist buffer")))
+
+(defun emms-playlist-set-playlist-buffer (&optional buffer)
+  "Set the current playlist buffer."
+  (interactive
+   (list (let* ((buf-list (mapcar #'(lambda (buf)
+                                      (list (buffer-name buf)))
+                                  (emms-playlist-buffer-list)))
+                (sorted-buf-list (sort buf-list
+                                       #'(lambda (lbuf rbuf)
+                                           (< (length (car lbuf))
+                                              (length (car rbuf))))))
+                (default (or (and emms-playlist-buffer-p
+                                  ;; default to current buffer
+                                  (buffer-name))
+                             ;; pick shortest buffer name, since it is
+                             ;; likely to be a shared prefix
+                             (car sorted-buf-list))))
+           (emms-completing-read "Playlist buffer to make current: "
+                                 sorted-buf-list nil t default))))
+  (let ((buf (if buffer
+                 (get-buffer buffer)
+               (current-buffer))))
+    (with-current-buffer buf
+      (emms-playlist-ensure-playlist-buffer))
+    (setq emms-playlist-buffer buf)
+    (when (called-interactively-p 'interactive)
+      (message "Set current EMMS playlist buffer"))
+    buf))
+
+(defun emms-playlist-new (&optional name)
+  "Create a new playlist buffer.
+The buffer is named NAME, but made unique.  NAME defaults to
+`emms-playlist-buffer-name'.  If called interactively, the new
+buffer is also selected."
+  (interactive)
+  (let ((buf (generate-new-buffer (or name
+                                      emms-playlist-buffer-name))))
+    (with-current-buffer buf
+      (when (not (eq major-mode emms-playlist-default-major-mode))
+        (funcall emms-playlist-default-major-mode))
+      (setq emms-playlist-buffer-p t))
+    (add-to-list 'emms-playlist-buffers buf)
+    (when (called-interactively-p 'interactive)
+      (switch-to-buffer buf))
+    buf))
+
+(defun emms-playlist-buffer-list ()
+  "Return a list of EMMS playlist buffers.
+The first element is guaranteed to be the current EMMS playlist
+buffer, if it exists, otherwise the slot will be used for the
+other EMMS buffers.  The list will be in newest-first order."
+  ;; prune dead buffers
+  (setq emms-playlist-buffers (emms-delete-if (lambda (buf)
+                                                (not (buffer-live-p buf)))
+                                              emms-playlist-buffers))
+  ;; add new buffers
+  (mapc (lambda (buf)
+          (when (buffer-live-p buf)
+            (with-current-buffer buf
+              (when (and emms-playlist-buffer-p
+                         (not (memq buf emms-playlist-buffers)))
+                (setq emms-playlist-buffers
+                      (cons buf emms-playlist-buffers))))))
+        (buffer-list))
+  ;; force current playlist buffer to head position
+  (when (and (buffer-live-p emms-playlist-buffer)
+             (not (eq (car emms-playlist-buffers) emms-playlist-buffer)))
+    (setq emms-playlist-buffers (cons emms-playlist-buffer
+                                      (delete emms-playlist-buffer
+                                              emms-playlist-buffers))))
+  emms-playlist-buffers)
+
+(defun emms-playlist-current-kill ()
+  "Kill the current EMMS playlist buffer and switch to the next one."
+  (interactive)
+  (when (buffer-live-p emms-playlist-buffer)
+    (let ((new (cadr (emms-playlist-buffer-list))))
+      (if new
+          (let ((old emms-playlist-buffer))
+            (setq emms-playlist-buffer new
+                  emms-playlist-buffers (cdr emms-playlist-buffers))
+            (kill-buffer old)
+            (switch-to-buffer emms-playlist-buffer))
+        (with-current-buffer emms-playlist-buffer
+          (bury-buffer))))))
+
+(defun emms-playlist-current-clear ()
+  "Clear the current playlist.
+If no current playlist exists, a new one is generated."
+  (interactive)
+  (if (or (not emms-playlist-buffer)
+          (not (buffer-live-p emms-playlist-buffer)))
+      (setq emms-playlist-buffer (emms-playlist-new))
+    (with-current-buffer emms-playlist-buffer
+      (emms-playlist-clear))))
+
+(defun emms-playlist-clear ()
+  "Clear the current buffer."
+  (interactive)
+  (emms-playlist-ensure-playlist-buffer)
+  (let ((inhibit-read-only t))
+    (widen)
+    (delete-region (point-min)
+                  (point-max)))
+  (run-hooks 'emms-playlist-cleared-hook))
+
+;;; Point movement within the playlist buffer.
+(defun emms-playlist-track-at (&optional pos)
+  "Return the track at POS (point if not given), or nil if none."
+  (emms-playlist-ensure-playlist-buffer)
+  (emms-with-widened-buffer
+   (get-text-property (or pos (point))
+                     'emms-track)))
+
+(defun emms-playlist-next ()
+  "Move to the next track in the current buffer."
+  (emms-playlist-ensure-playlist-buffer)
+  (let ((next (next-single-property-change (point)
+                                           'emms-track)))
+    (when (not next)
+      (error "No next track"))
+    (when (not (emms-playlist-track-at next))
+      (setq next (next-single-property-change next 'emms-track)))
+    (when (or (not next)
+              (= next (point-max)))
+      (error "No next track"))
+    (goto-char next)))
+
+(defun emms-playlist-previous ()
+  "Move to the previous track in the current buffer."
+  (emms-playlist-ensure-playlist-buffer)
+  (let ((prev (previous-single-property-change (point)
+                                               'emms-track)))
+    (when (not prev)
+      (error "No previous track"))
+    (when (not (get-text-property prev 'emms-track))
+      (setq prev (or (previous-single-property-change prev 'emms-track)
+                     (point-min))))
+    (when (or (not prev)
+              (not (get-text-property prev 'emms-track)))
+      (error "No previous track"))
+    (goto-char prev)))
+
+(defun emms-playlist-first ()
+  "Move to the first track in the current buffer."
+  (emms-playlist-ensure-playlist-buffer)
+  (let ((first (condition-case nil
+                   (save-excursion
+                     (goto-char (point-min))
+                     (when (not (emms-playlist-track-at (point)))
+                       (emms-playlist-next))
+                     (point))
+                 (error
+                  nil))))
+    (if first
+        (goto-char first)
+      (error "No first track"))))
+
+(defun emms-playlist-last ()
+  "Move to the last track in the current buffer."
+  (emms-playlist-ensure-playlist-buffer)
+  (let ((last (condition-case nil
+                  (save-excursion
+                    (goto-char (point-max))
+                    (emms-playlist-previous)
+                    (point))
+                (error
+                 nil))))
+    (if last
+        (goto-char last)
+      (error "No last track"))))
+
+(defun emms-playlist-delete-track ()
+  "Delete the track at point."
+  (emms-playlist-ensure-playlist-buffer)
+  (funcall emms-playlist-delete-track-function))
+
+;;; Track selection
+(defun emms-playlist-selected-track ()
+  "Return the currently selected track."
+  (emms-playlist-ensure-playlist-buffer)
+  (when emms-playlist-selected-marker
+    (emms-playlist-track-at emms-playlist-selected-marker)))
+
+(defun emms-playlist-current-selected-track ()
+  "Return the currently selected track in the current playlist."
+  (with-current-emms-playlist
+    (emms-playlist-selected-track)))
+
+(defun emms-playlist-selected-track-at-p (&optional point)
+  "Return non-nil if POINT (defaulting to point) is on the selected track."
+  (when emms-playlist-selected-marker
+    (or (= emms-playlist-selected-marker
+           (or point (point)))
+        (let ((p (previous-single-property-change (or point (point))
+                                                  'emms-track)))
+          (when p
+            (= emms-playlist-selected-marker
+               p))))))
+
+(defun emms-playlist-select (pos)
+  "Select the track at POS."
+  (emms-playlist-ensure-playlist-buffer)
+  (when (not (emms-playlist-track-at pos))
+    (error "No track at position %s" pos))
+  (when (not emms-playlist-selected-marker)
+    (setq emms-playlist-selected-marker (make-marker)))
+  (set-marker-insertion-type emms-playlist-selected-marker t)
+  (set-marker emms-playlist-selected-marker pos)
+  (run-hooks 'emms-playlist-selection-changed-hook))
+
+(defun emms-playlist-select-next ()
+  "Select the next track in the current buffer."
+  (emms-playlist-ensure-playlist-buffer)
+  (save-excursion
+    (goto-char (if (and emms-playlist-selected-marker
+                        (marker-position emms-playlist-selected-marker))
+                   emms-playlist-selected-marker
+                 (point-min)))
+    (condition-case nil
+        (progn
+          (if emms-repeat-playlist
+              (condition-case nil
+                  (emms-playlist-next)
+                (error
+                 (emms-playlist-first)))
+            (emms-playlist-next))
+          (emms-playlist-select (point)))
+      (error
+       (error "No next track in playlist")))))
+
+(defun emms-playlist-current-select-next ()
+  "Select the next track in the current playlist."
+  (with-current-emms-playlist
+    (emms-playlist-select-next)))
+
+(defun emms-playlist-select-previous ()
+  "Select the previous track in the current buffer."
+  (emms-playlist-ensure-playlist-buffer)
+  (save-excursion
+    (goto-char (if (and emms-playlist-selected-marker
+                        (marker-position emms-playlist-selected-marker))
+                   emms-playlist-selected-marker
+                 (point-max)))
+    (condition-case nil
+        (progn
+          (if emms-repeat-playlist
+              (condition-case nil
+                  (emms-playlist-previous)
+                (error
+                 (emms-playlist-last)))
+            (emms-playlist-previous))
+          (emms-playlist-select (point)))
+      (error
+       (error "No previous track in playlist")))))
+
+(defun emms-playlist-current-select-previous ()
+  "Select the previous track in the current playlist."
+  (with-current-emms-playlist
+    (emms-playlist-select-previous)))
+
+(defun emms-playlist-select-random ()
+  "Select a random track in the current buffer."
+  (emms-playlist-ensure-playlist-buffer)
+  ;; FIXME: This is rather inefficient.
+  (save-excursion
+    (let ((track-indices nil))
+      (goto-char (point-min))
+      (emms-walk-tracks
+        (setq track-indices (cons (point)
+                                  track-indices)))
+      (setq track-indices (vconcat track-indices))
+      (emms-playlist-select (aref track-indices
+                                  (random (length track-indices)))))))
+
+(defun emms-playlist-current-select-random ()
+  "Select a random track in the current playlist."
+  (with-current-emms-playlist
+    (emms-playlist-select-random)))
+
+(defun emms-playlist-select-first ()
+  "Select the first track in the current buffer."
+  (emms-playlist-ensure-playlist-buffer)
+  (save-excursion
+    (emms-playlist-first)
+    (emms-playlist-select (point))))
+
+(defun emms-playlist-current-select-first ()
+  "Select the first track in the current playlist."
+  (with-current-emms-playlist
+    (emms-playlist-select-first)))
+
+(defun emms-playlist-select-last ()
+  "Select the last track in the current buffer."
+  (emms-playlist-ensure-playlist-buffer)
+  (save-excursion
+    (emms-playlist-last)
+    (emms-playlist-select (point))))
+
+(defun emms-playlist-current-select-last ()
+  "Select the last track in the current playlist."
+  (with-current-emms-playlist
+    (emms-playlist-select-last)))
+
+;;; Playlist manipulation
+(defun emms-playlist-insert-track (track)
+  "Insert TRACK at the current position into the playlist.
+This uses `emms-playlist-insert-track-function'."
+  (emms-playlist-ensure-playlist-buffer)
+  (funcall emms-playlist-insert-track-function track))
+
+(defun emms-playlist-update-track ()
+  "Update TRACK at point.
+This uses `emms-playlist-update-track-function'."
+  (emms-playlist-ensure-playlist-buffer)
+  (funcall emms-playlist-update-track-function))
+
+(defun emms-playlist-insert-source (source &rest args)
+  "Insert tracks from SOURCE, supplying ARGS as arguments."
+  (emms-playlist-ensure-playlist-buffer)
+  (save-restriction
+    (narrow-to-region (point)
+                      (point))
+    (apply source args)
+    (run-hooks 'emms-playlist-source-inserted-hook)))
+
+(defun emms-playlist-current-insert-source (source &rest args)
+  "Insert tracks from SOURCE in the current playlist.
+This is supplying ARGS as arguments to the source."
+  (with-current-emms-playlist
+    (apply 'emms-playlist-insert-source source args)))
+
+(defun emms-playlist-tracks-in-region (beg end)
+  "Return all tracks between BEG and END."
+  (emms-playlist-ensure-playlist-buffer)
+  (let ((tracks nil))
+    (save-restriction
+      (narrow-to-region beg end)
+      (goto-char (point-min))
+      (emms-walk-tracks
+        (setq tracks (cons (emms-playlist-track-at (point))
+                           tracks))))
+    tracks))
+
+(defun emms-playlist-track-updated (track)
+  "Update TRACK in all playlist buffers."
+  (mapc (lambda (buf)
+          (with-current-buffer buf
+            (when emms-playlist-buffer-p
+              (save-excursion
+                (let ((pos (text-property-any (point-min) (point-max)
+                                              'emms-track track)))
+                  (while pos
+                    (goto-char pos)
+                    (emms-playlist-update-track)
+                    (setq pos (text-property-any
+                               (next-single-property-change (point)
+                                                           'emms-track)
+                               (point-max)
+                               'emms-track
+                               track))))))))
+        (buffer-list))
+  t)
+
+;;; Simple playlist buffer
+(defun emms-playlist-simple-insert-track (track)
+  "Insert the description of TRACK at point."
+  (emms-playlist-ensure-playlist-buffer)
+  (let ((inhibit-read-only t))
+    (insert (emms-propertize (emms-track-force-description track)
+                             'emms-track track)
+            "\n")))
+
+(defun emms-playlist-simple-update-track ()
+  "Update the track at point.
+Since we don't do anything special with the track anyway, just
+ignore this."
+  nil)
+
+(defun emms-playlist-simple-delete-track ()
+  "Delete the track at point."
+  (emms-playlist-ensure-playlist-buffer)
+  (when (not (emms-playlist-track-at (point)))
+    (error "No track at point"))
+  (let ((inhibit-read-only t)
+        (region (emms-property-region (point) 'emms-track)))
+    (delete-region (car region)
+                   (cdr region))))
+
+(defun emms-playlist-simple-shuffle ()
+  "Shuffle the whole playlist buffer."
+  (emms-playlist-ensure-playlist-buffer)
+  (let ((inhibit-read-only t)
+        (current nil))
+    (widen)
+    (when emms-player-playing-p
+      (setq current (emms-playlist-selected-track))
+      (goto-char emms-playlist-selected-marker)
+      (emms-playlist-delete-track))
+    (let* ((tracks (vconcat (emms-playlist-tracks-in-region (point-min)
+                                                            (point-max))))
+           (len (length tracks))
+           (i 0))
+      (delete-region (point-min)
+                     (point-max))
+      (run-hooks 'emms-playlist-cleared-hook)
+      (emms-shuffle-vector tracks)
+      (when current
+        (emms-playlist-insert-track current))
+      (while (< i len)
+        (emms-playlist-insert-track (aref tracks i))
+        (setq i (1+ i))))
+    (emms-playlist-select-first)
+    (goto-char (point-max))))
+
+(defun emms-playlist-simple-sort ()
+  "Sort the whole playlist buffer."
+  (emms-playlist-ensure-playlist-buffer)
+  (widen)
+  (let ((inhibit-read-only t)
+        (current (emms-playlist-selected-track))
+        (tracks (emms-playlist-tracks-in-region (point-min)
+                                                (point-max))))
+    (delete-region (point-min)
+                   (point-max))
+    (run-hooks 'emms-playlist-cleared-hook)
+    (mapc 'emms-playlist-insert-track
+          (sort tracks emms-sort-lessp-function))
+    (let ((pos (text-property-any (point-min)
+                                  (point-max)
+                                  'emms-track current)))
+      (if pos
+          (emms-playlist-select pos)
+        (emms-playlist-first)))))
+
+(defun emms-uniq-list (list stringify)
+  "Compare stringfied element of list, and remove duplicate elements."
+  ;; This uses a fast append list, keeping a pointer to the last cons
+  ;; cell of the list (TAIL).  It might be worthwhile to provide an
+  ;; abstraction for this eventually.
+  (let* ((hash (make-hash-table :test 'equal))
+         (result (cons nil nil))
+         (tail result))
+    (dolist (element list)
+      (let ((str (funcall stringify element)))
+        (when (not (gethash str hash))
+          (setcdr tail (cons element nil))
+          (setq tail (cdr tail)))
+        (puthash str t hash)))
+    (cdr result)))
+
+(defun emms-playlist-simple-uniq ()
+  "Remove duplicate tracks."
+  ;; TODO: This seems unnecessarily destructive.
+  (emms-playlist-ensure-playlist-buffer)
+  (widen)
+  (let ((inhibit-read-only t)
+        (current (emms-playlist-selected-track))
+        (tracks (emms-playlist-tracks-in-region (point-min)
+                                                (point-max))))
+    (delete-region (point-min) (point-max))
+    (run-hooks 'emms-playlist-cleared-hook)
+    (mapc 'emms-playlist-insert-track
+          (nreverse
+           (emms-uniq-list tracks 'emms-track-name)))
+    (let ((pos (text-property-any (point-min)
+                                  (point-max)
+                                  'emms-track current)))
+      (if pos
+          (emms-playlist-select pos)
+        (emms-playlist-first)))))
+
+(defun emms-default-ok-track-function (track)
+  "A function which OKs all tracks for playing by default."
+  t)
+
+;;; Helper functions
+(defun emms-property-region (pos prop)
+  "Return a pair of the beginning and end of the property PROP at POS.
+If POS does not contain PROP, try to find PROP just before POS."
+  (let (begin end)
+    (if (and (> pos (point-min))
+             (get-text-property (1- pos) prop))
+        (setq begin (previous-single-property-change (1- pos) prop))
+      (if (get-text-property pos prop)
+          (setq begin pos)
+        (error "Cannot find the %s property at the given position" prop)))
+    (if (get-text-property pos prop)
+        (setq end (next-single-property-change pos prop))
+      (if (and (> pos (point-min))
+               (get-text-property (1- pos) prop))
+          (setq end pos)
+        (error "Cannot find the %s property at the given position" prop)))
+    (cons (or begin (point-min))
+          (or end (point-max)))))
+
+(defun emms-shuffle-vector (vector)
+  "Shuffle VECTOR."
+  (let ((i (- (length vector) 1)))
+    (while (>= i 0)
+      (let* ((r (random (1+ i)))
+             (old (aref vector r)))
+        (aset vector r (aref vector i))
+        (aset vector i old))
+      (setq i (- i 1))))
+  vector)
+
+
+;;; Sources
+
+;; A source is just a function which is called in a playlist buffer.
+;; It should use `emms-playlist-insert-track' to insert the tracks it
+;; knows about.
+;;
+;; The define-emms-source macro also defines functions
+;; emms-play-SOURCE and emms-add-SOURCE.  The former will replace the
+;; current playlist, while the latter will add to the end.
+
+(defmacro define-emms-source (name arglist &rest body)
+  "Define a new EMMS source called NAME.
+This macro defines three functions: `emms-source-NAME',
+`emms-play-NAME' and `emms-add-NAME'.  BODY should use
+`emms-playlist-insert-track' to insert all tracks to be played,
+which is exactly what `emms-source-NAME' will do.  The other two
+functions will be simple wrappers around `emms-source-NAME'; any
+`interactive' form that you specify in BODY will end up in these.
+See emms-source-file.el for some examples."
+  (let ((source-name (intern (format "emms-source-%s" name)))
+        (source-play (intern (format "emms-play-%s" name)))
+        (source-add (intern (format "emms-add-%s" name)))
+        (source-insert (intern (format "emms-insert-%s" name)))
+        (docstring "A source of tracks for EMMS.")
+        (interactive nil)
+        (call-args (delete '&rest
+                           (delete '&optional
+                                   arglist))))
+    (when (stringp (car body))
+      (setq docstring (car body)
+            body (cdr body)))
+    (when (eq 'interactive (caar body))
+      (setq interactive (car body)
+            body (cdr body)))
+    `(progn
+       (defun ,source-name ,arglist
+         ,docstring
+         ,@body)
+       (defun ,source-play ,arglist
+         ,docstring
+         ,interactive
+         (if current-prefix-arg
+             (let ((current-prefix-arg nil))
+               (emms-source-add ',source-name ,@call-args))
+           (emms-source-play ',source-name ,@call-args)))
+       (defun ,source-add ,arglist
+         ,docstring
+         ,interactive
+         (if current-prefix-arg
+             (let ((current-prefix-arg nil))
+               (emms-source-play ',source-name ,@call-args))
+           (emms-source-add ',source-name ,@call-args)))
+       (defun ,source-insert ,arglist
+         ,docstring
+         ,interactive
+         (emms-source-insert ',source-name ,@call-args)))))
+
+(defun emms-source-play (source &rest args)
+  "Play the tracks of SOURCE, after first clearing the EMMS playlist."
+  (emms-stop)
+  (emms-playlist-current-clear)
+  (apply 'emms-playlist-current-insert-source source args)
+  (emms-playlist-current-select-first)
+  (emms-start))
+
+(defun emms-source-add (source &rest args)
+  "Add the tracks of SOURCE at the current position in the playlist."
+  (with-current-emms-playlist
+    (save-excursion
+      (goto-char (point-max))
+      (apply 'emms-playlist-current-insert-source source args))
+    (when (or (not emms-playlist-selected-marker)
+              (not (marker-position emms-playlist-selected-marker)))
+      (emms-playlist-select-first))))
+
+(defun emms-source-insert (source &rest args)
+  "Insert the tracks from SOURCE in the current buffer."
+  (if (not emms-playlist-buffer-p)
+      (error "Not in an EMMS playlist buffer")
+    (apply 'emms-playlist-insert-source source args)))
+
+;;; User-defined playlists
+;;; FIXME: Shuffle is bogus here! (because of narrowing)
+(defmacro define-emms-combined-source (name shufflep sources)
+  "Define a `emms-play-X' and `emms-add-X' function for SOURCES."
+  `(define-emms-source ,name ()
+     "An EMMS source for a tracklist."
+     (interactive)
+     (mapc (lambda (source)
+             (apply (car source)
+                    (cdr source)))
+           ,sources)
+     ,(when shufflep
+        '(save-restriction
+           (widen)
+           (emms-shuffle)))))
+
+
+;;; Players
+
+;; A player is a data structure created by `emms-player'.
+;; See the docstring of that function for more information.
+
+(defvar emms-player-stopped-p nil
+  "Non-nil if the last EMMS player was stopped by the user.")
+
+(defun emms-player (start stop playablep)
+  "Create a new EMMS player.
+The start function will be START, and the stop function STOP.
+PLAYABLEP should return non-nil for tracks that this player can
+play.
+
+When trying to play a track, EMMS walks through
+`emms-player-list'.  For each player, it calls the PLAYABLEP
+function.  The player corresponding to the first PLAYABLEP
+function that returns non-nil is used to play the track.  To
+actually play the track, EMMS calls the START function, passing
+the chosen track as a parameter.
+
+If the user tells EMMS to stop playing, the STOP function is
+called.  Once the player has finished playing, it should call
+`emms-player-stopped' to let EMMS know."
+  (let ((p (emms-dictionary '*player*)))
+    (emms-player-set p 'start start)
+    (emms-player-set p 'stop stop)
+    (emms-player-set p 'playablep playablep)
+    p))
+
+(defun emms-player-get (player name &optional inexistent)
+  "Return the value of entry NAME in PLAYER."
+  (let ((p (if (symbolp player)
+               (symbol-value player)
+             player)))
+    (emms-dictionary-get p name inexistent)))
+
+(defun emms-player-set (player name value)
+  "Set the value of entry NAME in PLAYER to VALUE."
+  (let ((p (if (symbolp player)
+               (symbol-value player)
+             player)))
+    (emms-dictionary-set p name value)))
+
+(defun emms-player-for (track)
+  "Return an EMMS player capable of playing TRACK.
+This will be the first player whose PLAYABLEP function returns
+non-nil, or nil if no such player exists."
+  (let ((lis emms-player-list))
+    (while (and lis
+                (not (funcall (emms-player-get (car lis) 'playablep)
+                              track)))
+      (setq lis (cdr lis)))
+    (if lis
+        (car lis)
+      nil)))
+
+(defun emms-player-start (track)
+  "Start playing TRACK."
+  (if emms-player-playing-p
+      (error "A player is already playing")
+    (let ((player (emms-player-for track)))
+      (if (not player)
+          (error "Don't know how to play track: %S" track)
+        ;; Change default-directory so we don't accidentally block any
+        ;; directories the current buffer was visiting.
+        (let ((default-directory "/"))
+          (funcall (emms-player-get player 'start)
+                   track))))))
+
+(defun emms-player-started (player)
+  "Declare that the given EMMS PLAYER has started.
+This should only be done by the current player itself."
+  (setq emms-player-playing-p player
+        emms-player-paused-p  nil)
+  (run-hooks 'emms-player-started-hook))
+
+(defun emms-player-stop ()
+  "Stop the current EMMS player."
+  (when emms-player-playing-p
+    (let ((emms-player-stopped-p t))
+      (funcall (emms-player-get emms-player-playing-p 'stop)))
+    (setq emms-player-playing-p nil)))
+
+(defun emms-player-stopped ()
+  "Declare that the current EMMS player is finished.
+This should only be done by the current player itself."
+  (setq emms-player-playing-p nil)
+  (if emms-player-stopped-p
+      (run-hooks 'emms-player-stopped-hook)
+    (sleep-for emms-player-delay)
+    (run-hooks 'emms-player-finished-hook)
+    (funcall emms-player-next-function)))
+
+(defun emms-player-pause ()
+  "Pause the current EMMS player."
+  (cond
+   ((not emms-player-playing-p)
+    (error "Can't pause player, nothing is playing"))
+   (emms-player-paused-p
+    (let ((resume (emms-player-get emms-player-playing-p 'resume))
+          (pause (emms-player-get emms-player-playing-p 'pause)))
+      (cond
+       (resume
+        (funcall resume))
+       (pause
+        (funcall pause))
+       (t
+        (error "Player does not know how to pause"))))
+    (setq emms-player-paused-p nil)
+    (run-hooks 'emms-player-paused-hook))
+   (t
+    (let ((pause (emms-player-get emms-player-playing-p 'pause)))
+      (if pause
+          (funcall pause)
+        (error "Player does not know how to pause")))
+    (setq emms-player-paused-p t)
+    (run-hooks 'emms-player-paused-hook))))
+
+(defun emms-player-seek (seconds)
+  "Seek the current player by SECONDS seconds.
+This can be a floating point number for fractions of a second, or
+negative to seek backwards."
+  (if (not emms-player-playing-p)
+      (error "Can't seek player, nothing playing right now")
+    (let ((seek (emms-player-get emms-player-playing-p 'seek)))
+      (if (not seek)
+          (error "Player does not know how to seek")
+        (funcall seek seconds)
+        (run-hook-with-args 'emms-player-seeked-functions seconds)))))
+
+(defun emms-player-seek-to (seconds)
+  "Seek the current player to SECONDS seconds.
+This can be a floating point number for fractions of a second, or
+negative to seek backwards."
+  (if (not emms-player-playing-p)
+      (error "Can't seek-to player, nothing playing right now")
+    (let ((seek (emms-player-get emms-player-playing-p 'seek-to)))
+      (if (not seek)
+          (error "Player does not know how to seek-to")
+        (funcall seek seconds)
+        (run-hook-with-args 'emms-player-time-set-functions seconds)))))
+
+(provide 'emms)
+;;; emms.el ends here
diff --git a/lisp/jack.el b/jack.el
similarity index 100%
rename from lisp/jack.el
rename to jack.el
diff --git a/lisp/later-do.el b/later-do.el
similarity index 100%
rename from lisp/later-do.el
rename to later-do.el
diff --git a/lisp/Makefile b/lisp/Makefile
deleted file mode 100644
index 85ff3e1..0000000
--- a/lisp/Makefile
+++ /dev/null
@@ -1,28 +0,0 @@
-EMACS=emacs
-SITEFLAG=--no-site-file
-ALLSOURCE=$(wildcard *.el)
-ALLCOMPILED=$(wildcard *.elc)
-SPECIAL=emms-auto.el emms-maint.el
-SOURCE=$(filter-out $(SPECIAL),$(ALLSOURCE))
-TARGET=$(patsubst %.el,%.elc,$(SOURCE))
-
-.PHONY: all clean
-.PRECIOUS: %.elc
-all: emms-auto.el $(TARGET)
-
-emms-auto.el: emms-auto.in $(SOURCE)
-       cp emms-auto.in emms-auto.el
-       -rm -f emms-auto.elc
-       @$(EMACS) -q $(SITEFLAG) -batch \
-               -l emms-maint.el \
-               -l emms-auto.el \
-               -f emms-generate-autoloads \
-               $(shell pwd)/emms-auto.el .
-
-%.elc: %.el
-       @$(EMACS) -q $(SITEFLAG) -batch \
-               -l emms-maint.el \
-               -f batch-byte-compile $<
-
-clean:
-       -rm -f *~ *.elc emms-auto.el
diff --git a/lisp/emms.el b/lisp/emms.el
deleted file mode 100644
index ff786b7..0000000
--- a/lisp/emms.el
+++ /dev/null
@@ -1,1539 +0,0 @@
-;;; emms.el --- The Emacs Multimedia System
-
-;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008,
-;;   2009, 2018, 2020  Free Software Foundation, Inc.
-
-;; Author: Jorgen Schäfer <forcer@forcix.cx>, the Emms developers (see AUTHORS 
file)
-;; Maintainer: Yoni Rabkin <yrk@gnu.org>
-;; Version: 5.4
-;; Keywords: emms, mp3, ogg, flac, music, mpeg, video, multimedia
-;; Package-Requires: ((cl-lib "0.5"))
-;; url: https://www.gnu.org/software/emms/
-
-;; This file is part of EMMS.
-
-;; EMMS is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-
-;; EMMS is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
-;; License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This is the very core of EMMS.  It provides ways to play a track
-;; using `emms-start', to go through the playlist using the commands
-;; `emms-next' and `emms-previous', to stop the playback using
-;; `emms-stop', and to see what's currently playing using `emms-show'.
-
-;; But in itself, this core is useless, because it doesn't know how to
-;; play any tracks --- you need players for this.  In fact, it doesn't
-;; even know how to find any tracks to consider playing --- for this,
-;; you need sources.
-
-;; A sample configuration is offered in emms-setup.el, and the
-;; Friendly Manual in the doc/ directory is both detailed, and kept up
-;; to date.
-
-
-;;; Code:
-
-(defvar emms-version "5.4"
-  "EMMS version string.")
-
-
-;;; User Customization
-
-(defgroup emms nil
-  "*The Emacs Multimedia System."
-  :prefix "emms-"
-  :group 'multimedia
-  :group 'applications)
-
-(defgroup emms-player nil
-  "*Track players for EMMS."
-  :prefix "emms-player-"
-  :group 'emms)
-
-(defgroup emms-source nil
-  "*Track sources for EMMS."
-  :prefix "emms-source-"
-  :group 'emms)
-
-(defcustom emms-player-list nil
-  "*List of players that EMMS can use.  You need to set this!"
-  :group 'emms
-  :type '(repeat (symbol :tag "Player")))
-
-(defcustom emms-show-format "Currently playing: %s"
-  "*The format to use for `emms-show'.
-Any \"%s\" is replaced by what `emms-track-description-function' returns
-for the currently playing track."
-  :group 'emms
-  :type 'string)
-
-(defcustom emms-repeat-playlist nil
-  "*Non-nil if the EMMS playlist should automatically repeat.
-If nil, playback will stop when the last track finishes playing.
-If non-nil, EMMS will wrap back to the first track when that happens."
-  :group 'emms
-  :type 'boolean)
-
-(defcustom emms-random-playlist nil
-  "*Non-nil means that tracks are played randomly. If nil, tracks
-are played sequentially."
-  :group 'emms
-  :type 'boolean)
-
-(defcustom emms-repeat-track nil
-  "Non-nil, playback will repeat current track.  If nil, EMMS will play
-track by track normally."
-  :group 'emms
-  :type 'boolean)
-
-(defvar-local emms-single-track nil
-  "Non-nil, play the current track and then stop.")
-
-(defcustom emms-completing-read-function
-  (if (and (boundp 'ido-mode)
-           ido-mode)
-      'ido-completing-read
-    'completing-read)
-  "Function to call when prompting user to choose between a list of options.
-This should take the same arguments as `completing-read'.  Some
-possible values are `completing-read' and `ido-completing-read'.
-Note that you must set `ido-mode' if using
-`ido-completing-read'."
-  :group 'emms
-  :type 'function)
-
-(defcustom emms-track-description-function 'emms-track-simple-description
-  "*Function for describing an EMMS track in a user-friendly way."
-  :group 'emms
-  :type 'function)
-
-(defcustom emms-player-delay 0
-  "The delay to pause after a player finished.
-This is a floating-point number of seconds.  This is necessary
-for some platforms where it takes a bit to free the audio device
-after a player has finished.  If EMMS is skipping songs, increase
-this number."
-  :type 'number
-  :group 'emms)
-
-(defcustom emms-playlist-shuffle-function 'emms-playlist-simple-shuffle
-  "*The function to use for shuffling the playlist."
-  :type 'function
-  :group 'emms)
-
-(defcustom emms-playlist-sort-function 'emms-playlist-simple-sort
-  "*The function to use for sorting the playlist."
-  :type 'function
-  :group 'emms)
-
-(defcustom emms-playlist-uniq-function 'emms-playlist-simple-uniq
-  "*The function to use for removing duplicate tracks in the playlist."
-  :type 'function
-  :group 'emms)
-
-(defcustom emms-sort-lessp-function 'emms-sort-track-name-less-p
-  "*Function for comparing two EMMS tracks.
-The function should return non-nil if and only if the first track
-sorts before the second (see `sort')."
-  :group 'emms
-  :type 'function)
-
-(defcustom emms-playlist-buffer-name " *EMMS Playlist*"
-  "*The default name of the EMMS playlist buffer."
-  :type 'string
-  :group 'emms)
-
-(defcustom emms-playlist-default-major-mode 'emms-playlist-mode
-  "*The default major mode for EMMS playlist."
-  :type 'function
-  :group 'emms)
-
-(defcustom emms-playlist-insert-track-function 
'emms-playlist-simple-insert-track
-  "*A function to insert a track into the playlist buffer."
-  :group 'emms
-  :type 'function)
-(make-variable-buffer-local 'emms-playlist-insert-track-function)
-
-(defcustom emms-playlist-update-track-function 
'emms-playlist-simple-update-track
-  "*A function to update the track at point.
-This is called when the track information changed.  This also
-shouldn't assume that the track has been inserted before."
-  :group 'emms
-  :type 'function)
-(make-variable-buffer-local 'emms-playlist-insert-track-function)
-
-(defcustom emms-playlist-delete-track-function 
'emms-playlist-simple-delete-track
-  "*A function to delete the track at point in the playlist buffer."
-  :group 'emms
-  :type 'function)
-(make-variable-buffer-local 'emms-playlist-delete-track-function)
-
-(defcustom emms-ok-track-function 'emms-default-ok-track-function
-  "*Function returns true if we shouldn't skip this track."
-  :group 'emms
-  :type 'function)
-
-(defcustom emms-playlist-source-inserted-hook nil
-  "*Hook run when a source got inserted into the playlist.
-The buffer is narrowed to the new tracks."
-  :type 'hook
-  :group 'emms)
-
-(defcustom emms-playlist-selection-changed-hook nil
-  "*Hook run after another track is selected in the EMMS playlist."
-  :group 'emms
-  :type 'hook)
-
-(defcustom emms-playlist-cleared-hook nil
-  "*Hook run after the current EMMS playlist is cleared.
-This happens both when the playlist is cleared and when a new
-buffer is created for it."
-  :group 'emms
-  :type 'hook)
-
-(defcustom emms-track-initialize-functions nil
-  "*List of functions to call for each new EMMS track.
-This can be used to initialize tracks with various info."
-  :group 'emms
-  :type 'hook)
-
-(defcustom emms-track-info-filters nil
-  "*List of functions to call when a track changes data, before updating
-the display.
-These functions are passed the track as an argument."
-  :group 'emms
-  :type 'hook)
-
-(defcustom emms-track-updated-functions nil
-  "*List of functions to call when a track changes data, after updating
-the display.
-These functions are passed the track as an argument."
-  :group 'emms
-  :type 'hook)
-
-(defcustom emms-player-started-hook nil
-  "*Hook run when an EMMS player starts playing."
-  :group 'emms
-  :type 'hook
-  :options '(emms-show))
-
-(defcustom emms-player-stopped-hook nil
-  "*Hook run when an EMMS player is stopped by the user.
-See `emms-player-finished-hook'."
-  :group 'emms
-  :type 'hook)
-
-(defcustom emms-player-finished-hook nil
-  "*Hook run when an EMMS player finishes playing a track.
-Please pay attention to the differences between
-`emms-player-finished-hook' and `emms-player-stopped-hook'.  The
-former is called only when the player actually finishes playing a
-track; the latter, only when the player is stopped
-interactively."
-  :group 'emms
-  :type 'hook)
-
-(defcustom emms-player-next-function 'emms-next-noerror
-  "*A function run when EMMS thinks the next song should be played."
-  :group 'emms
-  :type 'function
-  :options '(emms-next-noerror
-             emms-random))
-
-(defcustom emms-player-paused-hook nil
-  "*Hook run when a player is paused or resumed.
-Use `emms-player-paused-p' to find the current state."
-  :group 'emms
-  :type 'hook)
-
-(defcustom emms-seek-seconds 10
-  "The number of seconds to seek forward or backward when seeking."
-  :group 'emms
-  :type 'number)
-
-(defcustom emms-player-seeked-functions nil
-  "*Functions called when a player is seeking.
-The functions are called with a single argument, the amount of
-seconds the player did seek."
-  :group 'emms
-  :type 'hook)
-
-(defcustom emms-player-time-set-functions nil
-  "*Functions called when a player is setting the elapsed time of a track.
-The functions are called with a single argument, the time elapsed
-since the beginning of the current track."
-  :group 'emms
-  :type 'hook)
-
-(defcustom emms-cache-get-function nil
-  "A function to retrieve a track entry from the cache.
-This is called with two arguments, the type and the name."
-  :group 'emms
-  :type 'function)
-
-(defcustom emms-cache-set-function nil
-  "A function to add/set a track entry from the cache.
-This is called with three arguments: the type of the track, the
-name of the track, and the track itself."
-  :group 'emms
-  :type 'function)
-
-(defcustom emms-cache-modified-function nil
-  "A function to be called when a track is modified.
-The modified track is passed as the argument to this function."
-  :group 'emms
-  :type 'function)
-
-(defcustom emms-directory (expand-file-name "emms" user-emacs-directory)
-  "*Directory variable from which all other emms file variables are derived."
-  :group 'emms
-  :type 'string)
-
-(defvar emms-player-playing-p nil
-  "The currently playing EMMS player, or nil.")
-
-(defvar emms-player-paused-p nil
-  "Whether the current player is paused or not.")
-
-(defvar emms-source-old-buffer nil
-  "The active buffer before a source was invoked.
-This can be used if the source depends on the current buffer not
-being the playlist buffer.")
-
-(defvar emms-playlist-buffer nil
-  "The current playlist buffer, if any.")
-
-
-;;; Macros
-
-;;; These need to be at the top of the file so that compilation works.
-
-(defmacro with-current-emms-playlist (&rest body)
-  "Run BODY with the current buffer being the current playlist buffer.
-This also disables any read-onliness of the current buffer."
-  `(progn
-     (when (or (not emms-playlist-buffer)
-               (not (buffer-live-p emms-playlist-buffer)))
-       (emms-playlist-current-clear))
-     (let ((emms-source-old-buffer (or emms-source-old-buffer
-                                       (current-buffer))))
-       (with-current-buffer emms-playlist-buffer
-        (let ((inhibit-read-only t))
-          ,@body)))))
-(put 'with-current-emms-playlist 'lisp-indent-function 0)
-(put 'with-current-emms-playlist 'edebug-form-spec '(body))
-
-(defmacro emms-with-inhibit-read-only-t (&rest body)
-  "Simple wrapper around `inhibit-read-only'."
-  `(let ((inhibit-read-only t))
-     ,@body))
-(put 'emms-with-inhibit-read-only-t 'edebug-form-spec '(body))
-
-(defmacro emms-with-widened-buffer (&rest body)
-  `(save-restriction
-     (widen)
-     ,@body))
-(put 'emms-with-widened-buffer 'edebug-form-spec '(body))
-
-(defmacro emms-walk-tracks (&rest body)
-  "Execute BODY for each track in the current buffer, starting at point.
-Point will be placed at the beginning of the track before
-executing BODY.
-
-Point will not be restored afterward."
-  (let ((donep (make-symbol "donep")))
-    `(let ((,donep nil))
-       ;; skip to first track if not on one
-       (unless (emms-playlist-track-at (point))
-         (condition-case nil
-             (emms-playlist-next)
-           (error
-            (setq ,donep t))))
-       ;; walk tracks
-       (while (not ,donep)
-         ,@body
-         (condition-case nil
-             (emms-playlist-next)
-           (error
-            (setq ,donep t)))))))
-(put 'emms-walk-tracks 'lisp-indent-function 0)
-(put 'emms-walk-tracks 'edebug-form-spec '(body))
-
-(defvar emms-player-base-format-list
-  '("ogg" "mp3" "wav" "mpg" "mpeg" "wmv" "wma"
-    "mov" "avi" "divx" "ogm" "ogv" "asf" "mkv"
-    "rm" "rmvb" "mp4" "flac" "vob" "m4a" "ape"
-    "flv" "webm" "aif")
-  "A list of common formats which player definitions can use.")
-
-
-;;; User Interface
-
-(defun emms-start ()
-  "Start playing the current track in the EMMS playlist."
-  (interactive)
-  (unless emms-player-playing-p
-    (emms-player-start (emms-playlist-current-selected-track))))
-
-(defun emms-stop ()
-  "Stop any current EMMS playback."
-  (interactive)
-  (when emms-player-playing-p
-    (emms-player-stop)))
-
-(defun emms-next ()
-  "Start playing the next track in the EMMS playlist.
-This might behave funny if called from `emms-player-next-function',
-so use `emms-next-noerror' in that case."
-  (interactive)
-  (when emms-player-playing-p
-    (emms-stop))
-  (emms-playlist-current-select-next)
-  (emms-start))
-
-(defun emms-next-noerror ()
-  "Start playing the next track in the EMMS playlist.
-Unlike `emms-next', this function doesn't signal an error when called
-at the end of the playlist.
-This function should only be called when no player is playing.
-This is a good function to put in `emms-player-next-function'."
-  (interactive)
-  (when emms-player-playing-p
-    (error "A track is already being played"))
-  (cond (emms-repeat-track
-        (emms-start))
-       (emms-single-track              ; buffer local
-        (emms-stop))
-       ;; attempt to play the next track but ignore errors
-       ((condition-case nil
-             (progn
-               (emms-playlist-current-select-next)
-               t)
-           (error nil))
-        (if (funcall emms-ok-track-function
-                     (emms-playlist-current-selected-track))
-            (emms-start)
-          (emms-next-noerror)))
-        (t
-        (message "No next track in playlist"))))
-
-(defun emms-previous ()
-  "Start playing the previous track in the EMMS playlist."
-  (interactive)
-  (when emms-player-playing-p
-    (emms-stop))
-  (emms-playlist-current-select-previous)
-  (emms-start))
-
-(defun emms-random ()
-  "Jump to a random track."
-  (interactive)
-  (when emms-player-playing-p
-    (emms-stop))
-  (emms-playlist-current-select-random)
-  (emms-start))
-
-(defun emms-pause ()
-  "Pause the current player.
-If player hasn't started, then start it now."
-  (interactive)
-  (if emms-player-playing-p
-      (emms-player-pause)
-    (emms-start)))
-
-(defun emms-seek (seconds)
-  "Seek the current player SECONDS seconds.
-This can be a floating point number for sub-second fractions.
-It can also be negative to seek backwards."
-  (interactive "nSeconds to seek: ")
-  (emms-ensure-player-playing-p)
-  (emms-player-seek seconds))
-
-(defun emms-seek-to (seconds)
-  "Seek the current player to SECONDS seconds.
-This can be a floating point number for sub-second fractions.
-It can also be negative to seek backwards."
-  (interactive "nSeconds to seek to: ")
-  (emms-ensure-player-playing-p)
-  (emms-player-seek-to seconds))
-
-(defun emms-seek-forward ()
-  "Seek ten seconds forward."
-  (interactive)
-  (when emms-player-playing-p
-    (emms-player-seek emms-seek-seconds)))
-
-(defun emms-seek-backward ()
-  "Seek ten seconds backward."
-  (interactive)
-  (when emms-player-playing-p
-    (emms-player-seek (- emms-seek-seconds))))
-
-(defun emms-show (&optional insertp)
-  "Describe the current EMMS track in the minibuffer.
-If INSERTP is non-nil, insert the description into the current buffer instead.
-This function uses `emms-show-format' to format the current track."
-  (interactive "P")
-  (let ((string (if emms-player-playing-p
-                    (format emms-show-format
-                            (emms-track-description
-                             (emms-playlist-current-selected-track)))
-                  "Nothing playing right now")))
-    (if insertp
-        (insert string)
-      (message "%s" string))))
-
-(defun emms-shuffle ()
-  "Shuffle the current playlist.
-This uses `emms-playlist-shuffle-function'."
-  (interactive)
-  (with-current-emms-playlist
-    (save-excursion
-      (funcall emms-playlist-shuffle-function))))
-
-(defun emms-sort ()
-  "Sort the current playlist.
-This uses `emms-playlist-sort-function'."
-  (interactive)
-  (with-current-emms-playlist
-    (save-excursion
-      (funcall emms-playlist-sort-function))))
-
-(defun emms-uniq ()
-  "Remove duplicates from the current playlist.
-This uses `emms-playlist-uniq-function'."
-  (interactive)
-  (with-current-emms-playlist
-    (save-excursion
-      (funcall emms-playlist-uniq-function))))
-
-(defun emms-toggle-single-track ()
-  "Toggle if Emms plays a single track and stops."
-  (interactive)
-  (with-current-emms-playlist
-    (cond (emms-single-track
-          (setq emms-single-track nil)
-          (message "single track mode disabled for %s"
-                   (buffer-name)))
-         (t (setq emms-single-track t)
-            (message "single track mode enabled for %s"
-                   (buffer-name))))))
-
-(defun emms-toggle-random-playlist ()
-  "Toggle whether emms plays the tracks randomly or sequentially.
-See `emms-random-playlist'."
-  (interactive)
-  (setq emms-random-playlist (not emms-random-playlist))
-  (if emms-random-playlist
-      (progn (setq emms-player-next-function 'emms-random)
-             (message "Will play the tracks randomly."))
-    (setq emms-player-next-function 'emms-next-noerror)
-    (message "Will play the tracks sequentially.")))
-
-(defun emms-toggle-repeat-playlist ()
-  "Toggle whether emms repeats the playlist after it is done.
-See `emms-repeat-playlist'."
-  (interactive)
-  (setq emms-repeat-playlist (not emms-repeat-playlist))
-  (if emms-repeat-playlist
-      (message "Will repeat the playlist after it is done.")
-    (message "Will stop after the playlist is over.")))
-
-(defun emms-toggle-repeat-track ()
-  "Toggle whether emms repeats the current track.
-See `emms-repeat-track'."
-  (interactive)
-  (setq emms-repeat-track (not emms-repeat-track))
-  (if emms-repeat-track
-      (message "Will repeat the current track.")
-    (message "Will advance to the next track after this one.")))
-
-(defun emms-sort-track-name-less-p (a b)
-  "Return non-nil if the track name of A sorts before B."
-  (string< (emms-track-name a)
-           (emms-track-name b)))
-
-(defun emms-ensure-player-playing-p ()
-  "Raise an error if no player is playing right now."
-  (when (not emms-player-playing-p)
-    (error "No EMMS player playing right now")))
-
-(defun emms-completing-read (&rest args)
-  "Read a string in the minibuffer, with completion.
-Set `emms-completing-read' to determine which function to use.
-
-See `completing-read' for a description of ARGS."
-  (apply emms-completing-read-function args))
-
-(defun emms-display-modes ()
-  "Display the current EMMS play modes."
-  (interactive)
-  (with-current-emms-playlist
-    (message
-     "repeat playlist: %s, repeat track: %s, random: %s, single %s"
-     (if emms-repeat-playlist "yes" "no")
-     (if emms-repeat-track "yes" "no")
-     (if emms-random-playlist "yes" "no")
-     (if emms-single-track "yes" "no"))))
-
-
-;;; Compatibility functions
-
-(require 'emms-compat)
-
-
-;;; Utility functions
-
-(defun emms-insert-file-contents (filename &optional visit)
-  "Insert the contents of file FILENAME after point.
-Do character code conversion and end-of-line conversion, but none
-of the other unnecessary things like format decoding or
-`find-file-hook'.
-
-If VISIT is non-nil, the buffer's visited filename
-and last save file modtime are set, and it is marked unmodified.
-If visiting and the file does not exist, visiting is completed
-before the error is signaled."
-  (let ((format-alist nil)
-        (after-insert-file-functions nil)
-        (inhibit-file-name-handlers
-         (append '(jka-compr-handler image-file-handler epa-file-handler)
-                 inhibit-file-name-handlers))
-        (inhibit-file-name-operation 'insert-file-contents))
-    (insert-file-contents filename visit)))
-
-
-;;; Dictionaries
-
-;; This is a simple helper data structure, used by both players
-;; and tracks.
-
-(defsubst emms-dictionary (name)
-  "Create a new dictionary of type NAME."
-  (list name))
-
-(defsubst emms-dictionary-type (dict)
-  "Return the type of the dictionary DICT."
-  (car dict))
-
-(defun emms-dictionary-get (dict name &optional default)
-  "Return the value of NAME in DICT."
-  (let ((item (assq name (cdr dict))))
-    (if item
-        (cdr item)
-      default)))
-
-(defun emms-dictionary-set (dict name value)
-  "Set the value of NAME in DICT to VALUE."
-  (let ((item (assq name (cdr dict))))
-    (if item
-        (setcdr item value)
-      (setcdr dict (append (cdr dict)
-                           (list (cons name value))))))
-  dict)
-
-
-;;; Tracks
-
-;; This is a simple datatype to store track information.
-;; Each track consists of a type (a symbol) and a name (a string).
-;; In addition, each track has an associated dictionary of information.
-
-(defun emms-track (type name)
-  "Create an EMMS track with type TYPE and name NAME."
-  (let ((track (when emms-cache-get-function
-                 (funcall emms-cache-get-function type name))))
-    (when (not track)
-      (setq track (emms-dictionary '*track*))
-      ;; Prevent the cache from being called for these two sets
-      (let ((emms-cache-modified-function nil))
-        (emms-track-set track 'type type)
-        (emms-track-set track 'name name))
-      (when emms-cache-set-function
-        (funcall emms-cache-set-function type name track)))
-    ;; run any hooks regardless of a cache hit, as the entry may be
-    ;; old
-    (run-hook-with-args 'emms-track-initialize-functions track)
-    track))
-
-(defun emms-track-p (obj)
-  "True if OBJ is an emms track."
-  (and (listp obj)
-       (eq (car obj) '*track*)))
-
-(defun emms-track-type (track)
-  "Return the type of TRACK."
-  (emms-track-get track 'type))
-
-(defun emms-track-name (track)
-  "Return the name of TRACK."
-  (emms-track-get track 'name))
-
-(defun emms-track-get (track name &optional default)
-  "Return the value of NAME for TRACK.
-If there is no value, return DEFAULT (or nil, if not given)."
-  (emms-dictionary-get track name default))
-
-(defun emms-track-set (track name value)
-  "Set the value of NAME for TRACK to VALUE."
-  (emms-dictionary-set track name value)
-  (when emms-cache-modified-function
-    (funcall emms-cache-modified-function track)))
-
-(defun emms-track-description (track)
-  "Return a description of TRACK.
-This function uses the global value for
-`emms-track-description-function', rather than anything the
-current mode might have set.
-
-Use `emms-track-force-description' instead if you need to insert
-a description into a playlist buffer."
-  (funcall (default-value 'emms-track-description-function) track))
-
-(defun emms-track-updated (track)
-  "Information in TRACK got updated."
-  (run-hook-with-args 'emms-track-info-filters track)
-  (emms-playlist-track-updated track)
-  (run-hook-with-args 'emms-track-updated-functions track))
-
-(defun emms-track-simple-description (track)
-  "Simple function to give a user-readable description of a track.
-If it's a file track, just return the file name.  Otherwise,
-return the type and the name with a colon in between.
-Hex-encoded characters in URLs are replaced by the decoded
-character."
-  (let ((type (emms-track-type track)))
-    (cond ((eq 'file type)
-           (emms-track-name track))
-          ((eq 'url type)
-           (emms-format-url-track-name (emms-track-name track)))
-          (t (concat (symbol-name type)
-                     ": " (emms-track-name track))))))
-
-(defun emms-format-url-track-name (name)
-  "Format URL track name for better readability."
-  (url-unhex-string name))
-
-(defun emms-track-force-description (track)
-  "Always return text that describes TRACK.
-This is used when inserting a description into a buffer.
-
-The reason for this is that if no text was returned (i.e. the
-user defined a track function that returned nil or the empty
-string), a confusing error message would result."
-  (let ((desc (funcall emms-track-description-function track)))
-    (if (and (stringp desc) (not (string= desc "")))
-        desc
-      (emms-track-simple-description track))))
-
-(defun emms-track-get-year (track)
-  "Get year of TRACK for display.
-There is the separation between the 'release date' and the
-'original date'.  This difference matters e.g. for
-re-releases (anniversaries and such) where the release date is
-more recent than the original release date.  In such cases the
-user probably wants the original release date so this is what we
-show."
-  (or
-   (emms-format-date-to-year (emms-track-get track 'info-date))
-   (emms-format-date-to-year (emms-track-get track 'info-originaldate))
-   (emms-track-get track 'info-year)
-   (emms-track-get track 'info-originalyear)))
-
-(defun emms-format-date-to-year (date)
-  "Try to extract year part from DATE.
-Return nil if the year cannot be extracted."
-  (when date
-    (let ((year (nth 5 (parse-time-string date))))
-      (if year (number-to-string year)
-        (when (string-match "^[ \t]*\\([0-9]\\{4\\}\\)" date)
-          (match-string 1 date))))))
-
-
-;;; The Playlist
-
-;; Playlists are stored in buffers.  The current playlist buffer is
-;; remembered in the `emms-playlist' variable.  The buffer consists of
-;; any kind of data.  Strings of text with a `emms-track' property are
-;; the tracks in the buffer.
-
-(defvar emms-playlist-buffers nil
-  "The list of EMMS playlist buffers.
-You should use the `emms-playlist-buffer-list' function to
-retrieve a current list of EMMS buffers.  Never use this variable
-for that purpose.")
-
-(defvar emms-playlist-selected-marker nil
-  "The marker for the currently selected track.")
-(make-variable-buffer-local 'emms-playlist-selected-marker)
-
-(defvar emms-playlist-buffer-p nil
-  "Non-nil if the current buffer is an EMMS playlist.")
-(make-variable-buffer-local 'emms-playlist-buffer-p)
-
-(defun emms-playlist-ensure-playlist-buffer ()
-  "Throw an error if we're not in a playlist-buffer."
-  (when (not emms-playlist-buffer-p)
-    (error "Not an EMMS playlist buffer")))
-
-(defun emms-playlist-set-playlist-buffer (&optional buffer)
-  "Set the current playlist buffer."
-  (interactive
-   (list (let* ((buf-list (mapcar #'(lambda (buf)
-                                      (list (buffer-name buf)))
-                                  (emms-playlist-buffer-list)))
-                (sorted-buf-list (sort buf-list
-                                       #'(lambda (lbuf rbuf)
-                                           (< (length (car lbuf))
-                                              (length (car rbuf))))))
-                (default (or (and emms-playlist-buffer-p
-                                  ;; default to current buffer
-                                  (buffer-name))
-                             ;; pick shortest buffer name, since it is
-                             ;; likely to be a shared prefix
-                             (car sorted-buf-list))))
-           (emms-completing-read "Playlist buffer to make current: "
-                                 sorted-buf-list nil t default))))
-  (let ((buf (if buffer
-                 (get-buffer buffer)
-               (current-buffer))))
-    (with-current-buffer buf
-      (emms-playlist-ensure-playlist-buffer))
-    (setq emms-playlist-buffer buf)
-    (when (called-interactively-p 'interactive)
-      (message "Set current EMMS playlist buffer"))
-    buf))
-
-(defun emms-playlist-new (&optional name)
-  "Create a new playlist buffer.
-The buffer is named NAME, but made unique.  NAME defaults to
-`emms-playlist-buffer-name'.  If called interactively, the new
-buffer is also selected."
-  (interactive)
-  (let ((buf (generate-new-buffer (or name
-                                      emms-playlist-buffer-name))))
-    (with-current-buffer buf
-      (when (not (eq major-mode emms-playlist-default-major-mode))
-        (funcall emms-playlist-default-major-mode))
-      (setq emms-playlist-buffer-p t))
-    (add-to-list 'emms-playlist-buffers buf)
-    (when (called-interactively-p 'interactive)
-      (switch-to-buffer buf))
-    buf))
-
-(defun emms-playlist-buffer-list ()
-  "Return a list of EMMS playlist buffers.
-The first element is guaranteed to be the current EMMS playlist
-buffer, if it exists, otherwise the slot will be used for the
-other EMMS buffers.  The list will be in newest-first order."
-  ;; prune dead buffers
-  (setq emms-playlist-buffers (emms-delete-if (lambda (buf)
-                                                (not (buffer-live-p buf)))
-                                              emms-playlist-buffers))
-  ;; add new buffers
-  (mapc (lambda (buf)
-          (when (buffer-live-p buf)
-            (with-current-buffer buf
-              (when (and emms-playlist-buffer-p
-                         (not (memq buf emms-playlist-buffers)))
-                (setq emms-playlist-buffers
-                      (cons buf emms-playlist-buffers))))))
-        (buffer-list))
-  ;; force current playlist buffer to head position
-  (when (and (buffer-live-p emms-playlist-buffer)
-             (not (eq (car emms-playlist-buffers) emms-playlist-buffer)))
-    (setq emms-playlist-buffers (cons emms-playlist-buffer
-                                      (delete emms-playlist-buffer
-                                              emms-playlist-buffers))))
-  emms-playlist-buffers)
-
-(defun emms-playlist-current-kill ()
-  "Kill the current EMMS playlist buffer and switch to the next one."
-  (interactive)
-  (when (buffer-live-p emms-playlist-buffer)
-    (let ((new (cadr (emms-playlist-buffer-list))))
-      (if new
-          (let ((old emms-playlist-buffer))
-            (setq emms-playlist-buffer new
-                  emms-playlist-buffers (cdr emms-playlist-buffers))
-            (kill-buffer old)
-            (switch-to-buffer emms-playlist-buffer))
-        (with-current-buffer emms-playlist-buffer
-          (bury-buffer))))))
-
-(defun emms-playlist-current-clear ()
-  "Clear the current playlist.
-If no current playlist exists, a new one is generated."
-  (interactive)
-  (if (or (not emms-playlist-buffer)
-          (not (buffer-live-p emms-playlist-buffer)))
-      (setq emms-playlist-buffer (emms-playlist-new))
-    (with-current-buffer emms-playlist-buffer
-      (emms-playlist-clear))))
-
-(defun emms-playlist-clear ()
-  "Clear the current buffer."
-  (interactive)
-  (emms-playlist-ensure-playlist-buffer)
-  (let ((inhibit-read-only t))
-    (widen)
-    (delete-region (point-min)
-                  (point-max)))
-  (run-hooks 'emms-playlist-cleared-hook))
-
-;;; Point movement within the playlist buffer.
-(defun emms-playlist-track-at (&optional pos)
-  "Return the track at POS (point if not given), or nil if none."
-  (emms-playlist-ensure-playlist-buffer)
-  (emms-with-widened-buffer
-   (get-text-property (or pos (point))
-                     'emms-track)))
-
-(defun emms-playlist-next ()
-  "Move to the next track in the current buffer."
-  (emms-playlist-ensure-playlist-buffer)
-  (let ((next (next-single-property-change (point)
-                                           'emms-track)))
-    (when (not next)
-      (error "No next track"))
-    (when (not (emms-playlist-track-at next))
-      (setq next (next-single-property-change next 'emms-track)))
-    (when (or (not next)
-              (= next (point-max)))
-      (error "No next track"))
-    (goto-char next)))
-
-(defun emms-playlist-previous ()
-  "Move to the previous track in the current buffer."
-  (emms-playlist-ensure-playlist-buffer)
-  (let ((prev (previous-single-property-change (point)
-                                               'emms-track)))
-    (when (not prev)
-      (error "No previous track"))
-    (when (not (get-text-property prev 'emms-track))
-      (setq prev (or (previous-single-property-change prev 'emms-track)
-                     (point-min))))
-    (when (or (not prev)
-              (not (get-text-property prev 'emms-track)))
-      (error "No previous track"))
-    (goto-char prev)))
-
-(defun emms-playlist-first ()
-  "Move to the first track in the current buffer."
-  (emms-playlist-ensure-playlist-buffer)
-  (let ((first (condition-case nil
-                   (save-excursion
-                     (goto-char (point-min))
-                     (when (not (emms-playlist-track-at (point)))
-                       (emms-playlist-next))
-                     (point))
-                 (error
-                  nil))))
-    (if first
-        (goto-char first)
-      (error "No first track"))))
-
-(defun emms-playlist-last ()
-  "Move to the last track in the current buffer."
-  (emms-playlist-ensure-playlist-buffer)
-  (let ((last (condition-case nil
-                  (save-excursion
-                    (goto-char (point-max))
-                    (emms-playlist-previous)
-                    (point))
-                (error
-                 nil))))
-    (if last
-        (goto-char last)
-      (error "No last track"))))
-
-(defun emms-playlist-delete-track ()
-  "Delete the track at point."
-  (emms-playlist-ensure-playlist-buffer)
-  (funcall emms-playlist-delete-track-function))
-
-;;; Track selection
-(defun emms-playlist-selected-track ()
-  "Return the currently selected track."
-  (emms-playlist-ensure-playlist-buffer)
-  (when emms-playlist-selected-marker
-    (emms-playlist-track-at emms-playlist-selected-marker)))
-
-(defun emms-playlist-current-selected-track ()
-  "Return the currently selected track in the current playlist."
-  (with-current-emms-playlist
-    (emms-playlist-selected-track)))
-
-(defun emms-playlist-selected-track-at-p (&optional point)
-  "Return non-nil if POINT (defaulting to point) is on the selected track."
-  (when emms-playlist-selected-marker
-    (or (= emms-playlist-selected-marker
-           (or point (point)))
-        (let ((p (previous-single-property-change (or point (point))
-                                                  'emms-track)))
-          (when p
-            (= emms-playlist-selected-marker
-               p))))))
-
-(defun emms-playlist-select (pos)
-  "Select the track at POS."
-  (emms-playlist-ensure-playlist-buffer)
-  (when (not (emms-playlist-track-at pos))
-    (error "No track at position %s" pos))
-  (when (not emms-playlist-selected-marker)
-    (setq emms-playlist-selected-marker (make-marker)))
-  (set-marker-insertion-type emms-playlist-selected-marker t)
-  (set-marker emms-playlist-selected-marker pos)
-  (run-hooks 'emms-playlist-selection-changed-hook))
-
-(defun emms-playlist-select-next ()
-  "Select the next track in the current buffer."
-  (emms-playlist-ensure-playlist-buffer)
-  (save-excursion
-    (goto-char (if (and emms-playlist-selected-marker
-                        (marker-position emms-playlist-selected-marker))
-                   emms-playlist-selected-marker
-                 (point-min)))
-    (condition-case nil
-        (progn
-          (if emms-repeat-playlist
-              (condition-case nil
-                  (emms-playlist-next)
-                (error
-                 (emms-playlist-first)))
-            (emms-playlist-next))
-          (emms-playlist-select (point)))
-      (error
-       (error "No next track in playlist")))))
-
-(defun emms-playlist-current-select-next ()
-  "Select the next track in the current playlist."
-  (with-current-emms-playlist
-    (emms-playlist-select-next)))
-
-(defun emms-playlist-select-previous ()
-  "Select the previous track in the current buffer."
-  (emms-playlist-ensure-playlist-buffer)
-  (save-excursion
-    (goto-char (if (and emms-playlist-selected-marker
-                        (marker-position emms-playlist-selected-marker))
-                   emms-playlist-selected-marker
-                 (point-max)))
-    (condition-case nil
-        (progn
-          (if emms-repeat-playlist
-              (condition-case nil
-                  (emms-playlist-previous)
-                (error
-                 (emms-playlist-last)))
-            (emms-playlist-previous))
-          (emms-playlist-select (point)))
-      (error
-       (error "No previous track in playlist")))))
-
-(defun emms-playlist-current-select-previous ()
-  "Select the previous track in the current playlist."
-  (with-current-emms-playlist
-    (emms-playlist-select-previous)))
-
-(defun emms-playlist-select-random ()
-  "Select a random track in the current buffer."
-  (emms-playlist-ensure-playlist-buffer)
-  ;; FIXME: This is rather inefficient.
-  (save-excursion
-    (let ((track-indices nil))
-      (goto-char (point-min))
-      (emms-walk-tracks
-        (setq track-indices (cons (point)
-                                  track-indices)))
-      (setq track-indices (vconcat track-indices))
-      (emms-playlist-select (aref track-indices
-                                  (random (length track-indices)))))))
-
-(defun emms-playlist-current-select-random ()
-  "Select a random track in the current playlist."
-  (with-current-emms-playlist
-    (emms-playlist-select-random)))
-
-(defun emms-playlist-select-first ()
-  "Select the first track in the current buffer."
-  (emms-playlist-ensure-playlist-buffer)
-  (save-excursion
-    (emms-playlist-first)
-    (emms-playlist-select (point))))
-
-(defun emms-playlist-current-select-first ()
-  "Select the first track in the current playlist."
-  (with-current-emms-playlist
-    (emms-playlist-select-first)))
-
-(defun emms-playlist-select-last ()
-  "Select the last track in the current buffer."
-  (emms-playlist-ensure-playlist-buffer)
-  (save-excursion
-    (emms-playlist-last)
-    (emms-playlist-select (point))))
-
-(defun emms-playlist-current-select-last ()
-  "Select the last track in the current playlist."
-  (with-current-emms-playlist
-    (emms-playlist-select-last)))
-
-;;; Playlist manipulation
-(defun emms-playlist-insert-track (track)
-  "Insert TRACK at the current position into the playlist.
-This uses `emms-playlist-insert-track-function'."
-  (emms-playlist-ensure-playlist-buffer)
-  (funcall emms-playlist-insert-track-function track))
-
-(defun emms-playlist-update-track ()
-  "Update TRACK at point.
-This uses `emms-playlist-update-track-function'."
-  (emms-playlist-ensure-playlist-buffer)
-  (funcall emms-playlist-update-track-function))
-
-(defun emms-playlist-insert-source (source &rest args)
-  "Insert tracks from SOURCE, supplying ARGS as arguments."
-  (emms-playlist-ensure-playlist-buffer)
-  (save-restriction
-    (narrow-to-region (point)
-                      (point))
-    (apply source args)
-    (run-hooks 'emms-playlist-source-inserted-hook)))
-
-(defun emms-playlist-current-insert-source (source &rest args)
-  "Insert tracks from SOURCE in the current playlist.
-This is supplying ARGS as arguments to the source."
-  (with-current-emms-playlist
-    (apply 'emms-playlist-insert-source source args)))
-
-(defun emms-playlist-tracks-in-region (beg end)
-  "Return all tracks between BEG and END."
-  (emms-playlist-ensure-playlist-buffer)
-  (let ((tracks nil))
-    (save-restriction
-      (narrow-to-region beg end)
-      (goto-char (point-min))
-      (emms-walk-tracks
-        (setq tracks (cons (emms-playlist-track-at (point))
-                           tracks))))
-    tracks))
-
-(defun emms-playlist-track-updated (track)
-  "Update TRACK in all playlist buffers."
-  (mapc (lambda (buf)
-          (with-current-buffer buf
-            (when emms-playlist-buffer-p
-              (save-excursion
-                (let ((pos (text-property-any (point-min) (point-max)
-                                              'emms-track track)))
-                  (while pos
-                    (goto-char pos)
-                    (emms-playlist-update-track)
-                    (setq pos (text-property-any
-                               (next-single-property-change (point)
-                                                           'emms-track)
-                               (point-max)
-                               'emms-track
-                               track))))))))
-        (buffer-list))
-  t)
-
-;;; Simple playlist buffer
-(defun emms-playlist-simple-insert-track (track)
-  "Insert the description of TRACK at point."
-  (emms-playlist-ensure-playlist-buffer)
-  (let ((inhibit-read-only t))
-    (insert (emms-propertize (emms-track-force-description track)
-                             'emms-track track)
-            "\n")))
-
-(defun emms-playlist-simple-update-track ()
-  "Update the track at point.
-Since we don't do anything special with the track anyway, just
-ignore this."
-  nil)
-
-(defun emms-playlist-simple-delete-track ()
-  "Delete the track at point."
-  (emms-playlist-ensure-playlist-buffer)
-  (when (not (emms-playlist-track-at (point)))
-    (error "No track at point"))
-  (let ((inhibit-read-only t)
-        (region (emms-property-region (point) 'emms-track)))
-    (delete-region (car region)
-                   (cdr region))))
-
-(defun emms-playlist-simple-shuffle ()
-  "Shuffle the whole playlist buffer."
-  (emms-playlist-ensure-playlist-buffer)
-  (let ((inhibit-read-only t)
-        (current nil))
-    (widen)
-    (when emms-player-playing-p
-      (setq current (emms-playlist-selected-track))
-      (goto-char emms-playlist-selected-marker)
-      (emms-playlist-delete-track))
-    (let* ((tracks (vconcat (emms-playlist-tracks-in-region (point-min)
-                                                            (point-max))))
-           (len (length tracks))
-           (i 0))
-      (delete-region (point-min)
-                     (point-max))
-      (run-hooks 'emms-playlist-cleared-hook)
-      (emms-shuffle-vector tracks)
-      (when current
-        (emms-playlist-insert-track current))
-      (while (< i len)
-        (emms-playlist-insert-track (aref tracks i))
-        (setq i (1+ i))))
-    (emms-playlist-select-first)
-    (goto-char (point-max))))
-
-(defun emms-playlist-simple-sort ()
-  "Sort the whole playlist buffer."
-  (emms-playlist-ensure-playlist-buffer)
-  (widen)
-  (let ((inhibit-read-only t)
-        (current (emms-playlist-selected-track))
-        (tracks (emms-playlist-tracks-in-region (point-min)
-                                                (point-max))))
-    (delete-region (point-min)
-                   (point-max))
-    (run-hooks 'emms-playlist-cleared-hook)
-    (mapc 'emms-playlist-insert-track
-          (sort tracks emms-sort-lessp-function))
-    (let ((pos (text-property-any (point-min)
-                                  (point-max)
-                                  'emms-track current)))
-      (if pos
-          (emms-playlist-select pos)
-        (emms-playlist-first)))))
-
-(defun emms-uniq-list (list stringify)
-  "Compare stringfied element of list, and remove duplicate elements."
-  ;; This uses a fast append list, keeping a pointer to the last cons
-  ;; cell of the list (TAIL).  It might be worthwhile to provide an
-  ;; abstraction for this eventually.
-  (let* ((hash (make-hash-table :test 'equal))
-         (result (cons nil nil))
-         (tail result))
-    (dolist (element list)
-      (let ((str (funcall stringify element)))
-        (when (not (gethash str hash))
-          (setcdr tail (cons element nil))
-          (setq tail (cdr tail)))
-        (puthash str t hash)))
-    (cdr result)))
-
-(defun emms-playlist-simple-uniq ()
-  "Remove duplicate tracks."
-  ;; TODO: This seems unnecessarily destructive.
-  (emms-playlist-ensure-playlist-buffer)
-  (widen)
-  (let ((inhibit-read-only t)
-        (current (emms-playlist-selected-track))
-        (tracks (emms-playlist-tracks-in-region (point-min)
-                                                (point-max))))
-    (delete-region (point-min) (point-max))
-    (run-hooks 'emms-playlist-cleared-hook)
-    (mapc 'emms-playlist-insert-track
-          (nreverse
-           (emms-uniq-list tracks 'emms-track-name)))
-    (let ((pos (text-property-any (point-min)
-                                  (point-max)
-                                  'emms-track current)))
-      (if pos
-          (emms-playlist-select pos)
-        (emms-playlist-first)))))
-
-(defun emms-default-ok-track-function (track)
-  "A function which OKs all tracks for playing by default."
-  t)
-
-;;; Helper functions
-(defun emms-property-region (pos prop)
-  "Return a pair of the beginning and end of the property PROP at POS.
-If POS does not contain PROP, try to find PROP just before POS."
-  (let (begin end)
-    (if (and (> pos (point-min))
-             (get-text-property (1- pos) prop))
-        (setq begin (previous-single-property-change (1- pos) prop))
-      (if (get-text-property pos prop)
-          (setq begin pos)
-        (error "Cannot find the %s property at the given position" prop)))
-    (if (get-text-property pos prop)
-        (setq end (next-single-property-change pos prop))
-      (if (and (> pos (point-min))
-               (get-text-property (1- pos) prop))
-          (setq end pos)
-        (error "Cannot find the %s property at the given position" prop)))
-    (cons (or begin (point-min))
-          (or end (point-max)))))
-
-(defun emms-shuffle-vector (vector)
-  "Shuffle VECTOR."
-  (let ((i (- (length vector) 1)))
-    (while (>= i 0)
-      (let* ((r (random (1+ i)))
-             (old (aref vector r)))
-        (aset vector r (aref vector i))
-        (aset vector i old))
-      (setq i (- i 1))))
-  vector)
-
-
-;;; Sources
-
-;; A source is just a function which is called in a playlist buffer.
-;; It should use `emms-playlist-insert-track' to insert the tracks it
-;; knows about.
-;;
-;; The define-emms-source macro also defines functions
-;; emms-play-SOURCE and emms-add-SOURCE.  The former will replace the
-;; current playlist, while the latter will add to the end.
-
-(defmacro define-emms-source (name arglist &rest body)
-  "Define a new EMMS source called NAME.
-This macro defines three functions: `emms-source-NAME',
-`emms-play-NAME' and `emms-add-NAME'.  BODY should use
-`emms-playlist-insert-track' to insert all tracks to be played,
-which is exactly what `emms-source-NAME' will do.  The other two
-functions will be simple wrappers around `emms-source-NAME'; any
-`interactive' form that you specify in BODY will end up in these.
-See emms-source-file.el for some examples."
-  (let ((source-name (intern (format "emms-source-%s" name)))
-        (source-play (intern (format "emms-play-%s" name)))
-        (source-add (intern (format "emms-add-%s" name)))
-        (source-insert (intern (format "emms-insert-%s" name)))
-        (docstring "A source of tracks for EMMS.")
-        (interactive nil)
-        (call-args (delete '&rest
-                           (delete '&optional
-                                   arglist))))
-    (when (stringp (car body))
-      (setq docstring (car body)
-            body (cdr body)))
-    (when (eq 'interactive (caar body))
-      (setq interactive (car body)
-            body (cdr body)))
-    `(progn
-       (defun ,source-name ,arglist
-         ,docstring
-         ,@body)
-       (defun ,source-play ,arglist
-         ,docstring
-         ,interactive
-         (if current-prefix-arg
-             (let ((current-prefix-arg nil))
-               (emms-source-add ',source-name ,@call-args))
-           (emms-source-play ',source-name ,@call-args)))
-       (defun ,source-add ,arglist
-         ,docstring
-         ,interactive
-         (if current-prefix-arg
-             (let ((current-prefix-arg nil))
-               (emms-source-play ',source-name ,@call-args))
-           (emms-source-add ',source-name ,@call-args)))
-       (defun ,source-insert ,arglist
-         ,docstring
-         ,interactive
-         (emms-source-insert ',source-name ,@call-args)))))
-
-(defun emms-source-play (source &rest args)
-  "Play the tracks of SOURCE, after first clearing the EMMS playlist."
-  (emms-stop)
-  (emms-playlist-current-clear)
-  (apply 'emms-playlist-current-insert-source source args)
-  (emms-playlist-current-select-first)
-  (emms-start))
-
-(defun emms-source-add (source &rest args)
-  "Add the tracks of SOURCE at the current position in the playlist."
-  (with-current-emms-playlist
-    (save-excursion
-      (goto-char (point-max))
-      (apply 'emms-playlist-current-insert-source source args))
-    (when (or (not emms-playlist-selected-marker)
-              (not (marker-position emms-playlist-selected-marker)))
-      (emms-playlist-select-first))))
-
-(defun emms-source-insert (source &rest args)
-  "Insert the tracks from SOURCE in the current buffer."
-  (if (not emms-playlist-buffer-p)
-      (error "Not in an EMMS playlist buffer")
-    (apply 'emms-playlist-insert-source source args)))
-
-;;; User-defined playlists
-;;; FIXME: Shuffle is bogus here! (because of narrowing)
-(defmacro define-emms-combined-source (name shufflep sources)
-  "Define a `emms-play-X' and `emms-add-X' function for SOURCES."
-  `(define-emms-source ,name ()
-     "An EMMS source for a tracklist."
-     (interactive)
-     (mapc (lambda (source)
-             (apply (car source)
-                    (cdr source)))
-           ,sources)
-     ,(when shufflep
-        '(save-restriction
-           (widen)
-           (emms-shuffle)))))
-
-
-;;; Players
-
-;; A player is a data structure created by `emms-player'.
-;; See the docstring of that function for more information.
-
-(defvar emms-player-stopped-p nil
-  "Non-nil if the last EMMS player was stopped by the user.")
-
-(defun emms-player (start stop playablep)
-  "Create a new EMMS player.
-The start function will be START, and the stop function STOP.
-PLAYABLEP should return non-nil for tracks that this player can
-play.
-
-When trying to play a track, EMMS walks through
-`emms-player-list'.  For each player, it calls the PLAYABLEP
-function.  The player corresponding to the first PLAYABLEP
-function that returns non-nil is used to play the track.  To
-actually play the track, EMMS calls the START function, passing
-the chosen track as a parameter.
-
-If the user tells EMMS to stop playing, the STOP function is
-called.  Once the player has finished playing, it should call
-`emms-player-stopped' to let EMMS know."
-  (let ((p (emms-dictionary '*player*)))
-    (emms-player-set p 'start start)
-    (emms-player-set p 'stop stop)
-    (emms-player-set p 'playablep playablep)
-    p))
-
-(defun emms-player-get (player name &optional inexistent)
-  "Return the value of entry NAME in PLAYER."
-  (let ((p (if (symbolp player)
-               (symbol-value player)
-             player)))
-    (emms-dictionary-get p name inexistent)))
-
-(defun emms-player-set (player name value)
-  "Set the value of entry NAME in PLAYER to VALUE."
-  (let ((p (if (symbolp player)
-               (symbol-value player)
-             player)))
-    (emms-dictionary-set p name value)))
-
-(defun emms-player-for (track)
-  "Return an EMMS player capable of playing TRACK.
-This will be the first player whose PLAYABLEP function returns
-non-nil, or nil if no such player exists."
-  (let ((lis emms-player-list))
-    (while (and lis
-                (not (funcall (emms-player-get (car lis) 'playablep)
-                              track)))
-      (setq lis (cdr lis)))
-    (if lis
-        (car lis)
-      nil)))
-
-(defun emms-player-start (track)
-  "Start playing TRACK."
-  (if emms-player-playing-p
-      (error "A player is already playing")
-    (let ((player (emms-player-for track)))
-      (if (not player)
-          (error "Don't know how to play track: %S" track)
-        ;; Change default-directory so we don't accidentally block any
-        ;; directories the current buffer was visiting.
-        (let ((default-directory "/"))
-          (funcall (emms-player-get player 'start)
-                   track))))))
-
-(defun emms-player-started (player)
-  "Declare that the given EMMS PLAYER has started.
-This should only be done by the current player itself."
-  (setq emms-player-playing-p player
-        emms-player-paused-p  nil)
-  (run-hooks 'emms-player-started-hook))
-
-(defun emms-player-stop ()
-  "Stop the current EMMS player."
-  (when emms-player-playing-p
-    (let ((emms-player-stopped-p t))
-      (funcall (emms-player-get emms-player-playing-p 'stop)))
-    (setq emms-player-playing-p nil)))
-
-(defun emms-player-stopped ()
-  "Declare that the current EMMS player is finished.
-This should only be done by the current player itself."
-  (setq emms-player-playing-p nil)
-  (if emms-player-stopped-p
-      (run-hooks 'emms-player-stopped-hook)
-    (sleep-for emms-player-delay)
-    (run-hooks 'emms-player-finished-hook)
-    (funcall emms-player-next-function)))
-
-(defun emms-player-pause ()
-  "Pause the current EMMS player."
-  (cond
-   ((not emms-player-playing-p)
-    (error "Can't pause player, nothing is playing"))
-   (emms-player-paused-p
-    (let ((resume (emms-player-get emms-player-playing-p 'resume))
-          (pause (emms-player-get emms-player-playing-p 'pause)))
-      (cond
-       (resume
-        (funcall resume))
-       (pause
-        (funcall pause))
-       (t
-        (error "Player does not know how to pause"))))
-    (setq emms-player-paused-p nil)
-    (run-hooks 'emms-player-paused-hook))
-   (t
-    (let ((pause (emms-player-get emms-player-playing-p 'pause)))
-      (if pause
-          (funcall pause)
-        (error "Player does not know how to pause")))
-    (setq emms-player-paused-p t)
-    (run-hooks 'emms-player-paused-hook))))
-
-(defun emms-player-seek (seconds)
-  "Seek the current player by SECONDS seconds.
-This can be a floating point number for fractions of a second, or
-negative to seek backwards."
-  (if (not emms-player-playing-p)
-      (error "Can't seek player, nothing playing right now")
-    (let ((seek (emms-player-get emms-player-playing-p 'seek)))
-      (if (not seek)
-          (error "Player does not know how to seek")
-        (funcall seek seconds)
-        (run-hook-with-args 'emms-player-seeked-functions seconds)))))
-
-(defun emms-player-seek-to (seconds)
-  "Seek the current player to SECONDS seconds.
-This can be a floating point number for fractions of a second, or
-negative to seek backwards."
-  (if (not emms-player-playing-p)
-      (error "Can't seek-to player, nothing playing right now")
-    (let ((seek (emms-player-get emms-player-playing-p 'seek-to)))
-      (if (not seek)
-          (error "Player does not know how to seek-to")
-        (funcall seek seconds)
-        (run-hook-with-args 'emms-player-time-set-functions seconds)))))
-
-(provide 'emms)
-;;; emms.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]