Opusmodusで便利な関数たち

# はじめに
[この記事](https://qiita.com/Yuichi_Yogo/items/44182458cb42029c4e9e)でOpusmodusの基本的な使い方は説明したので、この記事では便利な機能を紹介します。
でも、そもそもCommon Lispのループやマクロで普通に書けるような物も含まれているので、lispつよい人は自分でゴリゴリ書いてもいいと思います。

# 乱数系

ジェネラティブなクリエイションにおいて、もはやランダムは**絶対正義**です。
手っ取り早くいろんな物をつくることができますね。
## rnd-pick
リストの中からランダムに一つ要素を取り出すことができます。

```clojure
(setf pitch-set '(c4 db4 f4 g4 bb4 c5))
(rnd-pick pitch-set)
```
何回か評価すると、

```clojure
1 > rnd-pick
db4
1 > rnd-pick
bb4
1 > rnd-pick
g4
```
実行する度に違う要素を取り出していますね。

## rnd-sample
一度に何個か要素を取り出したい時もあります。
そんな時は、

```clojure
(setf pitch-set '(c4 db4 f4 g4 bb4 c5))
(rnd-sample 5 pitch-set)
```

何回か評価すると、

```clojure
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`をしているだけなので、同じ要素が取り出されることもあります。
そうじゃなくて指定した個数の固有な要素が欲しいときありますよね？
**大丈夫です、それできるんです。**

```clojure
(setf pitch-set '(c4 db4 f4 g4 bb4 c5))
(rnd-unique 5 pitch-set)
```
何回か評価すると、

```clojure
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回上下するサイン波を生成する場合、

```clojure
(setf wave (gen-sine 1200 3 1))
```
評価すると、

```clojure
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個入ってます）

`list-plot`した結果が
![Screenshot 2018-09-03 07.07.29.png](https://qiita-image-store.s3.amazonaws.com/0/148589/fbc0c362-1f0e-eff3-b589-0688ea86548a.png)

似たような関数で`gen-triangle`や`gen-sawtooth`などがありますが波の形が違うだけで使い方は同じです。

gen-triangle
![Screenshot 2018-09-03 07.11.11.png](https://qiita-image-store.s3.amazonaws.com/0/148589/320c4121-7441-f4dc-ba96-2f7074a9cd97.png)

gen-sawtooth
![Screenshot 2018-09-03 07.12.07.png](https://qiita-image-store.s3.amazonaws.com/0/148589/e3688857-29e4-0391-8122-aa5aded7ce95.png)

## vector-to-pitch
ベクタはそのままだと小数の集まりなので、なんらかの音楽的データに変換したいところです。
`vector-to-pitch`を使って、C4からC6の音域の音高データに変換してみましょう。

```clojure
(setf wave (gen-sine 32 3 1))
(vector-to-pitch '(c4 c6) wave)
```
評価すると、

```clojure
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で表示すると、
![Screenshot 2018-09-03 07.18.57.png](https://qiita-image-store.s3.amazonaws.com/0/148589/4a24b4fc-298b-fb8d-e61f-b941bfc4baf2.png)
ちゃんとサイン波の形に音高を生成することができました。

ほかにも`vector-to-length`や`vector-to-velocity`などを使うことで、音価やダイナミクスにマッピングすることも可能です。

## tonality-map
`vector-to-pitch`でベクタを変換すると、指定した音域内で、平均律でアトーナルにマッピングされます。
でもこれでは困ることもありますよね。
**大丈夫です。スケールにマッピングできるんです**

```clojure
(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にクオンタイズしました。

```clojure
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)
```
![Screenshot 2018-09-03 07.26.53.png](https://qiita-image-store.s3.amazonaws.com/0/148589/dcac31f4-1eee-9749-f2e2-26ebf9a34c31.png)


# 繰り返し系
前回の記事では、omnを定数でベタ書きしていましたが、あんまり*人間向きの方法*ではありません。
必要最小限なパラメーター以外はなんらかの方法でループしたり再帰的に処理するのが吉でしょう。
## gen-repeat
`gen-repeat`を使うと、指定した回数omnをリピートさせることができます。

```clojure
(gen-repeat 2 '(q c4 d4 e4))
```
評価すると、

```clojure
1 > gen-repeat
(q c4 mf d4 e4 c4 d4 e4)
```

![Screenshot 2018-09-03 06.30.54.png](https://qiita-image-store.s3.amazonaws.com/0/148589/0d862824-d856-0038-ce8d-13e52a2ebdf7.png)
指定した回数（2回）繰り返されています。

## span
リストの長さを揃えて新しいリストを作りたい時に便利です。
例えば、先にピッチが生成されていて、そのピッチの個数分の音価を作りたい時などによく使います。

```clojure
(setf my-pitch '(c4 d4 e4 f4 g4 a4 b4))
(span my-pitch '(e s s))
```
評価すると、

```clojure
5 > 
(1/8 1/16 1/16 1/8 1/16 1/16 1/8)
```
![Screenshot 2018-09-03 07.36.56.png](https://qiita-image-store.s3.amazonaws.com/0/148589/8b47e4b1-b4f5-ad83-1e45-f697e15220b3.png)

このようにピッチの個数分の音価データを作ることができました。


# OMNを作る
音高や音価のデータをそれぞれ作った後、omnに変換するのはどうすればいいのでしょうか？
そのままの名前の関数があります。
## make-omn
ここに音高と音価のデータがそれぞれあるじゃろ？
( ＾ω＾) 
⊃ 　⊂ 

```clojure
(setf my-pitch '(c4 d4 e4 f4 g4 a4 b4))
(setf my-length (span pitch '(e s s)))
```

これを
( ＾ω＾) 
⊃)　 (⊂ 

( ＾ω＾) 
≡⊃⊂≡ 

こうじゃ…

```clojure
(setf my-omn (make-omn :pitch my-pitch :length my-length))
```
( ＾ω＾)
⊃ .. ⊂ 　 
‘∵ 　 
‘:’;

```clojure
6 > 
(e c4 s d4 e4 e f4 s g4 a4 e b4)
```
合体完了！
![Screenshot 2018-09-03 07.44.37.png](https://qiita-image-store.s3.amazonaws.com/0/148589/65dcdeeb-7234-3f94-7466-8b562d581a3c.png)

# まとめ
最後に、ここまでの内容をまとめた簡単なサンプル曲を書いてみました。

```clojure

(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*)
```
![Screenshot 2018-09-03 07.51.11.png](https://qiita-image-store.s3.amazonaws.com/0/148589/98df9aae-8991-2cb6-e0ea-cdeed27ddf21.png)


Opusmodusで楽しく音楽をコーディングしよう！！
興味があったら[Twitter](https://twitter.com/yuichi_yogo)もよろしくお願いします！