🎶

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