N.Yamazaki's blog

主に音声合成について思ったことを書いてみようと思います。
<< ESP32でサウンド出力時のクリックノイズ対策(I2S+内蔵DAC) | main | ESP32のPDMでサウンド出力+ノイズ対策 >>
AquesTalk-ESPを簡単に使うクラス(プログラム)

keywords: ESP32, 音声合成, マルチタスク, M5Stack
 

■概要


 

前記事では、ESP32用の音声合成ライブラリ AquesTalk pico for ESP32(AquesTalk-ESP)を紹介しました。
今回は、これを用いてバックグラウンドで内蔵DACから音声を出力するプログラム "AquesTalkTTS" を紹介します。

 

このAquesTalkTTSは、AquesTalk-ESPで音声を生成してI2S経由で内蔵DACから出力するまでを一つにまとめたC++のクラスです。初期化と発声の最短2ステップで簡単に音声合成できます。

 

当初はAquesTalk-ESPを非同期処理で使うテクニックを書こうと思っていたのですが、
そもそもESP32はFreeRTOS上で動いているので、素直にこのマルチタスク機能を使います。


 

 


■サンプルプログラム


 

M5Stackで動作します。

 

機能:

  • 時刻を表示
  • 左ボタン:年月日を読み上げ
  • 中ボタン:時分秒を読み上げ
  • 右ボタン:発声を中止

 ※ 読み上げ中も、時刻表示は毎秒変化します。
   ※ 発声中に別のボタンを押すと、即座に発声が切り替わります。

 

ダウンロード

 サンプルプログラム「M5_TalkingClock.zip」(AquesTalkTTSのソースコードも入っています)

 

 

■コード説明



サンプルプログラムをもとに、AquesTalkTTSクラスの使い方を示します。

 

M5_TalkingClock.ino(抜粋)

14 void setup()
15 {
・・・
21   iret = TTS.create(licencekey);
・・・
30 }
31 
32 void loop()
33 {
・・・
38   if(M5.BtnA.wasPressed()){
39     if(getLocalTime(&timeinfo)){
40       // 年月日の読み上げ
41       sprintf(koe,"<NUMK VAL=%d COUNTER=nenn>/<NUMK VAL=%d COUNTER=gatu>/<NUMK VAL=%d COUNTER=nichi>.",
42         timeinfo.tm_year+1900,timeinfo.tm_mon+1, timeinfo.tm_mday);
43       iret = TTS.play(koe, 100);
・・・
60   else if(M5.BtnC.wasPressed()){
61     TTS.stop();
62   }
63 
64   M5.update();
65 }

setup()の中で、AquesTalkTTSを初期化します(21行目)

 

loop()の中で、左ボタンが押されたら(38行目)、時間を取得し、数値読みタグで年月日の音声記号列を生成します(41行目)。あとは、TTS.play()を呼び出すだけです(43行目)。これで年月日が読み上げられます。音声出力はバックグラウンドで処理するので、TTS.play()はすぐに戻ります。

 

右ボタンが押されたら(49行目)、TTS.stop()を呼び出します。これで発声が停止します。発声中以外は特に何も起こりません。


※ あらかじめArduinoIDE上にAquesTalk-ESPをインストールしておく必要があります。
    インストール方法は、前記事の「ビルド準備 - ArduinoIDEの場合」の項を参照ください。
※ ライセンスキーが未指定の場合は、「ゆっくりしていってぬ」になります。

 


■AquesTalkTTSクラス(AquesTalkTTS.cpp/.h)の動作


 

AquesTalk-ESPとI2S経由で内蔵DACから音声出力するまでを1つのクラスにしています。
メソッドは create(), play(), stop(), release() の4つだけです。
create()で初期化、play()で音声合成開始、stopで発声停止、release()でメモリ解放します。

 

create()

AquesTalk-ESPの初期化を行っています。ワークバッファしてヒープ上に400byte確保されます。I2Sの初期化は行っていません。

 

play():

引数の音声記号列をAquesTalk-ESPにセットしてから、音声出力用のタスク(task_TTS_synthe())を起動します。

 

task_TTS_synthe():  (内部のタスク関数)

I2Sの初期化(DMAバッファが確保される)後、フレーム単位での音声合成を行いI2Sへ書き込みます。
最後のフレームまで生成したら、I2Sを解放します。
I2Sと内蔵DACは発声中だけ使用しますので、それ以外のときにビープなど他の音を出力することもできます。

 

stop():

不正な音声記号("#")を指定して、わざとAquesTalk-ESPがエラーで終了するようにしています。

 

※ 発声中にplay()を行うと、発声中のメッセージはその場で終了し、新たに指定したメッセージが始まります。
※ ArduinoIDE環境で動作確認しましたが、ESP-IDFでも動くと思います。
※ クリックノイズ対策済みです。

 

 

■リンク



「ESP32で音声合成(AquesTalk pico for ESP32)」
http://blog-yama.a-quest.com/?eid=970188

 

「ESP32でサウンド出力時のクリックノイズ対策(I2S+内蔵DAC)」
http://blog-yama.a-quest.com/?eid=970190

 

| AquesTalk | 22:10 | - | - |
PROFILE
Follow
CATEGORIES
LATEST ENTRIES
SEARCH THIS SITE
RECOMMEND
RECOMMEND
RECOMMEND
RECOMMEND
RECOMMEND
RECOMMEND
RECOMMEND
SONY MDR-CD900ST
SONY MDR-CD900ST (JUGEMレビュー »)

普段これで開発しています。
RECOMMEND
RECOMMEND
RECOMMEND
RECOMMEND