2015年10月1日木曜日

Processingで音を出してみる

 グラフィックスに特化したProcessingというプログラミング言語があります。今までちまちま使ってきたが音も出せると聞いたのでやってみることにした。果たして,音楽の成績が5段階のうち3だった俺は使いこなせるのでしょうか。

1.ライブラリのインストール

 Processingで音をだすためにはminimというライブラリを使うようだが,Processingのバージョンが3になり,自分でライブラリを追加しなければならないようです。Processingのバージョンが2の人は読み飛ばしてもらって問題ないと思います。
 まずProcessingを起動し,メニューバーの「スケッチ」をクリックすると「ライブラリのインポート」という項目があります。
 
 右側に出てきた項目の中にminimがあれば良いのですが,なければ「ライブラリの追加」をクリック。
 
 そうするとウィンドウが出てくるので上の「Filter」というテキストボックス内に「minim」と入力し,検索結果の中の「Minim」という項目をクリック。そんで「install」を押せばライブラリのインストールは終了。

2.音を鳴らしてみる

 次に音を鳴らしてみる。今回は「ラ」の音を出してみます。しかしそのためには「ラ」の音の周波数を調べる必要があるのですが,次の表を見れば大丈夫。これExcelで計算したの。計算で音階の周波数を求められるって,なんかロマンがあるというか美しさを感じるよね。


 音が一つ高くなると周波数が1.059463倍になる。ちなみにこの数字は2の12乗根で,こうすることで低いドと高いドの音(つまり1オクターブ異なる音)の周波数がちょうど2倍になる。こんなところで数学が出てくるとは思わんかった。昔の人は感覚でこの周波数を区別していたのだろうか。

 まぁそれは置いておくとして,「ラ」の音が440Hzであることが分かったので早速プログラムを作ってみる。
/**
 * ラの音を出力する
 * 2015/09/30
 */

import ddf.minim.*;
import ddf.minim.signals.*;

/* 音声出力用のオブジェクト */
Minim minim;
AudioOutput aout;
SineWave wave;

void setup() {
  /* 適当な大きさにウィンドウを表示する */
  size(256, 256);

  /* 初期設定 */
  minim = new Minim(this);
  aout = minim.getLineOut(Minim.STEREO);
  /* サイン波をとりあえず440[Hz](ラの音),大きさ80%を指定した */
  wave = new SineWave(440, 0.8, aout.sampleRate());
  aout.addSignal(wave);
  
}

void draw(){
  /* ウィンドウの背景を黒く塗っておく */
  background(0);
}

 このプログラムのsetup関数の中のwave = ……のところの440を別の周波数に変えれば別の音が出せます。

3.自動作曲するプログラム

 自動作曲というとなんか大げさじゃないかと思うかもしれないです。そのとおりでございます。ランダムに音を決めて音を鳴らしてみるだけです。ごめんなさい。

/**
 * ランダムに音を鳴らす
 * 2015/10/01
 */

import ddf.minim.*;
import ddf.minim.signals.*;

/* 音声出力用のオブジェクト */
Minim minim;
AudioOutput aout;
SineWave wave;

/* 2の12乗根 */
float FREQ_RATE = 1.0594631;
/* 「ラ」の音の周波数 */
float FREQ_BASE = 440.0;
/* 休止になる確率 */
float PAUSE_PERCENTAGE = 0.25;
/* 演奏する音階の範囲 */
int TONE_RANGE = 4;

void setup() {
  /* 適当な大きさにウィンドウを表示する */
  size(256, 256);

  /* 初期設定 */
  minim = new Minim(this);
  aout = minim.getLineOut(Minim.STEREO);
  /* サイン波をとりあえず440[Hz](ラの音),大きさ80%を指定した */
  wave = new SineWave(440, 0.8, aout.sampleRate());
  aout.addSignal(wave);

  /* 一秒間に8回draw関数が呼び出されるようにする */
  frameRate(8);
}

void draw() {
  float freq;
  int temp;

  if ( random(1) < PAUSE_PERCENTAGE ) {
    /* 休止では周波数を0にする */
    freq = 0;
  } else {
    /* -TONE_RAGEからTONE_RAGEの乱数を生成 */
    temp = (int)(random(-TONE_RANGE, TONE_RANGE));

    /* ラの周波数に(2の12乗根)のtemp乗を掛ける */
    /* こうすることでtempだけ違う音階を出力できる */
    freq = FREQ_BASE * pow(FREQ_RATE, temp);
  }
  /* 周波数freqの音を出す */
  wave.setFreq(freq);

  /* ウィンドウの背景を黒く塗っておく */
  background(0);
}

wave.setFreq([周波数(float型)])で任意の周波数の音が出せる。ランダムに周波数を決め,それを1秒間に8回出力している。それっぽくなってるように思えなくもないが,小学生が適当に鍵盤叩いてるようなもので,まるで音楽ではないですが大目に見てください.
 まぁまた時間があったら自動作曲プログラムとか作ってみます。マルコフ連鎖とか使えばそれっぽくなりそうだし。