世界を動かす技術を、日本語で。

10セントのMCUトークを作りました

概要

  • 10セントMCU で音声再生と合成に挑戦した事例紹介
  • 16KBフラッシュ 内に音声データとコードを収める圧縮技術の解説
  • 2ビットADPCM による短音声クリップの保存と再生手法
  • LPC音声合成 (Talkieライブラリ)で多数の単語・フレーズを実現
  • 実装や音質、ツール作成の工夫を具体的に説明

超小型MCUで音声再生に挑戦

  • CH32V003 など10セントMCUで音声出力実現
  • 1ビット音声 (GPIOトグル)から、 PWM出力 による波形再生へ進化
  • 8kHzサンプリング でPWMをDAC代用、SMDブザーから小型スピーカーへ変更
  • 16KBフラッシュ の厳しい容量制限下での音声再生

音声データ圧縮の工夫

  • 6秒の音声クリップ (「Open the pod bay doors HAL…」)を保存するための圧縮方式比較
  • 比較例
    • CD品質 (44.1kHz/16bit):約529KBで16KBに収まらず
    • 電話品質 (16kHz/16bit):約192KBで不可
    • 8bit PCM/8kHz :約48KBで不可
    • 4bit ADPCM/8kHz :約24KBで難しい
    • QOA (3.2bit/サンプル):約19KBで不可
    • 2bit ADPCM/8kHz :約12KBで 唯一可能
  • 2bit ADPCM 選定理由
    • 4:1圧縮で75%容量削減
    • デコーダ実装も 1.3KB以下 と超軽量
    • 音質は低いが 意外と聞き取れる

2ビットADPCMの仕組み

  • 予測値ステップサイズ を維持し、2ビット符号で差分を符号化
  • 00: 1ステップ下げる、01: 1ステップ上げる、10: 2ステップ下げる、11: 2ステップ上げる
  • 適応的にステップサイズを調整し、元音声の形状を大まかに再現
  • エンコードツール 作成でWAV→2bit ADPCM変換を自動化

LPC音声合成による長文再生

  • ADPCM では長い音声保存が難しいため、 LPC音声合成 (Talkieライブラリ)を導入
  • Talkie はTexas Instrumentsの1970年代LPC音声チップ互換ソフトウェア
  • Speak & Spell や初期アーケードゲーム、BBC Microなどで採用実績
  • 1フレーズ数百バイト で多数の単語・フレーズ保存可能
  • 音質はロボット的だが 明瞭で理解可能
  • カスタム音声 を作るには既存語彙の連結や新規LPCデータ生成が必要
    • BlueWizard・PythonWizardなどのツールでWAV→LPC変換
    • AIアシスタント 活用でオンライン変換ツールも自作

実験結果とまとめ

  • 2bit ADPCM で8秒弱の音声クリップ保存・再生に成功
  • Talkie LPC で多様なフレーズや単語の合成音声出力が可能
  • PWM出力 による音質は低いが、内容は十分伝わる
  • GitHub で全コード公開中
  • 超低コストMCU でも工夫次第で「話す」機能を実現可能

関連情報・サポート

  • 詳細なデモ動画やコードは GitHub ・ブログ上で公開
  • Patreonko-fi でのサポートも受付中
  • 執筆者: Chris Greening

Hackerたちの意見

面白いね。でもクリックする前は、見出しがマーベル映画についてのすごく低賃金のプレゼンテーションを指してるのかと思ったよ。

ほんとそれ。略語がいろんな分野で使われるのが嫌なんだよね。インサイダーじゃないと、読むのがめっちゃ混乱する。

いい仕事だね。特に「Speak and Spell」のTIの先行技術を引用してるのが良い。こういう合成は80年代初頭には結構一般的だったよね。学校のBBCマイクロにはフレーズを「*SAY」できるROMがあったし、クラシックMacにはMacinTalkがあった。もう一つ試してみる価値があるけど、かなり複雑なのはGSMのAMRだね。https://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_code...

これ素晴らしいね。スピーカー回路にローパスRCフィルターを使うチャンスを逃したのがもったいないな。8kHzのサンプルレートを使うって分かってるなら、そのカットオフでフィルターを設計すれば、もっと良い音になるよ(バズ音が消えるから)。

これ、オーディオアンプに接続するなら重要かも。31.25kHzのPWMで他の人の高価なツイーターを焼き切った経験があるから、痛い目にあったよ。

あのデバイスにi2cフラッシュチップをつなげて、もっとストレージを増やせるし、シリアル通信用のIOピンも余分に残せるよ。

すべてデバイス上でできるはずだよ。SAM、Software Automatic Mouthをチェックしてみて。*_tabsファイルの実際のデータはここにあるよ: https://github.com/ctoth/SAM/tree/master/src

動画の音声、TTSよりも洗練されてる気がする。デジタルオーディオのクリップを分析して、それをTTSの音素に変換してる感じだね。SAMが元のものを忠実に移植してるなら、テキストを発音ルールに従って音素に変換してるんだろうね。

数日前に同じマイクロコントローラー(ファミリー)で別のオーディオプロジェクトを見たよ: ModPlayRISCV。トラッカーモジュールを再生するんだ。PWMを使ってローパスフィルターをかけてる。すべてのサンプルを異なるレート/ボリュームでリングバッファにリサンプリング/スケーリングして、DMAでPWMコンパレータに送ってる。https://github.com/cpldcpu/ModPlayRISCV

音声を圧縮するためのいくつかのエンコーディングオプションを考えたよ。この部分のプレゼンテーションは、皮肉なことに、すごく冗長に感じるね。

このCH32マイクロコントローラーは素晴らしくて、めちゃくちゃ安いよ。おもちゃロボットを制御するために小さなDCモーターコントローラーを作ったんだ: https://github.com/h0lad/MiniSpeedController。大きいのはUSB HS、USB-C(5Gbps)や10/100MイーサネットのPHYが統合されてるんだよ(!)。開発環境(Mounriver Studio)も悪くないし、すぐにCMake/VSCodeに移行したいとは思わなかった。でも、ピンの計画ツールが必要だね。データシートを使って正しいピン機能や相互排除を見つけるのは本当に面倒だよ…。STM32はSTM32CubeIDEツールでこれをうまくやってるね。機能(USART1みたいな)を選ぶと、正しいピンが光るんだ。代替ピンも簡単に見つけられるし。彼らはOpenWCHのライセンスの問題も整理すべきだね(彼らのGitHubページ)。多く(全部?)のHALはオープンソースだけど、正しいバージョンとSPDXタグがついてるのはしばしばちょっと隠れてるんだ。

このボードでDCモーターの極性(方向)を変えられるの?

「俺のかっこいいPCBデザイン見て!」って言われて、回路図がないとイライラする。

コード生成なしのピンプランナーなら、ウェブサイトとして作れると思う。RP2350用に基本的なものを作ったよ。https://rp2350b.pinout.xyz/ STM32Cubeはアプローチが全然違って、相互排他的な機能や周辺機器をたくさん扱ってるし、コード生成の制御用の余分なものもいろいろあると思う。

最近のMounRiverのリリースは、明らかにVSCodeのシリアルナンバーを消しただけって感じだね。古いのはEclipseのシリアルナンバーを消したやつだった。

ピンマッピングの壁はちょっと嫌だったな。でも、Zephyr RTOSプロジェクトの進捗を追ってるけど、全体的にどんどんサポートが良くなってきてるよ。

SoXに組み込まれてる2400bps(1秒あたり300バイト)のLPC10コーデックについて触れておく価値があるかも。SoXがインストールされてるなら、rec -t lpc10 speech.lpcを試して、マイクに向かって10秒か15秒話してから^Cで止めてみて。それからplay speech.lpcで再生すると、すごくロボットっぽいけど、少なくとも英語の大人の男性の声だとかなり理解できるよ。300バイト/秒で12KiBのデータは41秒の録音音声になる。CH32V003でLPC10データをデコードするのはちょっと難しいかも。amd64でmake CFLAGS=-Osを実行してから、ld -r -o tmp.o *.oをsox-14.4.2+git20190427/lpc10内でやると、25243バイトのテキスト(.rodataなどを含む)と356バイトのデータを持つtmp.oができる。RISC-Vがそれを圧縮してCH32のフラッシュに収めるのは難しいと思う。あのディレクトリのコードは理解しにくいし、CにコンパイルされたFortranだしね。それでも、LPC10データをTalkieが理解できる形式に加工するのは可能かもしれない。

NESで使われてる1ビットDPCMコーデックの方がもっと簡単だよ。次のビットに応じて、サンプルごとに1ステップ上がったり下がったりするだけ。正弦波は出せないけど、三角波なら出せるし、懐かしい感じがする。

NESのDPCMは最大33kHzで動作するから、実際にはこの記事で使われている2ビット8kHzエンコーディングのビットレートの2倍なんだよね。16kHzで動かすとビットレートは合うけど、音質はかなり悪くなるよ。

それって、デジタルパルス信号(「正方形波」)に接続されたインテグレーターってことだよね? 例えば、これみたいなやつ?「https://tinyurl.com/28tcwwqc」