Haskellでの 音楽表現

以前,[Clojureで音楽組織プログラミング](http://qiita.com/nobkz/items/aea2c70a5fb03003f375)について書いた。

それを今度はHaskellで書こうと思う。

# Haskellによる音楽構造プログラミングについて。

## プログラマが音楽することについて

### 音楽家でない人が新しい音楽を作ることだってある

現代音楽では有名なヤニス クセナキスという人がいました。彼は音楽家を目指す以前は、建築家であり数学に堪能な人でした。そして、音楽家を目指し、そして偉大な現代音楽家オリヴィエ・メシアンに、師事し、尋ねました。

 **音楽家になるために、私は音楽の理論を学びたい。何を学ぶべきでしょうか?**

そして、メシアンは言いました。

**君は数学を知っている。なぜそれを作曲に応用しないのか。伝統的な修練は、あってもなくても同じではないか**

そして、クセナキスは気づきました。そして、音楽の構築に彼の持つ数学的な知識、建築の感覚を音楽に応用して、新しい音楽を作曲していきます。大変すごい言葉だと思います。そして、それはプログラマに対しても使えると僕は思います。メシアンの先の言葉を借りると、

**君はプログラミングを知っている。なぜそれを作曲に応用しないのか。伝統的な修練は、あってもなくても同じではないか**

という訳です。

さて、実際にクセナキスは音楽の構築するために、彼独自の **楽譜** を作成し構築していました。
これがその楽譜です。

![img_1426615_47725713_2.jpeg](https://qiita-image-store.s3.amazonaws.com/0/31381/925f3192-20a3-b155-f7ae-7687059605b5.jpeg)

![fig_1.gif](https://qiita-image-store.s3.amazonaws.com/0/31381/b436af18-3a24-a39e-db02-8d975d6b3959.gif)

非常に数学的、建築的な楽譜だと思います。クセナキスが独自に楽譜を作り音楽を構造にし、これを実際には、五線楽譜になり、演奏家に演奏をさせていました。

さて、彼がこのように楽譜を書いて作曲していたのであれば、ではプログラマの楽譜とはどのようになるのでしょうか?これが今回の本題です。そしてそれは僕は、「プログラミングのコード」そのものであると思います。

##Super Colliderについてちょっとだけ

###

さて、今回、Haskell + SuperColliderで音楽をプログラミングしていくわけですが、簡単にSuperColliderについて紹介して、おきます。

SuperColliderは、音楽プログラミング言語であり環境です。Super Colliderをは、内部クライアントとサーバを持っています。クライアントでプログラミングして言語を解釈し、それをScsynthサーバに投げ、サーバが音楽を鳴らすというわけです。アーキテクチャは以下のような感じです。

![スクリーンショット 2013-12-12 10.33.59.png](https://qiita-image-store.s3.amazonaws.com/0/31381/078acab0-5b9e-bfcc-babd-ab527bf4d2cc.png)


### hsc3について

hsc3は、そのSuperColliderクライアントです。

### インストールとか

インストールは

```bash
cabal install hsc3
```

です。んで、なんか、emacs-modeが用意されているので、.emacsやら、.emacs.d/init.elやらに、設定を追加します。

```el
(add-to-list 'load-path ".cabal/hsc/yourpath/emacs")
(setq hsc3-help-directory ".cabal/hsc/yourpath/Help/")
(require 'hsc3)
```

パスは適当なものを設定しておいてください。

### SCサーバを立ちあげる。

インストールされた、scsynthでやる。Mac だとこんな感じ。

```bash
/Applications/SuperCollider/SuperCollider.app/Contents/Resources/scsynth -u 57110
```

### てきとーになんか鳴らす

まず、emacsを立ちあげ、M-x hsc3-mode にします。そして、C-c > (>も入力してね。)すると、Replが立ち上がります。

んで、

```hs
import Sound.SC3

withSC3 (send (g_new [(1, AddToTail, 0)]))
audition (out 0 (sinOsc AR 440 0 * 0.1))
```

で,440HzのSin波が出力されます。んで、止めるときは

```hs
withSC3 reset
```

で、とりあえず止まります。

## Haskellによる音楽プログラミング

さて、Super Colliderについてはいろいろググって参照してもらうとして、

ここでは、Haskellでどう音楽を作っていくかについて、方法を述べていきたいと思います。

### 考えかたについて

僕は音楽プログラミングをするとき、大きく分けて2つのデータを記述することを考えています。

*  楽譜的データ
*  演奏情報的データ

楽譜的なデータとは、みなさんが思い浮ぶような五線楽譜のようなものではなく、むしろ、図形楽譜に近い考えをしています。どういうことかといえば、自由に解釈され演奏されうる、楽曲構造を表わしているということです。

そして、演奏情報データとは、その楽譜的なデータを解釈して、実際に音を作るデータのことです。

###  楽譜的データについて

以前、[Clojureで音楽組織プログラミング](http://qiita.com/nobkz/items/aea2c70a5fb03003f375)について書いたのは、基本的に楽譜的なデータをプログラミングで記述すべきということを書きました。

前回はリストで表わしていましたが、 **楽譜的なデータは別にそれはリストじゃなくても良くなんでもいい** のです。どのように解釈しても良いわけですし、演奏情報に解釈できれば良いのですから。ただリストは扱いやすかったから採用しただけです。

ちなみに、今回の楽譜的データというのはどのように時間的に音を配置するかという **時間的構造** として作成します。どういうことかといえば、楽譜的データの記述は実は **時間的構造以外にもありうる** ということも念頭に置いてください。

さて何かモチーフとなるデータを作っておきます。

```hs
sample = [1,1,3,3]
```

さてこれをどんどん好きに組みあわせて行きましょう

```hs
sample2 = sample ++ sample ++ reverse sample ++ [0,1,0]
sample3 = map (+2) sample2
```

好きに構造を大きくしても構いません。モチーフをつくるセンスは問われますが。自分は普段は2つの対比的データをつくり(たとえば変化が大きい、小さいなど)、組みあわせます。

ここで、どう構造化するか?について理論的なものを考えてみたいですけどね。

### 演奏情報のデータをつくる

さて、ここでは、 楽譜的なデータがInt型のリストなので、リストの要素を取りInt型に出力音を対応づけます。

```hs
performList list period inst = 
    let 
        interval = Constant_U $ Constant $ 1 / realToFrac (length list)
        freq =  Constant_U $ Constant $ realToFrac (1/period)
        z = impulse AR freq 0
    in
      foldr1 (+) $ map (\ (i,x) -> 
                            (toggleFF ((tDelay z $ i * interval * period ) +
                                       (tDelay z $ (i + 0.5)  * interval * period ))) *
                            (inst x)) $ zip [0..] list

```

さて、ここで, listと、period, instのデータがありますが、 **完全には演奏情報データは作らない** 良いと思います。なんでかっていると、作曲中、楽曲の時間構造などもまだつくられてなく、むしろ、**楽曲構造と演奏情報を互いに補いつつ楽曲を完成させていく** のが大事になってきます。

とは言うものの、 実際に音を出さないとつまらないので、音を出しましょう。(というより、実際にはもっと早くから音を聞いてます。)

### とりあえず音をならす

とりあえず以下のコードとで音を出しました。

```hs
phrase2 = performList sample3 5 (\ x -> saw AR (x * 200))
audition (out 0 phrase2)
```

音を実際に鳴らした時のやつ。
http://www.youtube.com/embed/xqdnujRfFrg



### 楽譜的データと演奏情報の混在するデータを更に組み合せる

基本的にフレームワークやデータ構造によりますが、さらに組みあわせることによって、音楽に構造をもっと持たせるようにします。

ただしこの時、以前決めたことや、フレームワークに依る制約によってどんどん、自由度が少なくなっていきます。

```hs
sawPhrase1 = performList sample3 10 (\ x -> saw AR (x * 200))
sawPhrase2 = performList sample3 5 (\ x -> saw AR (x * 200))
sawPhrase3 = performList sample3 1 (\ x -> saw AR (x * 200))

sawPhrase = sawPhrase1 + sawPhrase2 + sawPhrase3

sinPhrase1 = performList sample3 10 (\ x -> sinOsc AR (x * 200) 0)
sinPhrase2 = performList sample3 5 (\ x -> sinOsc AR (x * 200) 0)
sinPhrase3 = performList sample3 1 (\ x -> sinOsc AR (x * 200) 0)

sinPhrase = sinPhrase1 + sinPhrase2 + sinPhrase3
```

###  音を鳴らす

さて、また音を鳴らしてみましょう。

```hs
audition (out 0 sawPhrase4)
audition (out 0 sinPhrase4)
```

あと、適当に制作風景を流しまう。
http://www.youtube.com/embed/33om5LlFbEg

ブログ内で完成させる予定だったけど。
 **曲完成できなかった** 

## 最後にまとめ

最後にいろいろしましたが、

* プログラミングの音楽についての僕なりの考え
* Haskell + SuperCollider
* 演奏情報と時間的音楽構造によるプログラミング

について述べさせて頂きました。

### 曲完成できなかった。

言いわすれてたけど、曲を一曲完成させるつもりでした。

敗因 ：： 軽くなんかつくろうとおもったら、いろいろ凝りすぎた。凝り性つらい。

### あと書きたかったこと

モナドを使った音楽を書こうとしたけど、それには僕の時間が余りにも足りない!!!
実はもっと色々書きたかったけど、結局浅い内容になってしまいました。

実際に、Haskellらしい構文、表現における音楽性についてもっと書きたかった.....

## おまけ

紹介しようと思って、かいたけど、結局つかわなかったコード群

* なんかノイズ音楽作ろうと思ったけど、一般向けにはコア過ぎてアレだったやつ。

```hs
performNoize period =
    let
        freq =  Constant_U $ Constant $ realToFrac (1/period)
        z = impulse AR freq 0
        z' = tDelay z (0.5 * period)
        o = whiteNoise 'a' AR * 0.8
    in 
      mce [z * 0.1,toggleFF z' * o]
```

* なんかワンライナーで強引に書いたやつ。セミコロンあるからアレ。しかも曲になっているというw...

```hs
let {compose = foldl (flip (.)) id; rvb z s = let f i = let dly = mce [rand (z `joinID` i `joinID` 'a') 0 0.5 ,rand (z `joinID` i `joinID` 'b') 0 0.5] in allpassN i 0.05 dly (rand i 1.5 2) in compose (replicate 5 f) s; stpr = let {rate = mouseX KR 1.75 2.25 Exponential 0.1; clock = impulse KR rate 0; envl = decay2 clock 0.002 2.5; indx = stepper clock 0 0 15 1 0; freq = bufRdN 1 KR 10 indx Loop; ffreq = lag2 freq 0.1 + mce [0,0.3]; lfo = sinOsc KR 0.2 (mce [0,pi/2]) * 0.0024 + 0.0025; top = mix (lfPulse AR (freq * mce [1,1.5,2]) 0 0.3); chn = [\s -> rlpf s ffreq 0.3 * envl ,\s -> rlpf s ffreq 0.3 * envl,\s -> s * 0.5 ,\s -> combL s 1 (0.66 / rate) 2 * 0.8 + s ,\s -> s + (rvb 'a' s * 0.3) ,\s -> leakDC s 0.1 ,\s -> delayL s 0.1 lfo + s ,\s -> onePole s 0.9]} in compose chn top; stprInit = let n = [97.999,195.998,523.251,466.164,195.998,233.082,87.307,391.995,87.307,261.626,195.998,77.782,233.082,195.998,97.999,155.563] in do {_ <- async (b_alloc 10 128 1) ;send (b_setn 10 [(0,n)])}}in withSC3 (stprInit >> play (out 0 stpr))
```