身近な声から音声合成コーパス作成の簡略化への挑戦

2015 年度 卒業論文
身近な声から音声合成 コーパス作成の簡略化への挑戦
2016 年 2 月 22 日
08110007
上原 佳一
指導教員 木村 広 准教授
九州工業大学 工学部 マテリアル工学科
概要
話者の母音と「ん」を別の話者の子音と組み合わせてももとの話者の特徴は残る/ 母音 子音 - 母音のつながりから子音を切り出し使えば高品質な合成音声を出力できる/ 話者の
ひとつの有声音から母音と「ん」を合成できる/ の 3 つの仮説をもとに手軽にコーパス
を作成し、それをもとに日本語を発話する音声合成システム SSSV の開発を試みた。従
来法と比較して圧倒的に簡単に、誰でも作成できるようになり、作成されたコーパスを
自由に選び、それをもとに合成音声を作れるはずであったが、残念ながら本論文では実
用に耐えるシステムを作ることはできなかった。しかし、SSSV にはまだ改良の余地が
あり、今後の研究により実用レベルに達する可能性は十分にある。
目次
第 1 章 はじめに
3
第 2 章 関連研究
5
2.1 音声合成の歴史 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
2.2 UTAU について . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
第 3 章 SSSV
9
3.1 本論文で検証する仮説 . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
3.2 SSSV の概略 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
3.3 SSSV と UTAU との比較 . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
第 4 章 SSSV の実装
13
4.1 開発環境 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
4.2 開発したコード . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
4.3 音節の作成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.4 音量と音程の調整 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.5 音節の連結 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.6 操作性の向上 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
第 5 章 実験と結果
22
5.1 コーパスの作成時間
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
5.2 音と意味の聞きとり
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
5.3 オリジナル話者の推定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
第 6 章 考察
28
第 7 章 まとめ
34
付 録 A Appendix
38
A.1 ソースコード . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
1
2
A.1.1 main.lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
A.1.2 common.lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
A.1.3 waveio.lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
A.1.4 filename.lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
A.1.5 mpm.lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
A.1.6 td-psola.lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
A.1.7 cs-data.lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
A.1.8 concatenate.lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
A.1.9 gentext.lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
A.1.10 gui.lisp
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
A.1.11 gendb.lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3
第1章
はじめに
現在、合成音声はいろいろなところで使われている。例えば電車の車内放送やカーナ
ビの音声案内、iOS の Siri、PC のテキスト読み上げソフト、Vocaloid などがある。
合成音声は、大別して 3 つの方式に分けられる。ひとつは人の声道の様子をまねる調
音合成、もうひとつは人の声のフォルマントをまねるフォルマント合成、そして録音し
た人の声をつなぎ合わせる波形接続型合成であり、現在のコンピュータを使った音声合
成の主流は波形接続型合成である [1]。現在の合成音声は既に聞き取りやすく、十分に高
品質なものと言える。
しかし、基本的にはひとりの話者から大量の音素 (スピーチを構成するための単位、単
語や音節など) を採集してひとつのコーパス (音素を集めたデータベース) をつくり、あ
らゆるテキストをそのコーパスをもとに読み上げるというシステムであるゆえに、採集
した声に基づいてしか発話できないという制限がある。幼稚園での本の読み聞かせも、
PC などのテキスト読み上げも、目覚ましの声も、システムが提供する既存の声しか使え
ない。
ユーザーがコーパスを作ることができる既存の音声合成システムに UTAU1 がある。し
かし、 UTAU で日本語を発話させるためには日本語の音素すべてを含むコーパスを作る
必要があり、これには数時間かかる。
誰の声でも合成音声を簡単に作ることができるシステムがあったらどうだろう?幼稚
園での本の読み聞かせはお母さんの声、PC のテキスト読み上げはお気に入りのアナウ
ンサーの声、目覚ましのおはようが自分の片思いの人になったら楽しい。
筆者は、以下の 3 つの仮説を立てた。
• ある話者の母音「あ、い、う、え、お」と「ん」と別の話者の子音と組み合わせて
ももとの話者の声の特徴を十分に残せる。
• 母音 - 子音 - 母音のつながりから切り出した子音を使えば先の合成音声の品質は上
がる。
1
http://utau2008.web.fc2.com/index.html
4
• 話者のひとつの有声音から「あ, い, う, え, お, ん」を合成できる。
本研究ではこれらの仮説を検証するため SSSV(Speech Synthesis System with Vowel)
の開発を試みた。SSSV が成功すれば私の仮説は立証され、コーパスの作成は UTAU に
比べ圧倒的に簡単になり、誰でも簡単に望みの声で高品質な合成音声を作れるようにな
ると考えた。
しかし、残念ながら卒論の1年という短期間では実用に耐えるシステムをついに作る
ことができなかった。
本論文では、SSSV の概念、実装システムの詳細について、報告する。
5
第2章
2.1
関連研究
音声合成の歴史
音声合成の研究は古くは 1000 年頃からあり、最初の合成音声は 1779 年の Christian
Kratzenstein によるもの [2] で、これは母音を発音することができた。
その後 1791 年には Wolfgang von Kempelen [3] がふいごを使って発音させる機械を
作り、これは子音も発音できた。これらは人の声道の構造をまねて発声させる調音合成
であり、完成すれば他の方法よりも高品質な合成音声が得られると期待されている。
コンピュータを使った最初の音声合成システムは 1953 年に開発された Walter Lawrence
による PAT (Parametric Artificial Talker) である [4]。これは人の声のフォルマントを真
似て発音させるフォルマント合成であった。フォルマントとは、スペクトル包絡にあら
われるピークのことである。(図 2.1) 人は声道を制御することによりフォルマントを変化
させ、フォルマントのちがいを耳で聞き取って母音などを識別する。一般的なフォルマ
ント合成では、多くの倍音を含む音にバンドパスフィルタをかけ実現する。この例では
800Hz あたりにスペクトル包絡の最初のピーク、すなわち第一フォルマントがある。
PAT に続いて Gunner Fant は初の TTS (Text to Speech) システム OVE (Orator Verbis
Electris) を作った。現在では TTS は文字どおり、紙に書かれたテキストを読み上げるこ
とができるようになっており、例えば iPhone アプリの “i よむべえ”2 がある。
最近まで、コンピュータを使った音声合成はフォルマント合成が主であったが、マシ
ンパワーの増大により現在では録音した音声の波形をつなぎ合わせてスピーチを合成す
る波形接続型の合成が主流になっている。これは 1970 年代半ばの Joseph Olive [5] に
はじまる。
波形接続型の合成は、発話に必要なすべての音素をあらかじめコンピュータに準備し
ておき、必要に応じて音素を選択し、組み合わせ、発話させる。音素は、ラジオなどの
スピーチの録音 [6] や、話し方のきれいな人のスタジオ録音 [7] によって採集する。採集
した音素はコーパスとして管理される。高品質な合成音声を追求してきた結果、録音す
2
http://www.amedia.co.jp/product/iYomube/
6
図 2.1: 対数パワースペクトル (灰色) とその包絡線 (赤色)。800Hz あたりにピークがあり、これ
がフォルマントである。
べき音素は膨大な数になり、コーパスも巨大なものとなっている。
近年、この巨大なコーパスを録音された音源から作成しその中から音素を選択するた
めに、HMM (Hidden Markov Model) という統計手法を使った方法も出てきた。この方
法は録音された音源をある長さに分割しコーパスを作るとともに自然な音のつながり方
を学習し、それに基づいてコーパスから音素を選択していく [8]。これは波形接続型音声
合成においてよく使われる方法となっている。
2.2 UTAU について
UTAU はユーザーが録音した声を用いて合成音声をつくることができる波形接続型の
音声合成システムである。UTAU で歌わせたり話させたりするためには、必要な音素を
すべて録音している必要がある。音素の録音の仕方はいくつかあり、音節ごとに録音す
る単独音 (図 2.2)、ふたつの音節にまたがって録音する連続音 (図 2.3) などがある。日本
語を話させるために必要な音素数は単独音なら 1 音階あたり 140 ほど、連続音なら 1 音
階あたり 700 ほどである。録音した音素が正しく発音されるためには、音素の中の子音
の位置と母音の位置を指定する原音設定をする必要がある。原音設定の画面を図 2.4 に
示す。
7
K
A
図 2.2: 単独音の模式図 子音 - 母音の 1 音節からなる “か” の例。子音から母音に変化する中間の
遷移音を収録できる
A
K
A
図 2.3: 連続音の模式図 母音 - 子音 - 母音と 2 音節にまたがる。子音から母音に加え、母音から
子音に変化する中間の遷移音も収録できるが、採集する音素は多くなる
図 2.4: UTAU の原音設定画面 (単独音) 。前音とのクロスフェードの終点 (緑線) と母音発声開始
位置 (赤線) 、合成に使わない範囲 (青背景) と子音部 (赤背景、この範囲は最初に一度だけ再生さ
れる) を指定する
この図のように赤い線を母音のはじまりに、緑の線を前の音との重なりの終わりにな
るように手動で設定しなければならない。自動で原音設定をする setParam というソフ
トもあるが、誤検出もあり、最終的には手動で確認・設定しなければならない。
UTAU の UI を図 2.5 に示す。基本はピアノロールにノートを置いて、それに歌詞を入
れていく。そして音程や音量の時間的変化の設定、さらに子音の発声のタイミングを原
音設定の値からずらしたりフラグにより声質を変化させることもできる。しかし微妙な
音量や音程の変化を制御するだけでも大変な作業であり、その上声質や子音発声のタイ
ミングまで制御して望むとおりに合成音声を出力できる人は多くない。
8
図 2.5: UTAU の UI。ピアノロール (画面中央) にノートを置き、Lyric のテキストボックスに歌詞
を書き、ノートに歌詞を入れる。
9
第3章
3.1
SSSV
本論文で検証する仮説
筆者は音声合成について以下の考えを持っている。
1. 日本語で音節の中心となるのは 5 つの母音「あ, い, う, え, お」と「ん」である。
声の印象は音節の中心となるこれらの音により、その他の音の声の印象への影響は
小さいのではないか。ならば、 5 つの母音と「ん」を録音してもらいすべてのコー
パスで共通して使うシステムが提供する子音と組み合わせても本人の特徴を残せる
はずだ。
2. 母音 - 子音 - 母音のつながりの中から切り出した子音をシステムが提供すれば母音
から子音、子音から母音へつながる中間の遷移音を合成音声に反映でき、UTAU の
連続音と同等の品質を期待できる。
3. ケプストラム分析によりひとつの有声音から声帯振動とフォルマントを分離し、声
帯振動に「あ, い, う, え, お, ん」のフォルマントをかければひとつの音から音節の
中心となるすべての音を作ることができ、日本語を発話できる可能性がある。
本論文でこの筆者の仮説を立証したいと強く考えた。
そのため、仮説を表現したシステムを私の得意なプログラミングで実装し、そのシス
テムの挙動を客観的に評価し、場合によっては、理論の修正を行おうと考えた。
3.2 SSSV の概略
SSSV はユーザーの録音した母音と「ん」とシステムが提供する子音を組み合わせて日
本語の合成音声をつくる波形接続型の音声合成システムである。ユーザーは「あ」,「い」,
「う」,「え」,「お」,「ん」の音素をひとつひとつ図 3.2 のような wav ファイルとして
保存する必要があるが、これは「あ, い, う, え, お, ん」と録音した wav ファイルから
gendb によって自動でできる。SSSV の UI は図 3.3 のようであり、音源名を入力し、テ
10
図 3.1: ケプストラムのグラフ。Quefrency の値が小さい範囲はスペクトルの緩やかな変化スペ
クトル包絡を、大きい範囲は原音 (声帯振動) の情報をあらわす。
キストボックスにクオートとコンマがはいったひらがなのテキストを入力する。このテ
キストは gentext によって音節ごとに分かち書きされたクオートとコンマの入ったロー
マ字のテキストに変換され、音声合成器 genspeech に渡される。クオートとコンマは音
を高くする記号と低くする記号であり、これによって音程を段階的に変えることができ
る。SSSV ではオリジナルの話者の声の高さによって出力の声の高さが決まるので、オ
リジナルの話者の声の高さを考慮した調声は不要である。現段階で SSSV でできる調声
は段階的な音程の制御のみであり、音量や速さを変えることなどはできない。
図 3.2: gendb を用いて切り出した音「あ」。どこでも「あ」の発音であるため、無音や子音の位
置などを気にせず処理できる。
すべてのコーパスで共通して使われるシステムが提供する子音は筆者が録音した。
11
図 3.3: SSSV の UI。音源名を指定し、ファイルから読み込む場合はファイル名のみ、直接打ち
込む場合はテキストボックスへの入力のみ、打ち込んだテキストをファイルに保存する場合は保
存先のファイル名とテキストを入力し、音声生成ボタンで合成音声を生成する。
これをユーザーが用意するコーパスに含まれる母音と「ん」と連結し日本語を出力する。
3.3 SSSV と UTAU との比較
UTAU も SSSV もどちらも波形接続型の音声合成システムであり、SSSV のクロス
フェードや子音のパラメータ、ポルタメント (ふたつの音程を緩やかにつなげる) は UTAU
を参考にした。また、ユーザーが録音した声を用いて合成音声を作るという手法も UTAU
の影響である。
12
UTAU と SSSV の違いは、まず UTAU は歌声合成を想定したソフトウェアであるのに
対し SSSV はスピーチの生成を想定しているところである。そのため、 UTAU では話し
ている音程を調べ、さらに音程・音量・速さを微調整していく必要がありスピーチを生成
することが難しい。しかし、それだけの機能は備えている。対して SSSV はオリジナル
の話者の録音した音程でスピーチを生成するため、言葉による音の上がり下がりだけを
気にすればよい。しかし、音程は段階的にしか制御できず、音量や速さは制御できない。
そしてユーザーが準備すべき音素の数も違う。UTAU では音節ごとに録音した単独音、
ふたつの音節にまたがって録音した連続音があり、日本語では単独音は 140 ほど、連続
音は 700 ほどの音素が必要になる。対して SSSV で必要な音素は 5 つの母音と「ん」の
あわせて 6 つだけである。単独音は音節ごとに録音しているので、子音から母音ヘ向か
う中間の音も録音されており、連続音であればさらに、母音から子音へ向かう中間の音
も録音されている。しかし SSSV の持つ音素にはそれらの音は存在しない。
また、 UTAU はコーパスさえ用意すればあらゆる言語を出力できる。対して SSSV は
日本語しか出力できない。
表 3.1: SSSV と UTAU の比較。主要部分のみ。
SSSV
UTAU
方式
波形接続型
波形接続型
目的
スピーチ生成
歌声生成
録音する音素数
6
音程 (段階的)
日本語のみ
1 音階あたり 140 または 700 程度
音程・速さ・音量・声質・発声タイミング
あらゆる言語 (コーパスに依存)
制御できるパラメータ
発話できる言語
13
第4章
4.1
SSSV の実装
開発環境
OS
開発言語
ユーザインタフェース
OS X 10.10.5 Yosemite
Common Lisp SBCL 1.2.11
Active Tcl 8.6.4.1
SSSV の開発は Macintosh OS X Yosemite 上で、CommonLisp、ActiveTcl を利用
した。
CommonLisp は動的なデータ構造に強いプログラミング言語であり、SSSV のコア部
分の開発には適している。CommonLisp は規格が ANSI で定められ、その上で開発され
たプログラムはプラットフォームを超えて移植できる。Macintosh 上で開発した SSSV
は Linux や Windows 上でも理論上、変更なしに動作する。
Tcl/Tk は SSSV のインタフェース作成に利用した。Tk と呼ばれる簡易言語でプログ
ラムし、シンプルなユーザインタフェースをデザインするのに向いているとされる。
4.2
開発したコード
SSSV は表 4.1 に示す CommonLisp の 11 個のソースファイルに分けて実装した。
全部合わせても 1,000 行に満たない小さなプロジェクトにも見えるが、これは Com-
monLisp の関数型プログラミングの有効性によるものである。
同じ内容を関数型の CommonLisp と C 言語などの手続き型言語とで記述し、その生
産性を比較すると CommonLisp のそれは C 言語で書いた時の 5 ∼ 10 倍になるという
主張 [9] もあることを強調しておきたい。
筆者も開発言語に C 言語を選択していたら、卒論の期間内に動く SSSV まで辿りつ
けたかどうか、まったく自信はない。
SSSV の全ソースコードは 2016 年 2 月 22 日現在の最新のバージョンを本論文の付
録に収容している。
14
表 4.1: SSSV を構成するプログラムファイル。私が心血を注いだもの。
ファイル名
役割
行数
common.lisp
concatenate.lisp
cs-data.lisp
filename.lisp
gendb.lisp
gentext.lisp
gui.lisp
main.lisp
mpm.lisp
td-psola.lisp
waveio.lisp
システムが共通に使うユーティリティ
genspeech の音素の連結にかかわる部分
genspeech の子音のパラメータを持つ
genspeech で文字列からファイル名を返す
母音と「ん」が録音された wav からコーパスをつくる
ひらがなのテキストをローマ字のテキストに変換する
Tcl/tk による GUI の実装
genspeech を開始する部分
genspeech の音程検出の部分
genspeech の TD-PSOLA による音程移動の部分
wav ファイルの入出力の部分
56
196
49
9
59
99
72
118
99
27
124
908
total
4.3
音節の作成
音節はソースコード concatenate.lisp に定義した関数 make-syl で作る。関数 make-syl
を以下に示す。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
( defun make−syl ( s y l c u r nx )
( l e t * ( ( wav ( cond
( ( string= syl ” r r ” )
( make−array ( f l o o r ( * * f r * * v l e n * ) )
: initial−element 0))
( ( s t r i n g = s y l ” nn ” )
( l e t * ( ( v ( get−vowel s y l ) )
( vd ( p i t c h s h i f t v c u r * v p i t c h * ) ) )
( subseq ( l e n g t h e n vd * v l e n * )
0 ( floor ( * * vlen * * f r * ) ) ) ) )
( ( = ( length s y l ) 1 )
( l e t * ( ( v ( get−vowel s y l ) )
( vd ( p i t c h s h i f t v c u r * v p i t c h * ) ) )
( subseq ( l e n g t h e n vd * v l e n * )
0 ( floor ( * * vlen * * f r * ) ) ) ) )
( ( or ( po s i t i o n #\\ y s y l ) ( p o s i t i o n #\\w s y l ) )
( l e t * ( ( vc ( subseq+ s y l −1))
( v ( get−vowel vc ) )
( vd ( p i t c h s h i f t v c u r * v p i t c h * ) )
( v f r q ( * * v p i t c h * cur ) )
( vsd ( cv ( subseq+ s y l −2 −1) vd v f r q ) ) )
( i f (= ( length s y l ) 2 )
vsd
( l e t ( ( c ( i f ( s t r i n g = ( subseq+ s y l −2 −1) ” y ” )
15
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
( format n i l ” ˜ ay ”
( subseq+ s y l 0 −2))
( subseq+ s y l 0 − 2 ) ) ) )
( cv c vsd v f r q ) ) ) ) )
( t ( l e t * ( ( vc ( subseq+ s y l −1))
( v ( get−vowel vc ) )
( vd ( p i t c h s h i f t v c u r * v p i t c h * ) )
( v f r q ( * * v p i t c h * cur ) )
( c ( i f ( s t r i n g = ( subseq+ s y l −1) ” i ” )
( format n i l ” ˜ Ay ” ( subseq+ s y l 0 −1))
( subseq+ s y l 0 − 1 ) ) ) )
( cv c vd v f r q ) ) ) ) ) )
( a m p l i f y ( i f ( and ( not ( zerop c u r ) ) ( not ( zerop nx ) ) )
( portament wav c u r nx )
wav )
cur ) ) )
make-syl は音節の文字列、その音程の変化量と次の音の音程の変化量により、文字列
に対応する音を作り、次の音の音程に向けてその音にポルタメントをかけて返す。文字
列は、例えば “a”, “ki”, “sha”, “mya”, “rr”, “nn” のようなものである。
母音
母音の長さは 0.2 秒とした。かなりゆっくりとした話し方に感じるが、母音が短いと
聞き取れなくなってしまうのでこの値にした。この値は concatenate.lisp で定数 *vlen*
として定義している。
録音された母音は少なくとも 0.05 秒の長さが必要である。0.05 秒あれば、concate-
nate.lisp にある lengthen によりそれをクロスフェードさせてつなぎあわせ、合成に必
要な長さを得ることができる。SSSV では最初にファイルから母音を読み込み、音程を
一定にして連想リストに持っておくことで、計算コストを減らす工夫をおこなっている。
子音
‘k’ や ‘t’ は破裂音であり、空気の流れが一時的に止められるため、発声される直前に
0.05 秒程度の無音がある。
また、‘s’ や ‘sh’ のような摩擦音は破裂音よりも長く発声される。
このような子音の時間的な特徴をあらわすため、それぞれの子音には時間的なパラメー
タを 3 つ持たせた。
1. 発声前の無音の時間
16
2. 母音発声前の発声の時間
3. 母音とクロスフェードさせる時間
これらのパラメータについて、図 4.1 にまとめた。
K
A
time
1
2
3
図 4.1: 子音の 3 つの時間的パラメータ。1 の範囲は発声前の無音時間を、2 の範囲は母音発声前
の子音の発声時間を、3 の範囲は子音と母音のクロスフェードの時間をあらわす。
録音された子音の音量は大きすぎたり小さすぎたりする。なので、子音に音量のパラ
メータを持たせた。このパラメータによって子音の音量をコントロールする。
また、有声子音は声帯振動を伴い音程があるので、母音の音程に合わせる必要がある。
有声子音の音程検出を毎回やるのは効率が悪いので、有声子音にのみ音程のパラメータ
を持たせこれを読み込むという工夫をおこなった。これらのパラメータは cs.lisp に定義
してある。
わたり音 ‘y’, ‘w’ については、ユーザーが用意した母音の ‘i’, ‘u’ を使った。
これにより音が滑らかに繋がるようになり、SSSV の一つのブレークスルーとなった。
またオリジナルの話者の声が使われる場面も増えたので、よりオリジナルの話者らし
い声になったと思われる。
この点は本論文の知見として、強調しておく。
4.4
音量と音程の調整
録音した人によって、母音の音量・音程はさまざまである。子音の音量を一定に使え
るよう、母音の最大音量を common.lisp 中の関数 normalize を使って、7000 に正規化
した。normalize を以下に示す。
1
2
3
4
( defun n o r m a l i z e ( s i g l i m )
( l e t ( ( mx ( vecmax s i g ) ) )
(map ’ vector
( lambda ( e l )
17
5
6
( * e l ( / l i m mx ) ) )
sig ) ) )
normalize は入力信号の最大値を lim にする。それにより、母音と「ん」の音は一定で
あるとして処理を進めることができる。
さらに、音程を母音に合わせるため、子音の音程を調整した。その方法は TD-PSOLA
法 [10] によった。TD-PSOLA 法の実装はファイル td-psola.lisp 中にある。
録音された母音の音程は一定ではない。大抵の人の母音音程は図 4.2 のように発声中
に変動する。なので、ファイル main.lisp の 関数 pitch-average により音程を平均に揃
える。関数 pitch-average は以下の通り。
1
2
3
4
5
6
7
8
9
10
11
12
13
( defun pitch−average ( wd v )
( l e t ( ( f r q s ( caddr ( assoc v * v s p i t c h l i s t * : t e s t # ’ s t r i n g = ) ) ) )
( concatenate−wds
( loop f o r i from 0
below (− ( length wd ) * windowsize * ) by * p i t c h d e t e c t − s t e p *
for frq in frqs
do ( format t ” ˜ a / ˜ a˜% ” i f r q )
i f frq
collect ( p i t c h s h i f t
( subseq wd i (+ i * p i t c h d e t e c t − s t e p * ) )
( / ( cadr ( assoc v * v s p i t c h l i s t *
: t e s t # ’ string =))
frq ) ) ) ) ) )
関数 pitch-average は信号全体の音程を一定にそろえる。これにより、音素の連結部
での音程が連続的になる。
音程を正しく動かすためには、音程を知る必要があり、音程検出には MPM 法 [11] を
用いた。これはファイル mpm.lisp で実装した。
音程 (= 周波数) は FFT によっても求まる。FFT の周波数の分解能は FFT する信号の
長さによって (1 / 時間 (秒)) に決まり、2048 フレーム (0.05 秒程度) での分解能は 22Hz
ほどである。
対して MPM 法は最低 2 周期分の波形が必要であるが、これは 50Hz の音でも 0.04
秒、1764 フレームであり分解能は 250Hz 付近で 1.5Hz 程度である。
MPM 法は倍音が強かったりノイズが入っていたりすると音程が誤検出されることがあ
る。誤検出が疑われる場合は、検出値を mpm.lisp の smoothing により修正した。
smoothing を以下に示す。
1
2
3
( defun smoothing ( ps a v r )
( cond ( ( n u l l ps ) ’ ( ) )
(( < ( * a v r 1 . 5 ) ( c a r ps ) )
18
図 4.2: 録音された母音の音程の時間変化。大抵の録音の音程はこのように一定でないので、音
程を平均にそろえ一定にする必要がある。
4
5
6
7
( smoothing ( cons ( / ( c a r ps ) 2 ) ( c d r ps ) ) a v r ) )
(( > ( / a v r 1 . 5 ) ( c a r ps ) )
( smoothing ( cons ( * ( c a r ps ) 2 ) ( c d r ps ) ) a v r ) )
( t ( cons ( c a r ps ) ( smoothing ( c d r ps ) a v r ) ) ) ) )
smoothing は MPM 法による誤検出を修正する。MPM 法が誤検出した値はたいてい 2
倍ちがうことを利用して、信号の平均の音程から遠い値を、 2 倍動かすことで正しいと
思われる音程を推定する。
SSSV では 512 フレームごとに音声ファイル全体の音程を計算するので、これには時
間がかかる。0.5 秒ほどの母音の音程を 6 つ計算するのにかかる時間は、6 分 35 秒ほど
である。なので計算した周波数表はファイルに保存し 2 回目からはそれを読み込んで処
理するようにした。
日本語のアクセントは高低アクセントである。なので、音の上がり下がりを制御する
手段を提供しなければならない。そこで入力の音節につづくクオート・コンマで図 3.3 の
ように音程を制御するようにした。周波数はクオートひとつで 1.1 倍上がり、コンマひ
とつで 1.1 倍下がる。この幅は concatenate.lisp の*pitchd*で設定しており、TD-PSOLA
法によって音程を変えている。音程が不連続に変わると不自然なので、音の上がり下が
りがあるときにはタイムストレッチによってポルタメントをかけた。
19
4.5
音節の連結
最後には音節を連結していかなければならない。最初の方法では、音節を連結すると
きには出来上がっていく文を格納しているベクタと次の音節のベクタを足した長さのベ
クタを作って、それにデータを入れていた。そうすると出来上がっていく文を格納するた
めのベクタがどんどん大きくなり、処理が遅くなっていく。そこで完成した部分からファ
イルに書き出していくことで、大きなベクタを作らなくていいようにした。すると長文に
なっても同じペースで出力できるようになった。これは concatenate.lisp の concat-wavs
に実装している。concat-wavs を以下に示す。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
( defun concat−wavs ( l s t o u t tmp )
( p r i n t ( length l s t ) )
( cond
( ( n u l l l s t ) ( write−wave−part tmp o u t ) )
( ( = ( length tmp ) 0 )
( l e t ( ( wav ( readwave ( c a r l s t ) ) ) )
( write−wave−part
( subseq+ wav 0 (− ( f l o o r ( * * f r * * s y l s x f a d e * ) ) ) )
out )
( concat−wavs
( cdr l s t )
out
( subseq+ wav (− ( f l o o r ( * * f r * * s y l s x f a d e * ) ) ) ) ) ) )
( t ( l e t ( ( wav ( cross−fade tmp
( readwave ( c a r l s t ) )
* sylsxfade * ) ) )
( write−wave−part
( subseq+ wav 0 (− ( f l o o r ( * * f r * * s y l s x f a d e * ) ) ) )
out )
( concat−wavs
( cdr l s t )
out
( subseq+ wav (− ( f l o o r ( * * f r * * s y l s x f a d e * ) ) ) ) ) ) ) ) )
concat-wavs は次の音とクロスフェードしなければならない部分だけを持ち、計算の
終わった部分をファイルに書き出す。
4.6
操作性の向上
genspeech
SSSV の操作は シェルスクリプト genspeech だけでおこなえる。ターミナルを開き、
次のコマンドを入力することで音声合成を開始し、発話する。
20
$ ./genspeech voicebankname <<EOS
> wa, ga ha i wa rr ne’ ko de a, ru,, rr rr
> EOS
または入力する文字列を保存したファイルを次のように読み込ませる。
$ ./genspeech voicebankname < romaji.txt
コマンド中、 voicebankname は作成したコーパスのラベルである。
gentext
このようにローマ字を音節ごとに区切って書くのはやや大変なので、ひらがなを入力
し、それをローマ字文字列に変換し、標準出力に出力する補助プログラム gentext を作っ
た。gentext は標準入力からひらがなを受け取るので、入力は、
$ ./gentext <<EOS
> わ, がはいわ、ね’ こであ, る,,。
> EOS
となる。またはひらがなのテキストを保存したファイルを
$ ./gentext < hiragana.txt
のようにリダイレクトしても良い。
これを使うと、ひらがなの文字列から
$ ./gentext | ./genspeech voicebankname <<EOS
> わ, がはいわ、ね’ こであ, る,,。
> EOS
または、
$ ./gentext < hiragana.txt | ./genspeech voicebankname
として合成音声をつくることができる。
21
SSSV の GUI
ターミナルからのコマンドの投入で SSSV は完全にコントロールできるのだが、コマ
ンド入力やキーボードに不慣れなユーザのために、GUI(Graphical User Interface) を付
与し、操作をより簡単にすることをはかった。
作成した SSSV の GUI は図 3.3 に示す。音源名と、ファイル名またはひらがなのテキ
ストを入力し音声生成ボタンを押すことで、合成音声を作る。
この GUI は genspeech と gentext を呼び出すだけのシンプルなものである。
22
第5章
実験と結果
SSSV で重要なことは 3 つある
• コーパスの作成が簡単化できていること
• 合成した音声から意味を聞き取れること
• 合成した音声のオリジナル話者が識別できること
なので、実際にコーパスを作成してもらってそれにどれだけの時間がかかるかの評価
と、合成音声を聞いて何を言っているのかわかるかどうかの評価、そして合成音声のも
とになっている声が誰の声かわかるかどうかの評価を行った。
聞き取りの実験はふた通り行った。ひとつは 20 つの短文を聞いてもらい音を正確に
聞き取れるかどうか、もうひとつは 4 つの長文を聞いてもらい意味を聞き取れるかどう
かを評価した。
5.1
コーパスの作成時間
4 人の被験者に作業手順を教え、コーパスができるまでの時間を測った。手順は以下
である。まず Audacity で「あ, い, う, え, お, ん」と録音し、それを wav ファイルとして
保存。gendb で音を切り分ける。
コーパス作成に要した時間を表 5.1、被験者のうちの一人が録音した波形を図 5.1 に
示す。
5.2
音と意味の聞きとり
短文
短文の聞き取り実験では SSSV と UTAU で同じ 20 の文を出力し、20 人の被験者のう
ち半分は SSSV の出力を先に、半分は UTAU の出力を先に聞いてもらい、聞き取った言
23
表 5.1: コーパス作成にかかる作業時間の計測結果。UTAU の単独音のコーパス作成にかかる時
間は 2 時間程度であったから、それと比較すると 1/100 程度にまで短縮できている。
被験者
作業時間 (秒)
A
B
C
D
46
46
48
64
図 5.1: 録音された「あ, い, う, え, お, ん」の波形。このように間をあけて大体同じくらいの音量
で 6 つの音を録音すると、処理しやすい。音量差がありすぎたり間隔がなかったりすると、検出
できない
葉を書き取ってもらった。UTAU で使った音源は筆者が作成した単独音のコーパスであ
り、音程を SSSV と同じように動かした。調声はおまかせ調声でポルタメントをかけた
だけである。20 の文を以下に示す。
• 新幹線 (しん’ か’ んせん,)
• iPhone (あ’ いふぉん,)
• おいしいクッキー (お, いしいく’っきい,)
• うすいコーヒー (う, すいこおひい,)
• X 線回折 (えっく’ す’ せ’ ん’ か’ いせつ,)
• 父と子と聖霊 (ち’ ちと, こと, せ, いれい)
• 電子機器 (で, んしきき,)
• 光通信 (ひか’ り’ つ’ うしん,)
• 生体認証 (せい’ た’ い’ に’ んしょう,)
24
• 空中仮想キーボード (くう’ ちゅ’ う’ か’ そ’ う’ き’ い’ ぼ’ おど,)
• 吾輩は猫である (わ, がはいわね’ こである,)
• 人工知能 (じん’ こ’ う’ ち’ のう,)
• 微分と積分 (び, ぶんとせ, きぶん)
• 標準偏差 (ひょう’ じゅ’ ん’ へ’ んさ,)
• アイスクリーム (あい’ す’ く’ り’ いむ,)
• Android (あん’ ど’ ろ’ いど,)
• みたらしだんご (みた’ ら’ し’ だ’ んご,)
• 電源ケーブル (でん’ げ’ ん’ け’ えぶる,)
• 従来モデル (じゅう’ ら’ い’ も’ でる,)
• 表面処理 (ひょ, うめんしょり,)
結果、UTAU を先に聞いた人が UTAU で聞き取れた文の数は平均して 10.08 であった
のに対し、SSSV を先に聞いて聞き取れた文の数は平均して 9.75 であった。また、UTAU
を先に聞いて SSSV で聞き取れた文の数は平均して 14.25、SSSV を先に聞いて UTAU
で聞き取れた文の数は平均して 12.86 であった。
この実験では、SSSV は UTAU に近いレベルの合成音声を出力していると言えるだろ
うが、最初に聞いて聞き取れた文の数は半分程度であり実用的ではない。
また、この実験により聞き間違えやすい音も知ることができた。聞き間違え方の結果
(ただし聞き間違えた頻度が 1% 未満のものは除く) を表 5.2 に示す。これによれば、ch
と j, ts と k, hy と sh, ts と s, sh と s, b と r, 「う」と「ん」, w と m は 5% 以上聞き間違
えられており、特に認識されにくいことがわかる。
長文
長文の聞き取り実験では SSSV と UTAU による同じ 4 の文の出力、そのあとに筆者が
話して録音した音を聞いてもらい、聞き取った文章の要点を書き取ってもらった。UTAU
で使った音源は短文のときと同じで、調声も同じようである。20 人のマテリアルの学生・
25
表 5.2: 音素の出現回数と誤認識の結果
もとの音
出現回数 (20 の文の合計)
聞こえた音 (20 文 * 20 人の合計)
ん
18
18
5
4
8
18
3
4
2
3
18
4
3
22
10
11
7
5
2
30
2
う:7
あ
b
ch
d
え
g
h
hy
j
k
m
n
お
r
s
sh
t
ts
う
w
お:3
r:5, d:3, f:1, k:1, s:1
j:8, k:2, sh:2
b:4, t:3
あ:9, う:6, お:4
k:2
k:2, f:1
sh:3
sh:7, k:1
t:6
b:2, h:2, d:1, g:1, p:1
b:2, m:2, d:1, h:1, k:1
い:12, う:12
g:3, k:3, t:3, d:2, s:2
ts:3, z:3
s:9, j:2
k:9, d:2, n:2, ch:1
k:4, s:3, f:1, z:1
ん:30, お:28, い:19
m:2
先生に協力してもらい、馴染みのあると思われる材料の話題を半分、馴染みのないと思
われるプログラムの話題を半分にした。半分の文は UTAU を先に、もう半分は SSSV の
ものを先に聞いてもらった。4 の文を以下に示す。
• 鉄に炭素や窒素が固溶するとコットレル雰囲気が形成され、転位が動きにくくなる
(て, つにた’ んそや, ち’っそが, こ, ようすると,、こっと’ れ’ る’ ふ’ ん’ い’ きが, け, い
せいされてん’ い’ が’ うご’ き’ に’ くくな, る,,)
• オーステナイトの結晶粒の大きさは、フェライト・パーライトの結晶粒の大きさに
影響を与える
(おお’ す’ て’ な’ いとの, けっしょ’ うりゅう, の, お, おきさわ、ふぇら’ い’ と’ ぱ’ あ’
26
ら’ いとの, けっしょ’ うりゅう, の, お, おきさにえい’ きょ’ う’ を’ あたえる)
• Haskell は純粋関数型の言語で、代入や入出力のような副作用は基本的に排除され
る
(は’ すける, わ, じゅん’ す’ い’ か’ ん’ す’ う’ が’ た’ の’ げ’ んごで,、だい’ にゅ’ う’ や’
にゅう’ しゅ’ つりょく, の, よう, な, ふく’ さ’ ようわ, き, ほんてきには’ いじょ, さ
れる)
• Prolog は論理型の言語で、述語の真偽によってプログラムは動作する
(ぷろ’ ろ’ ぐ’ わ’ ろん’ り’ が’ た’ の’ げ’ んごで,、じゅ, つごのし’ んぎに, よ,ってぷろ’
ぐ’ らむわ, ど’ うさす, る,)
結果、材料の話題については最初から意味を聞き取れた人が SSSV、UTAU ともにひと
りであったが、SSSV では 5 人、惜しかった人がいた。2 回目を聞いたときには、SSSV
のものは 3 人が聞き取れたのに対し、UTAU では全員が聞き取れていた。3 回目を流し
たときには、全員がわかった。
プログラムの話題では、最初から意味を聞き取れた人はどちらもいなかった。惜しかっ
た人が SSSV ではふたり、UTAU ではひとりいた。2 回目を聞いたときには、SSSV で
はひとり聞き取れていたが、UTAU では聞き取れた人はいなかった。3 回目を流したとき
には、3 つめの文ではふたり、4 つめの文では 4 人聞き取れた。
5.3
オリジナル話者の推定
オリジナルの話者を伏せ、
「あ、い、う、え、お、ん」から SSSV によって合成した音
声を被験者に聞いてもらい、オリジナルの話者を推定できるか、実験をおこなった。オ
リジナル話者は被験者の既知の人から選んだ。
36 回の実験の結果、聞いただけでわかった人は 44% 、言われたらわかった人が 12%
、別人の声だと感じた人は 44% であった。また、録音された母音と「ん」を聞いても
らっても結果は同じようであった。
27
図 5.2: オリジナル話者推定の結果。YES はオリジナル話者を推定できた。YES with HELP はオ
リジナル話者が誰かを聞かされたらわかった。NO はオリジナル話者が誰かを聞かされても別人
だと感じた。
28
第6章
考察
以上の実験から、コーパスの作成にかかる時間に関しては筆者が UTAU の 1 音階単独
音のコーパスを作成するのにかかった時間は 2 時間ほどであるから、SSSV では UTAU
と比較して 1/100 ほどにまで短縮できた。
さらに手順を教えたらすぐにできたことから、UTAU での原音設定の難しさ (子音の発
声のタイミングの調整など) はこのシステムにおいては考えなくてよかったと言える。こ
れらから、コーパス作成の簡略化は十分にできていると評価できる。
もしケプストラム法を用いてひとつの有声音からすべての音を作ることができれば、
コーパス作成の負担はさらに小さくなり、またスピードが速く十分な長さを得ることが
難しい普段の話し声やアニメなどの声からも、音素を簡単に採集できただろうが、これ
はうまくいかなかった。
原音にフォルマントをかけて合成音声を作るフォルマント合成が可能であるなら、人
の声からフォルマントを取り去って作った原音に別の人の声のフォルマントをかけるこ
とによっても音声を合成できるのではないかと考え、実際に合成してみたが、この方法
ではオリジナル話者の特徴は残せないことが確認できた。もとの人の声の対数スペクト
ルとその包絡線を図 6.1 に、それからフォルマントの情報を取り去ったものを図 6.2 に、
他人の母音「あ」の対数スペクトルと包絡線を図 6.3 に、もとの人の声からフォルマン
トの情報を取り去り、さらに他人の母音のフォルマントをかけたものを図 6.4 に示す。
オリジナル話者の声から変わってしまったことに関しては、そのことからフォルマン
トに含まれる個人の特徴は大きいことがわかる。フォルマントは声道においてある周波
数帯が増幅しまたは減衰した結果であって、声道の形状は人それぞれ違うのでフォルマ
ントも人それぞれ違うものになるはずである。声帯振動だけでなくフォルマントまで含
めてその人の声であるのに、それを無視して別のフォルマントをかけたためにオリジナ
ル話者の声質から変わってしまったのだろう。
ノイズ的になった理由としては、聞いてみるとふたつの声が重なったようであったこ
とから、声帯振動の周波数によってフォルマントも変化させなければならない、または
完全には取り去れなかった残りのフォルマントが影響した、という可能性が考えられる。
29
図 6.1: もとの人の声のフォルマントの様子
ひとつの有声音から日本語を発話させる試みは失敗したが、それでも 6 音からなるコー
パスの作成にかかる時間は 1 分程度であり授業の合間にも作ることができるほどに手軽
で簡単になった。
短文の聞き取りでは半分弱、長文の聞き取りではほとんど聞き取れていないことから
できあがった合成音声の品質は悪く実用レベルには達していない。
また、オリジナルの話者が誰であるかは言われても半数程度しかわからないことから、
その人らしさは十分には残せなかったと言わざるを得ない。
短文の聞き取りでわかった聞き間違えやすい音の組み合わせは、似ている音が多かっ
た。例えば ‘ch’ と ‘j’ については、‘ch’ の発音は [tS] であり、‘j’ の発音はその有声音 [dZ]
である。‘ts’ と ‘k’ については、 ‘ts’ は破裂音ではじまり、‘k’ は破裂音である。‘b’ と ‘r’ は
似ていないように思われるが、日本語の ‘r’ (たたき音 [R]) は一度瞬間的な閉鎖を作る点
が破裂音と共通しており、それで有声破裂音 (‘b’ や ‘d’) を ‘r’ と聞き間違えることがあっ
たものと思われる。逆に ‘r’ を破裂音と間違えることが少ないのは、筆者が ‘r’ をふるえ
音で録音していたためだろう。
聞き取りの実験で結果が悪かった原因として、人の話し方 (音程・音量・長さ) を再現
できなかったことが考えられる。図 6.5, 6.6, 6.7 に「吾輩は猫である」の肉声を録音し
たもの、UTAU が出力したもの、SSSV が出力したものの波形を示す。図 6.8, 6.9, 6.10
にそれぞれの音程の変化を示す。
30
図 6.2: もとの人の声からフォルマントを取り去った様子
これによれば、人の話し声は UTAU や SSSV の出力のように音節ごとに途切れること
はなく、音程の変化は UTAU より緩やかであり、特に語尾の下がり方は段階的ではない。
これに似せるにはふたつの方法が考えられる。ひとつは辞書を使った自動調声であり、こ
の方法によればユーザーは最小限の入力で日本語らしい合成音声を得られるだろう。
もうひとつは手動での調声であり、この方法ではユーザーの負担は大きくなり、さら
に調声の熟練度によっても品質に差が出る。
しかし、熟練したユーザーによる表情のついた高品質な合成音声も期待できる。
オリジナルの話者の識別では、話者の録音した原音を聞いても誰だかわからないこと
から、その人の話し方を再現しないとその人として認識するのは難しいことがわかる。こ
れに対応するには、手動による音量・音程・速さ、さらに前の音とのクロスフェードの
時間や子音のパラメータの十分な設定方法を提供する必要があるだろう。
31
図 6.3: 他人のフォルマントの様子
図 6.4: もとの人の声からフォルマントを取り去って、他人のフォルマントをかけた様子
32
図 6.5: 肉声を録音した波形。破裂音と無声子音によるところ以外で音が途切れることはなく、音
量は一定でないことがわかる。
図 6.6: UTAU が出力した波形。1 音 1 音途切れていて、音量は一定していることがわかる。
図 6.7: SSSV が出力した波形。1 音 1 音途切れていて、音量は UTAU のように一定してはいな
いが肉声の録音とは違っていることがわかる。
図 6.8: 肉声を録音したものの音程の時間変化。おおよそ段階的に音程が変化しているように見
えるが、語尾の音程の下がり方は段階的でない。
33
図 6.9: UTAU の出力の音程の時間変化。音程の変化が完全に段階的であり、特に後半の様子が肉
声と違っている。
図 6.10: SSSV の出力の音程の時間変化。音程が段階的に変わっていることはわかるが、UTAU
のようにきれいではなく、肉声のようでもない。
第7章
まとめ
話者から採集した「あ、い、う、え、お、ん」の 6 つの音に、別に録音した子音を組
み合わせて日本語と認識できる合成音声を出力できる、子音 - 母音 - 子音のつながりの
中から切り出した子音を使うことにより合成音声の品質を上げられる、ひとつの有声音
から「あ, い, う, え, お, ん」を合成できるとの仮説をたて、SSSV (Speech Synthesis
System with Vowel) による実証を試みた。
SSSV は先行する UTAU に対して、コーパス作成においては時間的コストを大幅に軽
減しつつ合成音声の質においては肩を並べるレベルに達しており、この点では SSSV は
目標を達成することができた。
しかし、合成した音声から意味を正しく聞き取ることは難しく、合成音声がオリジナ
ル話者の特徴を十分に残していると認めることはできなかった。
6 つの音素によるコーパスからオリジナル話者の特徴を残した声で日本語を出力でき
るという仮説に関しては、ただ音を連結して音程を段階的に変化させるだけではできな
いことが確認されたが、母音 - 子音 - 母音のつながりの中から切り出した子音とひとつ
の有声音からの合成の実装には至らなかった。
大学生活を締めくくる論文としては残念な結果に終わってしまったが、SSSV には、音
素を組み合わせる際の音量・音程・長さなどを調整可能なよう改良する余地が残されて
いる。これにより SSSV はさらに日本語らしい発音、オリジナルの話者の話し方の特徴
を再現できる可能性があり、SSSV の合成音声の品質は飛躍的に向上すると思われる。
今後の研究に期待したい。
34
35
謝辞
本研究を進めるにあたり、指導してくださった木村 広先生に感謝します。また、Review
of Speech Synthesis Technology に音声合成に関する技術についてまとめてくださった
Semi Lemmetty さん、Common Lisp についてまとめてくださった Land of Lisp の著者
の Conrad Barski さん、実践 Common Lisp の著者の Peter Seibel さんに感謝します。
参考文献
[1] Sami
Lemmetty.
Review
of
speech
synthesis
technology.
http://research.spa.aalto.fi/publications/theses/lemmetty mst/thesis.pdf
(2015/09/07), 1999.
[2] John J. Ohala. Christian gottlieb kratzenstein: Pioneer in speech synthesis.
https://www.researchgate.net/profile/John Ohala/publication/267831415 CHRISTIAN GOTTLIEB K
(2016/02/21), 2011.
[3] W. von Kempelen. Mechanismus der menschlichen Sprache. Degen, 1791.
[4] Signals
research
and
development
establishment.
http://www.mindspring.com/ ssshp/ssshp cd/ss srde.htm (2016/02/21).
[5] Joseph Olive. Rule synthesis of speech from dyadic units. Acoustics, Speech,
and Signal Processing, IEEE International Conference on ICASSP ’77., 1977.
[6] 清 水 忠 明.
ベ ク ト ル 量 子 化 に よ る 小 規 模 規 則 音 声 合 成 器 の 開 発.
http://hdl.handle.net/11094/2800 (2015/07/24), 2001.
[7] J. Sangeetha, S. Jothilakshmi, S. Sindhuja, and V. Ramalingam. Text to speech
synthesis system for tamil. International Journal of Emerging Technology and
Advanced Engineering, Vol. 3, , 2013.
[8] 徳田恵一. Hmm による音声合成の基礎.
[9] 竹内郁雄. 初めての人のための LISP. 翔泳社, 2011.
[10] Eric MOULINES and Francis CHARPENTIER. Pitch-synchronous waveform processing techniques for text-to-speech synthesis using diphone. Speech Communication, Vol. 9, , 1990.
36
37
[11] Philip
McLeod
and
Geoff
Wyvill.
A
smarter
way
to
find
http://miracle.otago.ac.nz/tartini/papers/A Smarter Way to Find Pitch.pdf
(2015/11/09), 2005.
pitch.
38
付 録A
A.1
Appendix
ソースコード
A.1.1 main.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
( load ” concatenate . l i s p ” )
( defun r e a d − l i n e s ( )
( l e t ( ( l ( read−line n i l n i l ) ) )
( if l
( format n i l ” ˜ a ˜ a ” l ( r e a d − l i n e s ) )
” ” )))
( defun s t r i n g − s p l i t ( s t r )
( l e t ( ( sp ( p o s i t i o n #\ space s t r ) ) )
( i f sp
( cons ( subseq s t r 0 sp )
( s t r i n g − s p l i t ( subseq s t r (1+ sp ) ) ) ) ) ) )
( defun make−syls ( )
( loop f o r i from 0 below ( length * s y l s * )
do ( progn ( format t ” ˜ a : ˜ a˜% ” i ( e l t * s y l s * i
( writewave
( tempname i ) * f r *
( i f (= i (1− ( length * s y l s * ) ) )
( make−syl ( d e l p i t c h ( e l t * s y l s * i
( pitch ( elt * syls * i ) )
( pitch ( elt * syls * i ) )
* vspitch *)
( make−syl ( d e l p i t c h ( e l t * s y l s * i
( pitch ( elt * syls * i ) )
( p i t c h ( e l t * s y l s * (1+
* vspitch * ) ) ) ) ) )
( defun concat−syls ( )
( fopen ( o u t ” o u t p u t . d a t ” : o u t p u t )
( concat−wavs ( mapcar ( lambda ( n )
( tempname n ) )
( range (1− ( length * s y l s * ) ) ) )
out # ( ) ) ) )
))
))
))
i )))
39
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
( defun p r i n t − p i t c h s ( vsp )
( when vsp
( format t ” ˜ , 1 f ˜% ” ( c d r ( c a r vsp ) ) )
( p r i n t − p i t c h s ( c d r vsp ) ) ) )
( defun p i t c h p a i r ( v )
( p r i n t ( cons v ( p i t c h l i s t ( readwave ( v o i c e f i l e v ) ) ) ) ) )
( defun p i t c h p a i r s ( vs )
( i f ( n u l l vs )
’()
( cons ( p i t c h p a i r ( c a r vs ) ) ( p i t c h p a i r s ( c d r vs ) ) ) ) )
( defun concatenate−wds ( wds )
( l a b e l s ( ( aux ( wds r e t )
( i f ( n u l l wds )
ret
( l e t ( ( new−wd ( make−array (+ ( length r e t ) ( length (
c a r wds ) ) ) ) ) )
( loop f o r i from 0 below ( length r e t )
do ( s e t f ( e l t new−wd i ) ( e l t r e t i ) ) )
( loop f o r i from 0 below ( length ( c a r wds ) )
do ( s e t f ( e l t new−wd (+ i ( length r e t ) ) ) ( e l t
( c a r wds ) i ) ) )
( aux ( c d r wds ) new−wd ) ) ) ) )
( aux wds ( make−array 0 ) ) ) )
( defun pitch−average ( wd v )
( l e t ( ( f r q s ( caddr ( assoc v * v s p i t c h l i s t * : t e s t # ’ s t r i n g = ) ) ) )
( concatenate−wds
( loop f o r i from 0 below (− ( length wd ) * windowsize * ) by *
pitchdetect−step *
for frq in frqs
do ( format t ” ˜ a / ˜ a˜% ” i f r q )
i f frq
collect ( p i t c h s h i f t
( subseq wd i (+ i * p i t c h d e t e c t − s t e p * ) )
( / ( cadr ( assoc v * v s p i t c h l i s t * : t e s t # ’ s t r i n g
=)) frq ) ) ) ) ) )
( defun read−vowel ( v )
( normalize
( pitchshift
( pitch−average ( readwave ( v o i c e f i l e v ) ) v )
( / * v p i t c h * ( c d r ( assoc v * v s p i t c h * : t e s t # ’ s t r i n g = ) ) ) )
* vvolume * ) )
( defun v p a i r ( v )
( cons v ( read−vowel v ) ) )
40
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
( defun v p a i r s ( vs )
( i f ( n u l l vs )
’()
( cons ( v p a i r ( c a r vs ) )
( v p a i r s ( c d r vs ) ) ) ) )
( defun del−blank ( ss )
( cond
( ( n u l l ss ) ’ ( ) )
( ( s t r i n g = ( c a r ss ) ” ” ) ( del−blank ( c d r ss ) ) )
( t ( cons ( c a r ss ) ( del−blank ( c d r ss ) ) ) ) ) )
( defun main ( )
( defparameter * args * ( c d r sb−ext : * posix−argv * ) )
( defparameter * s y l s * ( del−blank ( s t r i n g − s p l i t ( r e a d − l i n e s ) ) ) )
( defparameter * v s p i t c h l i s t *
( fopen ( f i n ( format n i l ” v o i c e / ˜ A / f r q ” ( c a r * args * ) ) : i n p u t ’
character )
( if fin
( read f i n )
( fopen ( f o u t ( format n i l ” v o i c e / ˜ A / f r q ” ( c a r * args * ) ) :
o u t p u t ’ character )
( p r i n t ( p i t c h p a i r s ’ ( ” a ” ” i ” ” u ” ” e ” ” o ” ” nn ” ) ) f o u t ) ) ) ) )
( defparameter * v s p i t c h * ( mapcar ( lambda ( f r q )
( cons ( c a r f r q ) ( cadr f r q ) ) )
v
* spitchlist *))
( defparameter * v p i t c h * ( c d r ( assoc ” a ” * v s p i t c h * : t e s t # ’ s t r i n g
=)))
( defparameter * vs * ( v p a i r s ’ ( ” a ” ” i ” ” u ” ” e ” ” o ” ” nn ” ) ) )
( e n s u r e − d i r e c t o r i e s − e x i s t ” temp / ” )
( writewave ” a . wav ” 44100 ( c d r ( assoc ” a ” * vs * : t e s t # ’ s t r i n g = ) ) )
( make−syls )
( concat−syls )
( dat−>wav ” o u t p u t . d a t ” ” o u t p u t . wav ” )
( d e l e t e − f i l e ( probe−file ” output . dat ” ) ) )
( sb−ext : save−lisp−and−die ” . . / genspeech ”
: executable t
: t o p l e v e l ’ main )
A.1.2 common.lisp
1
2
3
4
5
6
7
8
( defparameter * f r * 44100)
( defun subseq+ ( s t r s t a r t & o p t i o n a l end )
( l e t ( ( l e n ( length s t r ) ) )
( subseq s t r
( i f (< s t a r t 0 ) (+ l e n s t a r t ) s t a r t )
( l e t ( ( e ( i f end
( i f (< end 0 ) (+ l e n end ) end )
41
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
len ) ) )
( i f (< l e n e )
len
e)))))
( defun n o r m a l i z e ( s i g l i m )
( l e t ( ( mx ( vecmax s i g ) ) )
(map ’ vector
( lambda ( e l )
( * e l ( / l i m mx ) ) )
sig ) ) )
( defun vecmax ( s i g )
( loop f o r i across s i g
maximize ( abs i ) ) )
( defun s m a l l e r ( x y )
( i f (< x y ) x y ) )
( defun a b s s m a l l e r ( x y )
( i f (< ( abs x ) ( abs y ) )
x y))
( defun range ( end &key ( s t a r t 0 ) ( step 1 ) )
( l a b e l s ( ( aux ( c u r r e t )
( i f ( i f (< step 0 )
(< c u r end )
(< end c u r ) )
ret
( aux (+ c u r step ) ( cons c u r r e t ) ) ) ) )
( reverse ( aux s t a r t ’ ( ) ) ) ) )
( defun vecrange ( n & o p t i o n a l s )
( l e t ( ( r e t ( make−array ( / n ( i f s s 1 ) ) ) ) )
( loop f o r i from 0 below n by ( i f s s 1 )
do ( s e t f ( e l t r e t i ) i ) )
ret ))
( defmacro fopen ( ( sym fname d i r e c t i o n & o p t i o n a l element−type ) &body
body )
‘ ( w i t h − o p e n − f i l e ( , sym , fname
: direction , direction
,@( i f ( eq : i n p u t d i r e c t i o n )
’ ( : if−does−not−exist n i l )
’ ( : i f − e x i s t s : supersede ) )
: element−type , ( i f element−type
element−type
’ ( quote ( unsigned−byte
8))))
,@body ) )
42
A.1.3 waveio.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
( load ”common . l i s p ” )
( defparameter * f r * 44100)
( defun read−bytes ( s t r n )
( i f ( zerop n )
()
( cons ( read−byte s t r ) ( read−bytes s t r (1− n ) ) ) ) )
( defun bytes−>i n t ( b y t e s )
( i f ( null bytes )
0
(+ ( c a r b y t e s ) ( * 256 ( bytes−>i n t ( c d r b y t e s ) ) ) ) ) )
( defun int− >b y t e s ( i b y t e s )
( i f ( zerop b y t e s )
()
( l e t ( ( c u r (mod i 2 5 6 ) ) )
( cons c u r ( int−>b y t e s ( / (− i c u r ) 256) (1− b y t e s ) ) ) ) ) )
( defun w r i t e − b y t e s ( s t r l s t )
( when l s t
( write−byte ( car l s t ) s t r )
( write−bytes s t r ( cdr l s t ) ) ) )
( defun writewave−aux ( s t r d a t )
(map n i l
( lambda ( d )
( let ( ( b ( floor d ) ) )
( w r i t e − b y t e s s t r ( int− >b y t e s ( i f (< b 0 ) (+ b 65536) b )
2))))
dat ) )
( defun writewave−aux ( s t r d a t )
(map ’ vector
( lambda ( d )
( let ( ( b ( floor d ) ) )
( w r i t e − b y t e s s t r ( int− >b y t e s ( i f (< b 0 ) (+ b 65536) b )
2))))
dat ) )
( defun writewave ( fname sampling−rate d a t )
( fopen ( f fname : o u t p u t )
( w r i t e − b y t e s f ’ ( # x52 #x49 #x46 #x46 ) )
( w r i t e − b y t e s f ( int− >b y t e s (+ ( * ( length d a t ) 2 ) 36) 4 ) )
( w r i t e − b y t e s f ’ ( # x57 #x41 #x56 #x45 ) )
( w r i t e − b y t e s f ’ ( # x66 #x6d #x74 #x20 ) )
( w r i t e − b y t e s f ’ ( # x10 #x00 #x00 #x00 ) )
43
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
( write−bytes f
( write−bytes f
( write−bytes f
( write−bytes f
( write−bytes f
( write−bytes f
( writewave−aux
’ ( # x01 #x00
( int− >b y t e s
’ ( # x10 #xb1
’ ( # x02 #x00
’ ( # x64 #x61
( int− >b y t e s
f dat ) ) )
#x01 #x00 ) )
sampling−rate 4 ) )
#x02 #x00 ) )
#x10 #x00 ) )
#x74 #x61 ) )
( * ( length d a t ) 2 ) 4 ) )
( defun write−wave−header ( f sampling−rate l e n )
( w r i t e − b y t e s f ’ ( # x52 #x49 #x46 #x46 ) )
( w r i t e − b y t e s f ( int−>b y t e s (+ ( * l e n 2 ) 36) 4 ) )
( w r i t e − b y t e s f ’ ( # x57 #x41 #x56 #x45 ) )
( w r i t e − b y t e s f ’ ( # x66 #x6d #x74 #x20 ) )
( w r i t e − b y t e s f ’ ( # x10 #x00 #x00 #x00 ) )
( w r i t e − b y t e s f ’ ( # x01 #x00 #x01 #x00 ) )
( w r i t e − b y t e s f ( int−>b y t e s sampling−rate 4 ) )
( w r i t e − b y t e s f ’ ( # x10 #xb1 #x02 #x00 ) )
( w r i t e − b y t e s f ’ ( # x02 #x00 #x10 #x00 ) )
( w r i t e − b y t e s f ’ ( # x64 #x61 #x74 #x61 ) )
( w r i t e − b y t e s f ( int−>b y t e s ( * l e n 2 ) 4 ) ) )
( defun write−wave−part ( d a t s t r )
(map n i l
( lambda ( d )
( let ( ( b ( floor d ) ) )
( w r i t e − b y t e s s t r ( int− >b y t e s ( i f (< b 0 ) (+ b 65536) b )
2))))
dat ) )
( defun write−wave−part ( d a t s t r )
(map ’ vector
( lambda ( d )
( let ( ( b ( floor d ) ) )
( w r i t e − b y t e s s t r ( int− >b y t e s ( i f (< b 0 ) (+ b 65536) b )
2))))
dat ) )
( defun f i l e l e n g t h ( fname )
( l a b e l s ( ( aux ( s t r r e t )
( i f ( read−byte s t r n i l n i l )
( aux s t r (1+ r e t ) )
ret )))
( fopen ( f fname : i n p u t )
( aux f 0 ) ) ) )
( defun dat−>wav ( i n o u t )
( l e t ( ( len ( f i l e l e n g t h in ) ) )
( fopen ( f i n i n : i n p u t )
( fopen ( f o u t o u t : o u t p u t )
( when ( and f i n f o u t )
44
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
( write−wave−header f o u t * f r * l e n )
( loop f o r b = ( read−byte f i n n i l n i l )
w h i l e b do ( w r i t e − b y t e b f o u t ) ) ) ) ) ) )
( defun readwave−aux ( s t r l e n b y t e s )
( l e t ( ( r e t ( make−array ( / l e n b y t e s ) : i n i t i a l − e l e m e n t 0 ) ) )
( loop f o r i from 0 below ( / l e n b y t e s )
do ( l e t ( ( v a l ( bytes−>i n t ( read−bytes s t r 2 ) ) ) )
( i f (<= 32768 v a l )
( s e t f ( e l t r e t i ) (− v a l 65536))
( setf ( elt ret i ) val ) ) ) )
ret ))
( defun readwave ( fname )
( fopen ( f fname : i n p u t )
( if f
( l e t * ( ( header ( read−bytes f (+ 4 4 4 4 4 2 2 4 4 2 2 4 4 ) ) )
( sampling−rate ( bytes−>i n t ( subseq header 24 2 8 ) ) )
( bit−by−sample ( bytes−>i n t ( subseq header 34 3 6 ) ) )
( data−length ( bytes−>i n t ( subseq header 40 4 4 ) ) ) )
( values
( readwave−aux f data−length ( / bit−by−sample 8 ) )
sampling−rate ) ) ) ) )
( defun change−framerate ( s r c o l d f r newfr )
( l e t * ( ( l e n ( f l o o r ( * ( length s r c ) ( / newfr o l d f r ) ) ) )
( r e t ( make−array l e n : i n i t i a l − e l e m e n t 0 ) ) )
( loop f o r i from 0 below l e n
do ( s e t f ( e l t r e t i ) ( e l t s r c ( f l o o r ( * i ( / o l d f r newfr
))))))
ret ))
A.1.4 filename.lisp
1
2
3
4
5
6
7
8
( defun c2fname ( c )
( format n i l ” cs / ˜ a . wav ” c ) )
( defun tempname ( n )
( format n i l ” temp / ˜ a . wav ” n ) )
( defun v o i c e f i l e ( v )
( format n i l ” v o i c e / ˜ a / ˜ a . wav ” ( c a r * args * ) v ) )
A.1.5 mpm.lisp
1
2
3
4
5
( load ” waveio . l i s p ” )
( load ”common . l i s p ” )
( defparameter * windowsize * 2048)
( defparameter * n s d f l e n * 1024)
45
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
( defparameter * p i t c h d e t e c t − s t e p * 512)
( defparameter * t * 0 )
( defun r ( wd t a u )
( loop f o r j from * t * t o (− (+ * t * * windowsize * ) t a u 1 )
sum ( * ( e l t wd j ) ( e l t wd (+ j t a u ) ) ) ) )
( defun m ( wd t a u )
( loop f o r j from * t * t o (− (+ * t * * windowsize * ) t a u 1 )
sum (+ ( expt ( e l t wd j ) 2 )
( expt ( e l t wd (+ j t a u ) ) 2 ) ) ) )
( defun n ( wd t a u )
( / ( * 2 ( r wd t a u ) ) (m wd t a u ) ) )
( defun pick−peaks ( prev n s d f i tmp )
( cond
( ( or ( n u l l n s d f ) (= ( length n s d f ) 1 ) ) ( l i s t tmp ) )
(( < ( c a r n s d f ) 0 ) ( i f (< 0 ( c d r tmp ) )
( cons tmp ( pick−peaks ( c a r n s d f ) ( c d r n s d f )
(1+ i ) ’ ( 0 . 0 ) ) )
( pick−peaks ( c a r n s d f ) ( c d r n s d f ) (1+ i ) ’ ( 0
. 0))))
( t ( i f ( and (< ( c d r tmp ) ( c a r n s d f ) )
(< prev ( c a r n s d f ) )
(< ( cadr n s d f ) ( c a r n s d f ) ) )
( pick−peaks ( c a r n s d f ) ( c d r n s d f ) (1+ i ) ( cons i ( c a r n s d f
)))
( pick−peaks ( c a r n s d f ) ( c d r n s d f ) (1+ i ) tmp ) ) ) ) )
( defun get−period ( ps )
( labels ( ( bigger ( x y )
( i f (< x y ) y x ) )
( pmax ( ps )
( i f (= ( length ps ) 1 )
( cdar ps )
( b i g g e r ( cdar ps ) ( pmax ( c d r ps ) ) ) ) )
( aux ( ps pmax )
( i f (< ( * pmax 0 . 9 5 ) ( cdar ps ) )
( caar ps )
( aux ( c d r ps ) pmax ) ) ) )
( aux ps ( pmax ps ) ) ) )
( defun g e t − f r q ( p e r i o d )
( f l o a t ( / 44100 p e r i o d ) ) )
( defun average−aux ( xs sum c n t )
( i f ( n u l l xs )
( i f ( zerop c n t )
0
46
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
( / sum c n t ) )
( average−aux ( c d r xs ) (+ ( c a r xs ) sum ) (1+ c n t ) ) ) )
( defun average ( xs )
( average−aux xs 0 0 ) )
( defun p i t c h d e t e c t − a u x ( wd )
( l e t ( ( n s d f ( mapcar ( lambda ( t a u )
( n wd t a u ) )
( range * n s d f l e n * ) ) ) )
( get−frq
( get−period
( c d r ( pick−peaks ( c a r n s d f ) ( c d r n s d f ) 0 ’ ( 0 . 1 ) ) ) ) ) ) )
( defun p i t c h d e t e c t ( wd )
( l e t * ( ( p i t c h e s ( mapcar ( lambda ( i )
( p i t c h d e t e c t − a u x ( subseq wd i ) ) )
( range (− ( length wd ) * windowsize * )
: step * n s d f l e n * ) ) )
( avr1 ( average p i t c h e s ) ) )
( average
( remove−if−not ( lambda ( x )
( and (< ( / avr1 1 . 3 ) x )
(< x ( * avr1 1 . 3 ) ) ) )
pitches ) ) ) )
( defun smoothing ( ps a v r )
( cond ( ( n u l l ps ) ’ ( ) )
(( < ( * a v r 1 . 5 ) ( c a r ps ) )
( smoothing ( cons ( / ( c a r ps ) 2 ) ( c d r ps ) ) a v r ) )
(( > ( / a v r 1 . 5 ) ( c a r ps ) )
( smoothing ( cons ( * ( c a r ps ) 2 ) ( c d r ps ) ) a v r ) )
( t ( cons ( c a r ps ) ( smoothing ( c d r ps ) a v r ) ) ) ) )
( defun p i t c h l i s t ( wd )
( l e t * ( ( p i t c h e s ( mapcar ( lambda ( i )
( p i t c h d e t e c t − a u x ( subseq wd i ) ) )
( range (− ( length wd ) * windowsize * )
: step * p i t c h d e t e c t − s t e p * ) ) )
( avr1 ( average p i t c h e s ) ) )
( l i s t ( average
( remove−if−not ( lambda ( x )
( and (< ( / avr1 1 . 3 ) x )
(< x ( * avr1 1 . 3 ) ) ) )
pitches ) )
( smoothing p i t c h e s avr1 ) ) ) )
A.1.6 td-psola.lisp
1
( load ” waveio . l i s p ” )
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
( ql : quickload : bordeaux−fft )
( defun near−period ( per i )
( l a b e l s ( ( aux ( p l c n )
( i f (<= ( abs p l c ) ( / per 2 ) )
n
( aux (− p l c per ) (1+ n ) ) ) ) )
( aux i 0 ) ) )
( defun td−psola ( wd d i f f p e r i o d )
( l e t ( ( r e t ( make−array ( length wd ) ) )
( per2 ( * p e r i o d (1+ ( f l o o r ( / 1 d i f f ) ) ) ) ) )
( loop f o r i from 0 below ( length r e t ) by ( f l o o r ( / p e r i o d d i f f ) )
do ( l e t ( ( n ( near−period p e r i o d i ) ) )
( loop f o r j from 0 below per2
i f ( and (< (+ i j ) ( length r e t ) )
(< (+ ( * n p e r i o d ) j ) ( length wd ) ) )
do ( s e t f ( e l t r e t (+ i j ) )
(+ ( e l t r e t (+ i j ) )
( * ( e l t wd (+ ( * n p e r i o d ) j ) )
( b o r d e a u x − f f t : hann j per2 ) ) ) ) ) ) )
ret ))
( defun t d − p s o l a − p i t c h s h i f t ( wd d i f f f r q )
( td−psola wd d i f f ( f l o o r ( / 44100 f r q ) ) ) )
A.1.7 cs-data.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
( defparameter * v o i c e d c s *
’ ( ” b ” ” d ” ” g ” ” j ” ”m” ” v ” ” y ” ” n ” ”w” ” z ” ” by ” ” dy ” ” gy ” ” j y ” ”my”
” vy ” ” ny ” ” wy ” ” zy ” ” r ” ” r y ” ) )
( defun p r e b l a n k ( c )
( cond
( ( member c ’ ( ” b ” ” by ” ” d ” ” dy ” ” g ” ” gy ” ” k ” ” t ” ” p ” ” ch ” ” chy ” ”
t s ” ” ky ” ” t y ” ” py ” ” t s y ” ) : t e s t # ’ s t r i n g =) 0 . 0 5 )
( ( member c ’ ( ” j ” ” j y ” ) : t e s t # ’ s t r i n g =) 0 . 0 3 5 )
( ( member c ’ ( ”m” ”my” ”w” ” wy ” ) : t e s t # ’ s t r i n g =) 0 . 0 2 )
( t 0)))
( defun pre ( c )
( cond
( ( member c ’ ( ” sh ” ” shy ” ) : t e s t # ’ s t r i n g =) 0 . 1 )
( ( member c ’ ( ” h ” ” hy ” ” f ” ” f y ” ” n ” ” ny ” ” r ” ” r y ” ” sh ” ” shy ” ” j ”
” j y ” ” t s ” ” t s y ” ” z ” ” zy ” ) : t e s t # ’ s t r i n g =) 0 . 0 8 )
( ( member c ’ ( ” b ” ” by ” ” d ” ” dy ” ” g ” ” gy ” ” v ” ” vy ” ” s ” ” sy ” ”m” ”
my” ” ch ” ” chy ” ”w” ” wy ” ” y ” ) : t e s t # ’ s t r i n g =) 0 . 0 5 )
( ( member c ’ ( ) : t e s t # ’ s t r i n g =) 0 . 0 2 )
( t 0.03)))
48
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
( defun xfade ( c )
( cond
( ( member c ’ ( ” b ” ” by ” ” d ” ” dy ” ” g ” ” gy ” ) : t e s t # ’ s t r i n g =) 0 . 1 5 )
( ( member c ’ ( ” s ” ” sy ” ”w” ” y ” ” wy ” ” z ” ” zy ” ) : t e s t # ’ s t r i n g =)
0.1)
( ( member c ’ ( ” h ” ” hy ” ” f ” ” f y ” ” ch ” ” chy ” ” j ” ” j y ” ) : t e s t # ’
s t r i n g =) 0 . 0 7 )
( ( member c ’ ( ” t s ” ” t s y ” ) : t e s t # ’ s t r i n g =) 0 . 0 2 )
( t 0.05)))
( defun camp ( c )
( cond
( ( member c
( ( member c
( ( member c
( ( member c
( ( member c
( ( member c
0.7)
( ( member c
( ( member c
( t 1)))
’ ( ) : t e s t # ’ s t r i n g =) 3 . 5 )
’ ( ” z ” ) : t e s t # ’ s t r i n g =) 3 )
’ ( ” vy ” ) : t e s t # ’ s t r i n g =) 2 . 5 )
’ ( ” zy ” ” r y ” ) : t e s t # ’ s t r i n g =) 2 )
’ ( ” g ” ” dy ” ” ky ” ” t ” ” t y ” ” gy ” ) : t e s t # ’ s t r i n g =) 1 . 5 )
’ ( ” t s ” ” t s y ” ” k ” ” n ” ” f ” ” h ” ” hy ” ) : t e s t # ’ s t r i n g =)
’ ( ” y ” ) : t e s t # ’ s t r i n g =) 0 . 5 )
’ ( ”w” ” sh ” ” shy ” ) : t e s t # ’ s t r i n g =) 0 . 3 )
( defun c p i t c h ( c )
( l e t ( ( cs ’ ( ( ” b ” 169 180) ( ” d ” 207) ( ” g ” 207) ( ” j ” 200)
( ”m” 196) ( ” v ” 185) ( ” y ” 268) ( ” n ” 198)
( ” r ” 200) ( ”w” 259) ( ” z ” 185)
( ” by ” 184) ( ” dy ” 220) ( ” gy ” 185) ( ” j y ” 200)
( ”my” 185) ( ” vy ” 185) ( ” ny ” 196)
( ” r y ” 172) ( ” wy ” 193) ( ” zy ” 1 8 5 ) ) ) )
( i f (member c ’ ( ” y ” ”w” ) : t e s t # ’ s t r i n g =)
( c d r ( assoc ( c2v c ) * v s p i t c h * : t e s t # ’ s t r i n g = ) )
( cadr ( assoc c cs : t e s t # ’ s t r i n g = ) ) ) ) )
A.1.8 concatenate.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
( load
( load
( load
( load
( load
( load
”common . l i s p ” )
” waveio . l i s p ” )
”mpm. l i s p ” )
” cs−data . l i s p ” )
” filename . l i s p ” )
” td−psola . l i s p ” )
( defparameter
( defparameter
( defparameter
( defparameter
( defparameter
( defparameter
* vlen * 0.2)
* portament−time * 0 . 1 )
* portament−interval * 0.001)
* cvolume * 1 )
* vvolume * 7000)
* pitchd * 1.1)
49
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
( defparameter * s y l s x f a d e * 0 . 0 0 5 )
( defparameter * c l e n * 0 . 4 )
( defun fade−in ( d a t sek )
( l e t ( ( l i m i t − f r a m e ( f l o o r ( * * f r * sek ) ) ) )
(map ’ vector
( lambda ( x i )
( f l o o r ( * x ( i f (< i l i m i t − f r a m e ) ( / i l i m i t − f r a m e ) 1 ) ) ) )
dat
( vecrange ( length d a t ) ) ) ) )
( defun fade−out ( d a t sek )
( l e t * ( ( l e n ( length d a t ) )
( l i m i t − f r a m e ( f l o o r ( * * f r * sek ) ) ) )
( i f (< l e n l i m i t − f r a m e ) ( format t ” l < f s , ˜ a , ˜ a˜% ” l e n
limit−frame ) )
(map ’ vector
( lambda ( x i )
( * x ( i f (< i (− l e n l i m i t − f r a m e ) ) 1 ( / (− l e n i )
limit−frame ) ) ) )
dat
( vecrange ( length d a t ) ) ) ) )
( defun add−zeros−to−head ( s i g n )
( l e t ( ( r e t ( make−array (+ ( length s i g ) n ) : i n i t i a l − e l e m e n t 0 ) ) )
( loop f o r i from n
f o r e l across s i g
do ( s e t f ( e l t r e t i ) e l ) )
ret ))
( defun cross−fade ( d1 d2 sek )
( l e t * ( ( x f f r a m e s ( f l o o r ( * * f r * sek ) ) )
( l e n (− (+ ( length d1 ) ( length d2 ) ) x f f r a m e s ) )
( r e t ( make−array l e n : i n i t i a l − e l e m e n t 0 ) )
( d1−fo ( fade−out d1 sek ) )
( d 2 − f i ( add−zeros−to−head ( fade−in d2 sek ) (− ( length d1 )
xfframes ) ) ) )
( loop f o r i from 0 below l e n
do ( s e t f ( e l t r e t i )
( i f (< i ( length d1 ) )
(+ ( e l t d1−fo i ) ( e l t d 2 − f i i ) )
( e l t d2−fi i ) ) ) )
ret ))
( defun l e n g t h e n ( d a t sek )
( i f (< ( length d a t ) (1+ ( f l o o r ( * * f r * sek ) ) ) )
( l e n g t h e n ( cross−fade d a t d a t 0 . 0 5 ) sek )
dat ) )
( defun concat−wavs ( l s t o u t tmp )
50
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
( p r i n t ( length l s t ) )
( cond
( ( n u l l l s t ) ( write−wave−part tmp o u t ) )
( ( = ( length tmp ) 0 ) ( l e t ( ( wav ( readwave ( c a r l s t ) ) ) )
( write−wave−part ( subseq+ wav 0 (− ( f l o o r
( * * f r * * sylsxfade * ) ) ) ) out )
( concat−wavs ( c d r l s t ) o u t ( subseq+ wav (−
( floor ( * * f r * * sylsxfade * ) ) ) ) ) ) )
( t ( l e t ( ( wav ( cross−fade tmp ( readwave ( c a r l s t ) ) * s y l s x f a d e
*)))
( write−wave−part ( subseq+ wav 0 (− ( f l o o r ( * * f r * *
sylsxfade * ) ) ) ) out )
( concat−wavs ( c d r l s t ) o u t ( subseq+ wav (− ( f l o o r ( * * f r * *
sylsxfade * ) ) ) ) ) ) ) ) )
( defun a m p l i f y ( wd & o p t i o n a l (amp 1 ) )
(map ’ vector
( lambda ( e l )
( * e l * cvolume * amp ) )
wd ) )
( defun p i t c h s h i f t (w ps & o p t i o n a l f r q )
( i f frq
( t d − p s o l a − p i t c h s h i f t w ps f r q )
( l e t * ( ( l e n (1− ( f l o o r ( / ( length w) ps ) ) ) )
( r e t ( make−array l e n : i n i t i a l − e l e m e n t 0 ) ) )
( loop f o r i from 0 below l e n
do ( s e t f ( e l t r e t i ) ( e l t w ( f l o o r ( * i ps ) ) ) ) )
ret )))
( defun c2v ( c )
( l e t ( ( c v l i s t ’ ( ( ” y ” . ” i ” ) ( ”w” . ” u ” ) ) ) )
( c d r ( assoc c c v l i s t : t e s t # ’ s t r i n g = ) ) ) )
( defun cv ( c vd v f r q )
( l e t * ( ( cd ( i f (member c ’ ( ”w” ” y ” ) : t e s t # ’ s t r i n g =)
( n o r m a l i z e ( get−vowel ( c2v c ) ) * vvolume * )
( a m p l i f y ( readwave ( c2fname c ) ) ( camp c ) ) ) )
( ps ( i f ( c p i t c h c )
( / vfrq ( cpitch c ))
1))
( cdps ( map−into ( make−array ( f l o o r ( * * f r * * c l e n * ) ) :
i n i t i a l − e l e m e n t 0)
( lambda ( e l )
el )
( i f (member c * v o i c e d c s * : t e s t # ’ s t r i n g =)
( p i t c h s h i f t cd ps ( c p i t c h c ) )
cd ) ) )
( vd−l ( subseq ( l e n g t h e n vd * v l e n * ) 0 ( f l o o r ( * * v l e n * * f r
*)))))
51
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
( cross−fade
( cross−fade ( make−array ( f l o o r ( * * f r * ( p r e b l a n k c ) ) ) :
i n i t i a l − e l e m e n t 0)
( subseq cdps 0 ( f l o o r ( * (+ ( pre c ) ( xfade c ) ) * f r
*)))
0)
vd−l
( min ( xfade c ) ( / ( length cdps ) * f r * ) ( / ( length vd−l ) * f r
*)))))
( defun l e n g t h s ( l s )
( i f ( null ls )
0
(+ ( length ( c a r l s ) ) ( l e n g t h s ( c d r l s ) ) ) ) )
( defun portament (w c u r nx )
( l a b e l s ( ( vappend ( v1 v2 )
( l e t * ( ( l 1 ( length v1 ) )
( l 2 ( length v2 ) )
( l e n (+ l 1 l 2 ) )
( r e t ( make−array l e n : i n i t i a l − e l e m e n t 0 ) ) )
( loop f o r i from 0 below l e n
do ( s e t f ( e l t r e t i )
( i f (< i l 1 )
( e l t v1 i )
( e l t v2 (− i l 1 ) ) ) ) )
ret ))
( vsappend ( vs )
( i f (< ( length vs ) 2 )
( c a r vs )
( vappend ( c a r vs ) ( vsappend ( c d r vs ) ) ) ) ) )
( l e t * ( ( i (− ( length w) ( f l o o r ( * * f r * * portament−time * ) ) ) )
( i n t e r v a l ( floor ( * * f r * * portament−interval * ) ) )
( p o r t a m e n t − l s t ( cons ( subseq w 0 i )
( loop f o r x from (+ i i n t e r v a l ) below (
length w) by i n t e r v a l
c o l l e c t ( l e t ( ( p o r t a m e n t r a t e (+ ( * ( /
(− ( / nx c u r ) 1 )
(* * fr
*
*
portament−time
*))
138
139
140
(− x i ) )
1)))
( p i t c h s h i f t ( subseq w (− x
interval ) x)
portamentrate ) ) ) ) ) )
52
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
( vsappend p o r t a m e n t − l s t ) ) ) )
( defun get−vowel ( v )
( c d r ( assoc v * vs * : t e s t # ’ s t r i n g = ) ) )
( defun make−syl ( s y l c u r nx v s p i t c h )
( l e t * ( ( wav ( cond
( ( s t r i n g = s y l ” r r ” ) ( make−array ( f l o o r ( * * f r * * v l e n
*))
: initial−element 0))
( ( s t r i n g = s y l ” nn ” ) ( l e t * ( ( v ( get−vowel s y l ) )
( vd ( p i t c h s h i f t v c u r *
vpitch * ) ) )
( subseq ( l e n g t h e n vd * v l e n * )
0 ( floor ( * * vlen * * f r
*)))))
( ( = ( length s y l ) 1 ) ( l e t * ( ( v ( get−vowel s y l ) )
( vd ( p i t c h s h i f t v c u r *
vpitch * ) ) )
( subseq ( l e n g t h e n vd * v l e n * )
0 ( floor ( * * vlen * * f r
*)))))
( ( or ( po s i t i o n #\y s y l ) ( p o s i t i o n #\w s y l ) )
( l e t * ( ( vc ( subseq+ s y l −1))
( v ( get−vowel vc ) )
( vd ( p i t c h s h i f t v c u r * v p i t c h * ) )
( v f r q ( * * v p i t c h * cur ) )
( vsd ( cv ( subseq+ s y l −2 −1) vd v f r q ) ) )
( i f (= ( length s y l ) 2 )
vsd
( l e t ( ( c ( i f ( s t r i n g = ( subseq+ s y l −2 −1) ” y ” )
( format n i l ” ˜ ay ” ( subseq+ s y l 0
−2))
( subseq+ s y l 0 − 2 ) ) ) )
( cv c vsd v f r q ) ) ) ) )
( t ( l e t * ( ( vc ( subseq+ s y l −1))
( v ( get−vowel vc ) )
( vd ( p i t c h s h i f t v c u r * v p i t c h * ) )
( v f r q ( * * v p i t c h * cur ) )
( c ( i f ( s t r i n g = ( subseq+ s y l −1) ” i ” )
( format n i l ” ˜ Ay ” ( subseq+ s y l 0 −1))
( subseq+ s y l 0 − 1 ) ) ) )
( cv c vd v f r q ) ) ) ) ) )
( a m p l i f y ( i f ( and ( not ( zerop c u r ) ) ( not ( zerop nx ) ) )
( portament wav c u r nx )
wav )
cur ) ) )
( defun p i t c h ( s y l )
( l a b e l s ( ( aux ( s r e t )
53
185
186
187
188
189
190
191
192
193
194
195
196
( cond
( ( s t r i n g = ( subseq+ s −1) ” ’ ” ) ( aux ( subseq+ s 0 −1)
(* ret * pitchd * ) ) )
( ( s t r i n g = ( subseq+ s −1) ” , ” ) ( aux ( subseq+ s 0 −1)
( / ret * pitchd * ) ) )
( t ret ) ) ) )
( i f ( and (<= 2 ( length s y l ) ) ( s t r i n g = ( subseq s y l 0 2 ) ” r r ” ) )
0
( aux s y l 1 ) ) ) )
( defun d e l p i t c h ( s y l )
( i f (member ( subseq+ s y l −1) ’ ( ” ’ ” ” , ” ) : t e s t # ’ s t r i n g =)
( d e l p i t c h ( subseq+ s y l 0 −1))
syl ))
A.1.9 gentext.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
( defun c u t ( s t r n )
( i f (= ( length s t r ) 0 )
’()
( cons ( subseq s t r 0 n ) ( c u t ( subseq s t r n ) n ) ) ) )
( defparameter * twochar−kanas *
( mapcar ( lambda ( kana roma )
( cons kana roma ) )
( c u t ” いぇうぃうぇきゃきゅきぇきょくぁくぃくぇくぉしゃしゅしぇしょすぃ
ちゃちゅちぇちょつぁつぃつぇつぉてぃとぅにゃにゅにぇにょひゃひゅ
ひぇひょふぁふぃふぇふぉみゃみゅみぇみょりゃりゅりぇりょぎゃぎゅ
ぎぇぎょぐぁぐぃぐぇぐぉじゃじゅじぇじょずぃでぃどぅびゃびゅびぇ
びょぴゃぴゅぴぇぴょ ˆ ˆ e3 ˆ ˆ 8 2 ˆ ˆ 9 4 ぁ ˆ ˆ e3 ˆ ˆ 8 2 ˆ ˆ 9 4 ぃ ˆ ˆ e3
ˆ ˆ 8 2 ˆ ˆ 9 4 ぇ ˆ ˆ e3 ˆ ˆ 8 2 ˆ ˆ 9 4 ぉ ” 2 )
’ ( ” ye ”
” wi ” ” we ”
” kya ” ” kyu ” ” kye ” ” kyo ”
” kwa ” ” kwi ” ” kwe ” ” kwo ”
” shya ” ” shyu ” ” shye ” ” shyo ”
” si ”
” chya ” ” chyu ” ” chye ” ” chyo ”
” tsa ” ” t s i ” ” tse ” ” tso ”
” t i ” ” tu ”
” nya ” ” nyu ” ” nye ” ” nyo ”
” hya ” ” hyu ” ” hye ” ” hyo ”
” fa ” ” f i ” ” fe ” ” fo ”
” mya ” ” myu ” ” mye ” ” myo ”
” rya ” ” ryu ” ” rye ” ” ryo ”
” gya ” ” gyu ” ” gye ” ” gyo ”
” gwa ” ” gwi ” ” gwe ” ” gwo ”
” ja ” ” ju ” ” je ” ” jo ”
” z i ” ” d y i ” ” du ”
” bya ” ” byu ” ” bye ” ” byo ”
54
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
” pya ” ” pyu ” ” pye ” ” pyo ”
” va ” ” v i ” ” ve ” ” vo ” ) ) )
( defparameter * onechar−kanas *
( mapcar ( lambda ( kana roma )
( cons kana roma ) )
( c u t ” あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむ
めもやゆよらりるれろわをんがぎぐげござじずぜぞだぢづでどばびぶべ
ぼぱぴぷぺぽ ˆ ˆ e3 ˆ ˆ 8 2 ˆ ˆ 9 4 っ 、 。 ” 1 )
’( ”a” ” i ” ”u” ”e” ”o”
” ka ” ” k i ” ” ku ” ” ke ” ” ko ”
” sa ” ” s h i ” ” su ” ” se ” ” so ”
” ta ” ” chi ” ” tsu ” ” te ” ” to ”
” na ” ” n i ” ” nu ” ” ne ” ” no ”
” ha ” ” h i ” ” f u ” ” he ” ” ho ”
”ma” ” mi ” ”mu” ”me” ”mo”
” ya ” ” yu ” ” yo ”
” ra ” ” r i ” ” ru ” ” re ” ” ro ”
” wa ” ” wo ” ” nn ”
” ga ” ” g i ” ” gu ” ” ge ” ” go ”
” za ” ” j i ” ” zu ” ” ze ” ” zo ”
” da ” ” j i ” ” zu ” ” de ” ” do ”
” ba ” ” b i ” ” bu ” ” be ” ” bo ”
” pa ” ” p i ” ” pu ” ” pe ” ” po ”
” vu ”
” rr ” ” rr ” ” rr rr ” )))
( defun kana2roma ( s t r f )
( unless ( zerop ( length s t r ) )
( i f (= ( length s t r ) 1 )
( cond
( ( member ( c a r ( coerce ( subseq s t r 0 1 ) ’ l i s t ) )
’ ( # \ space #\ #\ t a b #\ n e w l i n e )
: t e s t # ’ char =)
( kana2roma ( subseq s t r 1 ) f ) )
( ( s t r i n g = ( subseq s t r 0 1 ) ” ’ ” ) ( format f ” ’ ” )
( kana2roma ( subseq s t r 1 ) f
))
( ( s t r i n g = ( subseq s t r 0 1 ) ” , ” ) ( format f ” , ” )
( kana2roma ( subseq s t r 1 ) f
))
( t ( format f ” ˜A” ( c d r ( assoc ( subseq s t r 0 1 ) *
onechar−kanas *
: t e s t # ’ string = ) ) )
( kana2roma ( subseq s t r 1 ) f ) ) )
( cond
( ( member ( c a r ( coerce ( subseq s t r 0 1 ) ’ l i s t ) )
’ ( # \ space #\ #\ t a b #\ n e w l i n e )
: t e s t # ’ char =)
( kana2roma ( subseq s t r 1 ) f ) )
55
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
( ( s t r i n g = ( subseq s t r 0 1 ) ” ’ ” ) ( format f ” ’ ” )
( kana2roma ( subseq s t r 1 ) f
))
( ( s t r i n g = ( subseq s t r 0 1 ) ” , ” ) ( format f ” , ” )
( kana2roma ( subseq s t r 1 ) f
))
( ( assoc ( subseq s t r 0 2 ) * twochar−kanas * : t e s t # ’ s t r i n g =)
( format f ” ˜ a ” ( c d r ( assoc ( subseq s t r 0 2 ) * twochar−kanas
*
: t e s t # ’ string = ) ) )
( kana2roma ( subseq s t r 2 ) f ) )
( t ( format f ” ˜A” ( c d r ( assoc ( subseq s t r 0 1 ) *
onechar−kanas *
: t e s t # ’ string = ) ) )
( kana2roma ( subseq s t r 1 ) f ) ) ) ) ) )
( defun r e a d − l i n e s ( f )
( l a b e l s ( ( aux ( s t r )
( l e t ( ( l ( read−line f n i l n i l ) ) )
( if l
( aux ( format n i l ” ˜ a ˜ a ” s t r l ) )
str ))))
( aux ” ” ) ) )
( defun main ( )
( kana2roma ( r e a d − l i n e s * s t a n d a r d − i n p u t * ) * standard−output * ) )
( sb−ext : save−lisp−and−die ” . . / g e n t e x t ”
: executable t
: t o p l e v e l ’ main )
A.1.10 gui.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
( ql : quickload : l t k )
( ql : quickload : t r i v i a l − s h e l l )
( use−package : l t k )
( defun text−empty ? ( t e x t )
( zerop
( length
( loop f o r c across t e x t
i f ( not (member c ’ ( # \ space #\ r e t u r n #\ n e w l i n e #\ t a b )
: t e s t # ’ char = ) )
collect c ) ) ) )
( defun make−speech−command ( name fname t e x t )
( i f ( text−empty ? fname )
( format n i l ” echo \ ” ˜ a\ ” | . / g e n t e x t | . / genspeech ˜ a ”
t e x t name )
56
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
( i f ( text−empty ? t e x t )
( format n i l ” . / g e n t e x t < ˜ a | . / genspeech ˜ a ”
fname name )
( format n i l ” echo \ ” ˜ a\ ” > ˜ a && . / g e n t e x t < ˜ a | . / genspeech
˜a”
t e x t fname fname name ) ) ) )
( defun main ( )
( with−ltk ()
( l e t * ( ( frame1 ( make−instance ’ frame ) )
( l a b e l 1 ( make−instance ’ l a b e l
: t e x t ” 音源名 ”
: master frame1 ) )
( name ( make−instance ’ e n t r y
: master frame1 ) )
( frame2 ( make−instance ’ frame ) )
( l a b e l 2 ( make−instance ’ l a b e l
: t e x t ” ファイル名
( 読 み 込 み / 保 存 の 場 合) ”
: master frame2 ) )
( fname ( make−instance ’ e n t r y
: master frame2 ) )
( frame3 ( make−instance ’ frame ) )
( l a b e l 3 ( make−instance ’ l a b e l
: t e x t ” テキスト
( 読 み 込 み の と き 以 外) ”
: master frame3 ) )
( t e x t ( make−instance ’ t e x t
: r e l i e f : sunken
: borderwidth 2
: master frame3 ) )
( b t n ( make−instance ’ b u t t o n
: t e x t ” 音声生成 ” ) ) )
( pack frame1 )
( pack l a b e l 1 : s i d e : l e f t )
( pack name : s i d e : l e f t )
( pack frame2 )
( pack l a b e l 2 : s i d e : l e f t )
( pack fname : s i d e : l e f t )
( pack frame3 )
( pack l a b e l 3 : s i d e : t o p )
( pack t e x t : s i d e : t o p )
( pack b t n )
( b i n d b t n ”<ButtonRelease−1>”
( lambda ( e )
( s e t f ( t e x t b t n ) ” 生成中 ” )
( t r i v i a l − s h e l l : shell−command
( make−speech−command
( t e x t name ) ( t e x t fname ) ( t e x t t e x t ) ) )
;
( s e t f ( t e x t name ) ” ” )
57
65
66
67
68
69
70
71
72
;
;
( s e t f ( t e x t fname ) ” ” )
( setf ( text text ) ””)
( s e t f ( t e x t b t n ) ” 音声生成 ” ) ) )
)))
( sb−ext : save−lisp−and−die ” . . / g u i ”
: executable t
: t o p l e v e l ’ main )
A.1.11 gendb.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
( load ” waveio . l i s p ” )
( defun o u t f i l e n a m e ( v )
( format n i l ” v o i c e / ˜ a / ˜ a . wav ” * username * v ) )
( defun save−vowels ( vds )
( i f (< ( length vds ) 6 )
( format t ” Vowels D e t e c t i o n E r r o r ˜% ” )
( progn
( e n s u r e − d i r e c t o r i e s − e x i s t ( format n i l ” v o i c e / ˜ a / ” * username * ) )
(mapc ( lambda ( vd )
( writewave ( o u t f i l e n a m e ( c a r vd ) ) * f r * ( c d r vd ) ) )
vds ) ) ) )
( defun v o w e l d e t e c t ( wd )
( l e t ( ( l e n ( length wd ) ) )
( l a b e l s ( ( aux ( vs s t a r t c u r )
( cond
( ( n u l l vs ) ’ ( ) )
(( < l e n c u r )
( when s t a r t ( l i s t ( cons ( c a r vs ) ( subseq wd s t a r t
)))))
( s t a r t ( i f (< ( vecmax ( subseq wd c u r (+ c u r 1 0 0 0 ) ) )
* vowelamp * )
( i f (< (− c u r s t a r t ) ( * * vowellength−min *
* fr *))
( aux vs n i l (+ c u r 1 0 0 0 ) )
( cons ( cons ( c a r vs ) ( subseq wd s t a r t
cur ) )
( aux ( c d r vs ) n i l (+ c u r 1 0 0 0 ) ) ) )
( aux vs s t a r t (+ c u r 1 0 0 0 ) ) ) )
( t ( i f (< * vowelamp * ( abs ( e l t wd c u r ) ) )
( aux vs c u r c u r )
( aux vs n i l (1+ c u r ) ) ) ) ) ) )
( aux ’ ( ” a ” ” i ” ” u ” ” e ” ” o ” ” nn ” ) n i l 0 ) ) ) )
( defun voweldetect−and−save ( wd )
( save−vowels ( v o w e l d e t e c t wd ) ) )
58
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
( defun vecmax ( vec )
( loop f o r i across vec
maximize i ) )
( defun main ( )
( defvar * args * ( c d r sb−ext : * posix−argv * ) )
( defvar * i n f i l e n a m e * ( c a r * args * ) )
( defvar * username * ( cadr * args * ) )
( defparameter * vowels * ’ ( ” a ” ” i ” ” u ” ” e ” ” o ” ” nn ” ) )
( defparameter * f r * 44100)
( defparameter * vowellength−min * 0 . 3 )
( defparameter * wd * ( readwave * i n f i l e n a m e * ) )
( defparameter * vowelamp *
( / ( loop f o r i across * wd *
maximize ( abs i ) )
5))
( voweldetect−and−save * wd * ) )
( sb−ext : save−lisp−and−die ” . . / gendb ”
: executable t
: t o p l e v e l ’ main )