Actually, also this one:

emms-player-extensions.el v0.21:

;; v 0.21 [2005/07/18 16:42:51] In function `emms-seek', add a call for
;;        `emms-lyric-seek' (defined in `emms-lyric.el').

emms-lyric.el v0.3

;; v 0.3 [2005/07/19 17:53:25] Add `emms-lyric-find-lyric' for find
;;       lyric files in local repository `emms-lyric-dir'. Rewrite
;;       `emms-lyric-setup' to support more lyric formats.

;; v 0.2 [2005/07/18 16:10:02] Fix `emms-lyric-pause' bug. Now it works
;;       fine. Add `emms-lyric-seek', but which does not work very well
;;       currently.

-- 
William

;;; emms-lyric.el --- Display lyrics synchronically

;; Copyright (C) 2005 William XWL

;; Author: William XWL <[EMAIL PROTECTED]>
;; Maintainer: William XWL <[EMAIL PROTECTED]>
;; Created: 2005/07/17 15:08:18
;; Version: v 0.3
;; Keywords: emms music lyric
;; Last updated: 2005/07/19 23:32:26

;; 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-player-extensions.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.3 [2005/07/19 17:53:25] Add `emms-lyric-find-lyric' for find
;;       lyric files in local repository `emms-lyric-dir'. Rewrite
;;       `emms-lyric-setup' to support more lyric formats.

;; v 0.2 [2005/07/18 16:10:02] Fix `emms-lyric-pause' bug. Now it works
;;       fine. Add `emms-lyric-seek', but which does not work very well
;;       currently.

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

;;; Known bugs:

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

;; 2. `emms-lyric-seek' does work, but not very well. I've no idea
;;    currently.

;;; Todo:

;; 1. Fix bugs in `emms-lyric-seek'.
;; 2. Maybe the lyric setup should run before `emms-start'.
;; 3. Give a user a chance to choose when finding out multiple lyrics.
;; 4. Search lyrics from internet ?

;;; Code:

(require 'emms)
(require 'emms-player-extensions)
(require 'emms-source-file)

;;; User Customizations

(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.")

(defvar emms-lyric-dir ""
  "The directory of local Lyric files. `emms-lyric-find-lyric' will look
for lyrics here.")

;;; User Interfaces
 
(defun emms-lyric-stop ()
  "Stop displaying lyrics."
  (interactive)
  (when emms-lyric-display-lyric-p
    (cancel-function-timers 'emms-lyric-display)
    (unless emms-player-paused-p
      (setq emms-lyric-alist nil
            emms-lyric-timers nil
            emms-lyric-mode-line-string ""))))

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

;;; 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-elapsed-time 0
  "How long time has emms lyric played.")

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

;;; Functions:

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

    [00:39.67]I love you, Emacs!
or 
    [00:39]I love you, Emacs!

e.g,
    foo.mp3 foo.lrc

FILE is foo.mp3 here. To find foo.lrc, first looks up in current
directory, if not found, continue looking up in `emms-lyric-dir'."
  (let ((lrc-file
         (replace-regexp-in-string "\\.mp3$" ".lrc" file)))
    (unless (file-exists-p lrc-file)
      (setq lrc-file (emms-lyric-find-lyric file)))
    (if (and lrc-file
             (file-exists-p lrc-file)
             (not (string= lrc-file "")))
        (with-temp-buffer
          (insert-file-contents lrc-file)
          (while (search-forward-regexp "\\[[0-9:.]+\\].*" nil t)
            (let ((lyric-string (match-string 0))
                  (time 0)
                  (lyric ""))
              (setq lyric
                    (replace-regexp-in-string ".*\\]" "" lyric-string))
              (while (string-match "\\[[0-9:.]+\\]" lyric-string)
                (let ((time-string (match-string 0 lyric-string)))
                  (setq time (+ (* (string-to-number
                                    (substring time-string 1 3))
                                   60)
                                (string-to-number
                                 (substring
                                  time-string 4 (1- (length time-string)))))
                        lyric-string (substring lyric-string (length 
time-string))
                        emms-lyric-alist (append emms-lyric-alist `((,time 
,lyric))))
                  (setq time 0)))))
          t)
      (setq emms-lyric-alist nil)
      ;; (message "Lyric file not found.")
      nil)))

(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 (and 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)
          emms-lyric-pause-time nil
          emms-lyric-elapsed-time 0)))

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

(defun emms-lyric-pause ()
  "Pause displaying lyrics. User should not call this interactively. But
called by `emms-pause'."
  (when emms-lyric-display-lyric-p
    (if emms-player-paused-p
        (progn
          (emms-lyric-stop)
          (setq emms-lyric-pause-time (current-time)))
      (when emms-lyric-pause-time
        (setq emms-lyric-elapsed-time
              (+ (time-to-seconds
                  (time-subtract emms-lyric-pause-time
                                 emms-lyric-start-time))
                 emms-lyric-elapsed-time)))
      (emms-lyric-do-continue))))

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

(defun emms-lyric-do-continue ()
  "Continue displaying lyrics. Will be called by `emms-lyric-pause', and
that's why it has a do-continue name."
  (setq emms-lyric-start-time (current-time))
  (setq emms-lyric-timers
        (mapcar
         '(lambda (arg)
            (let ((time (- (car arg) emms-lyric-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)))

(defun emms-lyric-seek (sec)
  "Seek forward or backward lyrics.

SEC is a second string. e.g., \"+10\", \"-5\"."
  (when emms-lyric-display-lyric-p
    (let ((paused-orig emms-player-paused-p))
      (setq emms-player-paused-p t)
      (emms-lyric-stop)
      (setq emms-player-paused-p paused-orig))
    (let ((sec-num (string-to-number sec)))
      (setq emms-lyric-elapsed-time
            (+ emms-lyric-elapsed-time
               (time-to-seconds
                (time-subtract (current-time)
                               emms-lyric-start-time))
               sec-num))
      (when (< emms-lyric-elapsed-time 0) ; back to start point
          (setq emms-lyric-elapsed-time 0))
      (if (> sec-num 0)                 ; ajust a bit, why?
          (setq sec-num (+ sec-num 4))
        (setq sec-num (- sec-num 4))))
    (emms-lyric-do-continue)))

(defun emms-lyric-mode-line ()
  "Add lyric to the mode line."
  (unless (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))))

(defun emms-lyric-find-lyric (file)
  "Given a mp3 file, use `emms-source-file-gnu-find' to look for the
right lrc file for it. You should specify a valid `emms-lyric-dir'.

FILE is a mp3 file."
  (unless (string= emms-lyric-dir "")
    ;; If find two or more lyric files, only return the first one. Good
    ;; luck! :-)
    (car (split-string 
          (shell-command-to-string
           (concat emms-source-file-gnu-find " "
                   emms-lyric-dir " -name "
                   (replace-regexp-in-string
                    "\\.mp3$" ".lrc"
                    (file-name-nondirectory file))))
          "\n"))))


(provide 'emms-lyric)

;;; emms-lyric.el ends here
;;; emms-player-extensions.el - Add more user control functions for EMMS

;; Copyright (C) 2005 William XWL

;; Author: William XWL <[EMAIL PROTECTED]>
;; Version: v 0.21
;; Keywords: emms music mp3
;; Last updated: 2005/07/19 23:31:40

;; 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 add some more user control functions to EMMS, including
;; pause, seek, repeat. When "repeat", an or two extra stars will be
;; inserted in front of the `emms-mode-line-string', stands for
;; repeating current track and all tracks respectively.

;; Note: pause and seek only works with mplayer's slave mode. Put
;; something like this to your .emacs first:
;;
;; (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))

;; To use, put this file to your load-path and the following(together
;; with your other emms's settings) to your .emacs:
;; 
;;     (require 'emms-player-extensions)

;;; Change Log

;; v 0.21 [2005/07/18 16:42:51] In function `emms-seek', add a call for
;;        `emms-lyric-seek' (defined in `emms-lyric.el').

;; 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-player-extensions.el.

;; v 0.1 The initial version. Add `emms-pause', `emms-seek',
;;       `emms-repeat-curr', `emms-unrepeat-curr', `emms-repeat-all',
;;       `emms-unrepeat-all'.

;;; Todo:

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

;;; Codes:

(require 'emms)

;;; Variables:

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

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

;; how to pass parameters to a hook ?
;; (defvar emms-player-seeked-hook nil
;;   "*Hook run when an EMMS player seeks forward or backward.")

;;; User Interfaces:

(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.

SECOND is a string like \"-10\"."
  (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."))))

(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))))

;;; Functions:

;; pause, seek(mplayer only)
(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 (sec)
  "Depends on mplayer's -slave mode."
  (process-send-string
   emms-player-simple-process-name
   (concat "seek " sec "\n"))
  (emms-lyric-seek sec))

;; 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-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)))


(provide 'emms-player-extensions)

;;; emms-player-extensions.el ends here
_______________________________________________
Emms-help mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/emms-help

Reply via email to