MIDI と竹内関数

### javax.sound.midi を使って MIDI を鳴らします

もう少し正確に言うと, OS の方で設定されている MIDI 音源に MIDI メッセージを送ります.
適当な MIDI ファイル (拡張子 .mid) を探してきて, ダブルクリックで鳴るようようなら, 鳴るでしょう.

デフォルトのシンセサイザーで, チャンネル 0 番に, 音色デフォルト (たぶんピアノになっているでしょう) で,
C4 (ノート番号 48) の音を, ベロシティ 64 で, 1000ミリ秒鳴らすには,

```clj
(with-open [synth (doto (javax.sound.midi.MidiSystem/getSynthesizer) .open)]
  (let [channel (aget (.getChannels synth) 0)]
    (.noteOn channel 48 64)
    (Thread/sleep 1000)
    (.noteOff channel 48 64)))
```

とします.

MIDI メッセージは, 元々は楽器の操作を転送するものなので, 「何秒間鳴らす」というメッセージではなく,
「打鍵した」というメッセージ (note on) と「離鍵した」というメッセージ (note off) を,
適当なタイミングで送ることで, 音を鳴らしたり止めたりします.

ノート番号は 0~127 で半音単位で指定します. 48 が C4 (真ん中のド) です.
どんな音律で演奏するかは, 音源側に委ねられますが, 普通は何も設定しなければ 12平均律になっているでしょう.

ベロシティは「速度」という意味ですが, これも, 打鍵の速さを情報として送るところから来ています.
大抵の音源は, この打鍵速度の情報に基づいて音量を決めますので, さしあたり音量と考えても良いと思います.
0~127 で指定します.

もう少し高レイヤーが好みの方は, 便利なライブラリが沢山ありますので, そちらをどうぞ.
「俺が MIDI ソフトを作る」という低レイヤーの好きな方はいろいろ試してみてください.

以上です. というのもなんなのでもう少し.

### 竹内関数の引数の変遷を遅延シーケンスに

LISPer 大好き竹内関数です.

```clj
(defn tarai [x y z]
  (if (<= x y) y
    (tarai (tarai (dec x) y z)
           (tarai (dec y) z x)
           (tarai (dec z) x y))))
```

説明要らないですね.
さて, この竹内関数が再帰的に呼び出されている時の引数を, たらい回されている最中に知りたいとします.

```clj
(defn tarai [x y z]
  (println x y z)
  (if (<= x y) y
    (tarai (tarai (dec x) y z)
           (tarai (dec y) z x)
           (tarai (dec z) x y))))
```

```clj
user=> (tarai 2 1 0)
2 1 0
1 1 0
0 0 2
-1 2 1
1 0 2
0 0 2
-1 2 1
1 1 0
0 2 1
2
```

見る事はできますが, 使えないですね.

ちょっと手を加えて, 左の引数から順に正格評価されると仮定した場合に,
この関数が呼ばれた時の引数を遅延シーケンスで得られるようにしましょう.

```clj
(defn args-and-result [x y z]
  (if (<= x y) [[[x y z]] y]
    (let [[a0 r0] (args-and-result (dec x) y z)
          [a1 r1] (args-and-result (dec y) z x)
          [a2 r2] (args-and-result (dec z) x y)
          [a3 r3] (args-and-result r0 r1 r2)]
      [(cons [x y z] (lazy-seq (concat a0 a1 a2 a3))) r3])))

(defn args [x y z] (first (args-and-result x y z)))
```

args 関数に竹内関数の引数を与えると, 3つの引数をベクタにしたものの遅延シーケンスが得られます.

```clj
user=> (args 2 1 0)
([2 1 0] [1 1 0] [0 0 2] [-1 2 1] [1 0 2] [0 0 2] [-1 2 1] [1 1 0] [0 2 1])
```

また

```clj
(defn view-args [x y z t]
  (doseq [xyz (args x y z)]
    (println xyz)
    (Thread/sleep t)))
```

などとすれば t ミリ秒毎に, 引数の変遷を見る事ができます.

```clj
user=> (view-args 2 1 0 500)
[2 1 0]
[1 1 0]
[0 0 2]
[-1 2 1]
[1 0 2]
[0 0 2]
[-1 2 1]
[1 1 0]
[0 2 1]
nil
```

### 竹内関数で音楽生成

さて, [竹内関数で音楽生成](http://d.hatena.ne.jp/aike/20111112) という素敵なエントリをご存知でしょうか?
もしご存知でなければ, 是非ご覧に(お聞きに)なった上で, ここに戻ってきてください.

aike さんによる音楽生成を簡易に再現してみましょう.
ここでは, 和音を順番に鳴らすにとどめ, 自動アルペジオ機能はみなさんへの課題とします.

```clj
; 演奏中に音名も表示したいので,
(defn nn2name [nn]
  ({0 "c"   1 "cis" 2 "d"   3 "es"  4 "e"   5 "f"
    6 "fis" 7 "g"   8 "as"  9 "a"  10 "b"  11 "h"}
   (mod nn 12)))

; たらい回しの各回で, 引数を表示し且つ, arg2nn で指定された「引数 -> ノート番号」の対応に従い,
; t ミリ秒間, 和音を鳴らします.
(defn listen-args [x y z arg2nn t]
  (with-open [synth (doto (javax.sound.midi.MidiSystem/getSynthesizer) .open)]
    (let [channel (aget (.getChannels synth) 0)]
      (doseq [xyz (args x y z)]
        (println (apply str
                   (mapcat #(let [nn (arg2nn %)]
                              [% " -> (" (nn2name nn) "[" nn "])\t"]) xyz)))
        (dorun (map #(.noteOn channel (arg2nn %) 64) xyz))
        (Thread/sleep t)
        (dorun (map #(.noteOff channel (arg2nn %) 64) xyz))))))

; aike さんの割当: 0 を E4 として, ハ長調のダイアトニックトーンに割り当てます.
(def e-ph
  {-2 48 -1 50 0 52 1 53 2 55 3 57 4 59 5 60 6 62 7 64 8 65 9 67 10 69})

; 別の割当も試してみましょう.
(def c-io
  {-2 45 -1 47 0 48 1 50 2 52 3 53 4 55 5 57 6 59 7 60 8 62 9 64 10 65})
```

```clj
user=> (listen-args 2 1 0 c-io 1200)
2 -> (e[52])	1 -> (d[50])	0 -> (c[48])	
1 -> (d[50])	1 -> (d[50])	0 -> (c[48])	
0 -> (c[48])	0 -> (c[48])	2 -> (e[52])	
-1 -> (h[47])	2 -> (e[52])	1 -> (d[50])	
1 -> (d[50])	0 -> (c[48])	2 -> (e[52])	
0 -> (c[48])	0 -> (c[48])	2 -> (e[52])	
-1 -> (h[47])	2 -> (e[52])	1 -> (d[50])	
1 -> (d[50])	1 -> (d[50])	0 -> (c[48])	
0 -> (c[48])	2 -> (e[52])	1 -> (d[50])	
nil
```

音名で表示されている和音が演奏されましたか?

```clj
user=> (listen-args 10 5 0 e-ph 1200)
10 -> (a[69])	5 -> (c[60])	0 -> (e[52])	
9 -> (g[67])	5 -> (c[60])	0 -> (e[52])	
8 -> (f[65])	5 -> (c[60])	0 -> (e[52])	
7 -> (e[64])	5 -> (c[60])	0 -> (e[52])	
6 -> (d[62])	5 -> (c[60])	0 -> (e[52])	
5 -> (c[60])	5 -> (c[60])	0 -> (e[52])	
4 -> (h[59])	0 -> (e[52])	6 -> (d[62])	
3 -> (a[57])	0 -> (e[52])	6 -> (d[62])	
2 -> (g[55])	0 -> (e[52])	6 -> (d[62])	
...
```

とすると aike さんの動画と同じ和音の変遷が聞けます.  343,073 小節あるので気をつけてください.

クリスマス関係なくてすみません.
core.async も使ってなくてすみません.