見出し画像

Raspberry Pi 4をハイレゾ対応USB DACにする方法まとめ


2ヶ月ほど前よりRaspberry Pi 4をUSB DAC化するカスタムに取り組んできましたが、個人的に概ね満足する程度にはなりました。まだ解決したい問題は残っていますが当面のあいだは解決の見込みがありません。サッパリです。

そこでこれまで収集した先人たちの知恵の結晶(+私のいくばくかの努力の痕跡)をメモとして残しておきます。
こんなニッチな需要を求めて辿り着かれた人がこれを踏み台とし、より高みに至れますよう切に願います(そして成果物のわけまえを私にもください)

記事の内容柄テキスト量が多くなります(約1万字)
少し下の方にサンプルファイルを置いておきますので、ウンチクがお好きではない人は最後まで読まなくても環境さえ合えば試すことができます(ダウンロードリンクまではご確認ください)

今後個人的に改良することがあっても大きな記事の更新はしません。サポートもありません。気が向けばディスクイメージを差し替えることがあるかもしれませんが、その場合も告知はしません。

用意するもの

最低限必要なもの

  • Raspberry Pi 4(搭載メモリは問いません)

  • i2sサウンド拡張ハット(HiFiBerry DAC Plus互換)

  • microSDカード(4GB以上)

  • パソコン

  • カードリーダライター

  • Type Cケーブル(USB規格は2.0で十分)

HiFiBerry DAC Plus互換のサウンド拡張ハットを使用する前提で設定しています。他のドライバへの対応やラズベリーパイ本体からのライン出力は設定を変更する必要があります。
ラズベリーパイとホストをUSB接続するときにType-Aポートは使えません。通常は電源供給に使うType-CポートのみOTGに対応しています。パソコン・スマホ側はType-Aでも問題ありませんが、スマホの場合はOTG用アダプターが必要な場合があります。

あったほうが良いもの

  • Raspberry Pi用外部電源(GPIO等に接続)

パソコンによってはUSB出力のバスパワー電源でラズベリーパイを起動させることできますが、スマホからでは過負荷すぎです(警告が出ないようになっているので注意)ので外部電源はあったほうが良いでしょう。

必要に応じて使うもの

  • OTGアダプター

  • Type C接続用治具(V+を切断した中継アダプタ・中継ケーブル)

Android互換スマホをホストとして使う場合OTGアダプターが必要かもしれません。OTGアダプターはiPhoneの場合はLightning-Cameraアダプター等とされていることがあります。
治具はラズベリーパイを外部電源で動作させるときに使います。Type Cケーブルでパソコンやスマホを直接繋いでも動作するようですが、ノイズとかループとかが気になる。念の為切断したい場合は用意してください。

その他個人的に使っているもの

  • SD → microSDカード変換ケーブル

  • i2sサウンド拡張ハット用電源

  • USBアイソレーター

必須ではありませんのでお好みで。SD → microSDカード変換ケーブルについては後述します。
USBアイソレーターはUAC2に対応していないと動作しません。

設定内容

  • 32bit/384KHz設定(再生上限352.8KHz?)

  • 計算上100ms程度遅延

  • soxrによるリサンプリング

  • 音量少なめ(85%)

  • SDカードへのスワップ停止

  • SDカードに書込禁止

テスト環境

ホスト(MacBook ProまたはiPhone) → Raspberry Pi 4(4GB) → msBerry DAC → HPA(内蔵HPAまたはopa-dbuf3コピー) → MDR-1AM2

投稿時点での問題点

  • 24bit/192KHzより上は未確認ということ

  • 設定に反しラズパイ内部では352.8KHzの再生デバイスとして認識される(pacmdで確認)

  • ホストをパソコン(MacBook)としたとき一部の環境では一部設定が無効になる

  • 電源投入後ホストに接続せず一定時間放置後に接続すると再生されない(認識はする)30分は大丈夫で60分はダメの様子

そのほか使用しているmsBerryDAC特有の問題として、後付けの組込HPAを使用する場合に部品の構成によってはWiFiの誘導ノイズを拾いノイズが乗ることがあります。

動作報告やこれら問題点の改善を図れた場合などコメントなどでご一報いただければ嬉しいです。

サンプルダウンロード

ご注意
自己責任でお願いします
再配布や直リンクはご容赦ください

raspiod_fin.img.xz (634.6MB)

インストーラーはbalenaEtcherをご使用ください
(解凍せずにインストールできます)

※解凍後のイメージサイズは約3.08GBです
※MacBookとiPhoneでのみ動作確認しています(Windows、Android他は未確認です)
※24bit/192KHzまでの再生確認をしています(ハイレートの音源を持っていないので)


以下は設定の例と簡単な解説です



概要

当記事と同じようにラズパイをUSB DAC化する記事はありますが、私が参考にしながら最初に試行したとおりその多くは24bit/96KHz止まりとなっています。

この記事は試行錯誤の末にボトルネックをg_audioとalsaloopと仮定し、代替としてlibcompositeとpulseaudioを使用したものです。

↓経緯↓

またsoxrによるリサンプリングや音量の85%制限はDACチップ内での処理を考慮し音質へ配慮した結果です(蛇足になりますが個人的にはビットパーフェクトに固執していません)

標準のRaspberry Pi 4単体ではソフトウェアによる電源オフができないので、電源ブツ切りに少しでも耐えられるようにswap機能を停止してSDカードを書込禁止にしています。

以下に設定の手順を示します。問題解決方法も知りたいですが、よりスマートな記述があれば教えていただければ幸いです。
なお、設定の内容は記事公開時点のイメージファイルのものになります。今後イメージファイルの差し替えがあっても記事内容は更新されません。


実際の設定内容

サンプルイメージで使用しているのはbullseyeの64bit版です。32bit・64bitは問いません(最新のbookwormではシステムパーティションの仕様が変わったようでSDカード全体を書込禁止にすることはできないようです)
OSのインストールやアップデート、ユーザー設定、ネットワーク設定、操作やエディタなどの基本的なコマンドは省略します。


モジュールなどインストール

使用するモジュールとライブラリをインストールします。

$ sudo apt install -y pulseaudio
$ sudo apt-get install -y libsoxr-dev


config.txt

ラズパイの設定です。
なお、このファイルはSDカードを挿入したパソコンからでも編集可能です。

ファイルの場所    /boot/config.txt

arm_64bit=1
arm_boost=1

arm_freq=800

dtparam=i2c_arm=on
dtparam=i2s=on

dtparam=hdmi=off

[cm4]

[all]
dtoverlay=dwc2,dr_mode=peripheral
dtoverlay=hifiberry-dacplus
dtoverlay=disable-bt
dtoverlay=disable-wifi

arm_64=1について
32bitのOSを選択した場合はコメント化または削除してください。

arm_freq=800について
クロック設定です。ラズパイ4の発熱対策で省電力を図っていますが、不要ならコメント化または削除してください。

dtoverlay=hifiberry-dacplusについて
ドライバ設定です。ご愛用のi2sサウンド拡張ハットに合わせて変更してください。

ラズパイ本体からのライン出力について
想定していませんが必要なら改行してdtparam=audio=onを追記してください。ただし後述のdefault.paの内容の変更も必要になります(それについては言及しないので各自調べて変更してください)

最終的なファイルについて
最後まで設定を終え再起動をすると最後にinitramfs initrd.img〜という行が追記されることがありますが、その場合はそのままにしてください。


modules.conf

使用するモジュールの登録です。

ファイルの場合    /etc/modules-load.d/modules.conf

dwc2
libcomposite

dwc2について
このモジュールはlegacyですが、比較的新しいdwc-otgは使い方が分かりませんでした。


uac2.sh

libcompositeの設定です。

ファイルの場所    /home/pi/uac2.sh(新規作成)

#!/bin/bash
mkdir -p /sys/kernel/config/usb_gadget/g2
cd /sys/kernel/config/usb_gadget/g2

echo 0x1d6b > idVendor
echo 0x0104 > idProduct
echo 0x0100 > bcdDevice
echo 0x0200 > bcdUSB

mkdir -p strings/0x409
echo "0000000002" > strings/0x409/serialnumber
echo "so-en-oj" > strings/0x409/manufacturer
echo "RasPiOD_Product" > strings/0x409/product

mkdir -p configs/c.1/strings/0x409
echo "rasPi_USB_Audio" > configs/c.1/strings/0x409/configuration
echo 10 > configs/c.1/MaxPower

mkdir -p functions/uac2.0
echo 384000 > functions/uac2.0/c_srate
echo 3 > functions/uac2.0/c_chmask
echo 4 > functions/uac2.0/c_ssize
echo 0 > functions/uac2.0/p_chmask

ln -s functions/uac2.0 configs/c.1
ls /sys/class/udc > UDC

MaxPowerについて
ホストに通知する消費電力の数値を設定できます(実際の消費電力ではない)。この例ではiPhoneに警告を出さないために敢えて小さい値を代入しています。警告が必要な場合は250等に置き換えてください。

p_chmaskについて
本来は入力のチャンネル数を示す設定ですが、今回は不要なので0を代入しています(パソコン上で入力デバイスとしての表示がなくなる)


uac2.shに実行権限を付与

$ sudo chmod +x uac2.sh


uac2.service

uac2.shスクリプトを自動起動するためにserviceに登録します。

ファイルの場所    /etc/systemd/system/uac2.service(新規作成)

[Unit]
Description=do something

[Service]
ExecStart=/usr/bin/bash /home/pi/uac2.sh

[Install]
WantedBy=multi-user.target


serviceの再読込と有効化

$ sudo systemctl daemon-reload
$ sudo systemctl enable uac2.service



ここで一度再起動してください(再起動を省略して進めた場合、なぜかconfig.txtがうまく読み込めないような動作になり期待どおりに起動しないことがあります)
この時点でOTGやi2sサウンド拡張ハットが有効になり、パソコンやスマホなどから認識できるようになります。



default.pa

使用するデバイスを意図的に指定しています。再生デバイスを変更するときは自分の環境を調べて書き直す必要があります。
整理されていないコメント箇所が多数ありますが、理解が及んでいない箇所は残しているためです。

ファイルの場所    /etc/pulse/default.pa

#!/usr/bin/pulseaudio -nF

.fail

### Automatically restore the volume of streams and devices
load-module module-device-restore
load-module module-stream-restore restore_device=false
load-module module-card-restore

### Automatically augment property information from .desktop files
### stored in /usr/share/application
load-module module-augment-properties

### Should be after module-*-restore but before module-*-detect
load-module module-switch-on-port-available

### Load audio drivers statically
### (it's probably better to not load these drivers manually, but instead
### use module-udev-detect -- see below -- for doing this automatically)
load-module module-alsa-sink device=hw:0,0 tsched=0
load-module module-alsa-source device=hw:1,0 tsched=0

load-module module-loopback adjust_time=0 latency_msec=2

### Automatically restore the default sink/source when changed by the user
### during runtime
### NOTE: This should be loaded as early as possible so that subsequent modules
### that look up the default sink/source get the right value
load-module module-default-device-restore

### Make sure we always have a sink around, even if it is a null sink.
load-module module-always-sink

### Honour intended role device property
load-module module-intended-roles

### Automatically suspend sinks/sources that become idle for too long
load-module module-suspend-on-idle

### If autoexit on idle is enabled we want to make sure we only quit
### when no local session needs us anymore.
.ifexists module-console-kit.so
load-module module-console-kit
.endif
.ifexists module-systemd-login.so
load-module module-systemd-login
.endif

### Modules to allow autoloading of filters (such as echo cancellation)
### on demand. module-filter-heuristics tries to determine what filters
### make sense, and module-filter-apply does the heavy-lifting of
### loading modules and rerouting streams.
load-module module-filter-heuristics
load-module module-filter-apply

### Make some devices default
set-default-sink alsa_output.hw_0_0
set-default-source alsa_input.hw_1_0

### Allow including a default.pa.d directory, which if present, can be used
### for additional configuration snippets.
### Note that those snippet files must have a .pa file extension, not .conf
.nofail
.include /etc/pulse/default.pa.d

tsched=0について
標準のpulseaudioはタイマーベースのスケジューリングでDACにデータを送信していますが、なんとなく相性が悪そうなので(legacyな手法である)割り込みベースのスケジューリングに設定しています。
この設定をすると後述のdaemon.confでレイテンシーに関わる設定を有効化できます。

load-module module-loopbackについて
もともとファイルに存在しない行ですがalsaloop同等の動作をさせるために追記しています。入出力デバイスの記述を省略しているので、別途設定してある標準デバイスが自動的に指定されています。

adjust_time=0について
割り込みベースのスケジューリングにしてレイテンシーを調整しても数分の間隔で再生が途切れることがあったのですが、この設定をすると解消します。

latency_msec=2について
後述のdaemon.confでのバッファ設定の計算でレイテンシーが98msになるのがなんとなく気持ち悪いので2ms追加してます。。。特に意味はないかと思います笑笑

メモ: タイマーベースでも同等には動作します


daemon.conf

ファイルの場所    /etc/pulse/daemon.conf

lock-memory = yes
cpu-limit = no

high-priority = yes
nice-level = -11

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

flat-volumes = no

default-sample-format = s32le
default-sample-rate = 384000
alternate-sample-rate = 384000

default-fragments = 7
default-fragment-size-msec = 14

lock-memory = yesについて
後述のスワップ停止に合わせてpulseaudioもオンメモリで動作するようにしています。

resample-method = soxr-vhqについて
リサンプリングにsoxrを指定しています。お好みのライブラリがあれば(pulseaudioが対応していたら)ここで変更できます。

flat-volumes = noについて
音量調整はハードウェアボリュームでのみ行いたいのでアプリケーション毎に音量を調整できないようにしています。ただし手元の環境ではiPhoneでは期待どおり動作するものの、なぜかMacBookでは音量の調整ができてしまいます(Musicアプリの音量調整はアプリの中でデータそのものが変更されているのかもしれません)。
パソコンやスマホなどホスト側のボリュームで調整したいときはコメントアウトまたは値をyesにしてください。

default-sample-format = s32leについて
32bitで設定していますが仮に24bitで設定したいときもs32leとしてください。24bitのデータは4Byteで扱われることが一般的ですが、ラズパイ(Linux?)界隈では3Byteとして扱おうとするために齟齬が生まれて正しく動作しません。16bitは問題なく動作します。

default-fragments = 7
default-fragment-size-msec = 14について

いわゆるバッファの設定で上述のtsched=0を設定することで有効となります(タイマーベースのスケジューリングが有効のときは設定しても強制的に無効となります)。なお値に比例してレイテンシーが増えます。
値は試聴を重ねて決めても良いですが計算で得ることもできます(参考外部リンク


音量制限

DACチップ内部でオーバーサンプリング処理されるときリンギングのクリッピングが観測されるが入力音量を下げると回避できるそうなので、念の為あえて入力音量を85%ほどにしています(参考外部リンク)。ただしこの参考記事の例(矩形波など)は極端すぎて実際の使用状況に見合わないと認識していますし、あまり入力音量を下げない方がS/N比の観点的に都合が良いらしいので、この項目はスキップしても構わないと思います。

設定の前に一度pulseaudioの読み込みをし直します。

$ pulseaudio --kill
$ pulseaudio --start

次に入力音量を設定します。

$ pacmd set-source-volume @DEFAULT_SOURCE@ 0xD999

なお100%は0x10000です。お好みで調整してください。


スワップの無効化

$ sudo dphys-swapfile swapoff
$ sudo systemctl stop dphys-swapfile.service
$ sudo systemctl disable dphys-swapfile.service


システム設定

電源投入後にpulseaudioが立ち上がるように自動ログインの設定をし、同時にSDカードを書込禁止にします。

解除しない限りこの後の変更はできなくなります

$ sudo raspi-config

青い画面のメニューが表示されるので、下記手順で操作してください。

自動ログイン

1 System Options → S5 Boot / Auto Login → B2 Console Autologin

設定が終わると最初の画面に戻るので続けてください。
やり残した設定がある場合、現状までを確認したい場合、書込禁止が必要ない場合は <Finish> → <Yes>(再起動)してください。

書込禁止

4 Performance Options → P2 Overlay File System → <Yes> → <Ok> → <Yes> → <Ok> → <Finish> → <Yes>(再起動)

特にエラーなどがなければ完了です(たまにエラーが返ることがありますが、因子・解決方法はわかりません。実行前にログを消去するとエラー率高めです)。

お疲れさまでした。


主な参考リンク

OTG(Gedget Mode)

原点です。g_audioとalsaloopを使用したUSB DAC化を紹介しています。


ディスクイメージ圧縮

使用しているi2sサウンド拡張ハット「msBerryDAC」の設計者でもあります。ちなみに使用しているHPAも実体配置は自力ですが「op-dbuf3」を参考にしています。いつもお世話になってます!



コーヒーブレイク

以上で本編は終了しました。無事稼働しましたか?
コーヒーでも飲みながらゆっくり音楽を鑑賞してください^ ^

これ以下はなにもありません。取組中+記事作成で消費したコーヒー代ぶんくらい回収できたらなー程度の思いつきです笑笑

検索して調べれば出てくることばかりですので課金に値するコンテンツではありませんが、手間が省けてお役に立てたのなら気分でオキモチ程度お分けください
(特典というわけではないですが、購入された場合は万一記事を削除することがあったとしても読めるようです)

ここから先は

5字

¥ 300

この記事が気に入ったらチップで応援してみませんか?