ラテン語文を合成音声で読み上げる技術

こんにちは。@naoya_t です。

12/2の拙記事「[ラテン語文解析プログラムを書くことを目的としたラテン語学習（前編）](http://qiita.com/naoya_t/items/438dbad5398d54c57f0f)」で紹介した拙作解析ツール
https://github.com/naoyat/latin
では、MacOSXに搭載されている英文音声合成技術を利用して、ラテン語文を音読することが可能です。

この記事では、その辺りの事について語ってみたいと思います。

実装については [speak_latin.py](https://github.com/naoyat/latin/blob/master/speak_latin.py), [latin/latin_syllable.py](https://github.com/naoyat/latin/blob/master/latin/latin_syllable.py) あたりをご覧ください。

## デモ

```
$ echo "Cerēs erat dea frūmentī." | python latin.py -s
```

`-s` (--speech) が音読をONにするオプションです。

マクロン（長音記号）の入力が面倒なら、大文字を長音と認識させる `-m` (--capital-to-macron) オプションを使って

```
$ echo "vEnI, vIdI, vIcI." | python latin.py -m -s
```

のようにも使えます。

## 音声合成と発音

MacOSX の音声合成機能（text-to-speech）は今では英語以外の多くの言語での発話に対応していますが、細かい制御に対応しているのが（とりあえず手元のOS X 10.7.xでは）英語だけなので、発話したい内容を（北米）英語の発音記号に落としこむ必要があります。それぞれの音の高さ（周波数）や長さも設定する必要があります。

詳しくはApple社が公開している開発資料 https://developer.apple.com/library/mac/documentation/userexperience/conceptual/SpeechSynthesisProgrammingGuide/SpeechOverview/SpeechOverview.html#//apple_ref/doc/uid/TP40004365-CH3-SW6 辺りをご覧ください。

## 音素と長さ

ラテン語のアルファベットを、対応する音素の発音記号に置き換えます。

> 例："Crētā" → `k` `r` `EH` `t` `AA`

`EH` や `AA` は（`k`, `r`, `t` もそうですが）text-to-speech内部で用いられる音素表現です。

北米英語で用いられる音素に対応したものしか存在しないので、これを並べると何を喋っても北米訛りになる、という弱点が存在しますが、その点には目を瞑って頂ければ幸いです。

ちなみに母音の長短は（英語側で対応する短母音／長母音ではなく）音の長さで表しています。
（speak_latin.py の実装では、子音と短母音の長さを110msec、長母音の長さを220msecにしています。上の例では `k`, `r`, `t` が110msec、`EH`, `AA` が220msecです）

## 周波数（ピッチ）

ラテン語は高低アクセントなので、アクセントはとりあえず周波数の高低で表現することができます。

とりあえず、というのは、音声学的にどうこうというのはさておき、それっぽく聞こえるという精度を念頭においています。

## アクセントはどこに来るのか

ラテン語では2音節語は最初の音節（＝「paenultima 後ろから2番目の(音節)」）に、3音節語はpaenultimaの長短によって最初の音節ないし2番目の音節にアクセントが来ますので、アクセントが来る音節の周波数を他よりも高めに発声させます。

> 例: "Crētā" → C-rē-tā → C-[rē]-tā

speak_latin.py の実装では、低い方を135Hz（CとC#の間ぐらい？）、高い方をその4/3倍（低い音の4度上に相当）にしています。

音節の区切り方自体は概ね規則通りなので規則を実装します。(latin/latin_syllable.py)

- lūx → lūx
- caesar → cae-sar → [cae]-sar
- cōnsulēs → cōn-su-lēs → [cōn]-su-lēs
 
## 発音制御コマンド列の生成

ここまで来ればラテン語の文を、（北米英語の）音素・長さ・ピッチ（周波数）の列に分解することができるので、text-to-speechの"TUNEフォーマット"（https://developer.apple.com/library/mac/documentation/userexperience/conceptual/SpeechSynthesisProgrammingGuide/FineTuning/FineTuning.html#//apple_ref/doc/uid/TP40004365-CH5-SW7 参照）で表現し、APIを叩くなり say コマンドに

```
[[inpt TUNE]] 発音制御コマンド列 [[inpt TEXT]]
```

のように投げるなりすれば発話が可能です。

> 例："Crētā"

```
  k {D 110; P 135:0}
  r {D 110; P 180:0}
  EH {D 220; P 180:0}
  ~t {D 110; P 135:0}
  AA {D 220; P 135:0}
  % {D 110}
```

`~` は前後の音素を一続きに読まないための記号で、`%` は無音を表します。

## 発音制御コマンド列の例

元のラテン語文：

```
In Crētā īnsulā māgnum labyrinthum Daedalus aedificāvit plēnum viārum flexuōsārum.
```

発音制御コマンド列：

```tune.txt
[[inpt TUNE]]
   IY {D 110; P 135:0}
   n {D 110; P 135:0}
   % {D 110}

   k {D 110; P 135:0}
   r {D 110; P 180:0}
   EH {D 220; P 180:0}
   ~t {D 110; P 135:0}
   AA {D 220; P 135:0}
   % {D 110}

   IY {D 220; P 180:0}
   n {D 110; P 180:0}
   s {D 110; P 135:0}
   UW {D 110; P 135:0}
   l {D 110; P 135:0}
   AA {D 220; P 135:0}
   % {D 110}

   m {D 110; P 180:0}
   AA {D 220; P 180:0}
   g {D 110; P 180:0}
   n {D 110; P 135:0}
   UW {D 110; P 135:0}
   m {D 110; P 135:0}
   % {D 110}

   l {D 110; P 135:0}
   AA {D 110; P 135:0}
   b {D 110; P 135:0}
   yUW {D 110; P 135:0}
   r {D 110; P 180:0}
   IY {D 110; P 180:0}
   n {D 110; P 180:0}
   ~t {D 110; P 135:0}
   h {D 110; P 135:0}
   UW {D 110; P 135:0}
   m {D 110; P 135:0}
   % {D 110}

   d {D 110; P 180:0}
   AA {D 110; P 180:0}
   EH {D 110; P 180:0}
   d {D 110; P 135:0}
   AA {D 110; P 135:0}
   l {D 110; P 135:0}
   UW {D 110; P 135:0}
   s {D 110; P 135:0}
   % {D 110}

   AA {D 110; P 135:0}
   EH {D 110; P 135:0}
   d {D 110; P 135:0}
   IY {D 110; P 135:0}
   f {D 110; P 135:0}
   IY {D 110; P 135:0}
   k {D 110; P 180:0}
   AA {D 220; P 180:0}
   w {D 110; P 135:0}
   IY {D 110; P 135:0}
   ~t {D 110; P 135:0}
   % {D 110}

   p {D 110; P 180:0}
   l {D 110; P 180:0}
   EH {D 220; P 180:0}
   n {D 110; P 135:0}
   UW {D 110; P 135:0}
   m {D 110; P 135:0}
   % {D 110}

   w {D 110; P 180:0}
   IY {D 110; P 180:0}
   AA {D 220; P 180:0}
   r {D 110; P 135:0}
   UW {D 110; P 135:0}
   m {D 110; P 135:0}
   % {D 110}

   f {D 110; P 135:0}
   l {D 110; P 135:0}
   EH {D 110; P 135:0}
   ks {D 220; P 135:0}
   UW {D 110; P 135:0}
   OW {D 220; P 135:0}
   s {D 110; P 180:0}
   AA {D 220; P 180:0}
   r {D 110; P 135:0}
   UW {D 110; P 135:0}
   m {D 110; P 135:0}
   ~ {D 110; P 135:0}
   % {D 110}
[[inpt TEXT]]
```

## 結果

```
$ say < tune.txt
```

<audio src="http://www1419ue.sakura.ne.jp/tune.mp3" preload="none" controls>→ http://www1419ue.sakura.ne.jp/tune.mp3</audio> 

## 終わりに

12/25までまだまだ枠に空きがあるので、多分また何か書きます！