MacのEmacsにBGMとタイプ音をつけてみる


この記事は、SLP_KBITその2 Advent Calendar 2016 - Qiitaの12日目の記事です。

はじめに

遅刻しましたごめんなさい

EmacsLispの続きです。
今回は、EmacsにBGMとタイプ音を追加してみたいと思います!
実用性皆無の興味本位ですw

CLIから音楽再生

音楽再生を考えた時に、SSH経由で音って取れるのかな...?と疑問には思ったのですが、簡単に調べてみたところ、やっぱり無理そうだったので、今回はMacユーザ向けの記事になります。

Macだと、音楽は以下のコマンドで再生できるようです。

$ afplay music.mp3

めっちゃ簡単。これをEmacsから叩けばいいだけですね。

EmacsからShellコマンドを実行する

EmacsLispでは、外部のShellコマンドを実行するための関数が幾つか用意されています。

関数名 効果
shell-command-to-string シェルコマンドを実行し、実行結果を取得する (shell-command-to-string "echo hoge")
async-shell-command シェルコマンドを非同期に実行する (async-shell-command "echo hoge")
start-process-shell-command シェルコマンドを実行するプロセスを立ち上げる (start-process-shell-command "process-name" "buffer-name" "echo" "hoge")

shell-command-to-stringは、非同期ではないため、実行している間はEmacsが動作を停止していしまいます。そのため、これは利用できません。
今回は、start-process-shell-commandを利用します。async-shell-commandを利用しないのは、バッファ名やプロセス名を明示的に指定するためです。

起動時にBGMを再生する

まずは、起動時にBGMを再生出来るようにします。
BGMファイルは、適当なm4aファイルを.emacs.dディレクトリの中に入れておきます。
設定は以下の通り

(defun play-bgm()
  (start-process-shell-command "bgm-process" "bgm-buffer" "afplay" "./bgm.m4a"))

(add-hook 'emacs-startup-hook 'play-bgm)

以上。
start-process-shell-commandを実行して、音楽ファイルを再生する関数を作成して、emacs-startup-hookに引っ掛けるだけ。

Emacs終了時に音楽ファイルを終了する

前述の設定では、Emacsの終了時にActive processes exist; kill them and exit anyway? (yes or no)のように聞かれると思います。
これはちょっと面倒くさいので、Emacs終了時に強制的にBGMを止めるようにしたいと思います。
設定は以下の通り。

(defun kill-process-if-exit(name)
  (setq process (get-process name))
  (unless (eq process nil)
    (process-kill-without-query process)))

(defun save-buffers-kill-terminal-with-sound()
  (interactive)
  (kill-process-if-exit "bgm-process")                                                                                                                                                                          
  (save-buffers-kill-terminal))

(global-set-key "\C-x\C-c" 'save-buffers-kill-terminal-with-sound)

まず、引数に与えられたプロセス名のプロセスを削除するkill-process-if-exit関数を定義します。しかし、プロセスがない場合には何もしないようにunless文で指定しておきます。

通常、C-x C-cにバインドされている関数は、save-buffers-kill-terminalという関数です。
今回は、その直前に作成したプロセスを全て削除し、前述の関数を実行するsave-buffers-kill-terminal-with-soundという関数を定義し、C-x C-cをその関数にバインドし直します。

これで、終了時に問題なく終了できるようになったと思います。

タイプ音を追加する

次は、同様にタイプ音を追加します。
文字を入力したときのhookは、post-command-hookです。

(defun play-type-sound()
  (start-process-shell-command "sound-process" "sound-process" "afplay" "./type.m4a"))

(add-hook 'post-command-hook 'play-type-sound)

(defun save-buffers-kill-terminal-with-sound()
  (interactive)
  ;; 以下の行を追加
  (kill-process-if-exit "sound-process")
  ;; ここまで
  (kill-process-if-exit "bgm-process")                                                                                                                                                                          
  (save-buffers-kill-terminal))

これで完成です!

最後に

※ タイプ音は周りの人の迷惑にならない程度のものにしましょう。