N.Yamazaki's blog

主に音声合成について思ったことを書いてみようと思います。
ESP32で音声合成(AquesTalk pico for ESP32)

keywords: 音声合成 AquesTalk ESP32  I2S 
 

概要


 

AquesTalk pico for ESP32 (以下、AquesTalk-ESP)は、ESP32向けの音声合成ライブラリです。
これを使って、ESP-WROOM-32の内臓のDA(I2S経由)から合成音声を出力します。
アンプ・スピーカーを内蔵しているM5Stackなら、ソフトだけで簡単に音声合成できます。

 

 

 

AquesTalk pico for ESP32 (AquesTalk-ESP)の入手


 

アクエストのサイトからダウンロードできます。

 

・アクエスト > ダウンロード
   https://www.a-quest.com/download.html

 

ダウンロードしたZIPの中身は、ヘッダファイル aquestalk.h、ライブラリ libaquestalk.a、あとはドキュメントファイルです。
なお、ここでいうライブラリとはコンパイルしたオブジェクトを指し、ArduinoIDEのライブラリ(ソースコード等から構成されるもの)ではありません。また、AquesTalk-ESPは有償ソフトウェアであり、評価版ではナ行とマ行がすべてヌと発声される制限があります。

 

 

ビルド準備  ArduinoIDEの場合


 

ArduinoIDEによる開発環境上に、AquesTalk-ESPをインストールする手順を以下に示します。ArduinoIDEや、ArduinoIDEでESP32をビルドするための「Arduino core for the ESP32」はすでにインストールされているものとします。

 

1.  次の場所にライブラリとヘッダをコピーします。

{PATH_Arduino_ESP32}¥tools¥sdk¥lib¥libaquestalk.a
{PATH_Arduino_ESP32}¥tools¥sdk¥include¥aquestalk¥aquestalk.h

ここで、{PATH_Arduino_ESP32}は、「Arduino core for the ESP32」をインストールした場所です。 私の環境では次のとおりでした。

C:¥Program Files (x86)¥arduino¥hardware¥espressif¥esp32

aquestalk¥aquestalk.hのaquestalkフォルダは作成してください。

 

2.  次の場所にplatform.local.txtを作成します。同じ場所にplatform.txtがあるはずです。

{PATH_Arduino_ESP32}¥platform.local.txt

platform.local.txtには、以下を記述します。これは、コンパイル時のインクルードパスにaquestalkを追加し、リンク時にlibaquestalk.aを加える指定です。

compiler.c.extra_flags="-I{compiler.sdk.path}/include/aquestalk"
compiler.cpp.extra_flags="-I{compiler.sdk.path}/include/aquestalk"
compiler.c.elf.libs=-lgcc -lopenssl -lbtdm_app -lfatfs -lwps -lcoexist -lwear_levelling -lhal -lnewlib -ldriver -lbootloader_support -lpp -lsmartconfig -ljsmn -lwpa -lethernet -lphy -lapp_trace -lconsole -lulp -lwpa_supplicant -lfreertos -lbt -lmicro-ecc -lcxx -lxtensa-debug-module -lmdns -lvfs -lsoc -lcore -lsdmmc -lcoap -ltcpip_adapter -lc_nano -lrtc -lspi_flash -lwpa2 -lesp32 -lapp_update -lnghttp -lspiffs -lespnow -lnvs_flash -lesp_adc_cal -llog -lexpat -lm -lc -lheap -lmbedtls -llwip -lnet80211 -lpthread -ljson  -lstdc++ -laquestalk

compiler.c.elf.libsの部分は、Arduino core for the ESP32のバージョンによって異なるかもしれません。platform.txtからcompiler.c.elf.libsの部分をコピペして、最後に -laquestalk を加えます。

以上で準備は終わりです。

 


ビルド準備   ESP-IDFの場合


 

ESP-IDFの場合は、ArduinoIDEの場合とは異なり、アプリのプロジェクトの中にAquesTalkのライブラリとヘッダをコピーします。

具体的には次のようにプロジェクトのファイルを構成します(ここではプロジェクト名をhello_aquestalkとしています。~はmingw32ターミナル上でのホームディレクトリ)。


[ダウンロード hello_aquestalk.zip]

~/esp/hello_aquestalk/
    Makefile
    main/
        main.c
        aquestalk.h
        libaquestalk.a
        component.mk

なお、私のWindows上では以下のディレクトリになりました。

C:¥msys32¥home¥{USER_NAME}¥esp¥hello_aquestalk

MakefileはESP32-IDFの通常のままで、AquesTalkを使う上で特別な部分はありません。次の2行を記述します。

PROJECT_NAME := hello_aquestalk
include $(IDF_PATH)/make/project.mk

 

mainディレクトリを作成し、そのなかに、main.c, aquestalk.h,libaquestalk.a,component.mkを配置します。

component.mkには以下の記述を追加します。これは、リンク時にlibaquestalk.aを追加する指定です。この指定を忘れると、make時にAquesTalkの関数が未定義とのエラーになります。

COMPONENT_ADD_LDFLAGS += $(COMPONENT_PATH)/libaquestalk.a

以上で準備は終わりです。

 

 

サンプルコード


 

サンプルプログラムは、3つのメッセージを連続して音声出力するものです。
ArduinoIDEとESP-IDFの2つ用意していますが、ソースコードはほとんど同じです。
上のビルド準備が整っていれば、ArduinoIDEでは [マイコンボードに書き込む]、ESP-IDFでは 
$ make flash monitor で、GPIO25かGPIO26端子から音声信号が出力されるはずです。

 

・サンプルコードのダウンロード
    helllo_aquestalk(ArduinoIDE用)
    helllo_aquestalk(ESP-IDF用)

 


コード説明


 

以下はサンプルコードの抜粋です。
 

5|   #define LEN_FRAME 32
6|   uint32_t workbuf[AQ_SIZE_WORKBUF];
...
8|   void setup() {
...
12|   	Serial.println("Initialize AquesTalk");
13|   	iret = CAqTkPicoF_Init(workbuf, LEN_FRAME, "XXX-XXX-XXX");
...
17|   
18|   	DAC_Create();
...
21|   	Play("konnnichiwa.");
...
26|   	DAC_Release();
...
28|   }
...
34|   void Play(const char *koe)
35|   {
...
39|   	int iret = CAqTkPicoF_SetKoe((const uint8_t*)koe, 100, 0xffffU);
...
42|   	for(;;){
43|   		int16_t wav[LEN_FRAME];
44|   		uint16_t len;
45|   		iret = CAqTkPicoF_SyntheFrame(wav, &len);
46|   		if(iret) break; // EOD
47|   		
48|   		DAC_Write((int)len, wav);
49|   	}
50|   }
...
53|   //i2s configuration 
54|   const int i2s_num = 0; // i2s port number
55|   i2s_config_t i2s_config = {
56|   		 .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
57|   		 .sample_rate = 24000,
...
65|   };
66|   
67|   void DAC_Create()
68|   {
69|   	AqResample_Reset();
70|   
71|   	i2s_driver_install((i2s_port_t)i2s_num, &i2s_config, 0, NULL);
72|   	i2s_set_pin((i2s_port_t)i2s_num, NULL);
73|   }
...
81|   int DAC_Write(int len, int16_t *wav)
82|   {
83|   	int i;
84|   	for(i=0;i<len;i++){
85|   		// upsampling x3
86|   		int16_t wav3[3];
87|   		AqResample_Conv(wav[i], wav3);
88|   
89|   		// write to I2S DMA buffer
90|   		for(int k=0;k<3; k++){
91|   			uint16_t sample[2];
92|   			uint16_t us = ((uint16_t)wav3[k])^0x8000U;	// signed -> unsigned data 内蔵DA Only
93|   			sample[0]=sample[1]=us; // mono -> stereo
94|   			int iret = i2s_push_sample((i2s_port_t)i2s_num, (const char *)sample, 100);
95|   			if(iret<0) return iret; // -1:ESP_FAIL
96|   			if(iret==0) break;	//	0:TIMEOUT
97|   		}
98|   	}
...

 

CAqTkPicoF_Init()でAquesTalkを初期化します(13行目)。
引数にはワークバッファ、フレーム長、ライセンスキーを指定します。
ワークバッファは、AquesTalkが内部処理で使うメモリで、サイズが AQ_SIZE_WORKBUF の uint32_t 配列を指定します。AQ_SIZE_WORKBUF は aquestalk.h 内で定義されています。ワークバッファは音声合成処理を行っている時に必要で、一連の処理後は解放できます。これによりRAMを効率よく利用できます。

AquesTalkは、非同期処理にも対応できるように分割して音声を生成します。フレーム長とは、このときに一回に生成する音声波形の長さ(サンプル数)で、初期化時に指定します。指定可能な値の範囲は30-300で、ここでは32を指定しています。
最後の引数にはライセンスキーを指定し、評価版として使用するときはNULLを指定します。

 

AqTkPicoF_SetKoe()で、発声するメッセージ(音声記号列)を指定します(39行目)。
第2引数は発話速度でデフォルトが100。値を大きくするほど早い発声になります。
第3引数は最後の無音区間の長さです。通常デフォルトの0xFFFFUを指定すれば良いでしょう。

 

CAqTkPicoF_SyntheFrame()で、1フレームの音声データを取得します(45行目)。
サンプリング周波数が8KHzで、フレーム長に32サンプルを指定したので、32/8KHz=4ms毎に音声を生成することになります。戻り値が0以外なるまでこの関数を複数回呼び出します。
第1引数には16bit/PCM/モノラルの音声データが返されます。
第2引数は生成したデータのサンプル数が返ります。通常はフレーム長に等しく、最後のフレームだけフレーム長より小さくなることがあります。

 

DAC_Create()で、I2Sの初期化をします(67行目)。この中で、I2S経由で内蔵DACから出力する設定を指定しています。
AquesTalk picoの出力音声データは8KHzのサンプリング周波数ですが、AquesTalk-ESP32ライブラリには、これを3倍にアップサンプリングするサンプリング周波数変換関数(AqResample)が含まれています。
アップサンプリングにより、ローパスフィルタが使われていないオーディオ系に出力するときに、チロチロとした折り返し雑音を抑制することができます。もし、DA出力側にfc4KHz程度のLPFを入れられるのならば、アップサンプリングをせず8KHzのまま出力したほうがCPU負荷は少なくなります。

 

AqResample_Reset()は、アップサンプリング処理の初期化関数です(69行目)。
また、アップサンプリングに伴い、i2s_driver_install()で指定するconfigurationのサンプリング周波数には8KHzでなく24KHzを指定しています(57行目)。

 

DAC_Write()で、1フレーム(32サンプル)の音声をI2Sに出力しています(81行目)。
AqResample_Conv()のアップサンプリング処理により、1サンプルのデータが3サンプルに変換されます。これを1サンプルづつi2s_push_sample()でI2Sのバッファに出力します。

 

 

I2Sには符号無しデータを与える?!(内蔵DACの例外)



本来、I2Sのデータは符号付きです。16bitデータの場合、値は-32768〜32767の範囲で、センターの値は0となります。ところが、内臓DAの場合は、0-65535(下位8bitは無視)の範囲で、センターの値は32768にする必要があります。サンプルコードではこの変換を行っていますが(92行目)、外部接続のI2C-DACを使うときは、この変換をしてはNGです。

 


外付けDACを使うには


 

内蔵DACを使うと、I2Sの初期化時と、音声出力の最初にポップノイズが発生しています。原因の予想はついていますが、これについてはもう少しちゃんと調べてから書こうと思います。
コードを少し変更することで、ESP32の内蔵DACの代わりにPCM5102A搭載などの外付けI2S-DACを用いることもできます。
変更点は、

  • i2s_config.modeでI2S_MODE_DAC_BUILT_INフラグを外す
  • i2s_set_pin()で使用するピンの設定を行なう
  • 符号無しデータに変換している処理(92行目)をしない。

 

実際にRaspberry Pi用のPCM5102A搭載32bit 384kHz DAC完成基板を用いて動かしてみました。ただ、DACの設定がI2Sモードでは動かず、left justifiedにする必要があり、ちょっとモヤモヤしています。

 

 

ライセンスキーの入手



AquesTalk-ESPの評価版はナ行とマ行がすべてヌと発声される制限があります。ライセンスキーを購入することでこの制限が解除されます。

ライセンスキーの入手は、アクエストOnline Storeで「AquesTalk pico for ESP32 使用ライセンス」を購入します。このとき備考欄に使用するESP32モジュールのMACアドレスを記載する必要があります。その後に郵送されるライセンス証にライセンスキーが記載されており、このライセンスキーをCAqTkPicoF_Init()に指定します。

MACアドレスが不明の場合は、次のスケッチを実行します。

 

・アクエストOnline Store「AquesTalk pico for ESP32 使用ライセンス

 

[GetMAC.ino]

// Get default MAC Address
void setup() {
  Serial.begin(115200);
  uint8_t mac[6];
  esp_efuse_mac_get_default(mac);
  Serial.printf("¥nMAC Address = %02X:%02X:%02X:%02X:%02X:%02X¥r¥n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
void loop() {
}  

 

最後に


 

AquesTalk picoは、Flash(ROM)28KB、RAM:500B という極めて小さなリソースなので、他の処理に大きな負担をかけずに音声合成できます。アラートなどアプリのちょっとした部分に使用することもできると思います。
今回のコードは音声出力している間は他の処理ができない同期処理ですが、コードの書き方で音声出力と同時に表示を行うなど非同期の処理も可能です。この非同期で使う方法は次記事にする予定です。

 

次記事   「AquesTalk-ESPを簡単に使うクラス(プログラム)」

  http://blog-yama.a-quest.com/?eid=970191


リンク


 

・Arduino core for the ESP32 のインストール方法

  https://www.mgo-tec.com/arduino-core-esp32-install


・ESP-IDF ( ESP32 開発環境 ) の使い方

  https://www.mgo-tec.com/esp32-idf-howto-01


・ESP32でI2S+DACを使う

  https://qiita.com/h_nari/items/b52c525f0c5b35aaf692


・ESP-IDF Programming Guide - Build System
      http://esp-idf.readthedocs.io/en/latest/api-guides/build-system.html
 

| AquesTalk | 19:11 | - | - |
サンプリング周波数変換(リサンプリング)技術 - 応用編

keyword: サンプリング周波数変換、リサンプリング、サンプリングレート変換、アルゴリズム・方況

 

前記事(基本編)では、sinc関数を使ったサンプリング周波数の変換方法を紹介しました。
ただ、sinc関数は無限長(時間軸上で-∞から∞までの長さ)のため、そのままでは実装できません。今回は、これを有限長にする時のいくつかのテクニックを紹介します。


 

■sinc関数に窓関数をかけて有限長にする


sinc関数は、xが大きくなるにつれて次第に振幅が小さくなる関数なので、まずは適当な長さで打ち切った場合を考えてみます。

 

図1は打ち切る長さ(LW)を128、32、8と変えたときの周波数特性です。

長さを短くするほど、sinc関数の本来の周波数特性(理想のLPF)からずれていきます。遷移域(通過域から阻止域に向かう途中の徐々に減衰する部分)は短くするほど広くなり、阻止域の大きさは、短くするほど大きくなっているのがわかります。

 

図1 打ち切り長さによるsinc関数の特性の変化

 

阻止域の大きさ(サイドローブのゲイン)が大きいと、アップサンプリングの場合はナイキスト周波数で折り返した位置にエイリアシング(折り返し雑音)が現れます。ダウンサンプリングの場合は阻止域にあった信号が変換後に帯域内にエイリアシングとして出現します。これらのエイリアシングを少なくするためには、阻止域のゲインを小さくする必要があります。

 

遷移域の幅が大きいとナイキスト周波数付近の信号成分によるエイリアシングが現れます。通常、これは阻止域のより大きなエイリアシングが現れるので注意が必要です。このエイリアシングを少なくするためには、遷移域の幅を狭くする必要があります。

 

リサンプリング処理は上記2つのポイントを考慮して設計します。この2つを同時に満たすには窓長を長くします。ほかに方法はありません。しかし、窓長を長くすると、処理量の増加、遅延、プリエコーという問題が生じます。これについては後述します。

 

ところで、固定の長さでsinc関数を打ち切るというのは、sinc関数に矩形の窓関数をかけることと等価です。

矩形窓の代わりにブラックマン窓をかけた場合は図2のようになります。矩形窓と比べると、阻止域のゲインがより小さく、遷移域の幅はより広くなっていることが分かります。

このように窓関数によって特性のバランスを変えることができます。

 


図2. ブラックマン窓をかけた場合

 


■窓関数の選び方


世の中には多種の窓関数があります。Wikiの窓関数の説明では20種類以上の窓関数が示されています。なぜこんなにたくさんの種類があるのでしょうか。


窓関数には、阻止域のゲインは大きいけれど遷移幅は狭い、あるいは、阻止域のゲインは小さいけど遷移幅は広いなどがあり、いずれの窓関数もそれぞれ一長一短で、また、その周波数特性のカーブも微妙に異なります。
そのため、サンプリング周波数変換においては入力信号の特性や変換に要求される精度によって窓関数を選択することがあります。

 

例えば、入力信号に高域(ナイキスト周波数付近)の信号成分が多く重要視される場合は、阻止域が大きくても遷移域が狭いものが望ましく、24bitデータなど全帯域のエイリアシングを少なくする場合はその逆の阻止域のゲインが小さい窓関数を選択します。

 

また、阻止域のゲインも窓関数に応じて傾きが異なるため、これも選択の基準にすることもあります。

 

表1. 代表的な窓関数の遷移域幅と阻止域ゲイン
窓の種類 阻止域の大きさ 遷移域の幅
矩形         -13db 1(これを基準)
Hanning         -32db  2
Hamming         -41db  2
Kaiser         -46db(β=6.3) 2.2

 

 

■fcを下げる


リサンプリング処理は、遮断周波数(fc)をナイキスト周波数としたLPFフィルタリングと考えることができます。
そこで、fcをナイキスト周波数よりわずかに下げて遷移域を全体的に低域側にずらせば、遷移域のエイリアシングを少なくすることができます。


    sinc(x) ⇒ sinc(rx)  r:ナイキスト周波数に対するfcの割合

 

図3. fcを90%にしたときの周波数特性


デメリットは、ナイキスト周波数付近の信号レベルが小さくなります。例えば、fcを90%にした場合、fi48K fc24k*0.9=21.6KHz 21.6KHzの信号ゲインが3db小さくなります。

 

このテクニックは、入力ソースの信号にナイキスト周波数付近の信号成分が小さかったり無視できる場合に有効です。もっとも、この帯域を無視できるのであれば、それ以上高い周波数の折り返し雑音があっても無視してよいのではという考え方もできますが...。

 


■最小位相化


エイリアシングを少なくするには窓長を長くする必要がありますが、窓長を長くすると今度は遅延やプリエコーの問題が生じます。

 

遅延は通信や放送などのリアルタイムの変換が求められるときに問題となります。窓関数の長さをtwとすると、時刻tの変換値を得るには入力のt+tw/2までの値を使います。したがって、理論上tw/2(窓長の半分)の時間の遅延が生じ、窓長が長いほどその影響が大きくなります。

 

プリエコーとは、遅延と同様に、時刻tの変換値は入力のt+tw/2までの値を使うため、未来の信号の影響が先立って現れる現象をいいます。特に無音の後にアタックの強い信号が来るときに目立ちます。これも窓長が長いほど影響が大きくなり、例えば、窓長が4msのリサンプル処理にパルス状の信号を与えた場合、その2ms前から振幅が始まります。

 

この遅延やプリエコーは、"最小位相化"によって(理論上)なくすことができます。
これまで示した窓かけsinc関数は、すべて左右対称の時間波形です。これは線形位相(またはリニア位相)と呼ばれ、フーリエ変換したときの位相がすべて0になります。
これに対して、最小位相は時間波形では時刻0を中心に片側だけの波形となります。これは因果的な応答特性です。これにより時刻tの変換値を過去の入力値だけから求めることができ、遅延やプリエコーが無くなります。

 


図4.線形位相と最小位相化の時間特性


最小位相化は、窓かけsinc関数をケプストラムに変換後、時系列の片側を0で埋め、元の時間領域に戻すことで得られます。最小位相化を行っても周波数の振幅特性は変わりません。変化するのは位相だけです。

 

ちなみに、すべての位相がゼロなのが最小位相ではなく線形位相というのはややこしいですね。最小位相は本来は群遅延が最小という意味です。

 

リサンプリングにおける線形位相と最小位相の特徴をまとめると次のようになります。

 

●ゼロ位相:左右対称
・変換後の位相が変化しない
・遅延やプリエコーがある


●最小位相:片側のみ
・原理的な遅延が無い
・位相が変化する(波形の形が変化する)
・ゼロ位相より窓長を短くできる


SoXは、オプションの指定で最小位相を用いることができます。SoXのサイトには、オプション毎のさまざまな窓長や位相のサンプルが示されています。このなかで、-vsM -vM -vMa オプションが最小位相です。

 


■各種リサンプラーの実際のパラメータ


各リサンプラーで、44.1KHz⇒96KHzにリサンプリングするときのパラメータを調べてみました。

 

表2.各種Resamplerの分析パラメータ例
窓長 窓の種類 fc     処理量(参考値)
FFmpeg 32 Kaiser(beta=9) 1.0 1(これを基準)
SoX  156 Kaiser(beta=14) 0.96 2.6
AqResample  16 一般化ハミング  1.0 0.5

 

測定条件:

  • オプションは指定せずデフォルトでの値、
  • 窓長は入力サンプリング周期を1とした時の長さ、
  • fcはナイキスト周波数に対する比、
  • 処理量はWindows PC (CPU:Intel Haswell) で実データを変換したときの処理時間の実測(FFmpegを1に正規化)

 

処理量については、それぞれSIMDを使うなどの高速化を行っているため、動作環境によって大きく変わります。また、サンプリング周波数比によっても大きく変わり、特にSoXは比が大きい場合、急激に処理量が増える傾向があるようです。あくまでPC環境での目安にしてください。

 

インパルスレスポンスから求めたそれぞれの周波数特性は図5のようになりました(44.1KHz⇒96KHz)。

 

図5. FFmeg/SoX/AqResampleの周波数特性

SoXは遷移域の幅が狭く、ナイキスト周波数以下に収まっています。これによりナイキスト周波数付近のエイリアシングは無く理想LPFに近いことが分かります。阻止域の大きさはFFmpegより大きくなっています。窓長が長いのにこれはちょっと不思議な結果です。スイープ音を変換した場合はエイリアシングの抑制が-100db以上あったので、インパルス応答を用いた測定が適当でないのかもしれません。AqResampleは、窓長が短いため、遷移域の幅が広く、折り返し雑音がかなり目立ちます。FFmpegはその中間の特性です。

 

 

■最後に


ここまで、サンプリング周波数変換の特性について書いてきましたが、最終的なパラメータ等の選定基準は、実際に聴いてみて判断することが大切です。

 

今回3種類のResamplerを取り上げましたが、各々で変換したオーディオデータを実際に聴き比べてほしいと思います。Windows版 AqResampleは組み込み用のため処理量を優先し窓長をぎりぎりまで短くしています。数値上の特性では品質の劣化が激しそうですが、実際に聴取したらどう感じるでしょうか。

 

驚いたことに、高精度な処理でエイリアシングをなくしたものより、エイリアシングが残っているほうが、きらびやかでよりリアルに聞こえるなどという高評価が得られたことがありました。

数値だけを追い求め、人間が知覚できないレベルの品質にこだわったり、それを喧伝することについて、もっと考えるべきだと思います。
 

 

■おまけ - FFmpegの使い方(いろいろなオプション)


FFmpegでサンプリング周波数変換をするときの各種パラメータの指定方法です。

 

●窓長を指定
 filter_sizeに窓長を指定します。

>ffmpeg -i in.wav -af aresample=filter_size=64 -ar 48000 out.wav

 

●カットオフ周波数(fc)の指定
 resample_cutoffにカットオフ周波数を指定します。値は出力側のナイキスト周波数に対する比率です。

 下の例では、fc=48K/2*0.9=21.6KHzとなります。

>ffmpeg -i in.wav -af aresample=resample_cutoff=0.9 -ar 48000 out.wav

 

●Kaiser窓のβパラメータを指定
 kaiser_betaにβ値を指定します(2-16の間)。
 なお、βを変更すると窓長も変化するようです。このあたりの挙動は未確認です。

>ffmpeg -i in.wav -af aresample=kaiser_beta=12 -ar 48000 out.wav

 

●FFmpegでSoXと同等の変換を行うときの指定(44.1KHz->48KHzの場合)
 なお、以下は44.1KHz->48KHzの場合となります。
 fcは出力側のサンプリング周波数に合わせます fc=0.96*44.1/48=0.882
 また、複数のパラメータは':'で区切って指定します

>ffmpeg -i in.wav -af aresample=filter_size=156:resample_cutoff=0.882 -ar 48000 out.wav

 

●FFmpegでSoXのリサンプルエンジン(soxr)を使うときの指定
 resampler=soxr を指定します。

>ffmpeg -i in.wav  -af aresample=resampler=soxr -ar 48000 out.wav

 

 

■LINK


| 音声合成一般 | 15:32 | - | - |
サンプリング周波数変換(リサンプリング)技術 - 基本編

Keyword: サンプリング周波数変換、リサンプリング、サンプリングレート変換、アルゴリズム・方法

 

サンプリング周波数変換とは、オーディオデータなどのデジタル信号を、異なるサンプリング周波数の信号に変換する処理のことです。例えば、CD規格の44.1 kHzのデータをDVDの48kHzへ変換するときに使用します。

 

■原理



ここで、サンプリング周波数 fiからfoへの変換を考えます。fiとfoは単純な整数比である必要はありません。
Wikiでは、fiとfoの最小公倍数を求め、ゼロ値の内挿によるアップサンプリングを行い、LPFを通し、間引きする といった方法が示されています。しかし、以下の方法を使えば任意のサンプリング周波数にダイレクトに(ワンパスで)変換できます。

 

サンプリング周波数 fiからfoへ変換するということは、入力サンプルのfi/foおきに入力サンプルの補間値を求めることといいかえることができます。

 

ここで、
 Xn:入力信号のn番目の値
 Ym:出力信号のm番目の値
 X'(t):入力信号の時刻tの補間値(tは実数)
とすると、

formula

 

ここで、m x fi / foを、整数部(n)と小数部(dn)に分ける。

fomrmula

 

このとき、Ymは次式で求められます

formula

 

ここで、

sinc_func

 

 

upsampling

 

 

downsampling

 

 

■解説



繰り返しになりますが、サンプリング周波数 fiからfoへ変換するということは、入力サンプルのfi/foおきに入力サンプルの補間値を求めることです。

 

ただ、ここでの補間は、見かけの滑らかさとは違うことに注意が必要です。直線補間やスプライン補間などは折り返し雑音(エイリアシング)が酷くて実際には使えません。サンプリング周波数変換では式(1.1)と式(1.2)のようにsinc関数というもので補間します。

sinc関数の周波数特性は矩形特性で、カットオフ周波数がナイキスト周波数(fs/2)で急峻に減衰する理想のLPF特性です。

 

sinc関数の周波数特性

sinc_spec

 

ところで、sinc関数ってとても美しい式だと思いませんか。矩形の周波数特性の応答波形を、こんなシンプルな式で表現できます。しかも、いきなり原点が0で割るという、おちゃめな部分もあります。私がこれまでデジタル信号処理に携わってた中で一番お気に入りの関数です。

 

閑話休題。
式(1.1)と式(1.2)は、FIRデジタルフィルタの畳みこみ演算と似ています。違いはフィルタの係数列が固定ではなく、dnによって出力サンプル点毎に変化(シフト)する点です。これにより、フィルタをかけながら入力サンプル間の途中の値を求めているのです。

 

アップサンプリングとダウンサンプリングで式が異なるのは、sinc関数のカットオフ周波数(fc)を、アップサンプリングの場合は入力側のナイキスト周波数(fi/2)、ダウンサンプリングの場合は出力側のナイキスト周波数(fo/2)に合わせるためです。ダウンサンプリングの場合は、sinc関数がfiとfoの比によって横に伸長されたイメージです。

 

ここで、もうお気づきかもしれませんが、sinc関数は無限長のため、このままでは実装できません。なんらかの方法で有限長にする必要があります。

 

sinc関数はxが大きくなるにつれ振幅が次第に減少していく関数なので、適当な時点で打ち切ればよさそうですが、この部分はもう少しテクニックがあります。次回は応用編として、sinc関数を有限長にする方法について書こうと思います。

 

 

■おまけ(実践)


 

ここにWAVフォーマットのファイル in.wavがあるとします(このサンプリング周波数は任意です)。
これを、各種のコマンドプログラムで、44.1KHzのサンプリング周波数のout.wavに変換してみます。

 

FFmpegの場合
> ffmpeg -i in.wav -ar 44100 -y out.wav

 

SoXの場合
> sox in.wav -D out.wav rate 44100

 

AqResampleの場合
> AqResampleCmd in.wav 44100 out.wav

 

なお、最近のFFmpegはSoXのリサンプリングエンジンlibsoxrを内包しています。
以下のように"-af aresample=resampler=soxr"を指定することでlibsoxrを使用できます。

 

> ffmpeg -i in.wav  -af aresample=resampler=soxr -ar 44100 out.wav

 

基本的に、各プログラムの変換結果の違いは、使用している補間の関数(フィルタ係数)の違いとなります。


■リンク


 

| 音声合成一般 | 11:44 | - | - |
CentOS i386(32bit)でC++11を使う

環境:CentOS 6.9 i386

 

■debtoolsetでGCCのバージョンアップ

CentOSのGCCが4.4.7であり、C++11が使えない。GCCのバージョンアップを行うことにした。
ネットの情報によると、Software Collections のDeveloper Toolset というのをインストールすればよいとのこと。

しかし、その情報の通りに行うと、次のコマンドがエラーになってインストールできない。

# yum install devtoolset-4-gcc

[Errno 14] PYCURL ERROR 22 - "The requested URL returned error: 404 Not Found"

原因は、導入したリポジトリがx86_64用であるため。

 

■i386用のリポジトリ
そこで、見つけたi386用のリポジトリがこちら。
https://copr.fedorainfracloud.org/coprs/hhorak/devtoolset-4-rebuild-bootstrap2/

 

■インストール

# cd /etc/yum.repos.d/
# wget https://copr.fedorainfracloud.org/coprs/mlampe/devtoolset-4.1/repo/epel-6/mlampe-devtoolset-4.1-epel-6.repo
# yum install devtoolset-4-gcc devtoolset-4-binutils devtoolset-4-gcc-c++

 

■環境の切り替え
新しいバージョンのGCCを使うには次のコマンドで変更。

$ scl enable devtoolset-4 'bash'
$ g++ --version

これで、GCC 5.3.1の環境になり、C++11が無事に使えるようになった。

 

ちなみに、

 GCCはC++11 ABIの安定性の保証をバージョン5.1以降でのみ提供しています。

とのこと。

また、devtoolset-7(GCC 7.2)のリポジトリもあるようだ。
https://copr.fedorainfracloud.org/coprs/mlampe/devtoolset-7/repo/epel-6/mlampe-devtoolset-7-epel-6.repo


■参考LINK

「Developer Toolset 4でCentOS6にお手軽にGCC5.2をインストール」

CentOSで新しいGCCなどといった開発ツールを使いたい場合のメモ

CentOS 6でC/C++開発環境を整える

 

| その他 | 19:40 | - | - |
「ゆっくり声」は進化するか?!

■AquesTalk10をリリース

音声合成エンジンAquesTalkのリリースから約10年が経ち、ようやく新バージョン AquesTalk10 を、本日リリースしました。
「ゆっくり声」の音声合成エンジン、AquesTalk/AquesTalk2の後継バージョンです。

 

特徴:
・音声の周波数帯域を2倍にしてクリアな音質に
・音素データをすべて一から作り直り、さらにこれをチューニングをして、明瞭性を向上
・エンドユーザが複数の声質パラメータを操作して、自由に声質を作れる

 

当社サイトのデモページにて、9種のプリセット声種のサンプル音声が聴取できます。
また、評価版パッケージの中に、声質パラメータを自由に操作して音声合成できるサンプルアプリ「AqTk10App」が含まれています(評価版の制限あり)。

 

「 AqTk10App」

AqTk10App

 

■新しい声というジレンマ

AquesTalkの合成音声は、「ゆっくり声」として、長い間、多くのコンテンツに使われ、コンテンツの作者も、それを聴取するユーザーの耳にも、おなじみの声になっています。
これを新しい声に変更すると、サザエさんの声優が交代したときのように、間違いなく違和感が生じるでしょう。
幸い、声優と違って音声合成ソフトは歳をとらないので、ずっと同じ声を使えます。
実際、ゆっくり霊夢でよく使用されるAquesTalk F1は、2006年にリリースしてから11年間、声質は一切変わらないまま、今も使われています。そう考えると声を変えるニーズはそもそもあるのでしょうか。

一方、私としては、少しでも良いもの、進化したもの作り、それを多くの人に使ってもらいたいというエンジニアとしての勝手な欲求があります。

 

今回の新しい音声合成エンジンの開発にあたり、旧エンジンとの継続性を念頭に置きました。
新しい声になっても、これまでの声とできるだけ違和感が無いように、かつ、より良い声にすること。

これで、エンジン変更の壁を少しでも低くして、新しいエンジンを使ってもらおうと考えました。


今回、音声帯域を2倍に拡張しています。これまでの電話を通したような"こもった"音声が、テレビの音声くらいになりました。
音素片データも、すべて一新し、すべての音素にチューニングを施して明瞭性を向上させています。
 

ベースとなる音素片として、実況動画でよく使われる声種のF1E(女声1)、F2E(女声2)と、M1E(男声)の3種類を用意しています。

F1Eは、AquesTalk-F1のバージョンアップ版として、声質をできるだけ維持するように作り込みました。
音声合成の方式が異なるため、新規に作るより既存の声質に合わせるのは手間がかかる作業でしたが、違和感なくAquesTalk-F1から乗り換えられると自信を持っています。

F2Eは、AquesTalk-F2のバージョンアップ版としては少し声質が異なっています。
実況動画の「ゆっくり霊夢」と「ゆっくり魔理沙」の掛け合いを見ていると、2つの声質が似通っていて混同しやすいと感じていたため、F2EはF1Eとの違いを明確にしました。そのため、F2のバージョンアップ版としては、違和感があると思います。
うーむ。旧エンジンとの継続性が損なわれていますね。これで良かったのか・・・。
 

■実況動画で使われるか?

この新しい音声合成エンジンが実況動画で使われるようになるでしょうか。
あっという間に新しいエンジンに置き換えられることはありえませんが、完全スルーで今後も旧エンジンが使われ続けるるのは悲しいですね。
普及するかは正直わかりませんが、ゆっくり時間をかけて、少しずつこの新しいエンジンの声が使われていくことを願っています。
あと、AquesTalk10にはユーザが様々な声種を作れる機能があるので、過去にこだわらない新しい定番の声種が生まれるかもしれない。そんな期待もあります。

 

いずれにせよ、多くのユーザに使ってもらうには、まずは「SofTalk」「棒読みちゃん」「YukkuriMovieMaker」「ゆっくろいど」などの定番アプリケーションに採用してもらう必要がありますね。
 

 

「ゆっくり、つかっていってね!!!」

 

■Links

| AquesTalk | 17:38 | - | - |
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