Switchはイヤホン出力の音がひどいことで有名だ*1。
ブズズズズ………バババババ……
と熱雑音では明らかに説明できない周辺回路のお気持ちが音となって伝わってくる。
そこでUSB DACを使いたいのだが、どうも手持ちだとハイエンド機に限って動かない*2。別なやり方でデジタル音声を取り出さなければ。
取り出し方は様々ある。
- ドックのHDMI出力 + S/PDIFスプリッター(TVモード必須)
- Switch用Bluetoothトランスミッター(ぶっちゃけこれが一番オススメ)
- Switchが認識できるUSB DDCで同軸デジタルなどにする
- Raspberry PiのUACガジェット
Switchに直に接続できないDACを使いたい場合は、DDC必須*3でゴテゴテしてしまう。
「それなら本体に流れるデジタル信号(I2S)を直接取り出して、S/PDIFに変換するしかないよね!」と思いついた26の夜。早速やっていこう。なお、「自作が一番ゴテゴテするのでは?」というツッコミは受け付けておりません。
音声出力の解析
iFixitのページにあるように、Switchの中ではスマートアンプ Realtek ALC5639 が使われていて、DAC・ヘッドホン出力・スピーカー出力を一手に引き受けている。I2S(音声) + I2C(制御)でSoCと接続するこういうスマートアンプは組み込みでよく使われる*4。
このどこかのピンにI2Sが入力されている!ということで早速プローブを当てる。結果は以下の通り。
そしてはんだ付け。
下はオシロで波を出してみた図。上からBCLK(ビットクロック)、LRCLK(左右のチャンネルを区別するクロック*5)、SDATA(シリアライズされた音声データ)。
S/PDIFへの変換
I2SとS/PDIFは信号の種類が違うので変換しなければならない。信号を変換する装置といえば!?
デケデケデケデケ…デン!!
そう!FPGA!!!(予定調和)
今回はこのSiPeed Tang Nanoという開発ボードを使う。Shigezone店頭価格でなんと800円。意味不明なくらい安い*6。
GOWIN GW1N-1 (LittleBee) が搭載されているので開発はGOWIN EDAで行う*7。
FPGA内部では以下のタスクをやらせる。
- I2Sの信号をデシリアライズして左右合計32bitのフレームを得る
- フレームをFIFOに入れる*8
- FIFOからフレームを取り出してS/PDIF TXに入れる
- ええ感じにTXからS/PDIF信号が出る
前段のデシリアライズは手でSerdesを書いて対応。後段のS/PDIF TXはOpenCoresに実装があったのでこちらを使わせてもらった。
実装はもちろんGitHubに置いておきました。英語でのインストラクション付き。回路だけはんだ付けすればポン付けで動くようにしているので、GitHubのインストラクションやブレッドボードを参考に試してみて欲しい。
ちなみに面白いことに、Tang Nanoの赤LEDで光デジタルを直接出すことができるため、光デジタル対応DACであれば外付け部品ゼロで音を聴くことができる。最高!
普通の赤LEDで光デジタル鳴ったwwww
— puhitaku (@puhitaku) 2020年8月12日
激安FPGA SiPeed Tang Nanoから信号出してる。詳細は後ほど。 pic.twitter.com/NZPiPR8iQg
今後
このままだと持ち運べないのでうまいことまとめて外でも使えるようにしたい。3Dプリンターも届いたし。
参考ページ
*1:現行機だと変わってるかもしれないが未確認
*2:UAC 1しか対応してない説が濃厚。ローエンド機はそれで十分だが、ハイエンド機は対応ビットレートが高いので必然的にUAC 2/3を選択することになる。
*3:ところでDDCを好き好んで「「ジッタの減少」」に使ってる人々は果たして【体感】できてるんだろうか?そんな人間に体感できないオーダーのジッタなんてプラセボに比べたら数桁小さいですよ。個人的な感想です。
*4:NVIDIA Jetson TXで同じフットプリントの姉妹チップALC5640が使われているので、ひょっとするとNVIDIAの開発ボードのデザインを任天堂がそのまま採用したんじゃないかな〜とか推測できるのが楽しい。5639のデータシートは見つからないが、5640のデータシートは普通に手に入るため解析にも役に立った。
*5:厳密にはこれはクロックではなくデータ
*6:1万すら切れないAltera DE-0 Nanoとか鼻で笑えるような最高のFPGA学習キットが作れるのではないだろうかと妄想している。顧客が本当に必要としていた「入門機」はこれや!
*7:大手に比べると情報が少なくて最初ちょっと戸惑うが、素朴なぶんめっちゃ軽くて良い開発環境
*8:駆動するクロックが異なるため非同期FIFOを挟んでいる。I2S = 6.144MHz, S/PDIF TX = 6.144MHz * 8 = 49.152MHz。S/PDIFにはvalidフラグがあるので、FIFOのalmost_fullフラグをvalidにつなげることで予期せぬアンダーフローによるノイズを防ぐ意味合いもある。