音で絵を描く②

こんにちは。
AMDlabの藤井です。

今日は、以前紹介したProcessingで音に反応させて絵を描いた続編です。
前回は音の大きさに反応させて絵を描いていました。
今回は、音の周波数に応じてリアルタイムで絵を描いてみたいと思います。

耳は音波を周波数成分に分解して聞いています。
それをフーリエ変換(FFT:Fast Fourier Transform)という数学的処理によって行うことができます。
あらゆる周波数成分を含んだ波を各周波数ごとに分解して、それぞれの強さを取り出します。
周波数の成分ごとの分布を視覚化したものをスペクトルと言います。
フーリエ変換を逆に行うことも可能です。

ちなみに、フーリエ変換は、時間の関数を周波数の関数に変換する方法なので、音意外でも色々使用されています。
例えば、地震波の時間関数を変換して周期のスペクトルとして見ると、どの周期で建物が一番大きく地震の影響を受けるかを簡単に知ることができます。

話し出せば長くなるので、前置きはこの辺にしておきます。すみません…

さて、ProcesingにFFTを実装して、周波数で絵を描いてみましょう。
以前紹介したSoundライブラリには既にFFTクラスが入っているので、それを呼び出すだけで難しい式は考えなくても良いのです!

まずは、以前の投稿同様Soundライブラリをインポートします。
続いてbandsという変数を定義していますが、これはどれだけの幅をフーリエ変換するかというものです。
FFTのアルゴリズム上、2の累乗の数値をここに代入することになるのですが、値の大きさについては、どれだけ何を正確に行いたいかで決めて下さい。
大きくなるほど解析する周波数成分の幅が広くなりますので、周波数成分の解析が正確にできるようになります。ただし、時間変化に鈍くなります。
あまり大きくしすぎると落ちてしまうこともあるので注意して下さい。

import processing.sound.*;
AudioIn in;
FFT fft;
int bands = 512; // 2,4,8,16,32,64,... 2^x
float scale = 20.0; //Scale height

続いてセットアップのところですが、ここでFFTのbandsを入れます。

void setup() {
size(1000, 800);
in = new AudioIn(this, 0); // initialize
in.start(); // play
fft = new FFT(this, bands); // initialize FFT
fft.input(in);
}

描画の項です。
bandsを横幅にとって、解析結果を縦軸にとって、スケール倍して見やすくしております。
beginShape()で描画を始め、endShape()で描画を終えていますが、これはこの間にある点を結ぶようにしており、
結果折れ線グラフのような表現になっています。

void draw() {
background(0);
fft.analyze();
float w = width/float(bands); // graph width
noFill();
stroke(255,0,0);
beginShape(); // start to make shape
for (int i = 0; i < bands; i++) {
vertex(i * w, height - fft.spectrum[i] * height * scale);
}
endShape(); // finish
}

以上で終わりになります。
非常に簡単にリアルタイムで周波数解析をして描画するプロブラムが作成できました。
前回の音の大きさも併せて、色の表現も入れるとさらに面白い絵が描けそうですね^^

以下に全コードを載せておきます。参考までに。
またGithubの方にもアップしたら公開、周知致します。

import processing.sound.*;
AudioIn in;
FFT fft;
int bands = 512; // 2,4,8,16,32,64,... 2^x
float scale = 20.0; //Scale height

void setup() {
size(1000, 800);
in = new AudioIn(this, 0); // initialize
in.start(); // play
fft = new FFT(this, bands); // initialize FFT
fft.input(in);
}

void draw() {
background(0);
fft.analyze();
float w = width/float(bands); // graph width
noFill();
stroke(255,0,0);
beginShape(); // start to make shape
for (int i = 0; i < bands; i++) {
vertex(i * w, height – fft.spectrum[i] * height * scale);
}
endShape(); // finish
}

今日はこの辺で。

ARTICLES