| 1 | ;;; emms-player-simple.el --- A generic simple player. -*- lexical-binding: t; -*- |
| 2 | |
| 3 | ;; Copyright (C) 2003-2021 Free Software Foundation, Inc. |
| 4 | |
| 5 | ;; Authors: Ulrik Jensen <terryp@daimi.au.dk> |
| 6 | ;; Jorgen Schäfer <forcer@forcix.cx> |
| 7 | ;; Keywords: emms, mpg321, ogg123 |
| 8 | |
| 9 | ;; This file is part of EMMS. |
| 10 | |
| 11 | ;; EMMS is free software; you can redistribute it and/or modify |
| 12 | ;; it under the terms of the GNU General Public License as published by |
| 13 | ;; the Free Software Foundation; either version 3, or (at your option) |
| 14 | ;; any later version. |
| 15 | |
| 16 | ;; EMMS is distributed in the hope that it will be useful, |
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 19 | ;; GNU General Public License for more details. |
| 20 | |
| 21 | ;; You should have received a copy of the GNU General Public License |
| 22 | ;; along with EMMS; see the file COPYING. If not, write to the |
| 23 | ;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| 24 | ;; Boston, MA 02110-1301, USA. |
| 25 | |
| 26 | ;;; Commentary: |
| 27 | |
| 28 | ;; This is a simple player interface - if you have an external player |
| 29 | ;; that just expects the filename to play as an argument, this should |
| 30 | ;; be able to use it. See the define-emms-simple-player lines at the |
| 31 | ;; end of this file for examples. |
| 32 | |
| 33 | ;; Add the following to your `emms-player-list': |
| 34 | |
| 35 | ;; emms-player-mpg321 |
| 36 | ;; emms-player-ogg123 |
| 37 | |
| 38 | ;;; Code: |
| 39 | |
| 40 | ;; Version control |
| 41 | (defvar emms-player-simple-version "0.2 $Revision: 1.26 $" |
| 42 | "Simple player for EMMS version string.") |
| 43 | ;; $Id: emms-player-simple.el,v 1.26 2005/08/02 15:27:51 forcer Exp $ |
| 44 | |
| 45 | (require 'emms) |
| 46 | |
| 47 | ;; Customization |
| 48 | |
| 49 | (defmacro define-emms-simple-player (name types regex command &rest args) |
| 50 | "Define a simple player with the use of `emms-define-player'. |
| 51 | NAME is used to contruct the name of the function like |
| 52 | emms-player-NAME. TYPES is a list of track types understood by |
| 53 | this player. REGEX must be a regexp that matches the filenames |
| 54 | the player can play. COMMAND specifies the command line argument |
| 55 | to call the player and ARGS are the command line arguments." |
| 56 | (let ((group (intern (concat "emms-player-" (symbol-name name)))) |
| 57 | (command-name (intern (concat "emms-player-" |
| 58 | (symbol-name name) |
| 59 | "-command-name"))) |
| 60 | (parameters (intern (concat "emms-player-" |
| 61 | (symbol-name name) |
| 62 | "-parameters"))) |
| 63 | (player-name (intern (concat "emms-player-" (symbol-name name)))) |
| 64 | (start (intern (concat "emms-player-" (symbol-name name) "-start"))) |
| 65 | (stop (intern (concat "emms-player-" (symbol-name name) "-stop"))) |
| 66 | (playablep (intern (concat "emms-player-" (symbol-name name) "-playable-p")))) |
| 67 | `(progn |
| 68 | (defgroup ,group nil |
| 69 | ,(concat "EMMS player for " command ".") |
| 70 | :group 'emms-player |
| 71 | :prefix ,(concat "emms-player-" (symbol-name name) "-")) |
| 72 | (defcustom ,command-name ,command |
| 73 | ,(concat "The command name of " command ".") |
| 74 | :type 'string) |
| 75 | (defcustom ,parameters ',args |
| 76 | ,(concat "The arguments to `" (symbol-name command-name) "'.") |
| 77 | :type '(repeat string)) |
| 78 | (defcustom ,player-name (emms-player #',start #',stop #',playablep) |
| 79 | ,(concat "A player for EMMS.") |
| 80 | :type '(cons symbol alist)) |
| 81 | (emms-player-set ,player-name 'regex ,regex) |
| 82 | (emms-player-set ,player-name 'pause 'emms-player-simple-pause) |
| 83 | (emms-player-set ,player-name 'resume 'emms-player-simple-resume) |
| 84 | (defun ,start (track) |
| 85 | "Start the player process." |
| 86 | (emms-player-simple-start (emms-track-name track) |
| 87 | ,player-name |
| 88 | ,command-name |
| 89 | ,parameters)) |
| 90 | (defun ,stop () |
| 91 | "Stop the player process." |
| 92 | (emms-player-simple-stop)) |
| 93 | (defun ,playablep (track) |
| 94 | "Return non-nil when we can play this track." |
| 95 | (and (executable-find ,command-name) |
| 96 | (memq (emms-track-type track) ,types) |
| 97 | (string-match (emms-player-get ,player-name 'regex) |
| 98 | (emms-track-name track))))))) |
| 99 | |
| 100 | ;; Global variables |
| 101 | (defvar emms-player-simple-process-name "emms-player-simple-process" |
| 102 | "The name of the simple player process") |
| 103 | |
| 104 | (defun emms-player-simple-stop () |
| 105 | "Stop the currently playing process, if indeed there is one" |
| 106 | (let ((process (get-process emms-player-simple-process-name))) |
| 107 | (when process |
| 108 | (kill-process process) |
| 109 | (delete-process process)))) |
| 110 | |
| 111 | ;; Utility-functions |
| 112 | (defun emms-player-simple-start (filename player cmdname params) |
| 113 | "Starts a process playing FILENAME using the specified CMDNAME with |
| 114 | the specified PARAMS. |
| 115 | PLAYER is the name of the current player." |
| 116 | (let ((process (apply #'start-process |
| 117 | emms-player-simple-process-name |
| 118 | nil |
| 119 | cmdname |
| 120 | ;; splice in params here |
| 121 | (append params (list filename))))) |
| 122 | ;; add a sentinel for signaling termination |
| 123 | (set-process-sentinel process #'emms-player-simple-sentinel)) |
| 124 | (emms-player-started player)) |
| 125 | |
| 126 | (defun emms-player-simple-sentinel (proc str) |
| 127 | "Sentinel for determining the end of process" |
| 128 | (ignore str) |
| 129 | (when (or (eq (process-status proc) 'exit) |
| 130 | (eq (process-status proc) 'signal)) |
| 131 | (emms-player-stopped))) |
| 132 | |
| 133 | (defun emms-player-simple-pause () |
| 134 | "Pause the player by sending a SIGSTOP." |
| 135 | (signal-process (get-process emms-player-simple-process-name) |
| 136 | 'SIGSTOP)) |
| 137 | |
| 138 | (defun emms-player-simple-resume () |
| 139 | "Resume the player by sending a SIGCONT." |
| 140 | (signal-process (get-process emms-player-simple-process-name) |
| 141 | 'SIGCONT)) |
| 142 | |
| 143 | (defun emms-player-simple-regexp (&rest extensions) |
| 144 | "Return a regexp matching all EXTENSIONS, case-insensitively." |
| 145 | (concat "\\.\\(" |
| 146 | (mapconcat (lambda (extension) |
| 147 | (mapconcat (lambda (char) |
| 148 | (let ((u (upcase char)) |
| 149 | (d (downcase char))) |
| 150 | (if (= u d) |
| 151 | (format "%c" char) |
| 152 | (format "[%c%c]" u d)))) |
| 153 | extension |
| 154 | "")) |
| 155 | extensions |
| 156 | "\\|") |
| 157 | "\\)\\'")) |
| 158 | |
| 159 | (define-emms-simple-player mpg321 '(file url) |
| 160 | (emms-player-simple-regexp "mp3" "mp2") |
| 161 | "mpg321") |
| 162 | (define-emms-simple-player ogg123 '(file) |
| 163 | (emms-player-simple-regexp "ogg" "flac") |
| 164 | "ogg123") |
| 165 | (define-emms-simple-player speexdec '(file) |
| 166 | (emms-player-simple-regexp "spx") |
| 167 | "speexdec") |
| 168 | (define-emms-simple-player playsound '(file) |
| 169 | (emms-player-simple-regexp "wav") |
| 170 | "playsound") |
| 171 | (define-emms-simple-player mikmod '(file) |
| 172 | (emms-player-simple-regexp "669" "amf" "dsm" "far" "gdm" "it" |
| 173 | "imf" "mod" "med" "mtm" "okt" "s3m" |
| 174 | "stm" "stx" "ult" "apun" "xm" "mod") |
| 175 | "mikmod" "-q" "-p" "1" "-X") |
| 176 | (define-emms-simple-player timidity '(file) |
| 177 | (emms-player-simple-regexp "mid" "rmi" "rcp" "r36" "g18" "g36" "mfi") |
| 178 | "timidity") |
| 179 | (define-emms-simple-player fluidsynth '(file) |
| 180 | (emms-player-simple-regexp "mid") |
| 181 | "fluidsynth" "-aalsa" "-in" "/media/music/sf/FluidR3-GM.SF2") |
| 182 | (define-emms-simple-player alsaplayer '(file url) |
| 183 | (concat "\\`http[s]?://\\|" |
| 184 | (emms-player-simple-regexp "ogg" "mp3" "wav" "flac" "pls" "m3u")) |
| 185 | "alsaplayer" "--quiet" "--nosave" "\"--interface text\"") |
| 186 | |
| 187 | (emms-player-set emms-player-alsaplayer |
| 188 | 'pause |
| 189 | 'emms-player-alsaplayer-pause) |
| 190 | |
| 191 | ;;; Pause is also resume for alsaplayer |
| 192 | (emms-player-set emms-player-alsaplayer |
| 193 | 'resume |
| 194 | nil) |
| 195 | |
| 196 | (emms-player-set emms-player-alsaplayer |
| 197 | 'seek |
| 198 | 'emms-player-alsaplayer-seek) |
| 199 | |
| 200 | (defun emms-player-alsaplayer-pause () |
| 201 | (call-process "alsaplayer" nil nil nil "--pause")) |
| 202 | |
| 203 | (defun emms-player-alsaplayer-seek (sec) |
| 204 | (call-process "alsaplayer" nil nil nil "--relative" (format "%d" sec))) |
| 205 | |
| 206 | (provide 'emms-player-simple) |
| 207 | ;;; emms-player-simple.el ends here |