emms-help
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[emms-help] emms-lyric.el v0.1, emms+.el v0.2


From: William XWL
Subject: [emms-help] emms-lyric.el v0.1, emms+.el v0.2
Date: Sun, 17 Jul 2005 21:32:28 +0800
User-agent: Gnus/5.1007 (Gnus v5.10.7) Emacs/21.4 (gnu/linux)

Hi, all.

I've just written a emms-lyric.el, which allows you to play music and
display lyrics either on mode line or minibuffer synchronically.

And an update to emms+.el(renamed from emms-patch.el), which gives you
more user control level funtions, like pause, seek, repeat.

Anybody interested? :P

-- 
William
;; emms+.el - Add more user control functions for EMMS

;; Copyright (C) 2005 William XWL

;; Author: William XWL <address@hidden>
;; Version: v 0.2
;; Last updated: 2005/07/17 20:27:45

;; This file is not part of GNU Emacs.

;;{{{ GPL

;; This program 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 program 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, write to the Free Software
;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

;;}}}

;;; Commentary:

;; 1. Add `emms-pause', `emms-seek' for emms-player-mplayer, this
;; requires passing `-slave' parameter to mplayer, i.e,
;;
;; (setq emms-player-mplayer-command-name "mplayer"
;;       emms-player-mplayer-parameters '("-slave")
;;       emms-player-list
;;       '(emms-player-mplayer
;;         emms-player-mplayer-playlist
;;         emms-player-mpg321
;;         emms-player-ogg123))
;; 
;; 2. Add `emms-repeat-curr', `emms-unrepeat-curr', `emms-repeat-all',
;; `emms-unrepeat-all', `emms-set-repeat-curr-mark',
;; `emms-set-unrepeat-curr-mark', `emms-set-repeat-all-mark',
;; `emms-set-unrepeat-all-mark' to all existing players! When repeating,
;; an extra star '*'(repeat current track) or '**' (repeat all tracks)
;; will be inserted in front of the `emms-mode-line-string'. To achieve
;; this, i've added a new variable `emms-repeat-curr-track' and redefine
;; the function `emms-next-noerror'.
;;
;; 3. Use amixer.el to control volumes, which requires aumix installed,
;; and only works on Linux currently.
;; 
;; To use, put this file to your load-path and the following(together
;; with your other emms's settings) to your .emacs: 
;; 
;;     (require 'emms-patch)

;;; Change Log

;; v 0.2 [2005/07/17 20:22:53] And `emms-player-paused-p',
;;       `emms-player-player-paused-hook', and some modifications to
;;       cooperate with another package(`emms-lyric.el'). Rename this
;;       file from emms-patch.el to emms+.el.

;; v 0.1 The initial version

;;; Todo:

;; Hopefully, this package will change synchronically with
;; `emms-lyric.el' for cooperation.

;;; Codes:

(require 'emms)

;; amixer(only for Linux, comment following parts to enable.
;; (require 'amixer)
;; (setq amixer-mixer-program "aumix"
;;       amixer-volume-increment 1
;;       amixer-master-volume 35)

;; (global-set-key (kbd "C-M-9") 'amixer-decrement-volume)
;; (global-set-key (kbd "C-M-0") 'amixer-increment-volume)

;; mplayer: pause, seek

(defvar emms-player-paused-p nil
  "The EMMS player paused.")

(defvar emms-player-paused-hook nil
  "*Hook run when an EMMS player pauses playing.")

(emms-player-set emms-player-mplayer
                 'pause
                 'emms-player-mplayer-pause)

(emms-player-set emms-player-mplayer
                 'seek
                 'emms-player-mplayer-seek)

(defun emms-player-mplayer-pause ()
  "Depends on mplayer's -slave mode."
  (process-send-string
   emms-player-simple-process-name "pause\n")
  (if emms-player-paused-p
      (setq emms-player-paused-p nil)
    (setq emms-player-paused-p t))
  (run-hooks 'emms-player-paused-hook))

(defun emms-player-mplayer-seek (second)
  "Depends on mplayer's -slave mode."
  (process-send-string
   emms-player-simple-process-name
   (concat "seek " second "\n")))

(defun emms-pause ()
  "Pause the current player."
  (interactive)
  (when emms-player-playing-p
    (if (equal emms-player-playing-p
               'emms-player-mplayer)
        (funcall (emms-player-get emms-player-playing-p 'pause))
      (message "Pause is only available for mplayer."))))

(defun emms-seek (second)
  "Seek forward/backward."
  (interactive)
  (when emms-player-playing-p
    (if (equal emms-player-playing-p
               'emms-player-mplayer)
        (funcall (emms-player-get emms-player-playing-p 'seek) second)
      (message "Seek is only available for mplayer."))))

;; repeat(any player)
(mapcar '(lambda (player)               ; set up
           (mapcar* '(lambda (name value)
                       (emms-player-set player
                                        name
                                        value))
                    '(repeat-curr
                      unrepeat-curr
                      repeat-all
                      unrepeat-all)
                    '(emms-player-any-repeat-curr
                      emms-player-any-unrepeat-curr
                      emms-player-any-repeat-all
                      emms-player-any-unrepeat-curr)))
      emms-player-list)

(setq emms-repeat-curr-track nil)       ; *new* - repeat current track
(setq emms-repeat-playlist nil)         ; repeat all tracks

(defun emms-next-noerror ()             ; redefine this function
  "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-finished-hook'."
  (interactive)
  (when emms-player-playing-p
    (error "A track is already being played"))
  (cond (emms-repeat-curr-track         ; repeat current track only.
         (emms-start))
        ((emms-playlist-next)
         (emms-start))
        (emms-repeat-playlist
         (setq emms-playlist-current 0)
         (emms-start))
        (t
         (message "No next track in playlist"))))

(defun emms-player-any-repeat-curr ()
 (setq emms-repeat-curr-track t)
 (emms-set-repeat-curr-mark)
 (message "Repeat current track."))

(defun emms-player-any-unrepeat-curr ()
 (setq emms-repeat-curr-track nil)
 (emms-set-unrepeat-curr-mark)
 (message "Stop repeating current track."))

(defun emms-player-any-repeat-all ()
 (setq emms-repeat-curr-track nil
       emms-repeat-playlist t)
 (emms-set-repeat-all-mark)
 (message "Repeat all tracks."))

(defun emms-player-any-unrepeat-all ()
 (setq emms-repeat-curr-track nil
       emms-repeat-playlist nil)
 (emms-set-unrepeat-all-mark)
 (message "Stop Repeating all tracks."))

(defun emms-repeat-curr ()
  "Repeat current track."
  (interactive)
  (when emms-player-playing-p
    (funcall (emms-player-get emms-player-playing-p 'repeat-curr))))

(defun emms-unrepeat-curr ()
  "Stop repeating current track."
  (interactive)
  (when emms-player-playing-p
    (funcall (emms-player-get emms-player-playing-p 'unrepeat-curr))))

(defun emms-repeat-all ()
  "Repeat all tracks."
  (interactive)
  (when emms-player-playing-p
    (funcall (emms-player-get emms-player-playing-p 'repeat-all))))

(defun emms-unrepeat-all ()
  "Stop repeating all tracks."
  (interactive)
  (when emms-player-playing-p
    (funcall (emms-player-get emms-player-playing-p 'unrepeat-all))))

(defun emms-set-repeat-curr-mark ()
  "Add a star at front indicating repeats."
  (setq emms-mode-line-format " [ * %s ] "
        emms-mode-line-string
        (funcall emms-mode-line-mode-line-function)))

(defun emms-set-unrepeat-curr-mark ()
  "Remove star mark at front."
  (setq emms-mode-line-format " [ %s ] "
        emms-mode-line-string
        (funcall emms-mode-line-mode-line-function)))

(defun emms-set-repeat-all-mark ()
  "Add a star at front indicating repeats."
  (setq emms-mode-line-format " [ ** %s ] "
        emms-mode-line-string
        (funcall emms-mode-line-mode-line-function)))

(defun emms-set-unrepeat-all-mark ()
  "Remove star mark at front."
  (setq emms-mode-line-format " [ %s ] "
        emms-mode-line-string
        (funcall emms-mode-line-mode-line-function)))

;; recommend key bindings
;; (global-set-key (kbd "C-c e SPC") 'emms-pause)
;; (global-set-key (kbd "C-c e r")   'emms-repeat-curr)
;; (global-set-key (kbd "C-c e R")   'emms-unrepeat-curr)

;; (global-set-key (kbd "C-c e <left>")  (lambda () (interactive) (emms-seek 
"-10")))
;; (global-set-key (kbd "C-c e <right>") (lambda () (interactive) (emms-seek 
"+10")))
;; (global-set-key (kbd "C-c e <up>")    (lambda () (interactive) (emms-seek 
"-60")))
;; (global-set-key (kbd "C-c e <down>")  (lambda () (interactive) (emms-seek 
"+60")))

(provide 'emms+)

;; emms+.el ends here
;;; emms-lyric.el --- Display lyrics synchronically

;; Copyright (C) 2005 William XWL

;; Author: William XWL <address@hidden>
;; Maintainer: William XWL <address@hidden>
;; Created: 2005/07/17 15:08:18
;; Version: v 0.1
;; Keywords: emms music lyric
;; Last updated: 2005/07/17 20:34:51

;; This file is not part of GNU Emacs.

;;{{{ GPL

;; This program 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 program 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, write to the Free Software
;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

;;}}}

;;; Commentary:

;; This package enables you to play music files and display lyrics
;; synchronically! :-) Note, you have to install emms package and
;; emms+.el(written by me as well) first.

;; Put this file into your load-path and the following into your
;; ~/.emacs:
;;             (require 'emms-lyric)

;; Take a look at the "User Customizable" part for possible personal
;; customizations.

;;; Change Log:

;; v 0.1 [2005/07/17 20:07:30] Initial version.

;;; Known bugs:

;; 1. `emms-lyric-pause': Behave right when running for the first
;;    time. Which means, you can only pause-continue once. :(

;; 2. Sometimes music playing would be blocked by some process, like
;;    startup Gnus, while emms-lyric still goes on, thus make music and
;;    lyrics asynchronical.

;;; Todo:

;; 1. Fix `emms-lyric-pause' bug.
;; 2. Add `emms-lyric-seek' support.

;;; Code:

(require 'emms)
(require 'emms+)

;;; User Customizable

(defvar emms-lyric-display-lyric-p t
  "Whether to diplay lyrics or not.")

(defvar emms-lyric-display-lyric-on-mode-line t
  "Display lyrics on mode line.")

(defvar emms-lyric-display-lyric-on-minibuffer nil
  "Display lyrics on minibuffer.")

;;; Variables:

(defvar emms-lyric-alist nil
  "a list of the form: '((time0 lyric0) (time1 lyric1)...)). In short,
at time-i, display lyric-i.")

(defvar emms-lyric-timers nil
  "timers for displaying lyric.")

(defvar emms-lyric-start-time nil
  "emms lyric start time.")

(defvar emms-lyric-pause-time nil
  "emms lyric pause time.")

(defvar emms-lyric-mode-line-string ""
  "current lyric.")

;;; Functions:

(defun emms-lyric-setup (file)
  "Read FILE's lyric file (LRC format) if possible. The lyric file
should end up with \".lrc\", its format looks like:

    [00:39.67]I love you, Emacs!

e.g,

    foo.mp3
    foo.lrc

FILE is foo.mp3 here. "
  (let ((lrc-file
         (replace-regexp-in-string "\\.mp3" ".lrc" file)))
    (if (file-exists-p lrc-file)
        (with-temp-buffer
          (insert-file-contents lrc-file)
          (while (search-forward-regexp
                  "\\[[0-9][0-9]:[0-9][0-9]\\.[0-9][0-9]\\].*" nil t)
            (let ((lyric-string (match-string 0))
                  (time 0)
                  (lyric ""))
              (setq lyric
                    (replace-regexp-in-string ".*\\]" "" lyric-string))
              (while (string-match "\\[.*" lyric-string)
                (setq time (+ (* (string-to-number (substring lyric-string 1 3))
                                 60)
                              (string-to-number (substring lyric-string 4 9))
                              time)
                      lyric-string (substring lyric-string 10)
                      emms-lyric-alist (append emms-lyric-alist `((,time 
,lyric))))
                (setq time 0)))))
      (setq emms-lyric-alist nil)
      ;; (message "Lyric file not found.")
      )))

(defun emms-lyric-start ()
  "Start displaying lryics on the mode line at right time. User should
not call this interactively. But together with `emms-start'."
  (when emms-lyric-display-lyric-p
    (emms-lyric-setup (cdaddr (emms-playlist-current-track)))
    (setq emms-lyric-timers
          (mapcar '(lambda (arg)
                     (let ((time (car arg))
                           (lyric (cadr arg)))
                       (run-at-time
                        (concat (number-to-string time) " sec")
                        nil 'emms-lyric-display lyric)))
                  emms-lyric-alist))
    (setq emms-lyric-start-time (current-time))))

(add-hook 'emms-player-started-hook 'emms-lyric-start)

(defun emms-lyric-pause ()
  "Toggle displaying lyrics. User should not call this
interactively. But together with `emms-pause'."
  (when emms-lyric-display-lyric-p
    (if emms-player-paused-p
        (progn
          (emms-lyric-stop)
          (setq emms-lyric-pause-time (current-time)))
      (let ((elapsed-time
             (if emms-lyric-pause-time
                 (time-to-seconds
                  (time-subtract emms-lyric-pause-time
                                 emms-lyric-start-time))
               0)))
        (setq emms-lyric-start-time (current-time))
        (setq emms-lyric-timers
              (mapcar
               '(lambda (arg)
                  (let ((time (- (car arg) elapsed-time))
                        (lyric (cadr arg)))
                    (when (>= time 0)
                      (run-at-time
                       (concat (number-to-string time) " sec")
                       nil 'emms-lyric-display lyric))))
               emms-lyric-alist))))))

(add-hook 'emms-player-paused-hook 'emms-lyric-pause)

(defun emms-lyric-stop ()
  "Stop displaying lyrics."
  (interactive)
  (cancel-function-timers 'emms-lyric-display)
  (setq emms-lyric-mode-line-string ""))

(add-hook 'emms-player-stopped-hook 'emms-lyric-stop)
(add-hook 'emms-player-finished-hook 'emms-lyric-stop)

(defun emms-lyric-mode-line ()
  "Add lyric to the mode line."
  (when (and emms-lyric-display-lyric-p
             (not (member 'emms-lyric-mode-line-string
                          global-mode-string)))
    (setq global-mode-string
          (append global-mode-string '(emms-lyric-mode-line-string)))))

(defun emms-lyric-display (lyric)
  "Display lyric.

LYRIC is current playing lyric.

See `emms-lyric-display-lyric-on-mode-line' and
`emms-lyric-display-lyric-on-minibuffer' on how to config where to
display."
  (when emms-lyric-display-lyric-p
    (when emms-lyric-display-lyric-on-mode-line
      (emms-lyric-mode-line)
      (setq emms-lyric-mode-line-string lyric)
      (force-mode-line-update))
    (when emms-lyric-display-lyric-on-minibuffer
      (message lyric))))


(provide 'emms-lyric)

;;; emms-lyric.el ends here

reply via email to

[Prev in Thread] Current Thread [Next in Thread]