aboutsummaryrefslogtreecommitdiff
path: root/emms-player-mpg321-remote.el
diff options
context:
space:
mode:
authorDamien Elmes <emms@repose.cx>2006-06-15 06:30:00 +0000
committerDamien Elmes <emms@repose.cx>2006-06-15 06:30:00 +0000
commit395d69cb965b6905b7b87b6f8ae062dfe3423c56 (patch)
tree764e6f85977d0365f51a8549b8751ed44d271547 /emms-player-mpg321-remote.el
parenta835d3cdafbe77f6170ee148d0a4ca9c977bbd05 (diff)
add player-mpg321-remote
- allows seeking in files - handles files with errors in them (the mpg321 simple version skips over the files) darcs-hash:20060615063027-4e3e3-55f9b446189c86894879167259604cda28fe5215.gz
Diffstat (limited to 'emms-player-mpg321-remote.el')
-rw-r--r--emms-player-mpg321-remote.el201
1 files changed, 201 insertions, 0 deletions
diff --git a/emms-player-mpg321-remote.el b/emms-player-mpg321-remote.el
new file mode 100644
index 0000000..6b7790f
--- /dev/null
+++ b/emms-player-mpg321-remote.el
@@ -0,0 +1,201 @@
+;;; emms-player-mpg321-remote.el --- play files with mpg321 -R
+
+;; Copyright (C) 2006 Damien Elmes <emacs@repose.cx>
+
+;; Author: Damien Elmes <emacs@repose.cx>
+;; Keywords: emms, mp3, mpeg, multimedia
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; This file provides an emms-player which uses mpg321's remote mode
+;; to play files. This is a persistent process which isn't killed each
+;; time a new file is played.
+
+;; The remote process copes graciously with errors in music files, and
+;; allows you to seek in files.
+
+;; To enable this code, add the following to your emacs configuration:
+
+;; (require 'emms-player-mpg321-remote)
+;; (push 'emms-player-mpg321-remote emms-player-list)
+
+;;; Code:
+
+(require 'emms)
+(require 'emms-player-simple)
+
+;; --------------------------------------------------
+;; Variables and configuration
+;; --------------------------------------------------
+
+(defgroup emms-player-mpg321-remote nil
+ "*EMMS player using mpg321's remote mode."
+ :group 'emms-player
+ :prefix "emms-player-mpg321-remote")
+
+(defcustom emms-player-mpg321-remote-command "mpg321"
+ "*The command name of mpg321."
+ :type 'string
+ :group 'emms-player-mpg321-remote)
+
+(defcustom emms-player-mpg321-remote-parameters nil
+ "*Extra arguments to pass to mpg321 when using remote mode
+For example: (list \"-o\" \"alsa\")"
+ :type '(repeat string)
+ :group 'emms-player-mpg321-remote)
+
+(defcustom emms-player-mpg321-remote
+ (emms-player 'emms-player-mpg321-remote-start-playing
+ 'emms-player-mpg321-remote-stop-playing
+ 'emms-player-mpg321-remote-playable-p)
+ "*A player for EMMS."
+ :type '(cons symbol alist)
+ :group 'emms-player-mpg321-remote)
+
+(defvar emms-player-mpg321-remote-initial-args
+ (list "--skip-printing-frames=10" "-R" "-")
+ "Initial args to pass to the mpg321 process.")
+
+(defvar emms-player-mpg321-remote-process-name "emms-player-mpg321-remote-proc"
+ "The name of the mpg321 remote player process")
+
+(defmacro emms-player-mpg321-remote-add (cmd func)
+ `(emms-player-set 'emms-player-mpg321-remote
+ ,cmd ,func))
+
+(emms-player-mpg321-remote-add
+ 'regex (emms-player-simple-regexp "mp3" "mp2"))
+(emms-player-mpg321-remote-add
+ 'pause 'emms-player-mpg321-remote-pause)
+(emms-player-mpg321-remote-add
+ 'resume 'emms-player-mpg321-remote-pause)
+(emms-player-mpg321-remote-add
+ 'seek 'emms-player-mpg321-remote-seek)
+
+;; --------------------------------------------------
+;; Process maintenence
+;; --------------------------------------------------
+
+(defun emms-player-mpg321-remote-start-process ()
+ "Start a new remote process, and return the process."
+ (let ((process (apply 'start-process
+ emms-player-mpg321-remote-process-name
+ nil
+ emms-player-mpg321-remote-command
+ (append emms-player-mpg321-remote-initial-args
+ emms-player-mpg321-remote-parameters))))
+ (set-process-sentinel process 'emms-player-mpg321-remote-sentinel)
+ (set-process-filter process 'emms-player-mpg321-remote-filter)
+ process))
+
+(defun emms-player-mpg321-remote-stop ()
+ "Stop the currently playing process, if indeed there is one"
+ (let ((process (emms-player-mpg321-remote-process)))
+ (when process
+ (kill-process process)
+ (delete-process process))))
+
+(defun emms-player-mpg321-remote-process ()
+ "Return the remote process, if it exists."
+ (get-process emms-player-mpg321-remote-process-name))
+
+(defun emms-player-mpg321-remote-running-p ()
+ "True if the remote process exists and is running."
+ (let ((proc (emms-player-mpg321-remote-process)))
+ (and proc
+ (eq (process-status proc) 'run))))
+
+(defun emms-player-mpg321-remote-sentinel (proc str)
+ "Sentinel for determining the end of process"
+ (when (or (eq (process-status proc) 'exit)
+ (eq (process-status proc) 'signal))
+ (emms-player-stopped)))
+
+(defun emms-player-mpg321-remote-send (text)
+ "Send TEXT to the mpg321 remote process, and add a newline."
+ (let ((proc (emms-player-mpg321-remote-process)))
+ ;; we shouldn't be trying to send to a dead process
+ (assert proc)
+ (process-send-string proc (concat text "\n"))))
+
+;; --------------------------------------------------
+;; Interfacing with emms
+;; --------------------------------------------------
+
+(defun emms-player-mpg321-remote-filter (proc str)
+ (let* ((data (split-string str))
+ (cmd (car data)))
+ (cond
+ ;; stop notice
+ ((and (string= cmd "@P")
+ (string= (cadr data) "0"))
+ (if emms-player-mpg321-remote-mask-stop-message
+ (setq emms-player-mpg321-remote-mask-stop-message
+ nil)
+ (emms-player-stopped)))
+ ;; frame notice
+ ((string= cmd "@F")
+ ;; even though a timer is constantly updating this variable,
+ ;; updating it here will cause it to stay pretty much in sync.
+ (setq emms-playing-time
+ (truncate (string-to-number (nth 3 data))))))))
+
+(defun emms-player-mpg321-remote-start-playing (track)
+ "Start playing a song by telling the remote process to play it.
+If the remote process is not running, launch it."
+ (unless (emms-player-mpg321-remote-running-p)
+ (emms-player-mpg321-remote-start-process))
+ (emms-player-mpg321-remote-play-track track))
+
+(defun emms-player-mpg321-remote-stop-playing ()
+ "Stop the current song playing."
+ ;; we don't want to tell emms we've stopped playing, or it'll start
+ ;; playing the next track
+ (setq emms-player-mpg321-remote-mask-stop-message t)
+ (emms-player-mpg321-remote-send "stop"))
+
+(defun emms-player-mpg321-remote-play-track (track)
+ "Send a play command to the remote, based on TRACK."
+ (emms-player-mpg321-remote-send
+ (concat "load " (emms-track-get track 'name)))
+ (emms-player-started 'emms-player-mpg321-remote))
+
+(defun emms-player-mpg321-remote-playable-p (track)
+ ;; use the simple definition.
+ (emms-player-mpg321-playable-p track))
+
+(defun emms-player-mpg321-remote-pause ()
+ "Pause the player."
+ (emms-player-mpg321-remote-send "pause"))
+
+(defun emms-player-mpg321-remote-resume ()
+ "Resume the player."
+ (emms-player-mpg321-remote-send "pause"))
+
+(defun emms-player-mpg321-remote-seek (seconds)
+ "Seek forward or backward in the file."
+ ;; since mpg321 only supports seeking by frames, not seconds, we
+ ;; make a very rough guess as to how much a second constitutes
+ (let ((frame-string (number-to-string (* 35 seconds))))
+ ;; if we're not going backwards, we need to add a '+'
+ (unless (eq ?- (string-to-char frame-string))
+ (setq frame-string (concat "+" frame-string)))
+ (emms-player-mpg321-remote-send (concat "jump " frame-string))))
+
+(provide 'emms-player-mpg321-remote)
+;;; emms-player-mpg321-remote.el ends here