diff options
| -rw-r--r-- | Makefile | 41 | ||||
| -rw-r--r-- | doc/developer-release.txt | 2 | ||||
| -rw-r--r-- | emms-auto.el | 562 | ||||
| -rw-r--r-- | emms-auto.in (renamed from lisp/emms-auto.in) | 0 | ||||
| -rw-r--r-- | emms-bookmarks.el (renamed from lisp/emms-bookmarks.el) | 0 | ||||
| -rw-r--r-- | emms-browser.el (renamed from lisp/emms-browser.el) | 0 | ||||
| -rw-r--r-- | emms-cache.el (renamed from lisp/emms-cache.el) | 0 | ||||
| -rw-r--r-- | emms-compat.el (renamed from lisp/emms-compat.el) | 0 | ||||
| -rw-r--r-- | emms-cue.el (renamed from lisp/emms-cue.el) | 0 | ||||
| -rw-r--r-- | emms-history.el (renamed from lisp/emms-history.el) | 0 | ||||
| -rw-r--r-- | emms-i18n.el (renamed from lisp/emms-i18n.el) | 0 | ||||
| -rw-r--r-- | emms-info-libtag.el (renamed from lisp/emms-info-libtag.el) | 0 | ||||
| -rw-r--r-- | emms-info-metaflac.el (renamed from lisp/emms-info-metaflac.el) | 0 | ||||
| -rw-r--r-- | emms-info-mp3info.el (renamed from lisp/emms-info-mp3info.el) | 0 | ||||
| -rw-r--r-- | emms-info-ogginfo.el (renamed from lisp/emms-info-ogginfo.el) | 0 | ||||
| -rw-r--r-- | emms-info-opusinfo.el (renamed from lisp/emms-info-opusinfo.el) | 0 | ||||
| -rw-r--r-- | emms-info-tinytag.el (renamed from lisp/emms-info-tinytag.el) | 0 | ||||
| -rw-r--r-- | emms-info.el (renamed from lisp/emms-info.el) | 0 | ||||
| -rw-r--r-- | emms-last-played.el (renamed from lisp/emms-last-played.el) | 0 | ||||
| -rw-r--r-- | emms-librefm-scrobbler.el (renamed from lisp/emms-librefm-scrobbler.el) | 0 | ||||
| -rw-r--r-- | emms-librefm-stream.el (renamed from lisp/emms-librefm-stream.el) | 0 | ||||
| -rw-r--r-- | emms-lyrics.el (renamed from lisp/emms-lyrics.el) | 0 | ||||
| -rw-r--r-- | emms-maint.el (renamed from lisp/emms-maint.el) | 0 | ||||
| -rw-r--r-- | emms-mark.el (renamed from lisp/emms-mark.el) | 0 | ||||
| -rw-r--r-- | emms-metaplaylist-mode.el (renamed from lisp/emms-metaplaylist-mode.el) | 0 | ||||
| -rw-r--r-- | emms-mode-line-icon.el (renamed from lisp/emms-mode-line-icon.el) | 0 | ||||
| -rw-r--r-- | emms-mode-line.el (renamed from lisp/emms-mode-line.el) | 0 | ||||
| -rw-r--r-- | emms-player-mpd.el (renamed from lisp/emms-player-mpd.el) | 0 | ||||
| -rw-r--r-- | emms-player-mpg321-remote.el (renamed from lisp/emms-player-mpg321-remote.el) | 0 | ||||
| -rw-r--r-- | emms-player-mplayer.el (renamed from lisp/emms-player-mplayer.el) | 0 | ||||
| -rw-r--r-- | emms-player-mpv.el (renamed from lisp/emms-player-mpv.el) | 0 | ||||
| -rw-r--r-- | emms-player-simple.el (renamed from lisp/emms-player-simple.el) | 0 | ||||
| -rw-r--r-- | emms-player-vlc.el (renamed from lisp/emms-player-vlc.el) | 0 | ||||
| -rw-r--r-- | emms-player-xine.el (renamed from lisp/emms-player-xine.el) | 0 | ||||
| -rw-r--r-- | emms-playing-time.el (renamed from lisp/emms-playing-time.el) | 0 | ||||
| -rw-r--r-- | emms-playlist-limit.el (renamed from lisp/emms-playlist-limit.el) | 0 | ||||
| -rw-r--r-- | emms-playlist-mode.el (renamed from lisp/emms-playlist-mode.el) | 0 | ||||
| -rw-r--r-- | emms-playlist-sort.el (renamed from lisp/emms-playlist-sort.el) | 0 | ||||
| -rw-r--r-- | emms-score.el (renamed from lisp/emms-score.el) | 0 | ||||
| -rw-r--r-- | emms-setup.el (renamed from lisp/emms-setup.el) | 0 | ||||
| -rw-r--r-- | emms-show-all.el (renamed from lisp/emms-show-all.el) | 0 | ||||
| -rw-r--r-- | emms-source-file.el (renamed from lisp/emms-source-file.el) | 0 | ||||
| -rw-r--r-- | emms-source-playlist.el (renamed from lisp/emms-source-playlist.el) | 0 | ||||
| -rw-r--r-- | emms-stream-info.el (renamed from lisp/emms-stream-info.el) | 0 | ||||
| -rw-r--r-- | emms-streams.el (renamed from lisp/emms-streams.el) | 0 | ||||
| -rw-r--r-- | emms-tag-editor.el (renamed from lisp/emms-tag-editor.el) | 0 | ||||
| -rw-r--r-- | emms-url.el (renamed from lisp/emms-url.el) | 0 | ||||
| -rw-r--r-- | emms-volume-amixer.el (renamed from lisp/emms-volume-amixer.el) | 0 | ||||
| -rw-r--r-- | emms-volume-mixerctl.el (renamed from lisp/emms-volume-mixerctl.el) | 0 | ||||
| -rw-r--r-- | emms-volume-pulse.el (renamed from lisp/emms-volume-pulse.el) | 0 | ||||
| -rw-r--r-- | emms-volume.el (renamed from lisp/emms-volume.el) | 0 | ||||
| -rw-r--r-- | emms.el | 1528 | ||||
| -rw-r--r-- | jack.el (renamed from lisp/jack.el) | 0 | ||||
| -rw-r--r-- | later-do.el (renamed from lisp/later-do.el) | 0 | ||||
| -rw-r--r-- | lisp/Makefile | 28 | ||||
| -rw-r--r-- | lisp/emms.el | 1539 | 
56 files changed, 2107 insertions, 1593 deletions
| @@ -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 index d799e4a..d799e4a 100644 --- a/lisp/emms-auto.in +++ b/emms-auto.in diff --git a/lisp/emms-bookmarks.el b/emms-bookmarks.el index b579ca3..b579ca3 100644 --- a/lisp/emms-bookmarks.el +++ b/emms-bookmarks.el diff --git a/lisp/emms-browser.el b/emms-browser.el index f805b3b..f805b3b 100644 --- a/lisp/emms-browser.el +++ b/emms-browser.el diff --git a/lisp/emms-cache.el b/emms-cache.el index 792b1b8..792b1b8 100644 --- a/lisp/emms-cache.el +++ b/emms-cache.el diff --git a/lisp/emms-compat.el b/emms-compat.el index 94f9b45..94f9b45 100644 --- a/lisp/emms-compat.el +++ b/emms-compat.el diff --git a/lisp/emms-cue.el b/emms-cue.el index aefcafd..aefcafd 100644 --- a/lisp/emms-cue.el +++ b/emms-cue.el diff --git a/lisp/emms-history.el b/emms-history.el index 2f75571..2f75571 100644 --- a/lisp/emms-history.el +++ b/emms-history.el diff --git a/lisp/emms-i18n.el b/emms-i18n.el index 66a5eeb..66a5eeb 100644 --- a/lisp/emms-i18n.el +++ b/emms-i18n.el diff --git a/lisp/emms-info-libtag.el b/emms-info-libtag.el index 7954ab2..7954ab2 100644 --- a/lisp/emms-info-libtag.el +++ b/emms-info-libtag.el diff --git a/lisp/emms-info-metaflac.el b/emms-info-metaflac.el index 5a9f517..5a9f517 100644 --- a/lisp/emms-info-metaflac.el +++ b/emms-info-metaflac.el diff --git a/lisp/emms-info-mp3info.el b/emms-info-mp3info.el index b01217e..b01217e 100644 --- a/lisp/emms-info-mp3info.el +++ b/emms-info-mp3info.el diff --git a/lisp/emms-info-ogginfo.el b/emms-info-ogginfo.el index 2d8412f..2d8412f 100644 --- a/lisp/emms-info-ogginfo.el +++ b/emms-info-ogginfo.el diff --git a/lisp/emms-info-opusinfo.el b/emms-info-opusinfo.el index d636f7b..d636f7b 100644 --- a/lisp/emms-info-opusinfo.el +++ b/emms-info-opusinfo.el diff --git a/lisp/emms-info-tinytag.el b/emms-info-tinytag.el index fe21653..fe21653 100644 --- a/lisp/emms-info-tinytag.el +++ b/emms-info-tinytag.el diff --git a/lisp/emms-info.el b/emms-info.el index 5e8fae2..5e8fae2 100644 --- a/lisp/emms-info.el +++ b/emms-info.el diff --git a/lisp/emms-last-played.el b/emms-last-played.el index 529869a..529869a 100644 --- a/lisp/emms-last-played.el +++ b/emms-last-played.el diff --git a/lisp/emms-librefm-scrobbler.el b/emms-librefm-scrobbler.el index a49a458..a49a458 100644 --- a/lisp/emms-librefm-scrobbler.el +++ b/emms-librefm-scrobbler.el diff --git a/lisp/emms-librefm-stream.el b/emms-librefm-stream.el index 7df67cb..7df67cb 100644 --- a/lisp/emms-librefm-stream.el +++ b/emms-librefm-stream.el diff --git a/lisp/emms-lyrics.el b/emms-lyrics.el index 95b8e29..95b8e29 100644 --- a/lisp/emms-lyrics.el +++ b/emms-lyrics.el diff --git a/lisp/emms-maint.el b/emms-maint.el index fd5c4a4..fd5c4a4 100644 --- a/lisp/emms-maint.el +++ b/emms-maint.el diff --git a/lisp/emms-mark.el b/emms-mark.el index b7d2558..b7d2558 100644 --- a/lisp/emms-mark.el +++ b/emms-mark.el diff --git a/lisp/emms-metaplaylist-mode.el b/emms-metaplaylist-mode.el index d4616f0..d4616f0 100644 --- a/lisp/emms-metaplaylist-mode.el +++ b/emms-metaplaylist-mode.el diff --git a/lisp/emms-mode-line-icon.el b/emms-mode-line-icon.el index 82cf815..82cf815 100644 --- a/lisp/emms-mode-line-icon.el +++ b/emms-mode-line-icon.el diff --git a/lisp/emms-mode-line.el b/emms-mode-line.el index caac8b1..caac8b1 100644 --- a/lisp/emms-mode-line.el +++ b/emms-mode-line.el diff --git a/lisp/emms-player-mpd.el b/emms-player-mpd.el index 327938d..327938d 100644 --- a/lisp/emms-player-mpd.el +++ b/emms-player-mpd.el diff --git a/lisp/emms-player-mpg321-remote.el b/emms-player-mpg321-remote.el index de242ea..de242ea 100644 --- a/lisp/emms-player-mpg321-remote.el +++ b/emms-player-mpg321-remote.el diff --git a/lisp/emms-player-mplayer.el b/emms-player-mplayer.el index aa1f5c7..aa1f5c7 100644 --- a/lisp/emms-player-mplayer.el +++ b/emms-player-mplayer.el diff --git a/lisp/emms-player-mpv.el b/emms-player-mpv.el index c4fc541..c4fc541 100644 --- a/lisp/emms-player-mpv.el +++ b/emms-player-mpv.el diff --git a/lisp/emms-player-simple.el b/emms-player-simple.el index fd93137..fd93137 100644 --- a/lisp/emms-player-simple.el +++ b/emms-player-simple.el diff --git a/lisp/emms-player-vlc.el b/emms-player-vlc.el index 7c2130d..7c2130d 100644 --- a/lisp/emms-player-vlc.el +++ b/emms-player-vlc.el diff --git a/lisp/emms-player-xine.el b/emms-player-xine.el index 2fc60e7..2fc60e7 100644 --- a/lisp/emms-player-xine.el +++ b/emms-player-xine.el diff --git a/lisp/emms-playing-time.el b/emms-playing-time.el index 8b14e16..8b14e16 100644 --- a/lisp/emms-playing-time.el +++ b/emms-playing-time.el diff --git a/lisp/emms-playlist-limit.el b/emms-playlist-limit.el index 91eff1e..91eff1e 100644 --- a/lisp/emms-playlist-limit.el +++ b/emms-playlist-limit.el diff --git a/lisp/emms-playlist-mode.el b/emms-playlist-mode.el index 6979b79..6979b79 100644 --- a/lisp/emms-playlist-mode.el +++ b/emms-playlist-mode.el diff --git a/lisp/emms-playlist-sort.el b/emms-playlist-sort.el index e23604b..e23604b 100644 --- a/lisp/emms-playlist-sort.el +++ b/emms-playlist-sort.el diff --git a/lisp/emms-score.el b/emms-score.el index 8c783c5..8c783c5 100644 --- a/lisp/emms-score.el +++ b/emms-score.el diff --git a/lisp/emms-setup.el b/emms-setup.el index fed2a36..fed2a36 100644 --- a/lisp/emms-setup.el +++ b/emms-setup.el diff --git a/lisp/emms-show-all.el b/emms-show-all.el index f37ef5e..f37ef5e 100644 --- a/lisp/emms-show-all.el +++ b/emms-show-all.el diff --git a/lisp/emms-source-file.el b/emms-source-file.el index 2be6538..2be6538 100644 --- a/lisp/emms-source-file.el +++ b/emms-source-file.el diff --git a/lisp/emms-source-playlist.el b/emms-source-playlist.el index 327be8c..327be8c 100644 --- a/lisp/emms-source-playlist.el +++ b/emms-source-playlist.el diff --git a/lisp/emms-stream-info.el b/emms-stream-info.el index 2bc7a41..2bc7a41 100644 --- a/lisp/emms-stream-info.el +++ b/emms-stream-info.el diff --git a/lisp/emms-streams.el b/emms-streams.el index c3b2d11..c3b2d11 100644 --- a/lisp/emms-streams.el +++ b/emms-streams.el diff --git a/lisp/emms-tag-editor.el b/emms-tag-editor.el index ca7941a..ca7941a 100644 --- a/lisp/emms-tag-editor.el +++ b/emms-tag-editor.el diff --git a/lisp/emms-url.el b/emms-url.el index 59d5cfa..59d5cfa 100644 --- a/lisp/emms-url.el +++ b/emms-url.el diff --git a/lisp/emms-volume-amixer.el b/emms-volume-amixer.el index 190f6b0..190f6b0 100644 --- a/lisp/emms-volume-amixer.el +++ b/emms-volume-amixer.el diff --git a/lisp/emms-volume-mixerctl.el b/emms-volume-mixerctl.el index 4ca7820..4ca7820 100644 --- a/lisp/emms-volume-mixerctl.el +++ b/emms-volume-mixerctl.el diff --git a/lisp/emms-volume-pulse.el b/emms-volume-pulse.el index 440ab7f..440ab7f 100644 --- a/lisp/emms-volume-pulse.el +++ b/emms-volume-pulse.el diff --git a/lisp/emms-volume.el b/emms-volume.el index 7a6ff5f..7a6ff5f 100644 --- a/lisp/emms-volume.el +++ b/emms-volume.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/later-do.el b/later-do.el index 5908ac5..5908ac5 100644 --- a/lisp/later-do.el +++ b/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 | 
