Raspberry Pi PicoとMicroPythonで音声再生してみる
Raspberry Pi Pico での音声再生に関する情報が少なかったので書き残しておきます。
ネット上の WAV ファイルをストリーミング再生してみました。 これができれば API 経由で TTS を呼び出して再生したりできるので結構できることの幅が広がりそうです👍
本当は MP3 とかも再生したいところなんですが、Pico の性能的にリアルタイムでのデコードは厳しいものがありそう…
使ったもの
- Raspberry Pi Pico W
- MAX98357 を搭載した音声モジュール
- 4-8Ω, 30W のスピーカー
音声モジュールはこれを使いました。ただこの類の製品はレビューが少なく、当たりはずれも大きいので参考程度にしてください。
MAX98357 は I2S DAC とよばれる類のもので、I2S というシリアル通信でオーディオをやりとりするプロトコルに対応した DAC です。これを使えば、I2S で送られてきた音声データをアナログ信号に変換してスピーカーに出力することができます。
配線
一例です。信号関係の線はプログラムを直せばどこにつないでも大丈夫です。
Raspberry Pi Pico | MAX98357 (I2S DAC) |
---|---|
3.3V (Pin 36) | VIN |
GND (Pin 38) | GND |
GP10 (Pin 14) | BCK (Bit Clock) |
GP11 (Pin 15) | LRC (Word Select / Left-Right Clock) |
GP9 (Pin 12) | DIN (Data In) |
GAIN ピンは接続先と挟む抵抗によって、出力ゲインを5段階で調整できます。
ゲイン | 配線 |
---|---|
3dB | GAIN -> 100kΩ -> VIN |
6dB | GAIN -> VIN |
9dB | 未接続 (デフォルト) |
12dB | GAIN -> GND |
15dB | GAIN -> 100kΩ -> GND |
今回は 100kΩ の抵抗を介して VIN に落として、3dB のゲインにしました。
ソースコード
ソースコードを表示
ヘッダー周りと data チャンクの処理が甘いので気が向いたら直します。
解説
まず、Pico には WAV ファイルを丸々1つダウンロードして置いておけるほどの RAM の容量はないので、再生する部分だけを順次細切れでダウンロードしていきます。(いわゆるストリーミング)
CPython であれば、requests
モジュールの関数に stream=True
を渡してあげれば簡単に実現できるのですが、MicroPython の urequests
モジュールの関数にはこの引数は無いので、ストリーミングでダウンロードしたい場合には別のモジュールを使う必要があります。
(ちにみに、CPython と同じ感覚で stream=True
を書いても直接的なエラーは出なくて動くことには動きます。これのせいで沼った🕳️)
今回は mrequests
というモジュールを使いました。このモジュールを使えば MicroPython でもストリーミングでダウンロードすることができます。
mrequests の導入方法
まずリポジトリをクローンしてきます。
$ git clone https://github.com/SpotlightKid/mrequests.git
$ cd mrequests
依存関係をインストールしていきます。
$ pip install mpy-cross mpremote
最後に Pico にインストールします。
$ python install.py
初めに WAV のヘッダーを解析し、サンプリングレートやビット深度、チャンネル数などを取得、それを基に I2S を初期化します。
そしたら バッファサイズの分サーバーから取得 → I2S に書き込み をファイルの終端まで繰り返します。
MicroPython での I2S のサポートはテクニカルプレビュー段階らしいので、比較的新しいファームじゃないと動かないかもです。
まだ問題点も結構あって、たまに再生中にブチブチ切れたり、飛び飛びで再生されてスローみたいになったりします。I2S への書き込みをブロッキングでやってて、ダウンロード分の時間がかかってるからかなとも思ったのですが、他にも何か原因がある気がします。
何か分かる方いらっしゃったらコメントください!!
Raspberry Pi Pico 遊び、たのしい👾
Discussion