サウンドの基本(minimライブラリの使用)

minimはProcessing1.0以降のバージョンで標準のサウンドライブラリです。
それまでのライブラリが、ステレオ再生できなかったのに対して、minimはステレオになっています。
短いコードでオーディオのコントロールができます。
Processingをダウンロードした時点で、いくつかのサンプルは入っているのですが、以下のサイトのMinimをダウンロードすると、かなりの数のサンプルが入手できます。

https://github.com/ddf/Minim

また、上記のサイトはminimの全ての情報が載っています。英語なので大変かもしれませんが、もしminimを使っていて分からないことがあったら、まずはこのサイトを覗いてみましょう。

音楽ファイルの再生

さて、まずは基本中の基本である音声ファイルの再生です。再生自体は短いコードで済みますが、最後にサウンドデータをプログラムの中で終了させることを忘れないで下さい。
また、このサンプルは、pdeファイルと同じ階層にdataフォルダを作り、そこにsample.mp3がないと動きません。気をつけてください。
sample.mp3 (右クリックでダウンロード)

import ddf.minim.*;  //minimライブラリのインポート

Minim minim;  //Minim型変数であるminimの宣言
AudioPlayer player;  //サウンドデータ格納用の変数

void setup(){

  size(100, 100);
  minim = new Minim(this);  //初期化
  player = minim.loadFile("sample.mp3");  //sample.mp3をロードする
  player.play();  //再生
}

void draw(){

  background(0);
}

void stop(){

  player.close();  //サウンドデータを終了
  minim.stop();
  super.stop();
}

ボタンに音をつける

次はボタンに音をつけてみます。
以下のサンプルコードは次の音を利用しています。
button01a (右クリックでダウンロード)

フリーの音源は色々公開されているので、好きなものを探してみてください。
http://taira-komori.jpn.org/game01.html

import ddf.minim.*;  //minimライブラリのインポート

Minim minim;  //Minim型変数であるminimの宣言
AudioPlayer player;  //サウンドデータ格納用の変数

void setup(){

  size(200, 200);
  minim = new Minim(this);  //初期化
  player = minim.loadFile("button01a.mp3");  //button01a.mp3をロードする
  fill(0, 255, 0);  //最初は緑
}

void draw(){

  background(255);
  rect(50, 50, 100, 100);  //ボタンを描画
}

void stop(){

  player.close();  //サウンドデータを終了
  minim.stop();
  super.stop();
}

void mousePressed() {
  //もし、マウスが四角形ボタンの範囲内だったら、
  if (mouseX > 50 && mouseX < 150 && mouseY > 50 && mouseY < 150) {
    
    fill(255, 0, 0);  //赤で描画
 
    player.play();  //再生
    player.rewind();  //再生が終わったら巻き戻しておく
  }
}

void mouseReleased() {
  fill(0, 255, 0);  //マウスを放したら元に戻る
}

音とは一体何か

ひとまず音楽をプログラムから再生させることは成功しましたね。ここで、音の原理について考えてみましょう。
おそらく、皆さんは音が何かをそんなに意識的に考えたことはないでしょう。しかし、音がどのようにして発生して私達がどのように知覚しているかを考えることは、自分自身が音を作っていく過程において非常に重要です。全ては基本を理解する必要があるのです。
では、音とは一体なんでしょう。それは、「振動」です。例えば、物を叩けばそのものは振動しますが、その振動が実は空気を振動させ、あなたの鼓膜を振動させて・・・というように振動が伝搬していく訳です。通常人間はそんなことを意識して音は聞いていませんが、音を知覚するといことは、振動を知覚するということなのです。

参考サイト
http://poem.kagebo-shi.com/audio1/a01.html

波形とは

音の正体が振動であることを話しましたが、その振動は「波」として表されます。つまり、音は全て「波形」を持っています。実際に波形を見てみましょう。

import ddf.minim.*;  //minimライブラリのインポート
 
Minim minim;  //Minim型変数であるminimの宣言
AudioPlayer player;		//サウンドデータ格納用の変数
int waveH = 100;  //波形の高さ

void setup(){

  size(512, 200);

  minim = new Minim(this);  //初期化
 
 //バッファ(メモリ上のスペース。この場合は512要素のfloat型の配列)を確保し、
 //サウンドファイルを読み込む。バッファは指定しなければ1024。
  player = minim.loadFile("sample.mp3", 512);
  player.play();  //ファイルを再生
}

void draw(){

  background(0);
  stroke(255);
  //波形を描く
  //left.get()とright.get()が返す値は-1から+1なので、見やすくするために、
  //waveH(初期値は100)を掛けている。
  //サウンドファイルがモノラルの場合は、left.get()とright.get()が返す値は同じ。	
  for(int i = 0; i < player.left.size()-1; i++){

    point(i, 50 + player.left.get(i)*waveH);	//左の音声の波形を画面上に描く
    point(i, 150 + player.right.get(i)*waveH);	//右  〃
  }
}

void stop(){

  player.close();
  minim.stop();
  super.stop();
}

色んな音声ファイルを試してみてください。mp3以外にもwave, aiff, auなど様々なフォーマットのファイルが再生できます。
さて、波形を見ましたが、この波形は音をどのように表しているのでしょうか。
次の図を見てください。

縦軸が振幅(音の大きさ)、横軸が波長(音の高さ)です。この縦軸の高さが高ければ高い程、大きな音になります。また、横軸の波の密度が高ければ高いほど、高い音になります(次の図を参照)。

波形を見たときはこのような情報が視覚化されていると考えてください。

音の3要素

しかし、音には「大きさ」「高さ」に加えてもう一つの要素があります。それは「音色」です。この音色を理解しないことには、私達が普段どのような音を聞いているのかが分かりません。

音色

上記の波形は、実は純音と呼ばれるもので、その名の通り純粋な音です。よって波形もきれいなカーブを描いています。
以下のファイルを前述のプログラムで再生してみましょう。
sin00900.AIF
きれいな波形が出るはずです。これは、900Hz(周波数については後で説明します)の周波数の純音を再生しています。
しかし、実際に世の中にあふれている音は、こんなに純粋なものではありません。様々な周波数が重なってできたものです。このような音を複合音と呼びます。

マイクからの入力

もう少し色んな音の波形を見ていきましょう。次はマイク入力です。通常ノートパソコンなどはマイクが入っているので、そのまま再生しても機能しますが、デスクトップパソコンはマイクがついていない場合が多いので、気をつけてください。

import ddf.minim.*;  //minimライブラリのインポート
 
Minim minim;  //Minim型変数であるminimの宣言
AudioInput in;  //マイク入力用の変数
int waveH = 100;  //波形の高さ

void setup(){

  size(512, 200);

  minim = new Minim(this);  //初期化
 
  //バッファ(メモリ上のスペース。この場合は512要素のfloat型の配列)を確保し、マイク入力用の変数inを設定する。
  in = minim.getLineIn(Minim.STEREO, 512);
}

void draw(){

  background(0);
  stroke(255);
  //波形を描く
  //left.get()とright.get()が返す値は-1から+1なので、見やすくするために、
  //waveH(初期値は100)を掛けている。
  for(int i = 0; i < in.bufferSize()-1; i++){

    point(i, 50 + in.left.get(i)*waveH);	//左の音声の波形を画面上に描く
    point(i, 150 + in.right.get(i)*waveH);	//右  〃
  }
}

void stop(){

  in.close();
  minim.stop();  
  super.stop();
}

色んな音をマイクから入力してみてください。例えば、口笛は純音に近い波形が出るのに、自分の声は、先ほどMax/MSPで合成した波形のように、不規則な波形になっていませんか?
これは、人間の声が様々な周波数の波形が合成された音だということを証明しています。
身の回りの音がどのような性質を持っているのか確かめてみましょう。

音の波形の生成

それでは、Processingでサイン波を作って実際に出力してみましょう。

mySineWaveSignalScreenSnapz002
import ddf.minim.*;    //minimライブラリのインポート
import ddf.minim.signals.*;    //サイン波を発生させるためのライブラリ

Minim minim;
AudioOutput out;    //サウンド生成用の変数
SineWave sine;    //サイン波生成用の変数
float waveH = 50;    //振幅

void setup()
{
  size(512, 200);
  minim = new Minim(this);

  //サウンド出力用変数。
  out = minim.getLineOut(Minim.STEREO);
  
  //サイン波用の変数。バッファの初期値は1024、周波数は44100、ビット深度は16ビット。
  //これは、0~65535の段階に分割されるということです。 
  sine = new SineWave(440, 0.5, out.sampleRate());
  
  //ポルタメントスピード(音程の変化の滑らかさ)を200ミリセカンドに設定。小さい値になればなるほど、精度が上がる。
  sine.portamento(200);

  out.addSignal(sine);
}

void draw()
{
  background(0);
  stroke(255);
  // 波形を描く
  for(int i = 0; i < out.bufferSize()-1; i++)
  {
    point(i, 50 + out.left.get(i)*waveH);	//左の音声の波形を画面上に描く
    point(i, 150 + out.right.get(i)*waveH);	//右  〃
  }
}

void stop()
{
  out.close();
  minim.stop();
  super.stop();
}

音の波形の合成

それでは、次に上記のサイン波のコードを元にして2つの波を合成してみます。これは非常に簡単です。複数のサイン波をそれぞれ宣言(sine1, sine2)して、同じように実行すればいいのです。これは、outという変数に一緒に格納されるので、自動的に合成されて出力されます。

import ddf.minim.*;    //minimライブラリのインポート
import ddf.minim.signals.*;    //サイン波を発生させるためのライブラリ

Minim minim;
AudioOutput out;    //サウンド生成用の変数
SineWave sine1, sine2;    //サイン波生成用の変数
float waveH = 50;    //振幅

void setup()
{
  size(512, 200);
  smooth();
  minim = new Minim(this);

  //サウンド出力用変数。
  out = minim.getLineOut(Minim.STEREO);

  //サイン波用の変数。バッファの初期値は1024、サンプルレートは44100、ビット深度は16ビット。
  //これは、0~65535の段階に分割されるということです。 
  sine1 = new SineWave(440, 0.5, out.sampleRate());
  sine2 = new SineWave(1000, 0.2, out.sampleRate());

  //ポルタメントスピード(音程の変化の滑らかさ)を200ミリセカンドに設定。
  //小さい値になればなるほど、精度が上がる。
  sine1.portamento(200);
  sine2.portamento(200);

  out.addSignal(sine1);
  out.addSignal(sine2);
}

void draw()
{
  background(255);
  stroke(0);
  // 波形を描く
  for(int i = 0; i < out.bufferSize()-1; i++)
  {
    point(i, 50 + out.left.get(i)*waveH);	//左の音声の波形を画面上に描く
    point(i, 150 + out.right.get(i)*waveH);	//右  〃
  }
}

void stop()
{
  out.close();
  minim.stop();
  super.stop();
}

音の波形を再生中に変更

最後に、生成した音を再生中に変更してみましょう。以下のmouseMoved()とkeyPressed()を追加してみてください。

void mouseMoved() {
  
  //map関数は、0〜mouseXを0〜1000に変換
  float freq = map(mouseX, 0, width, 0, 1000);
  //周波数を設定
  sine1.setFreq(freq);
  
  //0〜mouseYを0〜1.0に変換
  float amp = map(mouseY, 0, height, 0, 1.0);
  //振幅を設定
  sine1.setAmp(amp);
}

void mousePressed() {
  //0〜mouseXを-1〜1に変換
  float pan = map(mouseX, 0, width, -1, 1);
  //左からより聞こえるか、右からより聞こえるかを設定
  sine1.setPan(pan);
}