非公式チュートリアル06 バッハ平均律1-1プレリュード冒頭の音形を作成する
さて、ずっと基礎的な動作の説明が続くと退屈してしまうので、ここからしばらくは今まで習ったことを元に幾つかのサンプルパッチを作成してみよう。
ページ名を「バッハ平均律」などとしたが、別にこれから「フーガ自動作成パッチ」などという対位法の先生が聞いたらぶったまげそうな代物を作るわけではない。(それはそれで興味のあることだが。)
ここではバッハの平均律クラヴィーア曲集の第1巻第1番ハ長調プレリュード冒頭の音形を作成することを目的としてパッチを作成する。
この曲については皆良くご存知のことと思うが、念のため各種リンク。
ヨハン・ゼバスティアン・バッハ 平均律クラヴィーア曲集第1巻第1曲 BWV846 プレリュード
なお、ここでの最終的な出力は、今まで習ったことをふまえてchord-seqに出力してある。本来ならばvoiceを使うとよりスマートなのだが、それは後に学ぶこととする。
また重要なのは、和音はもちろんのこと、その和音の構成音の数、繰り返しの回数などをフレキシブルに設定し、それらの数値を変えることで異なる結果が出力されるようにすることである。このフレキシビリティが達成できれば、あらゆるパッチを作る時に細部の勘が働くようになるだろう。
まずはこの曲の第1小節を見てみよう。
まずアルペジオを構成する音列は、冒頭から5音目までで構成されていることが分かる。
冒頭の2音は繰り返されないで、引き延ばされる。
残りの3音は引き延ばされないが、2回繰り返される。
このようなフレーズの全体が、もう一度繰り返される。
冒頭の2音は繰り返されないで、引き延ばされる。
残りの3音は引き延ばされないが、2回繰り返される。
このようなフレーズの全体が、もう一度繰り返される。
これをOpenMusicに順次当てはめて行けば良い。
まずは、音の引き延ばしについては考慮せず、アルペジオを作ることからはじめる。
最初にchordを作成してorderモードにし、ドミソドミ(C4, E4, G4, C5, E5)の5音からなる和音を入力する。(必ずorderモードで編集し、5音の和音が下から順に並ぶようにすること。)
同じようにドレラレファ(C4, D4, A4, D5, F5)のchordおよび、シレソレファ(B3, D4, G4, D5, F5)のchordも作成する。これでchordは3つ並んだことになる。
listを用意し、inputを4つに増やす。input 0, input 1, input 2にそれぞれ順番に作ったchordのそれぞれoutput 1からのコードを繋ぐ。input 3にはinput 0と同じく最初のchordを繋ぐ。(画像参照)
まずは最初の和音を参照しよう。それにはlistで1つにまとめた4つの和音からなるリストの最初の項を見れば良い。ということは、ここで必要なのはfirstである。
firstで得た和音の項がどれだけあるかをlengthで調べておこう。ここでは5音であることは自明だが、このようにlengthを置くことで、異なる数値が入力されてもフレキシブルに対応できるようになる。
さてlengthの結果を用いてarithm-serで1つずつ増える数列を作るのだが、ここで問題となるのは、LISPは0からものを数えるということである。もしlengthの数値をそのまま入力したら、(0 1 2 3 4 5)となり、合計6つの値が出力される。それでは事が上手く運ばないので、(0 1 2 3 4)となるように、lengthの後に 1- を用いて数値を減らしておく。
さてこれで(0 1 2 3 4)の数値リストが確保できたので、その数値に従ってnthで和音の各音を参照すればアルペジオが作れそうである。ということは、上述の第1小節の分析で見た「繰り返される音符」を指定するには、(0 1 2 3 4 ''2 3 4'')と指定すれば良いであろうと察しがつく。
それにはどうするかというと、繰り返される音符の数だけの値をこのリストの後ろの方から取り出し、リストの後にもう一度くっつけたら良さそうである。くっつけるには x-append を使う。
- 参照:非公式チュートリアル1
では「繰り返される音符の数だけの値をこのリストの後ろの方から取り出す」にはどうするかというと、last-nを用いる。この左辺に先ほどのリストを、右辺に取り出す音符の数を入力すれば良い。ここでは3を指定する。この3の数値は後でも使うので、とりあえずコメントを入れておこう。
この非公式チュートリアルではまだコメントの入れ方について言及していなかったので、ここで触れておく。コメントを入れるには、右クリックでcommentを指定すれば良い。またはcommand+クリックで新しいオブジェクトを出してcommentと入力しても良いが、これは面倒なので前記の方法を覚えておこう。また、フォントを変えて日本語を入力すると一旦は上手く言ったように見えるが、あとで保存の時にエラーが出てうまくいかない。コメントは半角英数で書くこと。フランス語など西ヨーロッパ言語のアクセント記号も打てるが、半角英数でもギメ(フランス語のカギ括弧)などの特殊な記号は使えない。
last-nで「繰り返される音符の数」(ここでは3)を取り出したが、その音符を今度は「指定した数だけ繰り返す」。ここでは2回繰り返すのだが、すでに基本の和音の音列に繰り返される音符も含まれているため、指定した数より1-で1回少なくした回数だけ繰り返せば良い。そこで2を指定した後に1-を置き、その後でrepeat-nの左辺に先ほどのlast-nを、右辺に1-を繋いで繰り返す。
このrepeat-nを、先ほど用意したx-appendの右辺に繋ぐ。
さて今度はフレーズ全体を繰り返すので、その繰り返す回数(ここでは2)を指定して、もう一つrepeat-nを用意して繰り返す。
ここまでの出力は ((0 1 2 3 4 (2 3 4)) (0 1 2 3 4 (2 3 4))) となる。このままでは括弧の数が合わないので、flatで括弧を取り去ると (0 1 2 3 4 2 3 4 0 1 2 3 4 2 3 4) となる。
このリストに従って、和音「ドミソドミ」 (6000 6400 6700 7200 7600) を先ほどのリストの順番に読み出せば、例のメロディになるというわけである。
さて、ここでomloopを用意する。inputは3つ用意する。(画像参照)
今までは最初の和音に従って数値を用意して来たが、和音は複数(ここでは4つ)与えられているので、2番目以降の和音の数値を指定すればそれぞれを読み出せる。
今までは最初の和音に従って数値を用意して来たが、和音は複数(ここでは4つ)与えられているので、2番目以降の和音の数値を指定すればそれぞれを読み出せる。
まず右から見て行こう。ここには最初のlistのlength、つまり和音の数(ここでは4)が入っているが、LISPは0からものを数えるので、1-を与えて0から3まで数えるようにする。その0から3までを順次出力させるにはforloopを用いる。
input 1には、最初の和音の数(ここでは5)が入る。これをom*で掛ければ、0*5=0, 1*5=1, 2*5=10, 3*5=15 がそれぞれ得られる。
これを先ほどの数値リスト (0 1 2 3 4 2 3 4 0 1 2 3 4 2 3 4) に順次足していくと、その出力は
((0 1 2 3 4 2 3 4 0 1 2 3 4 2 3 4) (5 6 7 8 9 7 8 9 5 6 7 8 9 7 8 9) (10 11 12 13 14 12 13 14 10 11 12 13 14 12 13 14) (15 16 17 18 19 17 18 19 15 16 17 18 19 17 18 19))
となる。
あとはcollectを用意して、output 0はeachtimeに繋ぐ。output 1はfinallyに繋ぐ前にflatを加え、二重括弧を取り去ってからfinallyに繋ぐと、その出力は
(0 1 2 3 4 2 3 4 0 1 2 3 4 2 3 4 5 6 7 8 9 7 8 9 5 6 7 8 9 7 8 9 10 11 12 13 14 12 13 14 10 11 12 13 14 12 13 14 15 16 17 18 19 17 18 19 15 16 17 18 19 17 18 19)
となる。
ここでもう1つomloopを用意する。inputは2つ用意する。(画像参照)
左辺には上記の出力結果を入力する。右辺には、和音のlistをflatしたものを接続する。ただしここにom+を挟んでおくと、あとで移調が出来るので、ここで用意しておこう。
左辺には上記の出力結果を入力する。右辺には、和音のlistをflatしたものを接続する。ただしここにom+を挟んでおくと、あとで移調が出来るので、ここで用意しておこう。
omloopの内部を表示し、input 0にlistloopを繋ぐ。その下にnthを用意し、右辺にはinput 1を繋ぐ。
collectを用意し、output 0はeachTimeに、output 1はfinallyに繋ぐ。
これでいよいよchord-seqを用意し、input 1(左から2番目)に上述のomloopの出力を繋ぐ。
これでevaluateすると、確かに例のメロディは出てくるのだが、音価(音符の長さ)が間延びしている。これは音価の初期設定が1000ms(1秒)であるためである。
chord-seqでそれぞれの音符の長さを調節するには、input 2と3を用いる。(LISPは0からものを数えるので、ここでは左から3番目、4番目のインプットのことである。)
input 2は、それぞれのchordのタイミングを指定する。長さが違う場合はそれぞれ0から何秒目に音が出るかということを指定して行くのだが、この曲では(音符の引き延ばしではなく出だしのみを考慮すれば)音価は常に一定なので、ここでは(0 200)と入力すれば200ミリ秒が指定される。
input 3は、それぞれの音符の音価を指定する。とりあえずここでは引き延ばしを考慮せず、全ての音符に同じ音価を与えてみることにする。
ここで気をつけなければならないのは、input 3にはリストを与えるということである。そのため、単一の数値であっても括弧でくくっておく必要がある。
ここで気をつけなければならないのは、input 3にはリストを与えるということである。そのため、単一の数値であっても括弧でくくっておく必要がある。
そこでここでは (200) という数値ボックスを用意し、それをinput 3に繋ぐ。それから dx->x を用意し、左辺には0を、右辺には(200)のボックスを繋ぐ。これで(0 200)が出力されるので、それをinput 2に繋ぐ。
ではchord-seqを再生してみよう。(ここでは冒頭の音符の引き延ばしはまだ考慮されていないが、)例のメロディがきちんと出力されていれば、とりあえずここまでは上手く行ったということである。
次に進む前に、ここで今までの過程をサブパッチに収めておこう。
すでにパッチの画面は大量のオブジェクトとコードで埋め尽くされている。これらをメインパッチに置いたままさらに加筆して行くと、最終的にそのパッチは非常に見にくいものとなる。これはスパゲッティコードと呼ばれるもので、昔からプログラム業界では忌避されて来た。
すでにパッチの画面は大量のオブジェクトとコードで埋め尽くされている。これらをメインパッチに置いたままさらに加筆して行くと、最終的にそのパッチは非常に見にくいものとなる。これはスパゲッティコードと呼ばれるもので、昔からプログラム業界では忌避されて来た。
そのようにならないために、ある程度のまとまりをサブパッチに入れることで、パッチ全体の見通しが遥かに良くなる。
ただしここで、特にループに於けるワンスモードなど、サブパッチに入れる(ローカル化する)ことによって動作が替わってくるものがあるので、その点には十分気をつけなければいけない。
参照
サブパッチに収める際、数値を変更することによって出力結果を変える事が出来る数値は、サブパッチの外からinputで持ってくるようにすると良い。これでメインパッチに置いた数値さえ変更すれば、出力を変更することが出来る。
ここでのサブパッチ内のinputは5つ用意する(画像参照)。またそれぞれのinputには名前がつけられるので、分かりやすく名付けておこう。
これでだいぶメインパッチはすっきり見やすくなったはずだ。
では、いよいよ「冒頭の音符の引き延ばし」について見て行くことにしよう。
もう一つのサブパッチを用意しよう。
inputは5つ用意する。画像でのそれぞれのinputの番号と場所に注意。
inputは5つ用意する。画像でのそれぞれのinputの番号と場所に注意。
まず左から順に見て行こう。先にも述べたように、この曲は各音の出だしは常に同じ音価(16分音符)が与えられている。
ここではchord-seqの出力なので16分音符という指定はせず(そのような指定をするクラスはvoiceである)、ミリ秒単位での指定となる。
先ほどは200を指定したが、それはサブパッチのinputを用いてメインパッチからの引数とする。ここではその数値にlistで括弧を足し、dx->xに入れることで、先ほどと同じような(0 200)を出力することとする。これはoutput 0にそのまま繋げば良い。
ここではchord-seqの出力なので16分音符という指定はせず(そのような指定をするクラスはvoiceである)、ミリ秒単位での指定となる。
先ほどは200を指定したが、それはサブパッチのinputを用いてメインパッチからの引数とする。ここではその数値にlistで括弧を足し、dx->xに入れることで、先ほどと同じような(0 200)を出力することとする。これはoutput 0にそのまま繋げば良い。
さて、ここでいよいよ「引き延ばした音」の音価について考慮する。
冒頭の音は2分音符なので16分音符8個分。2音目は付点8分音符(16分音符3個分)と4分音符(16分音符4個分)がタイで繋がっているので、16音符7個分となる。
これはつまり、フレーズ全体の数およびそれから1つ(ずつ)引いた数の16分音符の個数分の音価がそれぞれ必要になるということである。
フレーズの中のリピートする音符の数というのは、先ほども指定した。それをメインパッチに置いて1個目のサブパッチに引き込む形にしたので、同じ数値から引っ張ってくれば良い。
和音の構成音の数-リピートする音符の数*断片のリピートの回数 = リピートしない音符、つまり引き延ばされる音符の数である。逆に、
和音の構成音の数+リピートする音符の数*(断片のリピートの回数-1) = フレーズ全体の音符の数となる。
和音の構成音の数+リピートする音符の数*(断片のリピートの回数-1) = フレーズ全体の音符の数となる。
ここまでの説明を良く理解できていたら、このomloopの中身は明解である。
アルペジオのフレーズ全体の数(ここでは8)から、リピートしないで伸ばす音の数(ここでは2)に1-で1引いた数を順に引いて行く。LISPは0からものを数えるので、ここでのforloopの最初は0である。
8-0=8, 8-1=7で、この数値が先に述べた16分音符8個分ないし7個分にあたる。
それに音符1個分の長さ(ここでは200ms)を掛けた数が、保続する音の長さとなる。これで(1600 1400)という出力を得られたことになる。
8-0=8, 8-1=7で、この数値が先に述べた16分音符8個分ないし7個分にあたる。
それに音符1個分の長さ(ここでは200ms)を掛けた数が、保続する音の長さとなる。これで(1600 1400)という出力を得られたことになる。
ではomloopからサブパッチに戻ろう。保続しない音符は、その数だけ200を繰り返せば良いので、ここではrepeat-nを置き、x-appendで結合している。
ここでの出力は (1600 1400 200 200 200 200 200 200) となる。
ここでの出力は (1600 1400 200 200 200 200 200 200) となる。
さらにこれを、フレーズ全体の繰り返しの数だけ繰り返せば良いので、さらにrepeat-nを置き、最後にflatで多重括弧を除去して、その結果をoutput 1からメインパッチに出力すれば良い。
メインパッチに戻り、今のサブパッチの2つのアウトプットをそれぞれchord-seqのinput 2, 3に繋ぐ。
これで音符が伸ばされたことになる。chord-seqを開き、左下の上の部分をdurに変更する。音符の右に棒線が伸びているので、正しい長さかどうか確認しよう。
最後に、これは楽譜に直接書いていないことだが、冒頭2音の伸ばされた音と、伸ばさないで繰り返される音とを、別々のMIDIチャンネルで出力してみよう。
構成は今までのサブパッチと同様である。
和音のリストの冒頭firstの長さlengthに、リピートする音の長さおよびその回数に1引いたものを掛けたものを足したのが全体のフレーズである。またそのlengthからリピートする音を引いたものが、リピートしないで保続する音である。これの数だけMIDI ch.として2をリピートし、あとはフレーズの残りの音の数MIDI ch.として1をリピートする。それをフレーズ全体のリピート数および和音の数と掛ければ、全体の必要総数がリピートされる。
よってここでの出力は、
よってここでの出力は、
(2 2 1 1 1 1 1 1 2 2 1 1 1 1 1 1 2 2 1 1 1 1 1 1 2 2 1 1 1 1 1 1 2 2 1 1 1 1 1 1 2 2 1 1 1 1 1 1 2 2 1 1 1 1 1 1 2 2 1 1 1 1 1 1)
となる。これをchord-seqのinput 6(右から2番目)に繋ぐ。
メインパッチのchord-seqへ戻り、先ほどのdurを見てみると、今度は色が変わっているのが分かる。
またchannelを見てみると、それぞれの音符の脇にMIDI ch.の番号が表示される。
さて、MIDIチャンネルを変更したので、音色を変えてみよう。MIDIの音色変更にはpgmoutをevaluateすれば良い。
このように左辺にそれぞれの音色番号、右辺に対応するチャンネルを書く。また複数の変更はリストで一度に指定できる。
これで完成。
パッチの全体像はこのようになる。
パッチは完成したわけだが、話はこれで終わりではない。
せっかくフレキシブルにパラメータを変更できるように作ったのだから、パラメータを変更して異なる出力結果を見るのが重要だ。
上記画像のうち、
repeat time of each arpeggios を 3 に、
number of repeated notes を 2 に、
repeat time of the fragment of arpeggio を 5 に、
transposition を 200 に、
それぞれ変更してみよう。
repeat time of each arpeggios を 3 に、
number of repeated notes を 2 に、
repeat time of the fragment of arpeggio を 5 に、
transposition を 200 に、
それぞれ変更してみよう。
chord-seqの出力結果はこうはるはずだ。
ここで出力結果に何らかの異常があるということは、サブパッチの数式が上手く行っていないということだ。筆者もそれで何回もデバッグした。
デバッグには2種類ある。(これはどのプログラム言語にも共通する。)
ひとつは明確なエラーが出るもの。OpenMusicやMax/MSPあるいはBASICのようなインタプリタ言語なら途中で動きが止まるし、C言語やJavaのようなコンパイラ言語ならコンパイル時にエラーが出る。(厳密にいえばBASICコンパイラやCインタプリタは存在する。)
もう一つはエラーこそでないものの、期待したのと違う動きをするものである。
ひとつは明確なエラーが出るもの。OpenMusicやMax/MSPあるいはBASICのようなインタプリタ言語なら途中で動きが止まるし、C言語やJavaのようなコンパイラ言語ならコンパイル時にエラーが出る。(厳密にいえばBASICコンパイラやCインタプリタは存在する。)
もう一つはエラーこそでないものの、期待したのと違う動きをするものである。
一件上手く行ったように思えても、パラメータをわざと変えてみて、それに見合った動きをせず予想外の動きをするようであれば、そのプログラムにはバグがあるといえる。
全て上手く動くことを確認できたら、さらに改造して遊んでみよう。
最も簡単にできるのは、和音を変更することである。listのinputの数を足して、より多くの和音を与えることが出来る。
例えば上記画像の和音は、メシアンの「わが音楽語法 Mon language musical」第14章で提示されているvitrail(ヴィトライユ、英語でいうステンドグラス)と呼ばれる和音である。
これを用いてアルペジオの数値を調節すれば、バッハの平均律クラヴィーア曲集のプレリュードの音形であるにもかかわらず、メシアン風の響きを持つ音響が現れるというわけである。
これを用いてアルペジオの数値を調節すれば、バッハの平均律クラヴィーア曲集のプレリュードの音形であるにもかかわらず、メシアン風の響きを持つ音響が現れるというわけである。
もちろん、メシアンの語法は単なる和音ではなくリズムについても複雑な理論を伴うものなので、ただ単にアルペジオを並べても、それは真のメシアンの語法ではない。(この件については、後に扱うこととする。)
しかしながら、今までのパッチに例えば nth-random や permut-random を挟み込むこともできるし(ローカリティの問題があるので、repeat-nでの繰り返しをomloopに入れ替えるなどの工夫が必要)、あるいは現時点では全ての和音が同じ構成音数であることが前提だが、異なる構成音数の和音に対応させるには、アルゴリズムそのものの大胆な改造が必要になってくる。
今回の説明は非常に長いものだったが、このパッチを元にしつつ、乱数など色々な手を加えてみて、自分の創作の助けになるようなパッチを作ってみるのも一つの楽しみだろう。色々いじくりながら、自分なりの「創作補助」のパッチを作ってみてほしい。OpenMusicはあくまで「自動作曲」ではなく、「作曲補助」の手段として重要なのである。
参照
非公式チュートリアル 前後
添付ファイル
- unofficial-tutorial06-1.png
- unofficial-tutorial06-10.png
- unofficial-tutorial06-10_.png
- unofficial-tutorial06-11.png
- unofficial-tutorial06-11_.png
- unofficial-tutorial06-12.png
- unofficial-tutorial06-12_.png
- unofficial-tutorial06-2.png
- unofficial-tutorial06-2_.png
- unofficial-tutorial06-3.png
- unofficial-tutorial06-3_.png
- unofficial-tutorial06-4.png
- unofficial-tutorial06-4_.png
- unofficial-tutorial06-5.png
- unofficial-tutorial06-5main.png
- unofficial-tutorial06-5main_.png
- unofficial-tutorial06-5_.png
- unofficial-tutorial06-6-1.png
- unofficial-tutorial06-6-2.png
- unofficial-tutorial06-6-2_.png
- unofficial-tutorial06-6.png
- unofficial-tutorial06-7.png
- unofficial-tutorial06-7_.png
- unofficial-tutorial06-8.png
- unofficial-tutorial06-8_.png
- unofficial-tutorial06-9.png
- unofficial-tutorial06-chordseq1.png
- unofficial-tutorial06-chordseq1_.png
- unofficial-tutorial06-chordseq2.png
- unofficial-tutorial06-chordseq2_.png
- unofficial-tutorial06-chordseq3.png
- unofficial-tutorial06-chordseq3_.png
- unofficial-tutorial06-chordseq4.png
- unofficial-tutorial06-chordseq4_.png
- unofficial-tutorial06-chordseq5.png
- unofficial-tutorial06-chordseq5_.png
- unofficial-tutorial06.png