さまざまな入力(音・映像)

2019-10-02

本章のあらすじ

  • マイクを使って音に反応させる
  • カメラを使って映像を取得し利用する
カメラの映像から色を取りつつランダムウォーク

準備:ライブラリのインストール

Processingで音や映像を取得するには、ライブラリ(マイク入力や映像を扱う、特定の機能がセットになったもの)を利用します。Processingのメニュー「ツール→ツールを追加…」からインストールしましょう。

「Libraries」タブから「Sound」「Video」をそれぞれ検索、「The Processing Foundation」が作者になっているものを選択してインストールしてください。

Processing 3を使っていて、かつ最近のmacOSのバージョンを使っている場合、セキュリティ関連の問題によりエラーが出てしまう場合があります。これは一時的な問題で、Processingの次期バージョンが出れば解消する見込みですが、しばらくはこちらの記事などを参考に各々で回避策をとりましょう。

音の大きさ:音量

音は空気の振動(圧力の変化=音圧)により生じます。音量とは、音圧の大きさの実効値(均すとどのくらいの大きさになるか換算したもの)です。

左:小さい、右:大きい。緑色は実効値のイメージ

練習:Processingで音量を取得する

音量を扱うには、先ほどインストールしたSoundライブラリを利用します。Processingが公式で提供しているもので、音の入力を扱う際はお世話になります。

さっそくライブラリを組み込んだスケッチを準備しましょう。新しい概念がいくつか含まれていますが、しばらくは「こういうふうに書けば使えるのね」程度の理解で大丈夫です。

// マイクの音を扱うためのライブラリをインポート
import processing.sound.*;

// マイク
AudioIn in;
// 音量を取得してくれるもの
Amplitude amp;

void setup() {
  size(600, 600);
  strokeWeight(2);
  fill(255, 200, 100);

  // マイクを初期化(おまじない。現時点で深い意味は考えなくてOK)
  in = new AudioIn(this);
  in.start();

  // 音量の取得を開始
  amp = new Amplitude(this);
  amp.input(in);
}

void draw() {
  background(255);

  // マイクの音量を取得して、
  // 結果を変数 a に入れる
  float a = amp.analyze();

  // 音量の数値をコンソールに出力してみる
  println(a);
}

書き終わったらスケッチを実行して、PCのマイクのそばで音を出してみてください。コンソールに数値が流れていきますが、音に応じて変化しているのが確認できるでしょうか。

この数値がマイクで拾った音量です。結果が文字では味気ないので、試しに円を描いてそのサイズに反映してみましょう。 (→sound_amp

void draw() {
  

  // 音量を円のサイズに反映して描く
  float sz = a * 1000;
  ellipse(
    width / 2, height / 2,
    sz, sz
  );
}

発展

  • 一定以上の音量をトリガーとして、何か表現できないだろうか?
  • これまで作ってきたスケッチに組み込んでみると?
    • 音量で太さが変わるペン
    • 音量で色合いが変わるパレット
    • 音量で活発さが変わるエージェント
  • マイクに息を吹くと音量が上がる。この現象に自然に反応する表現はどんなだろう?

音の高低:周波数

音圧は周期的に変化します。周波数の小さな音は低く、周波数の大きな音は高く聞こえます。

左:周波数が小さいので低い音、右:周波数が高いので高い音

周波数成分の分析:FFT

耳に入ってくる音は、いろいろな周波数の波が重なったものです。まぜこぜになった音を周波数ごとに分解し、どの周波数の音がどれだけ含まれているかを解析する方法があり、FFT(Fast Fourier Transform: 高速フーリエ変換)と呼ばれています。このFFTも、先ほどと同じSoundライブラリで利用できます。

練習:FFTの使いかたを理解する

FFTを組み込んだサンプルコードを見てみましょう。 (→sound_fft

// マイクの音を扱うためのライブラリをインポート
import processing.sound.*;

// マイク
AudioIn in;
// 周波数を解析してくれるもの
FFT fft;

// 解析する周波数帯域の数
int COUNT = 64;
// 周波数成分の解析結果を入れる変数
float[] spectrum = new float[COUNT];

void setup() {
  size(600, 600);
  fill(0);
  noStroke();

  // マイクを初期化(おまじない。現時点で深い意味は考えなくてOK)
  in = new AudioIn(this);
  in.start();

  // 周波数解析を開始
  fft = new FFT(this, COUNT);
  fft.input(in);
}

void draw() {
  background(255);

  // マイクの音の周波数を解析して、
  // 結果を変数 spectrum に入れる
  fft.analyze(spectrum);
  // spectrum[0], [1], ... に数値が入る
  // spectrrm[0] が低い(周波数が小さい)音の成分、
  // 配列の数字が増えるほど高い(周波数が大きい)音の成分

  for (int i = 0; i < COUNT; i++) {
    rect(
      i * 10,
      height / 2,
      10,
      -spectrum[i] * 1000
    );
  }
}

fft.analyze() を実行すると、計算した周波数成分を float の配列に入れてくれるので、これを利用すればOKです。今回の例では、画面中央から上に向かって四角形を描いて表現してみました。

周波数成分は一瞬で変化してしまうので、一昔前のビジュアライザーのように「ふた」をつけてみるのもよいでしょう。余裕があればチャレンジしてみてください。 (→sound_fft_bars

発展

  • 音量や音程の可視化について、他の表現方法はないだろうか?
  • 高いほうの周波数成分は、声や音楽では出ないのであまり大きくならない。低い領域だけ可視化できないだろうか?
  • 「ふた」に速度・加速度を導入して、より自然な動きにできないだろうか?
  • 音の高低でものを操作できないだろうか?
  • これまで作ってきたスケッチに組み込んでみると?
    • 音の高低で色や大きさ、太さが変わる
    • 音の高低でエージェントの運動(速度の大きさや向き)が変わる

カメラの映像

練習:Processingでカメラの映像を取得する

カメラの映像の取得についても、冒頭でインストールした公式のライブラリを利用します。

まずはコードを書いてみましょう。

// カメラの映像を描く

// カメラの映像を扱うためのライブラリをインポート
import processing.video.*;

// カメラ
Capture cam;

void setup() {
  size(600, 600);

  // カメラを初期化(おまじない。現時点で深い意味は考えなくてOK)
  cam = new Capture(this);
  cam.start();
}

void draw() {
  // カメラが有効なら、映像を取り込む
  if (cam.available()) {
    cam.read();
  }

  background(0);

  // 映像を描く(カメラの映像は画像 PImage と同じように扱える)
  image(cam, 0, 0);
}

(→video

無事に映像は出たでしょうか?

ポイントは、取得したカメラの映像は画像(PImage)と同様に扱える1ということ。キャンバスに描いたり色を取得したりと、「画像」の章で覚えたことが活用できます。

練習:カメラの映像ではんこを作ってみる

コードを少し書き換えて、クリックした位置に映像を小さく描くようにしてみましょう。

// カメラの映像を扱うためのライブラリをインポート
import processing.video.*;

// カメラ
Capture cam;

void setup() {
  size(600, 600);

  background(255);

  // カメラを初期化
  cam = new Capture(this);
  cam.start();
}

void mousePressed() {
  // 映像を小さく描く
  image(cam, mouseX, mouseY, 80, 60);
}

void draw() {
  // カメラが有効なら、映像を取り込む
  if (cam.available()) {
    cam.read();
  }
}

mousePressed() に書いた処理と同じものを mouseDragged() ブロックにも書くと、動画をインクとしたペンのようなものが作れますね。カーソルの軌跡が時間の流れを描くようになりました。 (→video_stamp

練習:映像から色を取得してグリッドを描いてみる

整列」で扱ったグリッドに、映像から取得した色を適用すると、おもしろい効果が得られます。 (→video_grid

void draw() {
  // カメラが有効なら、映像を取り込む
  if (cam.available()) {
    cam.read();
  }

  background(0);

  for (int y = 0; y <= height; y += 40) {
    for (int x = 0; x <= width; x += 40) {
      fill(cam.get(x, y));
      ellipse(x, y, 20, 20);
    }
  }
}

発展

  • 色の明るさbrightness()や、彩度saturation()をうまく組み合わせられるだろうか? (→video_grid_brightness
  • 音量や音程を組み合わせた表現は作れるだろうか?
  • キャンバス上を動きまわるエージェントと組み合わせられないだろうか? (→video_grid_brightness
  • これまで作ってきたスケッチと組み合わせて、テクスチャや色パレットとして使えるだろうか?
  • 特徴的な色のマーカーを使って、マーカーを検出できるだろうか?

本章のまとめ

  • 音量・音程を取得するにはSoundライブラリを利用する
  • 映像を取得するにはVideoライブラリを利用する

  1. 発展的な内容だが、実装をみるとCaptureクラスはPImageを継承しているので、PImageとして扱えることが確認できる ↩︎