Chienomi

Linuxで(不毛な)「良い音」を目指す設定

Live With Linux::technique

これまで「PulseAudioでいいよ、めんどくさい」というスタンスで優れたオーディオ環境があるにも関わらず特にセッティングはしていなかった。

これはいけない1ということで、ハイクオリティオーディオ環境を構築するというネタを用意することにした。

読者諸兄姉はこれによって何かを変えることはなくても、これを知ることで変えなくて良いという正当な事実を知ることになるかもしれない。

前提

PulseAudioはルーティングを重視しており、「複数のアプリケーションが、複数のオーディオデバイスを扱う」を焦点にしている。 このため、複数のオーディオデバイスがある状況2で使い分けが可能であると同時に、PulseAudioを介することで手間なく確実に音を鳴らすことができるようになっている。

対してJackは単一のオーディオデバイスを扱う。 Jack自体はコンピュータには唯一選別されたオーディオデバイスがある前提になっている。

Jackを使う場合、オーディオデバイスに対して緻密な設定が必要だ。 デフォルト設定で扱える場合は良いが、サンプリングレート, フレーム, バッファーの明示的設定が必要な場合もある。

また、PulseAudioのようなアプリケーションごとの音量設定はできず、Jackによって音量コントロールすることもできない。 さらに、Jackはこのサンプリング周波数にあった入力しか受け付けられない。超めんどくさい。

全体で言えば、PulseAudioとJackを併用することである程度緩和できるが、PulseからJackに流して鳴らすことはほぼ意味がない。 DAW等でJackを扱うこと自体が目的なら別だが。

だが、これはそれほど特別な話ではない。 考えてもみてほしい。Windowsで高度なオーディオインターフェイスを扱うためにASIOやWASAPI排他を使う場合、ドライバでサンプリングレートやバッファー、ビット深度などを明示し、単一のアプリケーションが排他的に(その設定に従って)デバイスを利用するはずだ。

それでも「いい音で再生する」という場合、そんなに簡単な話ではなくなってくる。

Linuxにおいて手間をかけて「いい音で再生したい」というのは次の2要素が絡む。

  • ミキサーを通すので音が悪い
  • PulseAudioが自動で一番無難な設定でオーディオデバイスを使うから実力が発揮できない

先に言ってしまうと、後者は微妙な話で、オーディオ出力が96kとか192kであることは本当に意味がない。 なので、PulseAudioをやめてデバイスをちゃんと設定できることで有意義な変化があると考えるのは無理がある。

前者は少しある話であり、複数のアプリケーションからの音をひとつのオーディオ出力にするためにミキサーというものを介するのだが、ここで音を合成して調整する作業が行われるため、音質はある程度悪くなる。 特にALSAのミキサーはだいぶいまいちなアルゴリズムを使っているため、ALSAを調節使っていたときは、共有で使うか排他で使うかにかなりの差が出ていた。排他にすると、当然ながら音を出せるのはひとつのアプリケーションだけになる。

現代は一般的にPulseAudio、あるいはPipewireが排他的にALSAに接続されている。 ょってALSAのミキサーは使われず、代わりにPulseAudio、あるいはPipeWireがミキシングを行う。 品質的には大きく改善されており、通常不満のないクオリティになっている。

Jackもまたミキサーを持っており、Jackは複数のアプリケーションから扱われることを許容する。

つまり本気の本気でやるつもりであれば、ALSA排他モードにした上で、他のサウンドシステムに使わせず、プレイヤーが唯一のALSAを使うアプリケーションにする必要がある。

ASLA排他モードの話

ALSA排他モードのデバイスに対して正しく音声を入力する確実な方法は、「ffmpegでPCMに変換し、aplayを使って再生する」である。 当然ながら、応用が効かず利便性はとても低い。

それでいながら得られる利益は、私でもよく分からないというレベルのものだ。

もしあなたが音楽愛好家なのであれば、このようなことをすべきではない。

もしあなたが、静音室に最高の音響環境を用意し、心拍を落ち着かせ、目を閉じて集中し、静かに音楽を聴くことを趣味にしているのであればやる価値はあるかもしれない。

Jack

Overview

ここまで言えば分かるように、Jackを採用することでハッキリ分かるほど音が良くなるわけではない。 だが、ALSA排他で使うよりは実用的な使い方が可能なので、お遊び程度にはやってみてもいいだろう。

特にメリットがあるケースとして、オーディオデバイスを44100Hzで動かすか、48000Hzで動かすかというのがある。 CDがソースの場合は44100Hzで、ダウンロードミュージック主体のものだと48000Hzのほうが普通だが、この違いは当然リサンプリングによって解消されるため、音質劣化が発生する。 JackはALSAやPulseAudioなどと比べてこの再設定が簡単なので、これらを混ぜて聴くことが少ないのであればJackを使うメリットはなくはない。

基本的な方針としては、まずひとつのインターフェイスをPulseAudioから外し、Jackに使わせる。 この状態でそのインターフェイスから音を出すにはJackでの再生が必要となり、クライアントアプリが限られる。 音楽再生専用であればそれでもいいが、そうでない場合はmodule-jack-sinkを使ってPulseAudio経由でJackに音を流すことができる。

Jackでの音楽再生は、mpvを使うのが簡単で、単純に--ao=jackオプションをつければよく、必要であればリサンプリングも自動でやってくれる。 また、Audacious, Strawberry, ClementineなどでJackに出力することも可能。

実際にAudio4DJを使ってやってみよう。

Audio4DJはNative Instrumentsのオーディオインターフェイスであり、44100Hz/48000/88200/96000Hzの16ビット録音・再生が可能。 ステレオ4系統持っていて、Ch.AとCh.Bともに入力または出力を選択できる。デュプレックスではないため、同一チャンネルの入力と出力は排他。 Ch.B出力時にはモニター端子(ヘッドフォン)にも出力される。

前準備

以前はPAMの設定をしたり、デバイスの設定を詰めたりといろいろあったけど、今のManjaro Cinnamonはすぐ使える状態になっている。 (Realtimeが有効になってても使えないなら諦めるようになっただけなので、realtimeは使えない)

以前言っていたのは、/etc/security/limits.conf

@realtime        -       rtprio          99
@realtime        -       memlock         unlimited

と書いた上でユーザーをaudio, realtimeグループに追加して再起動という手順だった。 現在はこれは特に必要ないと思われる。(しても良い)

Jackを使う

私はJackのデバイス設定を楽に変更したいので、jackを常時起動してPulseAudioがdetectする形式ではなく、qjackctlを使う形式のほうが好み。

qjackctl

まずは、PulseAudioからデバイスを外す。

qjackctl

qjackctlを起動する。

設定を行う。選択肢にAudio4DJがあるので、これを選べばAudio4DJから再生される。

カードの一覧は/proc/asound/cardsにあるので、catすれば良い。

❯ cat /proc/asound/cards
 0 [HDMI           ]: HDA-Intel - HDA ATI HDMI
                      HDA ATI HDMI at 0xfca24000 irq 120
 1 [Generic        ]: HDA-Intel - HD-Audio Generic
                      HD-Audio Generic at 0xfce00000 irq 121
 2 [V1             ]: USB-Audio - Volt 1
                      Universal Audio Volt 1 at usb-0000:0e:00.3-1, high speed
 3 [Audio4DJ       ]: snd-usb-caiaq - Audio 4 DJ
                      Native Instruments Audio 4 DJ (usb-0000:07:00.3-6)

カード名でシンボリックリンクが作られている。 あまり意味はないが、/proc/asound/Audio4DJ/idにカードの名前が書かれている。

❯ cat /proc/asound/Audio4DJ/id
Audio4DJ

その下にpcm0cpcm0pといったディレクトリがあるが、cは録音デバイス、pは再生デバイスである。 /proc/asound/Audio4DJ/pcm0p/sub0はデバイス0, サブデバイス0、つまりAudio4DJ,0,0を意味している。 Audio4DJは/proc/asound/Audio4DJ/pcm0p/sub1を持っており、/proc/asound/Audio4DJ/pcm0p/sub1/infoを見るとsubdevice: 1が確認できる。

❯ cat /proc/asound/Audio4DJ/pcm0p/sub1/info
card: 3
device: 0
subdevice: 1
stream: PLAYBACK
id: Audio 4 DJ
name: Audio 4 DJ
subname: subdevice #1
class: 0
subclass: 0
subdevices_count: 2
subdevices_avail: 2

つまり、Audio4DJの再生デバイスはAudio4DJ,0,0, Audio4DJ,0,1のふたつがある。

qjackctlに戻る。選択肢にはAudio4DJAudio4DJ,0があるが、どちらもAudio4DJ,0,0を意味している。 Ch.Bから出力したい場合はAudio4DJ,0,1と手書きする必要がある。

インターフェースを選択する

プロファイルを保存しておくとすぐに切り替えられるので便利。 サンプルレート, フレーム/ピリオド, ピリオド/バッファーはデフォルトで通ったけど、サンプルレートは44100か48000か明示しないとあまり意味がないと思う。 (ハイレゾ再生時はリサンプリングを避けるためだけに96000Hzにしても良い)

設定を保存したら開始する。 設定が間違っていたりするとこの時点でエラーになる。 解消に苦労してここで心が折れた人も少なくないはず。

Jackを開始

試しに

mpv --ao=jack 09.ミリオンタイムズ.flac

してみる。 ちなみに、この曲はハイレゾ音源で96kHz/24bit. mpvの出力を見るとJackに対して48000Hz/24bitで出力されているのがわかる。

❯ mpv --ao=jack 09.ミリオンタイムズ.flac
 (+) Video --vid=1 [P] 'cover.jpg' (mjpeg 411x398 1.000fps) (external)
 (+) Audio --aid=1 (flac 2ch 96000Hz)
File tags:
 Artist: HOOKSOFT
 Album: Eスクールライフ オリジナルサウンドトラック
 Title: ミリオンタイムズ
 Track: 9
Displaying cover art. Use --no-audio-display to prevent this.
VO: [gpu] 411x398 yuv444p
Cannot lock down 107341340 byte memory area (Cannot allocate memory)
AO: [jack] 48000Hz stereo 2ch floatp
Cannot use real-time scheduling (RR/5) (1: Operation not permitted)
JackClient::AcquireSelfRealTime error
AV: 00:01:10 / 00:04:54 (24%)

Jackのグラフにも出ている。

qjackctlのグラフ

Jackに対してPulseAudioからルートしたい場合は

pacmd load-module module-jack-sink

とする。 これでSinkにJackが加わるため、ALSAインターフェイスなどを経由してPulseAudioに入ってきた音をJackに流すことができる。

Jack Sink

逆にJackに入ってきた音をPulseAudioに回したい場合は、

pacmd load-module module-jack-source

とする。

ここまでの感想

すごく不便。

アプリケーションごとのボリュームコントロールがなくなるし、出力音量を調整する方法も(標準では)ないのでプレイヤーとして使うようなものじゃない。 Pro Audioとしてはわからなくはないんだけど、Pro Audioのワークフローに絞っているので、普通に欲しい機能がない。 まぁ、インターフェイス側にアクティブボリュームがついてて、コンピュータからは常に100%で出してくれればいいではあるんだけども……

Jackを使う場合の利点として、サンプリング周波数の設定がしやすいこと、Jack自身はリサンプリングを常に行わないことが挙げられる。 ビット深度に関して疑問を持つかもしれないが、Jack (jack2)自体は常に32bit floatでルーティングする。 浮動小数点数であるため、精度は落ちうるが、オーバーフローはしない。これを出力するときに整数値(何ビットの整数であるかはALSAのハードウェアドライバとしてのビット深度に依存する)にして出力するシンプルな仕組みである。

「リサンプリングは音質を悪化させる」と聞けば「ならリサンプリングしなければいい」と思うかもしれない。 しかし、実用上必要だからリサンプリングしているのである。

Jackはリサンプリングを行わないが、そのためにJackクライアント(つまりmpvやAudacious, VLCといったアプリケーション)はffmpegやGStreamerなどを使ってリサンプリングを行い、Jackに合わせた形で出力している。 このようにリサンプリングが必要である場合、PulseAudioにリサンプリングされるより良い結果であるとは限らない。

PulseAudio経由でJackに流すと音はさらに悪くなる要素を持っていることになるので、結局PulseAudioの利便性にはかなわない。

これはPipeWireにもある問題で、PulseAudioは音を扱う非常に幅広いケースに対して柔軟なソリューションを提供しているけれど、JACKもPipeWireも非常に狭いケースだけを見て最適なソリューションを提供しようとしているため、「それではダメなんだ」ということになりがち。 JACKのほうは「JACKはあくまでこのためのものだから!」というスタンスだけど、PipeWireは「これがすべて!」と主張しているのでもっと厄介だったりするけど。

結局のところPulseAudioでどんな音源でもつっこめて、どんなアプリからでも音がならせて、最終的にちゃんと音が鳴るというのが最強で、好きなプレイヤーで、そのときに合ったスピーカーから音楽を聴く、これが一番音楽が楽しめる。

少なくともWindowsで普通にMMEで音を聴くよりはずっと良い音で聴ける(MMEのミキサー品質はとても低いので)のでそれでいいじゃないか。 WASAPI共有でCore Audioを使うのより優れているとは言わないが、十分楽しめる。 だいたいPulseAudioはそれまで長く音声に苦しめられたLinuxerを救ったソフトウェアなのだし、良いものなのだ。

もし、良いオーディオインターフェイスを持ちながら、オーディオインターフェイスを活かす設定をせずに使っていることに苦しんでいる人がいたら、私はこういいたい。

PulseAudioでいいじゃないか。現実環境でひとつの設定でパーフェクトな答えを出せるわけがないのだから。

真の答

PulseAudioは非常に優れており、人は(PipeWireなどは使わず)PulseAudioを使うべきである。

なので、PulseAudioでなるべく良い音にすることを考えたほうが良い。

結論としては、PulseAudioのリサンプリングメソッドを良いものにすること、不必要なリサンプリングを避けることが効果的だ。

よって、/etc/pulse/daemon.conf

resample-method = soxr-hq
avoid-resampling = true

のように書くべきである。 avoid-resamplingは必要がなければリサンプリングを避ける。 デバイスが対応してるかどうかにもよるが、結構有用なオプション。

resample-methodはリサンプリングを行う場合に使うメソッドを選択する。 デフォルトはspeex-float-1であり、より(CPUを使い、レイテンシーは発生するが)品質を重視したものがspeex-float-10である。

また、speexではなくsoxrを使うものもある。 pacmd --list-sinksしてデバイスが16bitまでであればsoxr-hqが、24bitや32bitのデバイスがあるならsoxr-vhqがベストとなる。

これでpulseaudio -kとしてPulseAudioを再起動すれば、今までより良いサウンドで再生されるはずだ。 ちなみに、これは相対的には音への影響が大きい部分の変更なので、これで違いが分からないのであればつまりそういうことだ。 そして、ほとんどの場合は分からないだろう。こだわる意味など最初からなかったのだ。

おまけ

PulseAudioのavoid-resampling

avoid-resampling= If set, try to configure the device to avoid resampling. This only works on devices which support reconfiguring their rate, and when no other streams are already playing or capturing audio. The device will also not be configured to a rate less than the default and alternate sample rates.

とあり、これを真に受けるとミキサーとしてはJackは32bit floatで混ぜて整数に丸めるのに対して、PulseAudioはリサンプリングすると受け取れるから、複数の音がsinkに入っている場合はJackのほうが劣化がなさそうに見える。 しかし、実際は複数の音をsinkに流してもリサンプリングしないので、manpageが古いのではないか。 (他にもpulae-maemon.conf(5)の記述が古い箇所はある。)

この記事で触れていないことからも分かるように、私は今の環境でALSAの設定を詰めることはしていない。 ビット深度を設定するには必要なのだが、ALSAの設定はかなり沼なので、避けているのだ。 また、そもそもそれをしていない理由のひとつとして、Volt1は16bitで認識されるのに対し、Audio4DJは24bitで認識されるという事情もある。 どうしても24bitで聞きたい場合3はAudio4DJから聴くことで解決できる。