1 ;;; emus.el --- Simple music player for Emacs. -*- lexical-binding:t -*-
3 ;; Author: Tim Vaughan <timv@ughan.xyz>
5 ;; Keywords: multimedia
6 ;; URL: https://thelambdalab.xyz/emus
10 ;; This is a simple package for playing audio from a local library
19 "Simple music player for Emacs."
22 (defcustom emus-directory "~/Music/"
23 "Directory containing audio files for emus."
26 (defcustom emus-mpg123-program "mpg123"
27 "Name of (and, optionally, path to) mpg123 binary."
33 (defvar emus-library nil
34 "Emus audio library.")
36 (defun emus-get-audio-files ()
37 "Get all mp3 files in main emus directory."
38 (directory-files-recursively emus-directory ".*\\.mp3"))
40 (defvar emus-records nil)
42 (defun emus-make-record (filename tagstr)
46 (dolist (line (split-string tagstr "\n"))
47 (let ((found-artist (elt (split-string line "@I ID3v2.artist:") 1))
48 (found-album (elt (split-string line "@I ID3v2.album:") 1))
49 (found-title (elt (split-string line "@I ID3v2.title:") 1)))
51 (found-artist (setq artist found-artist))
52 (found-album (setq album found-album))
53 (found-title (setq title found-title)))))
54 (list artist album title filename)))
56 (defun emus-record-artist (record)
59 (defun emus-record-album (record)
62 (defun emus-record-title (record)
65 (defun emus-record-file (record)
68 (defun emus-update-records (then)
69 (let ((proc (emus-get-process))
71 (filenames (emus-get-audio-files)))
72 (setq emus-records nil)
73 (set-process-filter proc (lambda (proc string)
74 (setq tagstr (concat tagstr string))
75 (when (string-suffix-p "@P 1\n" string)
76 (add-to-list 'emus-records
77 (emus-make-record (car filenames)
80 (setq filenames (cdr filenames))
82 (emus-send-cmd "lp" (car filenames))
83 (set-process-filter proc nil)
85 (emus-send-cmd "lp" (car filenames))))
90 (defvar emus-proc-in-use nil)
92 (defun emus-get-process ()
93 "Return current or new mpg123 process."
94 (let* ((emus-process-raw (get-process "emus-process"))
95 (emus-process (if emus-process-raw
96 (if (process-live-p emus-process-raw)
98 (kill-process emus-process-raw)
102 (make-process :name "emus-process"
103 ;; :buffer (get-buffer-create "*emus-process*")
104 :command `(,emus-mpg123-program "-R")))))
106 (defun emus-send-cmd (cmd &rest args)
107 (process-send-string (emus-get-process)
109 (seq-reduce (lambda (s1 s2) (concat s1 " " s2)) args cmd)
115 (defvar emus-currently-playing nil)
117 (defun emus-play-record (record)
118 (setq emus-currently-playing record)
119 (emus-send-cmd "l" (emus-record-file record)))
124 (setq emus-currently-playing nil))
126 (defun emus-playpause ()
131 (defun emus-volume (pct)
132 (emus-send-cmd "v" (number-to-string pct)))
134 (defvar emus-current-volume 10)
136 (defun emus-volume-delta (delta)
137 (setq emus-current-volume (max 0 (min 100 (+ emus-current-volume delta))))
138 (emus-volume emus-current-volume))
140 (defun emus-volume-up ()
142 (emus-volume-delta 10))
144 (defun emus-volume-down ()
146 (emus-volume-delta -10))
152 (defun emus-render-record (record)
155 (propertize (format "%-20.20s" (emus-record-artist record))
156 'face 'font-lock-keyword-face)
157 (propertize (format "% -20.20s" (emus-record-album record))
158 'face 'font-lock-function-name-face)
159 (propertize (format " %s" (emus-record-title record))
160 'face 'font-lock-string-face))
161 'action #'emus-click-record
166 (defun emus-render-records ()
167 (with-current-buffer "*emus*"
168 (let ((inhibit-read-only t))
171 (goto-char (point-min))
172 (dolist (record emus-records)
173 (emus-render-record record))))))
175 (defun emus-click-record (button)
176 (emus-play-record (button-get button 'emus-record)))
178 (defun emus-browse ()
179 "Switch to *emus* audio library browser."
181 (switch-to-buffer "*emus*")
183 (emus-volume emus-current-volume)
185 (emus-render-records)
186 (emus-update-records #'emus-render-records)))
188 (defvar emus-mode-map
189 (let ((map (make-sparse-keymap)))
190 (define-key map (kbd "SPC") 'emus-playpause)
191 (define-key map (kbd "o") 'emus-stop)
192 (define-key map (kbd "+") 'emus-volume-up)
193 (define-key map (kbd "=") 'emus-volume-up)
194 (define-key map (kbd "-") 'emus-volume-down)
195 (when (fboundp 'evil-define-key*)
196 (evil-define-key* 'motion map
197 (kbd "SPC") 'emus-playpause
199 (kbd "+") 'emus-volume-up
200 (kbd "=") 'emus-volume-up
201 (kbd "-") 'emus-volume-down))
205 (define-derived-mode emus-mode special-mode "Emus"
206 "Major mode for EMUS music player.")
208 (when (fboundp 'evil-set-initial-state)
209 (evil-set-initial-state 'emus-mode 'motion))
213 ;;; emus.el ends here