coding, photo, plant and demo

*MPDにgeneric decoderを追加した

audio mpd tech 20140228 233420

はじめに

MPD(Music Player Daemon)に任意のデコーダを追加する仕組みを追加(移植)しました。

Generic Decoder

Raspberry Pi + RuneAudioで音楽を鳴らしてみる にて、MPDでmdxとかマイナーなサウンドファイルを鳴らしたいので続く、と書きました。
しかしながら、MPDで新しいサウンド形式に対応するためにはmpdを書きなおしてビルドする必要があります。これはメンテも含めて結構面倒くさいです。実際2年前にMDX pluginを書いたことがあるのですが、既にMPDのアップデートでリベースが単純には行きません。しかも適当に繋いだのでメモリリークがあるのかクラッシュすることもあり、そのときにはmpdごと飛んでいました。

良い解決策はないかと調べたら、Generic Decoderなるパッチの存在を知りました。
http://mpd.wikia.com/wiki/GenericDecoder

これは外部デコーダをパイプで繋げてMPDの再生に対応させるものです。これなら標準出力にPCMを流す汎用的なプレイヤを簡単に繋ぐことが出来ますし、別のプロセスで動くのでデコーダが多少不安定でも我慢できます。なんで素晴らしいパッチなんだ!

と思ったのですが残念ながら最新のMPDにはこのパッチは当たりませんでした。2007年のパッチなので7年前か…そりゃ当たるわけない。

Generic Decoderの最新版へのリベース

ということで頑張って最新版へリベースしました。その中で気づいたこと、やったこと等を幾つかメモ。

  • ファイル名やクラス名などの様々なシンボルがリファクタリングの結果変わってる
  • 名前は変われど基本的な構造は意外と変わっていない?意外とちょろいかも
  • streamのdecodeのみでmdxで必要な肝心のfileのデコードの実装が無いことに気づく
  • fileのデコードを実装する
  • streamのデコードは個人的には要らないので今回は捨てる
  • generic_decoderとgeneric_tagreaderを分けている意味がわからないので、generic_tagreaderを廃してgeneric_decoderにまとめる
  • programに対してsuffixを渡す意味が分からないので廃止
    • ファイル形式毎にscript分けたほうが独立性が高くて良いと思う
  • 文字列からaudio formatへの変換関数が消えている…ひとまず44100:16:2に固定で
  • 動くようになった感じがするけどやたら重いぞ?と思ったらパイプからの読み込みがなぜか敢えてノンブロッキングになっててビジーループになってる!意味不明なのでブロッキングとする
  • mpdから起動したスクリプトは再生停止時にmpdからkillされます。このときスクリプトの中で起動したデコーダはパイプが壊れるためSIGPIPEシグナルでプロセスが死ぬはず。amd64 ubuntu12では死んでた。なのに、何故かraspi(rune audio)上だとスクリプトから起動したデコーダが生存してしまう。よく分からないのでスクリプト上でexecでデコーダを呼び、スクリプトとは別にプロセスが起動しないようにした

差分はこちら。
https://github.com/mitsuman/MPD/commit/2a5dceee0d32fa60a1b150d1a290991adb8e1965

やり残してること

  • stream対応
  • audio formatの変更
  • gettagの効率化
  • シーク対応 (可能なら)
  • コントリビュート (可能なら)

ビルド方法

git clone git://git.musicpd.org/master/mpd.git
git checkout generic-decoder
./autogen.sh
./configure --enable-generic
make
make install

/usr/local以下にインストールされるので、それに合わせて設定を変えてください。

使い方

一例です。

mpd.confに
generic_decoder {
        suffix          "mdx"
        pcm_format      "44100:16:2"
        program         "/usr/local/bin/decoder_mdx.sh"
}
を追加。これで拡張子がmdxのファイル(大文字小文字の区別なし)は/usr/local/bin/decoder_mdx.shを使ってデコードすることになります。

この場合、
/usr/local/bin/decoder_mdx.sh filerawdecode hoge.mdx | aplay -f cd
で音がなるように/usr/local/bin/decoder_mdx.shを作る必要があります。
例えばこんなふう。
#!/bin/sh

# mdx2wav from https://github.com/mitsuman/mdx2wav
MDX2WAV=/usr/local/bin/mdx2wav

ACTION="${1}"
case "${ACTION}" in
        rawdecode | filerawdecode)
                INPUT="${2}"
                OUTPUT="${3}"
                $MDX2WAV "${INPUT}"
                ;;

        gettag)
                TAGNAME="${2}"
                INPUT="${3}"
                             case "${TAGNAME}" in
                                time) $MDX2WAV -m "${INPUT}" ;;
                                title) $MDX2WAV -t "${INPUT}" | iconv -f SHIFT_JIS -t UTF-8 ;;
                                *) exit 1 ;;
                             esac ;;

        *)
                echo "$0 filerawdecode <inputfile>" >&2
                echo "$0 gettag <tagname> <inputfile>" >&2
                exit 1 ;;
esac

最後に

というわけでMPDでmdxとかが聴けるようになりました。

標準出力を受けるのは汎用的でunix的で良いんだけど、シークとかに自然な感じでは対応しづらいよね。うーん、どうせなら頑張ってxmms2のプラグインを読めるようにする方が良かった説!