SoundVisualizer
要件
classic visualiserが実現している「動くもの」をもう少し詳しく定義すると
- 音楽に反応する
- 音を視覚化したラインあるいはサークル
- 次々と現れては消えいくような(fade out)画像
となる.
必要なライブラリあるいは技術
音楽の再生
Processingが提供する音楽関連のライブラリには,minimがある. minimのQuickstart Guideには,音楽ファイル(wav)を再現するcodeと,inputの音に反応するcodeがサンプルとして例示されている.
import ddf.minim.*;
Minim minim;
AudioPlayer player;
void setup()
{
size(100, 100);
minim = new Minim(this);
player = minim.loadFile("Perfume_globalsite_sound.wav"); //Perfumeのwavに変更
player.play();
}
void draw()
{
// do what you do
}
音への反応
Getting An AudioInputにaudioinputに反応して踊る線のcodeがsampleとしてあげられている. 変更した箇所は,
- keyPressed関連を取り払ったのと,
- left,rightからの入力に反応させていたのをmixの反応に変え,
- さらに感度を上げている.
import ddf.minim.*;
Minim minim;
AudioInput in;
void setup()
{
size(512, 200, P3D);
minim = new Minim(this);
// use the getLineIn method of the Minim object to get an AudioInput
in = minim.getLineIn();
}
void draw()
{
background(0);
stroke(255);
// draw the waveforms so we can see what we are monitoring
for (int i = 0; i < in.bufferSize() - 1; i++)
{
line( i, 100 + in.mix.get(i)*400, i+1, 100 + in.mix.get(i+1)*400 );
}
}
視覚化の基礎技術
fade out画像は,前のframeとblendすればいいと考え,googleった.
にそのものズバリのcodeがあった.これから,
- blend
- camera
のアイデアをそのまま使って実装.
次のは,cameraを使わずに,大きなsin関数にして動いて行くモード.
import ddf.minim.*;
Minim minim;
AudioInput in;
int c_drift;
void setup()
{
size(1024,400, P3D);
minim = new Minim(this);
// use the getLineIn method of the Minim object to get an AudioInput
in = minim.getLineIn();
}
void draw()
{
PImage beforeImage = get();
background(0);
float dy;
c_drift = c_drift+10;
stroke(255, 255-c_drift%255, c_drift%255);
// draw the waveforms so we can see what we are monitoring
for (int i = 0; i < in.bufferSize() - 1; i++)
{
dy=50*sin(float(i)/float(width)*2.0*PI+float(c_drift)/500.0);
line( i, 200+dy + in.mix.get(i)*400, i+1, 200+dy + in.mix.get(i+1)*400 );
}
blend(beforeImage, 0, 0, width, height, -1, -1, width+2, height+2, SCREEN);
}
もっとも基礎となる実装コード
blend関数をいじると画像がいろいろ調整できる.さらに,カメラ位置の移動によって, 「音が踊っている」ような画像が生成される.
import ddf.minim.*;
Minim minim;
AudioInput in;
int max_i;
int tickMax = 100;
void setup() {
frameRate(40);
size(600, 600, P3D);
minim = new Minim(this);
in = minim.getLineIn();
max_i=in.bufferSize();
//camera(0, 500, 0, 0, 0, 0, 0, 1, 0);
//ambientLight(200, 200, 200);
background(0);
}
void draw() {
PImage beforeImage = get();
background(0);
stroke(255);
strokeWeight(1);
for (int i = 0; i < max_i - 1; i++) {
line( i, 300+in.mix.get(i)*400, i+1, 300+in.mix.get(i+1)*400 );
}
//camera(cos(TWO_PI/tickMax * frameCount) * 800, -500,
// sin(TWO_PI/tickMax * frameCount) * 800,
// 0, 0, 0, 0, 1, 0);
blend(beforeImage, 1, 1, width, height, -1, -1, width, height, SCREEN);
}
おまけ(circloid)
直線のままでは飽きてくるので,円状(circloid)の画像とした.
in draw for (int i=1; i< 20;i++) { draw_circloid(300, 00, 80, 128+127/(i), i*10); }
void draw_circloid(int x0, int y0, int r0, int s_trap, int c_i) { strokeWeight(2); stroke(255, 255-c_i, c_drift, s_trap); for (int i = 0; i < max_i - 1; i++) { float theta_i, theta_j; float x_i, y_i, x_j, y_j; float r_i, r_j; theta_i = float(i)/float(max_i - 1)*TWO_PI; theta_j = float(i+1)/float(max_i - 1)*TWO_PI; r_i=in.mix.get(i)*200+r0; r_j=in.mix.get(i+1)*200+r0; x_i = r_i*cos(theta_i)+x0; y_i = r_i*sin(theta_i)+y0; x_j = r_j*cos(theta_j)+x0; y_j = r_j*sin(theta_j)+y0; line( x_i, y_i, x_j, y_j); } }
全部放り込んだもの.形状の中心位置や色はいじっている.
import ddf.minim.*;
Minim minim;
AudioInput in;
int max_i;
int c_drift;
int tickMax = 100;
void setup() {
frameRate(40);
size(600, 600, P3D);
minim = new Minim(this);
in = minim.getLineIn();
max_i=in.bufferSize();
camera(0, 500, 0, 0, 0, 0, 0, 1, 0);
ambientLight(200, 200, 200);
background(0);
}
void draw() {
PImage beforeImage = get();
background(0);
stroke(255);
strokeWeight(1);
c_drift = (c_drift+20)%255;
for (int i = 0; i < max_i - 1; i++) {
line( i-500, in.mix.get(i)*200, i+1-500, in.mix.get(i+1)*200 );
}
for (int i=1; i< 20;i++) {
draw_circloid(200, 0, 80, 128+127/(i), i*10);
}
camera(cos(TWO_PI/tickMax * frameCount) * 800, -500,
sin(TWO_PI/tickMax * frameCount) * 800,
0, 0, 0, 0, 1, 0);
blend(beforeImage, 0, 0, width, height, -1, -1, width+2, height+2, SCREEN);
}
void draw_circloid(int x0, int y0, int r0, int s_trap, int c_i) {
strokeWeight(2);
stroke(255, 255-c_i, c_drift, s_trap);
for (int i = 0; i < max_i - 1; i++) {
float theta_i, theta_j;
float x_i, y_i, x_j, y_j;
float r_i, r_j;
theta_i = float(i)/float(max_i - 1)*TWO_PI;
theta_j = float(i+1)/float(max_i - 1)*TWO_PI;
r_i=in.mix.get(i)*200+r0;
r_j=in.mix.get(i+1)*200+r0;
x_i = r_i*cos(theta_i)+x0;
y_i = r_i*sin(theta_i)+y0;
x_j = r_j*cos(theta_j)+x0;
y_j = r_j*sin(theta_j)+y0;
line( x_i, y_i, x_j, y_j);
}
}
まとめ
processingでiTunesのvisuallizerもどきを作成した.processingの標準関数として用意されている.
- minim:音楽の再生と視覚化
- blend:画像のblend(混ぜ合わせ)
によってvisualizer実現に必要な基礎的挙動の実装が可能であることがわかった. カメラ,blend, 色,形の中心位置などをある程度のランダムさで制御すれば,iTunesのvisualizerっぽいものが出来る.
ただし,
- 色やcameraの調整は微妙
- iTunesのvisualizerがどれだけ調整されているかを実感
- もう少し高度なblendが必要.
- 各形状によってblendの方向を変えるような操作が見られる
しかし,「iTunesのvisualizerみたいなものを自分の手で作る」と言う長年の目標を達成する基礎技術が手に入ったことは感激.もうすこしcoolなのを作ろう.
Keyword(s):
References:[CompAInfo] [CompAInfo15] [CompAInfo19] [FirstYearEducation14] [SoundVisualizer]