はじめに
この記事でOpusmodusの基本的な使い方は説明したので、この記事では便利な機能を紹介します。
でも、そもそもCommon Lispのループやマクロで普通に書けるような物も含まれているので、lispつよい人は自分でゴリゴリ書いてもいいと思います。
乱数系
ジェネラティブなクリエイションにおいて、もはやランダムは絶対正義です。
手っ取り早くいろんな物をつくることができますね。
rnd-pick
リストの中からランダムに一つ要素を取り出すことができます。
(setf pitch-set '(c4 db4 f4 g4 bb4 c5))
(rnd-pick pitch-set)
何回か評価すると、
1 > rnd-pick
db4
1 > rnd-pick
bb4
1 > rnd-pick
g4
実行する度に違う要素を取り出していますね。
rnd-sample
一度に何個か要素を取り出したい時もあります。
そんな時は、
(setf pitch-set '(c4 db4 f4 g4 bb4 c5))
(rnd-sample 5 pitch-set)
何回か評価すると、
1 > rnd-sample
(c5 bb4 bb4 c5 c4)
1 > rnd-sample
(g4 bb4 f4 bb4 bb4)
1 > rnd-sample
(c4 f4 db4 f4 bb4)
欲しい個数まとめてリストにして返してくれます。
rnd-unique
rnd-sample
は、指定した回数rnd-pick
をしているだけなので、同じ要素が取り出されることもあります。
そうじゃなくて指定した個数の固有な要素が欲しいときありますよね?
大丈夫です、それできるんです。
(setf pitch-set '(c4 db4 f4 g4 bb4 c5))
(rnd-unique 5 pitch-set)
何回か評価すると、
rnd-unique
(db4 f4 c4 bb4 g4)
1 > rnd-unique
(db4 c5 g4 bb4 f4)
1 > rnd-unique
(c4 f4 c5 bb4 g4)
毎回、被りなくランダムな要素を抽出することができました。
ベクタ系
サイン波、三角派、ホワイトノイズなどを使って、数学的にパラメーターを生成することもできます。
返り値は全てlispのベクタです。
また、ベクタを見やすくグラフで表示してくれるlist-plot
という関数があるので便利です。
gen-sine, gen-triangle, gen-sawtooth
たとえば、1200個の点からなる3回上下するサイン波を生成する場合、
(setf wave (gen-sine 1200 3 1))
評価すると、
1 > gen-sine
(0.0 0.15643448 0.309017 0.45399052 0.58778524 0.70710677 0.809017 0.8910065 0.95105654 0.98768836 1.0 0.98768836 0.9510565 0.89100647 0.809017 ... )
(※長いので省略。1200個入ってます)
似たような関数でgen-triangle
やgen-sawtooth
などがありますが波の形が違うだけで使い方は同じです。
vector-to-pitch
ベクタはそのままだと小数の集まりなので、なんらかの音楽的データに変換したいところです。
vector-to-pitch
を使って、C4からC6の音域の音高データに変換してみましょう。
(setf wave (gen-sine 32 3 1))
(vector-to-pitch '(c4 c6) wave)
評価すると、
1 > vector-to-pitch
(c5 g5 b5 c6 gs5 d5 g4 d4 c4 d4 g4 d5 gs5 c6 b5 g5 c5 f4 cs4 c4 e4 bb4 f5 bb5 c6 bb5 f5 bb4 e4 c4 cs4 f4)
⌘+3で表示すると、
ちゃんとサイン波の形に音高を生成することができました。
ほかにもvector-to-length
やvector-to-velocity
などを使うことで、音価やダイナミクスにマッピングすることも可能です。
tonality-map
vector-to-pitch
でベクタを変換すると、指定した音域内で、平均律でアトーナルにマッピングされます。
でもこれでは困ることもありますよね。
大丈夫です。スケールにマッピングできるんです
(setf wave (gen-sine 32 3 1))
(setf raw-pitch (vector-to-pitch '(c4 c6) wave))
(tonality-map '(major :root 'd4) raw-pitch)
ルートをD4にしてD majorにクオンタイズしました。
4 >
(d5 a5 cs6 d6 a5 e5 a4 e4 d4 e4 a4 e5 b5 d6 cs6 a5 d5 g4 d4 d4 fs4 b4 g5 cs6 d6 b5 g5 b4 fs4 d4 d4 g4)
繰り返し系
前回の記事では、omnを定数でベタ書きしていましたが、あんまり人間向きの方法ではありません。
必要最小限なパラメーター以外はなんらかの方法でループしたり再帰的に処理するのが吉でしょう。
gen-repeat
gen-repeat
を使うと、指定した回数omnをリピートさせることができます。
(gen-repeat 2 '(q c4 d4 e4))
評価すると、
1 > gen-repeat
(q c4 mf d4 e4 c4 d4 e4)
span
リストの長さを揃えて新しいリストを作りたい時に便利です。
例えば、先にピッチが生成されていて、そのピッチの個数分の音価を作りたい時などによく使います。
(setf my-pitch '(c4 d4 e4 f4 g4 a4 b4))
(span my-pitch '(e s s))
評価すると、
5 >
(1/8 1/16 1/16 1/8 1/16 1/16 1/8)
このようにピッチの個数分の音価データを作ることができました。
OMNを作る
音高や音価のデータをそれぞれ作った後、omnに変換するのはどうすればいいのでしょうか?
そのままの名前の関数があります。
make-omn
ここに音高と音価のデータがそれぞれあるじゃろ?
( ^ω^)
⊃ ⊂
(setf my-pitch '(c4 d4 e4 f4 g4 a4 b4))
(setf my-length (span pitch '(e s s)))
これを
( ^ω^)
⊃) (⊂
( ^ω^)
≡⊃⊂≡
こうじゃ…
(setf my-omn (make-omn :pitch my-pitch :length my-length))
( ^ω^)
⊃ .. ⊂
‘∵
‘:’;
6 >
(e c4 s d4 e4 e f4 s g4 a4 e b4)
まとめ
最後に、ここまでの内容をまとめた簡単なサンプル曲を書いてみました。
(setf wave (gen-sine 64 5 1))
(setf my-pitch
(tonality-map '(minor-pentatonic)
(vector-to-pitch
'(c4 c6)
wave
)
)
)
(setf my-length (span my-pitch '(s)))
(setf my-omn (make-omn :pitch my-pitch :length my-length))
(def-score qiita-tutorial-2
(:key-signature '(c minor)
:time-signature '(4 4)
:tempo 144)
(piano :omn my-omn)
)
(display-musicxml *last-score*)
(display-midi *last-score*)
Opusmodusで楽しく音楽をコーディングしよう!!
興味があったらTwitterもよろしくお願いします!