Emacs のメディアプレイヤー EMMS がイイ感じ

Emacs はエディタというよりも環境だ。音楽再生だってできるぜ。
EMMS は Emacs でコントロールするメディアプレイヤーだ。というても、 Emacs 「が」再生するのではなくて MPlayer などの外部コマンドを呼び出しているのだが。独自でプレイリストを管理している。

本家サイト

EMMS はたくさんのファイルから成るので「 apt-get install emms 」などパッケージシステムから導入したほうがよいだろう。

で、俺設定。けっこう短い。プレイヤーは MPlayer 一本でとりあえず十分だ。 mp3 、 wav 、 ogg などなどいろんなフォーマットに対応しているし、シークできるからね。 mpg321 じゃシークできないようだ。

(require 'emms-setup)
(require 'emms-i18n)
(emms-standard)
(emms-default-players)
(setq emms-repeat-playlist t)
(setq emms-player-list '(emms-player-mplayer))
(setq emms-source-file-default-directory "~/music/")

再生は M-x emms-play-file 、曲を加えるのは M-x emms-add-file から。以下のように全曲一覧を S 式形式でファイルに出力しておいて、そこから C-x C-e で選択・実行したほうが手軽だと思う。

# ふぅ〜 (emms-play-file "foo.mp3")
# ばぁ〜 (emms-play-file "bar.mp3")

プレイリストは M-x emms-playlist-mode-go で開く。 p/n で前後の曲を再生、 C-p/C-n で前後の曲を選択、 RET で再生、 P で一時停止、 s で停止、 q でプレイリストを閉じる。<と>で 10 秒 *1 シークする。まぁ Emacs 的にわかりやすい操作性だろう。

もちろん gnuclient/emacsclient から EMMS に指示することもできるぞ。

anything との連携

anything.el と統合する anything-emms.el が EmacsWiki にある。しかし、起動のたびに再帰的に音楽ファイルを探索するため、起動が遅いから俺は使っていない。でもとりあえず使いたい人は以下の Emacs Lisp を順次インストールしよう。

M-x install-elisp.el http://www.emacswiki.org/cgi-bin/wiki/download/anything.el

M-x install-elisp.el http://www.emacswiki.org/cgi-bin/wiki/download/anything-extension.el

M-x install-elisp.el http://www.emacswiki.org/cgi-bin/wiki/download/anything-emms.el

M-x anything-emms-file で選択〜

XMMS からの移行

Debian sidに移行してみたいが、あきらめた - http://rubikitch.com/に移転しました ではあきらめたが、ついに Debian sid に移行。しかし、 XMMS のいろいろなプラグインはパッケージからなくなってしまったようだ。けっこう好きだったのに残念。今は XMMS2 という形で生まれ変わっているが、互換性がないので旧 XMMS の動作をさせようと思ったがうまくいかなかった。そこで EMMS に白羽の矢が立った。

で、 EMMS / gnuclient にある程度 XMMS 互換のコマンドラインオプションを持たせようとさくっと Ruby スクリプトを書いてみた。とりあえず 1 曲しか指定できないがどうぞ。なお、 emacsclient を使っている人は環境変数 EMMS_CLIENT に emacsclient と指定しておいてね。

ダウンロードできるように http://www.rubyist.net/~rubikitch/archive/emms に置いておいた。

#!/usr/local/bin/ruby
require 'optparse'

def lisp (src)
  client = ENV['EMMS_CLIENT'] || 'gnuclient --batch'
  system %Q!#{client} --eval "#{src}"!
end

def play (file, enqueue)
  if enqueue and file
    lisp %Q ((progn
                (let ((current-prefix-arg nil))
                           (emms-add-file #{file.dump}))
                (emms-stop)
                (save-excursion
                  (set-buffer " *EMMS Playlist*")
                  (emms-playlist-mode-last)
                  (forward-line -1)
                  (emms-playlist-mode-play-smart))))
  elsif file
    lisp %Q ((let (current-prefix-arg)
             (emms-play-file #{file.dump})))
  else
    lisp %((emms-start))
  end
end

def stop (*args)         lisp %((emms-stop))          end
def fwd (*args)          lisp %((emms-next))          end
def rew (*args)          lisp %((emms-previous))      end
def seek_forward (*args) lisp %((emms-seek-forward))  end
def seek_back (*args)    lisp %((emms-seek-backward)) end
def pause (*args)        lisp %((emms-pause))         end
def info (*args)         lisp %((princ (emms-info-track-description (emms-playlist-current-selected-track)))) end
def info_ratpoison (*args) lisp %((ratpoison-echo (emms-info-track-description (emms-playlist-current-selected-track)))) end

def play_pause (*args)
  lisp %((if emms-player-playing-p
             (emms-pause)
             (emms-start)))
end
def play_stop (*args)
  lisp %((if emms-player-playing-p
             (emms-stop)
             (emms-start)))
end
def remove (*args)
  lisp %Q ((progn
              (save-excursion
                (set-buffer " *EMMS Playlist*")
                (goto-char emms-playlist-selected-marker)
                (emms-playlist-delete-track)
                (ignore-errors (emms-next))
                )))
end


conf = Struct.new (:enqueue, :operation).new
ARGV.options {|o|
  o.on ("-e", "Enqueue") {|x| conf.enqueue = true }
  o.on ("-p", "Play") {|x| conf.operation = :play }
  o.on ("-s", "Stop") {|x| conf.operation = :stop }
  o.on ("-u", "Pause") {|x| conf.operation = :pause }
  o.on ("-t", "Play/Pause") {|x| conf.operation = :play_pause }
  o.on ("--play-stop", "Play/Stop"){|x| conf.operation = :play_stop }
  o.on ("-f", "--fwd", "Next track") {|x| conf.operation = :fwd }
  o.on ("-r", "--rew", "Previous track") {|x| conf.operation = :rew }
  o.on ("--remove", "Remove") {|x| conf.operation = :remove }
  o.on ("--forward", "Seek forward") {|f| conf.operation = :seek_forward }
  o.on ("--back", "Seek back") {|f| conf.operation = :seek_back }
  o.on ("--info-ratpoison") {|f| conf.operation = :info_ratpoison }
  if ARGV.empty?
    print o
    exit 1
  end
  o.parse!
}

file = ARGV.first ? File.expand_path (ARGV.first) : nil
__send__ conf.operation, file, conf.enqueue

オプションはこちら。

Usage: emms [options]
    -e                               Enqueue
    -p                               Play
    -s                               Stop
    -u                               Pause
    -t                               Play/Pause
        --play-stop                  Play/Stop
    -f, --fwd                        Next track
    -r, --rew                        Previous track
        --remove                     Remove
        --forward                    Seek forward
        --back                       Seek back
        --info-ratpoison

あとは xbindkeys とかでメディアキーに割り当てておけば再生・停止・シークなど自由自在。

*1:おわっ、なんとハードコードされている!