SoundVisualizer

Processing課題の例 -- 関西学院大学理工学部情報科学科 教授 西谷滋人

目的

iTunesのclassic visualiserを実現するようなcodeをprocessingで実装する.

要件

classic visualiserが実現している「動くもの」をもう少し詳しく定義すると

  1. 音楽に反応する
  2. 音を視覚化したラインあるいはサークル
  3. 次々と現れては消えいくような(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の標準関数として用意されている.

  1. minim:音楽の再生と視覚化
  2. blend:画像のblend(混ぜ合わせ)

によってvisualizer実現に必要な基礎的挙動の実装が可能であることがわかった. カメラ,blend, 色,形の中心位置などをある程度のランダムさで制御すれば,iTunesのvisualizerっぽいものが出来る.

ただし,

  1. 色やcameraの調整は微妙
    • iTunesのvisualizerがどれだけ調整されているかを実感
  2. もう少し高度なblendが必要.
    • 各形状によってblendの方向を変えるような操作が見られる

しかし,「iTunesのvisualizerみたいなものを自分の手で作る」と言う長年の目標を達成する基礎技術が手に入ったことは感激.もうすこしcoolなのを作ろう.

Last modified:2017/05/19 18:26:22
Keyword(s):
References:[CompAInfo] [CompAInfo15] [CompAInfo19] [FirstYearEducation14] [SoundVisualizer]