プログラミング
ETH-68: Linux用イーサネットオーディオインターフェース
ETH-68: Ethernet Audio Interface for Linux (naturalsystems.io)
要約
ETH-68はLinux向けの低遅延イーサネットオーディオインターフェースです。48kHz/64サンプルバッファで3.620ミリ秒のラウンドトリップ遅延を実現し、複数のユニットを同期させてチャンネル数を拡張しても遅延は増加しません。6系統のバランスライン入力と8系統のバランスライン出力を備え、48kHzおよび96kHzのサンプルレートに対応しています。JACKまたはPipeWireと連携して使用でき、RME HDSPe AIO Pro PCIeカードと同等以上の遅延性能を示します。
全文翻訳
eth68はLinux向けのイーサネットオーディオインターフェースです。
非常に低遅延: 48kHz、64サンプルバッファで3.620ミリ秒のラウンドトリップ遅延
スケーラブル: 複数のユニットを同期させて、ラウンドトリップオーディオ遅延を増加させることなくチャンネル数を増やせます
1/4インチTRSコネクタに6系統のバランスラインレベル入力
1/4インチTRSコネクタに8系統のバランスラインレベル出力
48kHzおよび96kHzのサンプルレート
Burr-Brown PCM3168Aコーデック
DIN MIDI接続
1U 19インチラックシャーシ
JACKとの使用
eth68はSTM32H7マイクロコントローラ上でカスタムのベアメタルファームウェアを実行し、netJACK1マスターエンドポイントをエミュレートします。eth68とのオーディオ交換を開始するには、netoneバックエンドを持つJACKサーバーを起動します。
jackd -d netone
eth68からの最初の受信キャプチャパケットを受信すると、JACKはeth68の物理的なIOに対応するIOポートを作成します。
JACK対応アプリケーションを起動し、eth68のIOに接続します。
PipeWireとの使用
pw-eth68クライアントを使用してPipeWireセッションに直接接続することも可能です。このPipeWireクライアントは、netoneバックエンドを持つJACKサーバーと同様の動作を実装します。
PipeWire対応アプリケーションを起動し、eth68のIOに接続します。
オーディオ遅延
オーディオ遅延とは、オーディオ信号自体がオーディオハードウェアおよびソフトウェアレイヤーを通過する際の可聴遅延のことです。オーディオ遅延は、ハードウェアとソフトウェアの両方のバッファリング、およびオーディオコーデックのデジタルフィルターグループ遅延から生じます。ラウンドトリップオーディオ遅延は、ループバックケーブルを使用して測定できます。オーディオ遅延が大きいシステムでは、MIDIキーボードのキーを押してからソフトウェアシンセサイザーからの音を聞くまでの間に、知覚できる遅延があります。様々な実験により、リスニングコンテキストに応じて5〜20ミリ秒の遅延知覚閾値が確立されています。
eth68は、48kHzで64サンプルバッファサイズ、jack_delayとループバックケーブルを使用して測定した結果、3.620ミリ秒のラウンドトリップオーディオ遅延を達成します。
以下の表は、48kHzおよび96kHzの様々なバッファサイズでのjack_delayによるeth68のラウンドトリップ遅延測定値をまとめたものです。
| Buffer Size | 48 kHz | 96 kHz |
|---|---|---|
| 32 | 2.288 ms | 1.148 ms |
| 64 | 3.620 ms | 1.814 ms |
| 96 | 4.954 ms | 2.480 ms |
| 128 | 6.287 ms | 3.147 ms |
| 256 | 11.621 ms | 5.814 ms |
RME HDSPe AIO Pro PCIeカードと比較して:
| Buffer Size | 48 kHz | 96 kHz |
|---|---|---|
| 32 | -.--- -- | -.--- -- |
| 64 | 3.62 ms | 2.14 ms |
| 96 | -.--- -- | -.--- -- |
| 128 | 6.28 ms | 3.48 ms |
| 256 | 11.62 ms | 6.14 ms |
eth68は、48kHzでRMEカードの遅延性能に匹敵し、96kHzでは0.33ミリ秒上回ります。
マルチユニット同期
複数のeth68ユニットを同期させてチャンネル数を増やすことができます。同期は以下のように達成されます。
高周波(HF)クロックの共有。1つのeth68ユニットがマスタークロックとなり、HFクロックを生成し、BNCケーブルで追加のeth68ユニットにデイジーチェーン接続します。HFクロックを共有することで、ユニット間のサンプルドリフトが排除されます。
eth68ctl.pyを使用してブロードキャストUDP同期コマンドを送信することで、ユニット間のサンプルオフセットをゼロにします。すべてのユニットは、約1サンプル時間(48kHzで20.8マイクロ秒)以内に同期ブロードキャストメッセージを受信し、DMA転送を直ちに再開します。これにより、ユニット間のサンプルオフセットは-1、0、または+1サンプルになります。
JACKインターフェースを介したマルチユニット操作には、中間プロキシアプリケーションeth68proxyの使用が必要です。なぜなら、netjackは複数のマスターからのデータのマージ/分割、または複数のマスターへのデータの分割/マージを想定していないからです。eth68proxyは、複数のeth68からのキャプチャパケットを1つの大きなnetjack互換キャプチャパケットにマージし、netjackからの大きな再生パケットを分割して各eth68ユニットに小さな再生パケットを配信する処理を行います。
2つの同期されたeth68とeth68proxyを実行すると、netjackは自動的にチャンネル数の倍増を検出し、JACKポートを作成します。
上記のスコープショットは、Reaperからの同じのこぎり波オシレータによって駆動される、2つの同期ユニットからの1つの出力を示しています。
上の画像では、スコープはのこぎり波の下降エッジでトリガーされており、緑色のトレースは明確にするために20ミリボルト上にシフトされています。波形は、48kHzで1マイクロ秒未満、つまりサンプルの1/20未満に整列されています。
同期されたeth68ユニットと動作する場合、ラウンドトリップオーディオ遅延は、単一のeth68ユニットのみの場合と同じです。これは、最初のユニットからの出力を2番目の同期ユニットへの入力にループバックし、jack_delayを実行することで検証されました。eth68proxyを介した追加のホップにより、処理遅延にわずかなペナルティがありますが、私のシステムではxrunの頻度を測定可能に増加させるほどではありません。
PipeWireインターフェースを使用する場合、pw-eth68が複数のeth68からのデータストリームを管理するため、eth68proxyは不要です。
処理遅延
処理遅延とは、オーディオバッファのすべての処理を完了するのにかかる時間のことです。処理遅延は、デッドライン時間よりも短くなければなりません。そうでない場合、xrun(オーバーランまたはアンダーラン)が発生し、可聴グリッチを引き起こします。xrunがない場合、処理遅延は可聴ではありません。
処理遅延は、ホストOSの応答性を調整したり、より高性能なホストコンピュータを使用したりするなど、いくつかの方法で削減および制御できます。
eth68は、処理遅延の測定とデバッグのために3.3Vのデジタル信号LATMONを生成します。この信号はリアパネルのBNCコネクタで利用可能です。以下はスコープでの表示です。
LATMONは、キャプチャデータがキャプチャDMAバッファで利用可能になるとすぐにHIGHになります。eth68が受信した再生データを再生DMAバッファにコピーし終えると、LATMONはLOWになります。したがって、LATMONパルスの幅は、各サイクルの総処理遅延の正確な測定値であり、マイクロコントローラでの処理遅延、ネットワーク送信遅延、ホストOS遅延、DAWでの信号処理遅延など、データパスのすべての要素に影響されます。
LATMONパルス幅をリアルタイムでヒストグラム化すると、処理遅延とそれに伴うジッターの感覚が得られます。
上記のプロットでは、垂直破線は48kHzで64サンプルバッファのデッドライン時間である1333マイクロ秒に引かれています。破線の右側またはその線上にあるパルス幅は、xrunを引き起こします。典型的なサイクルの処理遅延は約625マイクロ秒であり、デッドラインまで708マイクロ秒(50%以上のマージン)を残しています。上記のデータは、Bitwigが中程度のDSP負荷のプロジェクトを実行中にキャプチャされたものです。
stress -c 6でいくつかのhogをディスパッチすることで、遅延性能を人為的に悪化させることができます。これにより、ホストシステムはビジーワークで占有され、応答性が低下し、LATMONパルス幅分布がデッドラインに近づきます。
ネットワーク設定
eth68はデフォルトで12.12.12.10:3000にキャプチャパケットを送信します。開始する最も簡単な方法は、ホストIPを12.12.12.10に設定し、jackd -d netoneを実行することです。他の構成については、eth68ctl.pyスクリプトを使用してeth68のネットワーク設定を調整できます。
eth68の設定を照会します。
python eth68ctl.py 12.12.12.10 query
出力:
--------------------------
header: 2820800604
board_id: 3407900
source_ip: 12.12.12.100 (202116196)
netmask_ip: 255.255.255.0 (4294967040)
gateway_ip: 12.12.12.1 (202116097)
destination_ip: 12.12.12.10 (202116106)
destination_port: 3000
mode: 0
period_size: 64
sample_rate: 48000
capture_channels: 6
playback_channels: 8
footer: 2603798065
--------------------------
出力から、eth68のIPアドレスが12.12.12.100であり、12.12.12.10:3000にキャプチャパケットを送信していることがわかります。ethc68ctl.pyへの最初の引数は、eth68とLAN接続を共有するインターフェース上のホストIPです。eth68ctl.pyは、ネットワーク設定が間違っている場合でも常に通信が可能であることを保証するブロードキャストUDPを使用してeth68(s)を制御します。
設定は「set」サブコマンドを使用して変更できます。例えば、宛先IPを12.12.12.50に変更するには:
python eth68ctl.py 12.12.12.10 --board_id 3407900 set destination_ip 12.12.12.50
eth68ctl.pyは、サンプルレートのようなネットワーク関連以外の設定を変更するためにも使用されます。
python eth68ctl.py 12.12.12.10 --board_id 3407900 set sample_rate 96000