ようこそ。

鷹足です。このブログでは、学校でのことやコンピュータ関係のことを書くと思いますが、どうぞよろしくお願いします。

2018年4月30日月曜日

PulseAudioとTimidity

PulseAudioでのtimidityの利用を試みたのですが、なかなか一筋縄ではいきませんでした。忘れないように、方法をメモっておきましょう…。

私の環境では、オーディオサーバーとして(ALSAの上に)PulseAudioが動いています。Gentoo Linuxでは、デフォルトのinitシステムはsystemdではなくOpenRCなので、PulseAudioはudev+Consolekitによってユーザーごとに起動されています。

PulseAudioは、(私の理解の限りでは)ALSAに対応、かつPulseAudio非対応の普通のアプリケーションがALSAを使おうとすると、仮想のALSAデバイスを使ってデータをPulseAudioに転送した上でうまいこと処理してまとめてサウンドカードに出力してくれます。
つまり、
アプリケーション -> ALSA仮想デバイス -> PulseAudio -> ALSA物理デバイス
という処理をたどることで、アプリケーションにはALSAを使っているように思わせつつすべてのサウンド出力をPulseAudio側で管理し、ハードウェアとのやりとりはPulseAudioのみが(ALSAを介して)行う、ということのようです。

さて、timidity++はネイティブではPulseAudioに対応していないようですが、これ単体でMIDIファイルの再生に使う場合には、上の仕組みがうまく働きしっかり再生してくれます。
(MIDIファイルを入力) -> timidity++ ->  ALSA仮想デバイス -> PulseAudio -> ALSA物理デバイス
という感じですね。

問題は、仮想MIDIインターフェース(ALSAシーケンサー)として使う場合です。aplaymidiやRosegardenその他のMIDIデータを出力するソフトウェアを使う場合、timidity++をこちらのモードで起動することになります。
アプリケーション -> timidity++ -> ALSA仮想デバイス -> PulseAudio -> ALSA物理デバイス
という流れにしなければなりません。ところが、Gentoo Linuxで提供しているinitスクリプトは、timidityユーザーとしてtimidity++を起動しようとします。そうすると、どういうわけか、上記のように既存のALSA仮想デバイスに接続せず、直接物理デバイスにつなぎに行ってしまうようなんですね。(あるいは、timidityユーザーとしてもう1つPulseAudioを立ち上げようとするのか?)
その結果、物理デバイスへのアクセスが競合してしまい、timidityかその他のアプリケーションのどちらかで音が出なくなります。

[alsa-sink-ALC892 Analog] alsa-sink.c: Error opening PCM device front:2: デバイスもしくはリソースがビジー状態です
こんな感じのエラーになるわけです。

PulseAudioがユーザー単位で動いている以上、それを利用するtimidity++がシステムのデーモンとして振る舞うのは難しい、ということですね…。これは原理的に仕方ないっぽいです。 PulseAudioにはSystem-wideモードなるものもあるようですが、あちこちで書かれているように組込み用途以外では非推奨扱いです。Gentooでもuseフラグがマスクされています。

そういうわけで、timidity++をユーザー側で動かすことにしました。
 /etc/conf.d/timidityを見てみると、initスクリプトが使っているtimidityのオプションが書いてあるので、これをユーザーがログインした時に自動実行されるようにしておけばよろしいわけですね。

デスクトップ環境で使えればいいと割りきれるなら、適宜シェルスクリプトを書いて 、~/.config/autostart-scriptsあたりからシンボリックリンクを張りましょう。多重起動が気になる人は、その辺の判定処理も付けておけばいいと思います。
 私は、終了用のシェルスクリプトを書いて~/.config/plasma-workspace/shutdownからシンボリックリンクを張りました。KDEなら、これで開始時にtimidity++を起動、終了時にkillというのが実現できます。

きれいな方法ではないですが、一応はこれでデーモンモードのtimidity++とPulseAudioが共存できるようになりました。