はじめに
Praat は、音声に関して様々な分析が行えるフリーソフトであり、音声学の研究で広く用いられている。このソフトは、GUI ((Graphical User Interfaceの略。典型的にはマウスを使ってアイコンやボタンを押すことで様々な操作を実行する。)) が基本である。ただ、これだけでなく、スクリプト機能もある。スクリプトを活用すれば、色々と楽ができる。例えば、GUIでは何度もマウスをクリックしなくてはならなかったものが、スクリプトを書くことで一気に処理できるようになる。しかし、かつてのPraat のスクリプトの文法は、必ずしも分かりやすいものではなかった。文法が終始一貫していなかったため、やりたいことによって書き方がかなり変わってしまうことがあったのである。
その Praat のスクリプトの文法が、2013年春に大きく変わった。以前の文法より新しい文法の方がずっと書きやすいものになっている。要点をまとめると、以下の通りになる。
- バージョン 5.3.44 (2013年4月7日)からスクリプトの文法が順次改革されている。
- ただし、一気に改革されたのではない。当分は古い文法と新しい文法が混在する形が続くと思われる。
- 今回の文法の改革の主眼は variable-substitution-free scripting(変数の置換に悩まされないスクリプト記述)である。
- これによって、一貫した文法でスクリプトを書くことができるようになった。
- 古い文法では、やりたいことによって書き方がかなり違っていたので、使い分けを覚えるのが大変だった。
- なお、古い文法(バージョン5.3.43以前の文法)に基づいて書かれたスクリプトも、最新バージョンのPraatで問題なく動かすことが可能である。つまり、後方互換性が保たれている。

以下、Praat のスクリプトの変更点について、詳しく述べていきたい。まず、全般的な変更点について述べた後、個別具体的な変更点について述べる。
一貫した文法に
Praat のスクリプトの新しい文法では、書き方が終始一貫するようになった。これは古い文法に比べて優れている点である。
古い文法では、命令と引数を括弧で区切る場合と、スペースで区切る場合があった。以下の例で言うと、1行目の abs が丸括弧で区切る場合で、2行目の echo がスペースで区切る場合である。
abs(53) echo 53
上記の例で、1行目に用いられている abs という命令は絶対値を計算する命令で、53 を引数としてとっている。ここでは括弧を用いて、引数と命令の名前(つまり abs)とが区切られている。2行目に用いられている echo という命令はメッセージを表示する命令で、これも 53 を引数としてとっている。こちらはスペースを用いて、引数と命令の名前(つまり echo)とが区切られている。古い文法では、丸括弧で区切る方式の命令に対して、スペース区切りの方式で書くとエラーが出た。その逆の場合も同様にエラーが出た。よって、どちらの方式で書くかちゃんと覚えていなくてはならなかったのである。
新しい文法ではecho のようなスペースで区切る方式の命令は放棄され、丸括弧で区切る方式に統一された。このため、どちらの方式で書くかをわざわざ覚える必要がなくなった。新しい文法では以下のように書く。
abs(53) writeInfoLine(53)
ここで、writeInfoLine は、echo の代わりに導入された命令である。これは echo と同様にメッセージを表示する命令だが、丸括弧で区切る方式で記述する。
また、引数が複数ある場合、古い文法ではコンマで区切る場合とスペースで区切る場合があった。
より抽象的な形で説明しなおそう。なお、以下では説明のために hoge と piyo という命令を挙げているが、実際にはこういう命令は存在しない。あくまでも抽象的な説明のために出した例である。さて、Praat のスクリプトの新しい文法では、命令の書き方が以下のような形に統一されている。
hoge(a, b, c) piyo(d, e)
つまり、まず命令の名前(上の例では hoge と piyo)を書き、その後の丸括弧の中に引数を記述していく。また、コンマを置くことで引数と引数を区切る。上の例では、hoge は3つの引数(aとbとc)を持ち、piyo は2つの引数(dとe)を持つ。
実は、古い文法では、この書き方に統一されていなかった。古い文法では、上に挙げた丸括弧とコンマで区切る方式の他に、スペースだけで区切る方式もあった。下記で hoge は丸括弧とコンマで区切る方式で、piyo はスペースだけで区切る方式である。
hoge(a, b, c) piyo d e
つまり、古い文法では2つの方法を使い分ける必要がある。このため、使い分けの方法を覚えなくてはならず、面倒だったのだ。
抽象的な話をしてきたので、具体的な例で補足しよう。古い文法でメッセージを表示するために用いられた echo という命令はスペースで区切る方式の命令であった。
echo lorem ipsum
これが、新しい文法では以下のように丸括弧とコンマで区切る形式になっている。
writeInfoLine("lorem ipsum")
また、古い文法ではスペースが文脈によって様々な働きをしていた。
echo lorem ipsum
先ほどの古い文法での例を再掲しよう。ここで、echo と lorem の間のスペースと、lorem と ipsum の間のスペースは意味合いが違う。echo と lorem の間は命令とその引数を区切るためのスペースである。これに対して、lorem と ipsum の間のスペースは命令と引数を区切っているわけではなく、単に単語の切れ目を示すだけのスペースである。
このように古い文法では、スペースが様々な働きを持つために、あるスペースがどういう意味なのか理解することが難しかった。新しい文法では、命令と引数は丸括弧で区切られ、引数と引数はコンマで区切る形式に統一された ((ただし、ごく一部に古い文法の名残が残っている。)) 。よって、スペースの意味が分かりにくいということがなくなったのである。
具体的変更点
入出力
メッセージウィンドウへの表示
スクリプトからメッセージウィンドウ ((Praat Infoというウィンドウにメッセージが表示される。)) にメッセージを表示する場合、古い文法では echo や printline という命令を使ったが、新しい文法では writeInfoLine や appendInfoLine といった命令を使うようになった。
古い文法での echo や printline では命令の後に、表示したい文言をそのまま入力した。例えば、lorem ipsum という文言を表示したい場合、以下のように入力すればよかった。
echo lorem ipsum printline lorem ipsum
これが、新しい文法では以下のようになる。
writeInfoLine("lorem ipsum") appendInfoLine("lorem ipsum")
つまり、表示したい文言を丸括弧で囲む形式に変わったのだ。
ここで、writeInfoLine と appendInfoLine の使い分けについて説明しておこう。まず、writeInfoLine を使用した場合、メッセージウィンドウの中身をすべて消した後に、メッセージを表示する。つまり、上書きである。これに対し、appendInfoLine はメッセージウィンドウにすでにすでに書かれている内容のあとに、メッセージを付け加える。つまり、追記である。なお、古い文法での echo は上書き、printline は追記の働きを果たす。
また、新しい文法には、メッセージを表示する命令として、writeInfo というものもある。この命令は上書きでメッセージウィンドウにメッセージを表示するが、最後に改行を行わない点で writeInfoLine と異なっている。つまり、writeInfoLine は最後に改行を行い、writeInfoは最後に改行を行わないのだ。appendInfo という命令もある。appendInfoLine が最後に改行を行うのに対し、appendInfo は最後に改行を行わない。つまり、最後に Line がついていると改行を行い、ついていないと改行を行わないのだ。
ファイルへの入出力
なお、メッセージウィンドウではなく、ファイルにメッセージを書き出したい場合は、writeFileLine, appendFileLine, writeFile, appendFile という命令を使う。write で始まるものが上書きで、append で始まるものが追記となり、最後に Line があれば改行を行うということはメッセージウィンドウに出力する場合と同じである。
これらの命令をまとめると以下のようになる。
命令 | 上書きか追記か | 出力先 | 最後の改行 |
---|---|---|---|
writeInfoLine | 上書き | メッセージウィンドウ | 最後に改行する |
appendInfoLine | 追記 | メッセージウィンドウ | 最後に改行する |
writeInfo | 上書き | メッセージウィンドウ | 最後に改行しない |
appendInfo | 追記 | メッセージウィンドウ | 最後に改行しない |
writeFileLine | 上書き | ファイル | 最後に改行する |
appendFileLine | 追記 | ファイル | 最後に改行する |
writeFile | 上書き | ファイル | 最後に改行しない |
appendFile | 追記 | ファイル | 最後に改行しない |
なお、ファイルの中身を読み込んで文字列変数に入力するには以下のようにする。
hoge$ = readFile$("piyo.txt")
古い文法では、ファイル入出力は以下のように記述していた。以下のスクリプトで1行目がファイルからの入力 ((新しい文法での readFile$ に対応。)) 、2行目がファイルへの上書き出力 ((新しい文法での writeFileInfo に対応。)) 、3行目がファイルへの追記出力 ((新しい文法での appendFileInfo に対応。)) を示している。
hoge$ < piyo.txt hoge$ > piyo.txt hoge$ >> piyo.txt
古い文法の方は、タイプする量は少ないものの、書き方が他の命令とかなり異なっている。新しい文法の方が、他の命令と終始一貫したものとなっている。
変数の中身を出力する
新しい文法で変数の中身を出力する場合は、以下のようにする。以下のスクリプトを実行すると、apples というメッセージが表示される。
a$ = "apples" writeInfoLine(a$)
また、次のようにすれば普通の文字列と変数の中身を合わせて出力できる。コンマで区切るのがポイントである。以下のスクリプトを実行すると、I have 42 apples というメッセージが表示される。
a$ = "apples" b = 42 writeInfoLine("I have ", b, " ", a$)
なお、上記のスクリプトを古い文法で書くと以下のようになる。
a$ = "apples" b = 42 echo I have 'b' 'a$'
GUIメニューのコマンドの呼び出し
Praat のスクリプトからは GUIメニューでのコマンドを呼び出すこともできる。古い文法ではGUIメニューのコマンドをそのまま書くことでコマンドを呼び出せた。これに対して、新しい文法では do や do$ といった命令を使ってコマンドを呼び出すようになった。
例えば、GUIメニューで Help から Praat Intro というメニューを選ぶと Praat のマニュアルが表示される。これをスクリプトから呼び出したければ、古い文法では単に以下のように記述すればよかった。
Praat Intro
これに対して、新しい文法では以下のように記述する。
do("Praat Intro")
新しい文法では、do を付けなくてはならなくなった分だけ、面倒になったように見える。だが、do を使うと、GUIメニューでのコマンドを変数に入れられるというメリットがある。例えば、以下では a$ という文字列変数に、Praat Info というコマンド名の文字列を代入した上で、do で呼び出している。
a$ = "Praat Intro" do(a$)
多くのGUIメニューのコマンドは、引数を要求する。GUIで動かすときは、引数は対話的に入力することができるが、スクリプトからコマンドを呼び出す場合は、基本的にスクリプト中に引数を記述することが必要となる。古い文法では、コマンドと引数の境界が分かりにくかったのだが、新しい文法では境界が分かりやすくなった。
例えば、GUIメニューには音声ファイルを開くコマンドとして、Read from file… というものがある。このコマンドは、どのファイルを開くのかという指定をする引数を伴わなくてはならない。古い文法の場合、以下のように記述した。
Read from file... sound.wav
コマンドと引数を区切っているのは、file… と sound.wav の間のスペースである。ここで、Read と from の間にもスペースがあるが、これはコマンドと引数を区切るスペースではない ((from と file… の間のスペースも Read と from の間のスペースと同様にコマンドと引数を区切るスペースではない。)) 。つまり、1つの行の中にコマンドと引数を区切るスペースとそうでないスペースが混在しているのである。これでは間違いが起きやすい。
これに対し、新しい文法では、do を使い、コンマで区切っている。区切りに使うのはあくまでもコンマということになり、境界が分かりやすくなっている。
do("Read from file...", "sound.wav")
より厳密に言うと、do は1つ以上の引数をとる命令である。そして、1つ目の引数がGUIでのコマンド名、2つ目以降の引数がGUIでのコマンドがとる引数になるのだ ((ちなみに、引数を要さないGUIでのコマンド—ー例えば Praat Introーーに対して、do(“Praat Intro”, 5) のように2つ目の引数を付けてもエラーは起きない。ただ無視されるだけである。)) 。
また、何らかの数値を返すGUIコマンドの場合は、以下のようにすることで、数値変数に数値を格納することができる。
power = do("Get power...", 0.0, 0.0)
なお、do の他に、do$ というものもある。基本的には do を使えばよいのだが、返り値が文字列になる場合は do$ を使う必要がある。例えば、ある区間に付されたラベルの文字列を取得する Get label of interval… は文字列を返すので、do$ を使う。
label$ = do$("Get label of interval...", 1, 2)
ちなみに、do と do$ の両方が使えるGUIコマンドもある。
power1 = do("Get power...", 0.0, 0.0) power2$ = do$("Get power...", 0.0, 0.0)
上記のスクリプトの場合、power1 には数値のみ(例えば 0.019375055982011204)が格納される。これに対して、power2 には数値に単位の文字列が加わったもの(例えば 0.019375055982011204 Pa2)が格納される。
数値と文字列を相互に変換する
Praat スクリプトでは数値と文字列を区別する。新しい文法では、数値を文字列に変換するには以下のように string$ という命令を使う。
a = 5 b$ = string$(a)
逆に文字列を数値にしたければ、number という命令を使う。
c$ = "7" d = number(c$)
なお、古い文法では以下のように、シングルクオーテーションとダブルクオーテーションを駆使して、数値と文字列を相互変換していた ((古い文法では、シングルクオーテーションで囲むことによって、変数の中身を取り出していた。つまり、”‘a'” というのはシングルクオーテーションで a の中身を取り出し、さらにダブルクオーテーションで囲むことによって、文字列として認識させているのである。古い文法のように、シングルクオーテーションとダブルクオーテーションが混ざっていると人間にとっては読みづらく、ミスも多くなる。新しい文法のような書き方の方がバグが少なくなる。))。
a = 5 b$ = "'a'" c$ = "7" d = 'c$'
サブルーチン
新しい文法ではサブルーチンを呼び出す際に、@ を使うようになった。また、サブルーチンは、procedure と endproc で囲んで定義する。以下の例では、半径から円の面積を求めて表示するサブルーチン cicleArea が定義されている。1行目で、@circleArea(10) とすることで、半径を示す引数を10にして、面積を求めて表示するサブルーチンを呼び出している。
@circleArea(10) procedure circleArea (radius) area = pi * radius ^ 2 writeInfoLine(area) endproc
なお、古い文法ではサブルーチンを呼び出すために、call という命令を用いていた。以下のように、古い文法では call の後に空白をはさんで、サブルーチン名と引数が記述されていた。
call circleArea 10 procedure circleArea radius area = pi * radius ^ 2 echo 'area' endproc
また、サブルーチンの定義方法は procedure と endproc を使うという点では新しい文法と同じだが、引数 ((この例で言うと radius。)) は丸括弧で区切るのではなく、単にスペースで区切るのみであるという違いがある。