Praatスクリプト入門(4):周波数を変更してみる その2

概要
Praatスクリプトの入門講座その4。for による繰り返しを扱う。

繰り返しの方法

本入門講座の目次は「Praatスクリプト入門:目次」というページをご覧いただきたい。また、前回の講座を見たい人は「Praatスクリプト入門(3):周波数を変更してみる その1」というページをご覧いただきたい。

前回までのスクリプトでは、音を1回しか再生しなかった。ここで、複数回再生したい場合はどうすればよいだろうか。スクリプトの一部をコピーしていけば、同じような作業を繰り返してみせることが一応できる。例えば、以下のスクリプトでは1000 Hzの正弦波を作成して3回再生した上で、作成した音を削除する。

do("Create Sound from formula...", "sineWave1000", 1, 0.0, 1.0, 44100, "sin(2*pi*1000*x)")
do("Play")
do("Play")
do("Play")
do("Remove")

しかし、プログラミングでコピーは禁物である。もし、先ほどのスクリプトで、最初に Play の代わりに、Pray と誤って書いてしまったらどうなるだろうか。誤ったのに気づかずコピーをしてしまったとすると、以下のようになるはずだ。

do("Create Sound from formula...", "sineWave1000", 1, 0.0, 1.0, 44100, "sin(2*pi*1000*x)")
do("Pray")
do("Pray")
do("Pray")
do("Remove")

これではスクリプトがちゃんと動かないので、Pray を Play に直す必要が出てくる。コピーを繰り返したので、3回も直さなくてはならない。これでは修正が面倒だ。また、今は誤っているところがまとまって出ているので修正しやすいのだが、複雑なスクリプトでは修正する場所があちらこちらに分散してしまい、こちらは直したがあちらは直していないということになりかねない。

先ほどのスクリプトにはもう1つ問題がある。それは繰り返す回数を変更しにくいということだ。先ほどのスクリプトでは、再生回数は3回と決まっている。再生回数を5回とか9回とかに変えたい場合は、do(“Play”) を何度もコピーしなくてはならない。それよりも、もっと汎用的なスクリプトにすべきだる。例えば、再生回数を格納する数値変数を用意しておき、そこに5という数値を入れれば5回再生し、9という数値を入れれば9回再生するといったようにした方が望ましい。

コピーを使わずに繰り返したい場合どうするか。Praatで繰り返しの作業を行うには、for 構造を使うのが便利である。例えば、以下のスクリプトでは、for 構造を用いて1から5までの整数の和がいくつになるかを求めている。

sum = 0
for i from 1 to 5
  sum = sum + i
endfor
writeInfoLine(sum)

上のスクリプトの1行目では、合計を入れるための箱として、sum という数値変数を用意している。この sum に、1を加え、2を加え、3を加え、4を加え、最後に5を加えることで、1から5までの整数の和を求めている。

2行目から4行目が繰り返しを示す for 構造である。for 構造は、for で始まり、endfor で終わる。そして、繰り返したい作業内容は、for と endfor の間に記述する。if のときと同様に、for と endfor に挟まれたものはインデントをつけると見やすくなる。

作業を繰り返し行う際には、繰り返したい作業を for と endfor で挟み込む。

上のスクリプトの2行目では、for i from 1 to 5 と書いてある。これは、数値変数 i が1の時から始め、5になる時まで同じ作業を繰り返せという意味だ。つまり、i が1の場合、i が2の場合、i が3の場合、i が4の場合、i が5の場合の計5回の繰り返しが行われることになる。ここでは i という名前の変数を設定したが、名前は別に i でなくとも構わない。例えば、for abcde from 1 to 5 とすれば、abcde が1の場合から5の場合まで計5回繰り返される。また、上の例では、1から5としたが、他の数でも問題ない。for i from 18 to 24 ならば、i が18の場合から24の場合まで繰り返すことになる。

for 構造の確認
  1. 上記のスクリプトの3行目の sum = sum + i がどういう操作なのか説明せよ。等号(=)の左側の sum と右側の sum に入っている数がどうなっているかについて着目するとよい。また、i が1の場合、3行目ではどんな計算が行われるか。i が2, 3, 4, 5の場合はどうか。
  2. 上記のスクリプトを変更して、1から15までの整数の和を求めよ。
  3. 上記のスクリプトを変更して、38から74までの整数の和を求めよ。

以下のスクリプトを実行すると、1000 Hzの正弦波の音が3回流れる。ここでは先ほどのスクリプトと異なり、for で値が変化する変数(ここでは i )が for と endfor の間で使われていない。こういうこともある。

do("Create Sound from formula...", "sineWave1000", 1, 0.0, 1.0, 44100, "sin(2*pi*1000*x)")
for i from 1 to 3
  do("Play")
endfor
do("Remove")
繰り返す回数を変更する

上記のスクリプトを変更して、音を再生する回数を5回にせよ。

周波数の数列を作る

100 Hz, 200 Hz, 300 Hz, 400 Hz, 500 Hzという5つの正弦波の音を作ることを考えよう。つまり、周波数の数値を100ずつ増やしていくわけだ。

100ずつ増やせれば楽なのだが、for 構造では数値を1つずつしか増やすことができない。このため、少し工夫をする必要がある。以下のスクリプトを実行すると、100, 200, 300, 400, 500という数列が出力される。

writeInfo("Frequencies: ")
for i from 1 to 5
  frequency = 100 * i
  appendInfo(frequency)
  appendInfo(" ")
endfor
appendInfo(newline$)
周波数の数列を作る
  1. writeInfo と writeInfoLine にはどのような違いがあるか。上記のスクリプトの1行目を writeInfoLine に書き換えることで違いを確認せよ。
  2. 上記のスクリプトの for 構造(2行目から6行目)が何をしているか順を追って説明せよ。
  3. 上記のスクリプトの4行目は、なぜ writeInfo でなく、appendInfo なのか。Praatスクリプト入門(2):音を合成してみるで学んだことを踏まえて説明せよ。
  4. 上記のスクリプトの4行目と5行目を1つにまとめよ。すなわち、appendInfo を1回しか使わない形に改めよ。
  5. 上記のスクリプトの最終行はどんなことをしているか。この行を取り払うことで、この行の働きを確かめよ。取り払う前と取り払う後で、スクリプト実行終了時の Praat Info ウィンドウでのカーソルの位置に着目するとよい。その結果を踏まえて newline$ がどういう意味を持つか説明せよ。
  6. 上記のスクリプトを書き換えて、200, 400, 600, 800, 1000という数列を出力するようにせよ。
  7. 上記のスクリプトを書き換えて、1000, 1100, 1200, 1300, 1400という数列を出力するようにせよ。
  8. 110, 220, 440, 880, 1760, 3520 という2倍になっていく数列を上のスクリプトのように出力するには、どうすれば良いか。for 構造をうまく使って処理せよ。

さまざまな周波数の音を一度に作る

今までのことを踏まえて、さまざまな周波数の音を一度に作るスクリプトを書こう。具体的に言えば、100 Hz, 200 Hz, 300 Hzと周波数を100ずつ増やしていき、500 Hzまでの正弦波の音をつくる。合成される音は合わせて5個である。なお、話を簡単にするために、frequency に50未満の値、あるいは20000を超えた値が代入された場合の処理は割愛した。

# Input the main frequency
multiplier = 100
writeInfoLine("Making Sounds")
soundType$ = "sineWave"

for i from 1 to 5
  frequency = multiplier * i
  # Make the name of the sound
  soundName$ = soundType$ + string$(frequency)
  do("Create Sound from formula...", soundName$, 1, 0.0, 1.0, 44100, "sin(2*pi*frequency*x)")
  appendInfoLine("Created ", soundName$)
  do("Play")
  appendInfoLine("Played ", soundName$)
  do("Remove") 
endfor

appendInfoLine("Finished")
この回で扱った内容を復習しよう
  1. なぜプログラミングでコピーは禁物なのか。
  2. 最後のスクリプトを書き換えて、200 Hz, 400 Hz, 600 Hzと周波数を200ずつ増やしていき、1000 Hzまでの正弦波の音が合成されるスクリプトにせよ。
  3. 最後のスクリプトを書き換えて、1000 Hz, 1100 Hz, 1200 Hzと周波数を100ずつ増やしていき、1400 Hzまでの正弦波の音が合成されるスクリプトにせよ。
  4. 最後のスクリプトを書き換えて、110 Hz, 220 Hz, 440 Hz, 880 Hz, 1760 Hz, 3520 Hzの正弦波の音が合成されるスクリプトにせよ。
  5. 最後のスクリプトを書き換えて、正弦波の音の代わりにのこぎり波の音を出すスクリプトにせよ。なお、1000 Hzののこぎり波の数式は、1000*x-floor(1000*x) である。
  6. 最後のスクリプトに、frequency に50未満の値、あるいは20000を超えた値が代入された場合の処理を付け加えよ。

本入門講座の続きは「Praatスクリプト入門(5):入力用ウィンドウを作る」というページをご覧いただきたい。