数学で音楽を作る実験「セル・オートマトン ミュージック」

f:id:karaage:20150126231955j:plain

音楽は数学か?

 最近以下の2つの記事を読んで思った疑問です。

 タイトル自体は凄い面白いなと思ったのですが、記事は両方とも音楽制作者からの視点だけで、実は自分が期待した物とは大分違っていました。
 普通に考えれば、もちろん音楽=数学ではないですが、数学は科学の女王と呼ばれるくらいなので、芸術(音楽)に対しても同じように女王様とM男的な関係があるのではないかと思ったわけです。あ、MはMusicのMね。

 そんなわけで、もうちょっと数学よりから音楽と数学の関係を考えてみたいと考えたとき「数学で音楽を作ってみたらどうだろう?」と思いついたので、実際に作ってみることにしました。つまりは、数学から音楽をつくることができれば、構成論的に数学と音楽の関係というものを理解出来るのじゃないかという仮説です。思いついたら即実行!というわけでレッツトライ!

セル・オートマトンで音楽を作る

 数学から音楽を作るにあたり、普通だと先行研究とかを調べるところですが、自分の趣味ですし、すぐ思いついたことがあったので今回はパス。思いついたのは、セル・オートマトンを使って音楽をつくるという手法。多分99.999%以上の確率でほぼ同じことをやっている人はいると思いますので、誰か詳しい人は凄い人とか先行研究をこっそり教えて下さい。今回は無視です。

 セル・オートマトンというのは、以前下記の記事で自動的に絵を描くのに使用しました。今回は、それを音楽に適用しようという話です。

 簡単に説明すると、セル・オートマトンというのは単純なルールに従うセル(細胞)を並べると、ルールによってセルが様々な振る舞いをするというモデルです。今回作ったモデルは、横一列に並んだセルが、ランダムに生成されたルールに従って下に下にどんどん新しいセルを作っていくモデルになっています。そこに、横一列に並んだセルの数を全て足して5で割った余りの数 0〜4 に5種類の音を割り当てることで、自動的に音楽を生成する仕組みを実現しています。5種類の音は、音楽理論で適当に並べてもキレイに聞こえる組み合わせを選んでいます。専門用語では、Cマイナーのペンタトニックスケールといいます。
 本当は図を描いて説明しようと思ったけど、あまりに面倒くさいのでパス!誰か描いて!

セル・オートマトン ミュージック

 百聞は一見に如かずというわけで、とりあえず動画みるとちょっとイメージがつかめるかもしれません。黒い点の一つ一つがセル(細胞)です。実行するたびにルールとセルの初期配置が変わるので、毎回異なったパターンが生まれます。
 最初の方は単調な絵と音しかでませんが、 37秒あたりで面白いパターンが生まれ、音楽も多少は面白みがある曲になっていることがわかっています。これは、カオスの縁 (Edge of Chaos) と呼ばれる領域で、セル・オートマトン (CA) の振る舞いを評価する変数 λ(ラムダ)が0.5に近いと見られる現象です。つまりここで、ある意味音楽と言うものを数学のパラメータで表現することが可能になっていると言えるわけです。言い過ぎかな?

 今回の実験はここまでなのですが、これに和音とかリズムとか音色もパラメータ化してもっと発展させていくと、良い音楽というものを数学で定式化することもできてしまうかもしれませんね。もちろんそこにはどういう手法を使うかとか、そもそも良い音楽とは何かという定義の難しさとか色々な難しさはあるのですけどね。あと、この手の分野でそれほど目覚ましい発展を聞かないのは、難しさの他にあまりお金にならないというのがあるのかもしれないですね。

 ちなみに和音にするには、今回の1次元のセル・オートマトンを2次元に拡張すればよいです。知っている人はピンとくるでしょうが、いわゆるライフゲームと呼ばれる物になります。気が向くか、この記事に反応があったら作るかもしれません。

まとめ

 というわけで、最初に戻り「数学は音楽か?」と問われると、自分としての回答は「同じ物ではないけど、数学で音楽がつくれるから、きっと凄い密接な関係があるよ!」という至極当たり前な結論に落ち着きました。
 異なる分野を色々組み合わせることで新しいものを生み出すというのは、凄い可能性を秘めているので、音楽やっている人も数学に限らず色々な分野のことも学ぶのが重要なのじゃないかなと思います。もちろんそれは音楽、数学に限った話ではないですが。分野に捕われず多くのことを学びましょう。

 あと、プログラムのソースコードとか興味ある人は続きを読むをクリック下さい。

関連記事

ソースコード

 Processing 2.2.1 で作成しています。コピペして再生すれば動くと思います。音楽を出すのに minimというライブラリを使用しています。基本は関連記事の自分が過去作ったプログラムを組み合わせただけです。

import ddf.minim.*;
import ddf.minim.ugens.*;

Minim minim;
AudioOutput out;

final int x = 600;
final int y = 600;
final int max_ptn = 8;
final int max_count = 600;
 
int tmp_y = 0;
int[] tmp_cell = new int[x+2];
int[] cell = new int[x];
int[] cellPtn = new int[max_ptn];


void setup(){  
  frameRate(5);
  size(x, y);
  initCell();

  minim = new Minim(this);
  
  // use the getLineOut method of the Minim object to get an AudioOutput object
  out = minim.getLineOut();  

}
 
void initCell(){
  background(255);
 
  tmp_y = 0;
 
  for(int i=0; i<x+2; i++){
    tmp_cell[i]=((int)random(2)+1)%2;
  }
 
  for(int i=0; i<max_ptn; i++){
    cellPtn[i]=((int)random(2)+1)%2;
  }
}
 
void draw(){
  drawCell();
}
 
void drawCell(){
  for(int i=1; i<x+1; i++){
    int cell_value = 0;
    cell_value +=  tmp_cell[i-1]*4;
    cell_value +=  tmp_cell[i]*2;
    cell_value +=  tmp_cell[i+1];
 
    switch(cell_value){
      case 0:
        cell[i-1]=0;
      break;
      case 1:
        cell[i-1]=cellPtn[1];
      break;
      case 2:
        cell[i-1]=cellPtn[2];
      break;
      case 3:
        cell[i-1]=cellPtn[3];
      break;
      case 4:
        cell[i-1]=cellPtn[4];
      break;
      case 5:
        cell[i-1]=cellPtn[5];
      break;
      case 6:
        cell[i-1]=cellPtn[6];
      break;
      default:
        cell[i-1]=cellPtn[7];
      break;
    }
 
    if(cell[i-1]==1){
      point(i-1, tmp_y);
    }
  }

  for(int i=0; i<x; i++){
    tmp_cell[i] = cell[i];
  }
  tmp_cell[x]=cell[0];
  tmp_cell[x+1]=cell[1]; 

  int tmp_total = 0;
  for(int i=0; i<x; i++){
    tmp_total += cell[i];
  }

//  println("cellTotal=" + tmp_total);

  if(tmp_total%5 == 0){
    out.playNote( 1, 1, "C" );
    println("C");
  }

  if(tmp_total%5 == 1){
    out.playNote( 1, 1, "D#" );
    println("D#");
  }

  if(tmp_total%5 == 2){
    out.playNote( 1, 1, "F" );
    println("F");
  }    

  if(tmp_total%5 == 3){
    out.playNote( 1, 1, "G" );
    println("G");
  }

  if(tmp_total%5 == 4){
    out.playNote( 1, 1, "A#" );
    println("A#");
  }

  if(tmp_y < y){
    tmp_y++;
  }
}

void mousePressed(){
  initCell();
}