波形を描く

再生中の音の波形を描画したい場合があるだろうね。オーディオデータの入出力を操作するMinimの中のクラスは全てAudioSourceクラスの派生クラスだ(ただしAudioSnippetは除く)。
AudioSourceクラスは3つのAudioBufferメンバを定義し、AudioSourceクラスを拡張したクラス群に継承される。AudioPlayerクラスはまさにそのようなクラスで、AudioPlayerオブジェクトによってこれらのバッファにアクセスすることができる。バッファはleft、right、mixという名前。
それぞれ左チャンネル、右チャンネル、そして左右のミックスを含んでいる。あなたが再生しているファイルがモノラルだとしても、3つの全てのバッファは取得できるし値も返ってくる。モノラルのファイルを再生してみると、単純に全てのバッファが同じ情報を持っているということがわかるだろう。では波形を描いてみよう。前回(メタデータを抽出する)のdraw関数をこのように再定義する:

void draw()
{
  background(0);
  stroke(255);
  // 線で隣の値をつなぐことで波形を描く
  // 値は-1から1の間にノーマライズ(均一化)されているのでそれぞれ値を50倍する 
  // 拡大しなかったらただの線にしか見えないかも
  for(int i = 0; i < song.bufferSize() - 1; i++)
  {
    line(i, 50 + song.left.get(i)*50, i+1, 50 + song.left.get(i+1)*50);
    line(i, 150 + song.right.get(i)*50, i+1, 150 + song.right.get(i+1)*50);
  }
}

この描画コードはsongクラスがどんな種類の入力や出力でも機能する。何故なら全ての入出力はAudioSourceクラスを拡張していて、バッファを提供する形式になっているから。と言っても上のコードには2つ問題点がある。setup関数はデフォルトだと100×100になってしまうのと、僕らはバッファがどれだけ長いかを知らない(つまりsong.bufferSize()がどんな数を返すのかということ)。最初の問題の解決は簡単で、ウィンドウサイズを512×200にすればいいだけ。2番目の問題は、loadFileを呼ぶ時にバッファの長さを指定することで解決可能。ということでsetup関数はこうなる:

void setup()
{
  size(512, 200);
 
  minim = new Minim(this);
 
  // サンプルバッファのサイズを512に指定
  // デフォルトのバッファサイズは1024
  song = minim.loadFile("mysong.wav", 512);
  song.play();
}

これで僕らはバッファの中身と全く同じ大きさの表示用スクリーンを持っていることになる。もしバッファサイズを指定しなければ、1024サンプルになる。

訳注:前回のサンプルから書き換える場合、変数名をgrooveからsongに変えておかないと動きません。