Example Emms setups

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Example Emms setups

Yoni Rabkin-2

Hello all,

I'd like to add to the Emms manual a more robust example of an Emms
setup. The manual has an example simply setup, but I think it would be
nice to also have an example of how a more mature setup looks like.

Anyone who would like to, please send in examples of your Emms setups,
or parts of them, so that I can choose interesting bits to add to the
example I'm planning for the manual.

--
   "Cut your own wood and it will warm you twice"

Reply | Threaded
Open this post in threaded view
|

Re: Example Emms setups

Pierre Neidhardt-2
Hi!

Here is my (unfiltered) config:

https://gitlab.com/ambrevar/dotfiles/-/blob/master/.emacs.d/lisp/init-emms.el

Some of it is clunky, I haven't touched it in a while.
Let me know if you think some chunks are of interest, maybe I can clean
it up for you.

Cheers!

--
Pierre Neidhardt
https://ambrevar.xyz/

signature.asc (521 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Example Emms setups

Mike Kazantsev-2
In reply to this post by Yoni Rabkin-2
On Sat, 19 Dec 2020 22:19:09 -0500
Yoni Rabkin <[hidden email]> wrote:

> Anyone who would like to, please send in examples of your Emms setups,
> or parts of them, so that I can choose interesting bits to add to the
> example I'm planning for the manual.

https://github.com/mk-fg/emacs-setup/blob/master/core/fg_emms.el

git says that it's been there since 2009, so might not be very modern
or up-to-date.


--
Mike Kazantsev // fraggod.net

Reply | Threaded
Open this post in threaded view
|

Re: Example Emms setups

Fran Burstall (Gmail)
In reply to this post by Yoni Rabkin-2


On Sun, 20 Dec 2020 at 03:19, Yoni Rabkin <[hidden email]> wrote:

Hello all,

I'd like to add to the Emms manual a more robust example of an Emms
setup. The manual has an example simply setup, but I think it would be
nice to also have an example of how a more mature setup looks like.

Anyone who would like to, please send in examples of your Emms setups,
or parts of them, so that I can choose interesting bits to add to the
example I'm planning for the manual.

Main interest here is that I use the fashionable use-package macro:

(use-package emms-setup
  :if (daemonp)
  :load-path "~/projects/emms"
  :init
  ;; stolen from: http://mbork.pl/2015-12-05_Emms_and_hydra
 
  (defun emms-status (&optional print-message)
    "Returns the status of Emms - one of `playing', `paused' and
`stopped'.  If called interactively, prints an appropriate
message.  If called from Lisp code, returns an appropriate
symbol."
    (interactive "p")
    (let ((status
           (if emms-player-playing-p
               (if emms-player-paused-p
                   'paused 'playing)
             'stopped)))
      (if print-message
          (message "Emms status: %s." status)
status)))

  (defun emms-status-track (&optional print-message)
    "Return or print in the echo area the status of Emms.  If playing,
include the current track info."
    (interactive "p")
    (let ((status (emms-status))
          (fun (if print-message #'message #'format)))
      (if (eq status 'stopped)
          (funcall fun "Emms stopped.")
(funcall fun "Emms %s, current track: %s."
status
(emms-track-description
                  (emms-playlist-current-selected-track))))))

  (defhydra hydra-emms (:timeout 6 :columns 4)
    "
Emms: %s(emms-status-track)
"
    ("SPC" emms-pause "Play/Pause")
    ("s" emms-stop "Stop")
    ("<left>" emms-previous "Backward")
    ("<right>" emms-next "Forward")
    ("<down>" emms-volume-lower "Volume down")
    ("<up>" emms-volume-raise "Volume up")
    ("+" emms-add-directory "Add directory")
    ("C-+" emms-add-directory-tree "Add directory tree")
    ("RET" emms "Show playlist")
    ("r" emms-shuffle "Shuffle tracks")
    ("q" ignore "Exit" :exit t))

  (global-set-key (kbd "C-c e") 'hydra-emms/body)

  (defun emms-add-files-to-cache ()
    "Search music library for new tracks and add them to the cache."
    (interactive)
    (mapc (lambda (file) (emms-track 'file file))
 (seq-filter #'(lambda (path) (not (gethash path emms-cache-db)))
     (directory-files-recursively "/media/shared/music" "\.mp3$\\|\.wav$\\|\.aif$\\|\.ogg"))))
  ;; track listings
  (defun pad-string (str len)
    "Return a string of length LEN starting with STR, truncating or padding as necessary."
    (let* ((str-len (length str))
  (extra-len (- len str-len)))
      (if (>= extra-len 0)
 (concat str (make-string extra-len ? ))
(concat (substring str 0 (- len 3)) "..."))))

  (defun my-track-description-function (track)
    "Detailed track listing for TRACK."
    (let* ((artist (emms-track-get track 'info-artist))
  (album (emms-track-get track 'info-album))
  (title (emms-track-get track 'info-title))
  (type (emms-track-get track 'type))
  (name (emms-track-get track 'name))
  (year (emms-track-get-year track)))
      (if (eq type 'file)
 (concat
  (pad-string (if artist artist "Unknown artist") 30)
  "    "
  (pad-string title 30)
  "    "
  (pad-string (if album album "") 30)
  "    "
  year)
(concat (symbol-name type) ":" name)))
    )

  (add-hook 'emms-playlist-mode-hook
   (lambda () (setq-local emms-track-description-function #'my-track-description-function)))
 
  :config
  (emms-all)
  (emms-default-players)
  (setq emms-source-file-default-directory "/media/shared/music/")
  (put 'emms-browser-delete-files 'disabled nil)
  ;; tags
  (require 'emms-info-libtag)
  (setq emms-info-functions '(emms-info-libtag))
  (setq emms-info-libtag-known-extensions
(regexp-opt '("mp3" "mp4" "m4a" "ogg" "flac" "spx" "wma" "aif")))
 
  ;; notifications
  (require 'emms-dbus)
  (emms-dbus-enable)
  ;; covers
  (setq emms-browser-covers #'emms-browser-cache-thumbnail-async)
  (setq emms-browser-thumbnail-small-size 64)
  (setq emms-browser-thumbnail-medium-size 128)
  ;; filters
  (emms-browser-make-filter "all" #'ignore)
  (emms-browser-make-filter "recent"
     (lambda (track) (< 30
        (time-to-number-of-days
  (time-subtract (current-time)
        (emms-info-track-file-mtime track))))))
  (emms-browser-set-filter (assoc "all" emms-browser-filters))
  ;; history
  (emms-history-load)
  ;; libre-fm
  (emms-librefm-scrobbler-enable))

---Fran
Reply | Threaded
Open this post in threaded view
|

Re: Example Emms setups

Bob Newell
In reply to this post by Yoni Rabkin-2
My setup. Kind of complicated but there are a few interesting bits,
mostly about compatibility between Linux and Termux, and some fancy
footwork with mpv volume control. The code is quite "raw" and let's
just say, unstylish. All the play choices are in a separate elisp
file, which I didn't think would be of much interest so it's not
included here.

;; Startup file for EMMS.

;;; 2020-12-03 'file' control is gone from mpv, so converted to
;;             ipc socket, requiring 'socat' utility.
;;; 2020-11-08 Minor fixes; remove redundant calls.
;;; 2019-04-09 Spotify startup code for helm-spotify-new.
;;; 2018-07-11 Some fixes needed for EMMS changes wrt file input.
;;; 2018-06-12 Made volume control keys persistent again.
;;; 2018-06-10 No more vlc or vlc volume control.
;;;            Everything is mpv and drop-file commands so we
;;;            can have almost the same code for both termux and linux.
;;; 2018-06-08 Moved emms stuff from startup.el and newage.el.
;;; 2018-04-03 Fixed volume reset problem so volume remains
;;;            stable between plays or repeat plays when using
;;;            mpv under Termux.
;;; 2017-10-10 Fixed playlist problems; vlc must be externally
;;;            set to no repeating. Use internal emms variables
;;;            to control track and playlist repeat.
;;; 2016-08-22 Went to autogeneration of play entries based
;;;            on ~/dwhelper directory, using aux. macro.
;;; 2016-07-30 Finally got relative seek working.
;;; 2016-07-10 With so many additions, now keeping play choices
;;;            in alpha order. Mostly.
;;; 2016-06-23 Added .mkv, which was somehow omitted.
;;; 2015-01-31 Streamlined; don't need to track play state
;;;            when switching playlists. Just kill any
;;;            previous play state first.
;;; 2015-01-08 Changed player from cvlc to vlc.

;;; Music content and EMMS setup. Nearly uniform between Linux and
;;; Termux. Uses mpv. Includes volume control and seeking.

(require 'emms-setup)
(emms-all)
(emms-default-players)
(setq emms-source-file-default-directory "~/dwhelper/")
(require 'emms-player-simple)

;;; Allow for multiple cards on one computer. Not used any longer?
;;; With mpv we use a drop-file command method of volume control, rather
;;; than changing system volume. This is to make volume control work with no
;;; changes between termux and linux.
;(if (string= (system-name) "dakine")
;    (setq emms-volume-amixer-card 1)
;    (setq emms-volume-amixer-card 0))

;;; Set up "new" mpv methods almost (not quite) universal across
;;; devices.

(require 'emms-player-mpv)
    (setq emms-player-mpv-ipc-method nil)
;;    (setq emms-player-mpv-ipc-method 'unix-socket)
    (setq emms-player-list '(emms-player-mpv))

(require 'emms-volume)

;;; Still not completely correct but fully working. In Linux the input
;;; file is shown twice, but it's necessary to work in Termux. I leave
;;; the Linux reference explicit to guard against future changes to
;;; EMMS. Note that --no-ytdl is necessary for some live streams to
;;; work correctly (found on the internet to solve the problem of an
;;; early stream termination). Also, --volume-max=150 allows for a
;;; boost when max volume isn't quite enough.

;;; Why won't ~ work here?
(if termuxing
    ;; remove --no-ytdl from termux, but don't remember why
       (setq emms-player-rjn-mpv-parameters
     (list "--quiet" "--really-quiet" "--volume-max=150" "--no-audio-display"
       "--input-ipc-server=/data/data/com.termux.files/home/.emacs.d/emms/mpv-input.sock"
))
       (setq emms-player-rjn-mpv-parameters
     (list "--no-ytdl" "--quiet" "--really-quiet" "--volume-max=150"
"--no-audio-display"
       "--input-ipc-server=/home/bnewell/.emacs.d/emms/mpv-input.sock" )))

;;; Reset global and minor mode volume keys, as C-c + and C-c - are
;;; used in org-mode.

(defun emms-player-volume-keys (&rest args)
  (interactive)
;;;  (global-set-key (kbd "C-c e +") 'emms-volume-mode-plus)
;;;  (global-set-key (kbd "C-c e -") 'emms-volume-mode-minus)
  (global-set-key (kbd "C-c e +") 'emms-player-mpv-volume-up)
  (global-set-key (kbd "C-c e -") 'emms-player-mpv-volume-down)
;;; Over-ride minor mode key definitions to refer to mpv.
  (define-key emms-volume-minor-mode-map (kbd "+") 'emms-player-mpv-volume-up)
  (define-key emms-volume-minor-mode-map (kbd "-") 'emms-player-mpv-volume-down)
)
(emms-player-volume-keys)

;;; For volume control use 5% steps. A little slow but works okay, and
;;; 10% is too coarse.

   (defun emms-player-mpv-volume-up ()
     (interactive)
     (if (get-process "emms-player-mpv")
(progn
      (setq mpv-volume-value (+ mpv-volume-value 5))
      (emms-player-mpv-change-volume)
      (emms-volume-mode-start-or-extend))
       (message "EMMS player not playing")))

   (defun emms-player-mpv-volume-down ()
     (interactive)
     (if (get-process "emms-player-mpv")
(progn
     (setq mpv-volume-value (- mpv-volume-value 5))
     (emms-player-mpv-change-volume)
     (emms-volume-mode-start-or-extend))
       (message "EMMS player not playing")))

(defvar mpv-volume-value 100) ;; rather arbitrary
(defun emms-player-mpv-change-volume (&optional args)
     (if (> mpv-volume-value 150)
(setq mpv-volume-value 150))
     (if (< mpv-volume-value 0)
(setq mpv-volume-value 0))

     (let* ((mpv-volume-readable (number-to-string mpv-volume-value))
    (cmd (format "echo 'set volume %s' | socat - %s"
          mpv-volume-readable (concat start-home
"/.emacs.d/emms/mpv-ipc.sock"))))
       (message (concat "Vol " mpv-volume-readable " pct"))
       (call-process-shell-command cmd nil nil nil))) ;; end of volume function

   ;; Set volume to last known state, or default if none.
   ;; Otherwise the volume will reset itself on every play
   ;; or repeat play.

    (global-set-key (kbd "C-c e +") 'emms-player-mpv-volume-up)
    (global-set-key (kbd "C-c e -") 'emms-player-mpv-volume-down)

;;; To ensure stable volume between mpv invocations.
    (advice-add 'emms-player-mpv-start :before #'emms-player-mpv-rjn-setup)

;;; The list manipulations have to be done carefully.
(defun emms-player-mpv-rjn-setup (&optional args)
  (let ( (temp-parms emms-player-rjn-mpv-parameters))
  (setq emms-player-mpv-parameters
(add-to-list 'temp-parms
   (concat "--volume=" (number-to-string mpv-volume-value))
))))

;;; Control functions. Not all of them necessary, just nice mnemonics.

(defun play-playing () "What are we playing now" (interactive)
  (if (eq play-now-playing nil)
      (message "Nothing playing!")
      (message (concat "Now playing " play-now-playing))))

(defun play-restart () "Restart the music" (interactive)
(emms-seek-to 0))

(defun play-stop () "Stop the music" (interactive)
(play-stop-stuff)
(message "Play stopped"))

(defun play-pause () "Pause the music" (interactive)
  (emms-pause))

(defun play-seek (seek-time)
  "Move play position relatively"
  (interactive "nSeek +/- how many seconds? ")
  (play-pause)
  ;;; A number preceeded by + or - goes to relative point.
  (emms-player-mpv-seek seek-time)
  (play-resume))

(defun play-seek-abs (seek-time)
  "Move play position absolutely"
  (interactive "nSeek to what position in seconds? ")
  (play-pause)
  (emms-player-mpv-seek-to seek-time)
  (play-resume))

(defun play-resume () "Resume the music" (interactive)
; No check if it's really paused.
(emms-pause))

(defun play-playlist () "Go to playlist" (interactive)
  (play-stop-stuff)
  (emms-playlist-mode-go)
)

(defun play-stop-stuff ()
  (emms-stop)
  (spotify-kill)
 (setq play-now-playing nil)
 (sleep-for 2)
)

;;; Necessary? emms-player-volume-keys is called at startup of Emacs.
;;; But this undoes spotify volume keys, which don't seem to work.
(advice-add 'emms-play-file :before #'emms-player-volume-keys)
(advice-add 'emms-play-url :before #'emms-player-volume-keys)
(advice-add 'emms-play-playlist :before #'emms-player-volume-keys)

;; We load newage.elc from here, in order to do things in the right order.
(load-library (concat start-lisp-home "newage.elc"))

;; Experimental spotify. Seems like a waste of time.

;;(add-to-list 'load-path (concat start-lisp-home "/spotify"))
;;(require 'spotify)

(defun spotify-kill (&rest args)
  (interactive)
   (if (not termuxing)
    (if (not (string= (shell-command-to-string "pgrep -x \"spotify\"") ""))
       (async-shell-command "killall -9 spotify >/dev/null 2>&1"))
;;; This would be better but doesn't seem to work.
;;;       (start-process "kill-spotify" nil "killall" "spotify"))
))

(defun spotify-check (&rest args)
  (interactive)
  "See if spotify is running and if not, run it"
  (if (not termuxing)
   (if (string= (shell-command-to-string "pgrep -x \"spotify\"") "")
    (progn
       (play-stop-stuff)
       (message "Starting Spotify")
       (start-process "spotify" nil "spotify")
       (setq play-now-playing "Spotify")
       (spotify-player-volume-keys)
       (sleep-for 2))
    )
   (async-shell-command (concat "termux-open " args)))
  )
;;; To ensure spotify is running before trying to play stuff.
(advice-add 'helm-spotify-plus-play-href :before #'spotify-check)

;; Settings
(setq spotify-oauth2-client-secret "secret letters and numbers")
(setq spotify-oauth2-client-id "secret letters and numbers")

(defun spotify-player-volume-keys ()
  (interactive)
  (global-set-key (kbd "C-c e +") 'spotify-volume-plus)
  (global-set-key (kbd "C-c e -") 'spotify-volume-minus)
)

(defun spotify-volume-plus ()
  (interactive)
  (shell-command "~/data/code/spotvolplus.py")
  )

(defun spotify-volume-minus ()
  (interactive)
  (shell-command "~/data/code/spotvolminus.py")
  )

(provide 'startup-emms)