風呂瀬 信五

p5.jsと音の共鳴:アルゴリズムが紡ぐ聴覚と視覚のジェネラティブアート

クリエイティブコーディングの世界で、ピクセルやベクトルを操ることに慣れた私たちが、次なる表現の扉を開く鍵は、その姿を見ることのできない「音」にあるのかもしれません。プログラミングで音を可視化したい、あるいは自らの視覚アートに聴覚的な深みを与えたいと願いながらも、その第一歩をどこに踏み出せばよいか迷っているのなら。この記事は、p5.js という羅針盤を手に、音と視覚が共鳴する表現の海へと漕ぎ出すための、ささやかな水先案内となるでしょう。

音とは何か、クリエイティブコーディングにおけるその可能性

音とは、時間の流れそのものを内包した現象です。一枚の静止画とは異なり、音には始まりと終わりがあり、その間には刻々と変化する響きの連なりが存在します。クリエイティブコーディングにおいて音を扱うということは、この時間軸という新たな次元をキャンバスに導入することを意味します。それは、単に映像にBGMを添えるといった従属的な関係に留まりません。アルゴリズムを通じて音の構造そのものを生成し、その構造が直接的に視覚を形成する、あるいは視覚的な変化が音響的な風景を変容させる、といった双方向の関係性を築くことができるのです。

p5.js は、私たちにそのための強力な言語を与えてくれます。音の物理的な特性である周波数(音の高さ)、振幅(音の大きさ)、そして波形(音色)といった要素を、コード上で数値として捉えることを可能にします。これにより、音はもはや外部から与えられる既成の素材ではなく、ピクセルや頂点と同様に、私たちの創造的な意思によってリアルタイムに生成・操作可能な、生きたマテリアルへと変わります。この視点の転換こそが、聴覚と視覚の間に、これまでになかった新しい関係性を紡ぎ出すための出発点となるのです。

p5.sound.jsへの招待:音を操るための詩的な道具箱

p5.jsで音の世界を旅するにあたり、まず手に入れるべき道具が p5.sound.js ライブラリです。これは p5.js の公式アドオンであり、Web Audio API の複雑な側面を優雅に覆い隠し、アーティストやデザイナーが直感的に音を扱えるように設計されています。導入は極めてシンプルで、通常は HTML ファイルにスクリプトタグを一行追加するだけで、私たちのスケッチは音を聴き、語り始める準備が整います。

このライブラリは、音に関する様々な機能を持つオブジェクトの集合体、いわば「詩的な道具箱」として考えることができます。例えば、p5.SoundFile は既存の音声ファイルを読み込み、再生や停止、ループといった基本的な操作を司ります。p5.AudioIn はマイクからの入力を受け付け、私たちの声や周囲の環境音をスケッチに取り込む扉となります。そして、p5.Oscillator はサイン波や矩形波といった電子的な音の源をアルゴリズムによって生成し、p5.FFT は音という複雑な波を周波数ごとの成分に分解し、その構造を分析するための解析ツールとして機能します。

まずは、最も基本的な一歩として、音声ファイルを再生してみましょう。以下のコードは、preload 関数でサウンドファイルを読み込み、マウスクリックで再生と停止を切り替えるだけのシンプルなスケッチです。しかし、ここにはすでに、ユーザーのアクションが聴覚的な結果を引き起こすという、インタラクティブな音響表現の萌芽が含まれています。

let song;

function preload() {
  // 音声ファイルを事前に読み込む
  song = loadSound('assets/your-sound.mp3');
}

function setup() {
  createCanvas(710, 200);
  background(100);
  text('Click to play / stop', 10, 20);
}

function mousePressed() {
  if (song.isPlaying()) {
    // .isPlaying() は再生中かどうかの真偽値を返す
    song.stop();
    background(100);
    text('Click to play / stop', 10, 20);
  } else {
    song.play();
    background(180, 220, 150);
    text('Playing...', 10, 20);
  }
}

この小さなコード片が、p5.sound.js という広大な世界への入り口です。ここから、私たちは音を分析し、生成し、そして視覚と結びつける、より深い探求へと進んでいきます。

音の可視化:聴覚情報を視覚へと変換するアルゴリズム

音を「見る」とは、一体どのような体験でしょうか。p5.sound.js を使えば、私たちは音の持つ様々な側面を数値データとして抽出し、それを視覚的な要素へとマッピングできます。この聴覚から視覚への「翻訳」こそが、音響可視化 (Audio Visualization) の核心です。この翻訳のプロセスに決まった正解はなく、どの音の特性を、どの視覚的パラメータに、どのような関係式で結びつけるかという選択そのものが、アーティストの表現となります。

最も基本的なアプローチの一つは、音の振幅、つまり音量を視覚化することです。p5.Amplitude オブジェクトは、現在の音量を 0.0 から 1.0 の範囲の数値として取得する機能を提供します。この値を円の半径や矩形の高さ、あるいは色の明度に直接結びつけるだけで、音の強弱に同期して脈動するグラフィックが生まれます。

さらに一歩進んで、音の「音色」や「構成」を可視化するためには、周波数分析が不可欠です。ここで活躍するのが p5.FFT (Fast Fourier Transform: 高速フーリエ変換) です。FFT は、音という複雑な波を、様々な周波数の単純なサイン波の集合体として分解します。これにより、「どの周波数帯域(低音、中音、高音)の音が、どれくらいの強さで鳴っているか」というスペクトル情報を配列として得ることができます。このスペクトル配列を元にすれば、クラシックなスペクトラムアナライザのような表現も容易に実装できます。

let mic, fft;

function setup() {
  createCanvas(710, 400);
  noFill();
  stroke(255);

  // マイク入力を開始
  mic = new p5.AudioIn();
  mic.start();

  // FFTオブジェクトを初期化し、入力をマイクに設定
  fft = new p5.FFT();
  fft.setInput(mic);
}

function draw() {
  background(0);

  // 周波数スペクトルを分析
  let spectrum = fft.analyze();

  beginShape();
  // 配列をループして、各周波数帯のエネルギーを線の高さとして描画
  for (let i = 0; i < spectrum.length; i++) {
    let x = map(i, 0, spectrum.length, 0, width);
    let h = -height + map(spectrum[i], 0, 255, height, 0);
    vertex(x, height);
    vertex(x, h);
  }
  endShape();
}

このコードは、マイクから入力された音の周波数スペクトルをリアルタイムで折れ線グラフとして描画します。自分の声や部屋で流れる音楽が、そのまま視覚的な地形として現れる様は、音と光の根源的な結びつきを直感的に感じさせてくれるでしょう。

音の生成と変容:アルゴリズムが織りなすサウンドスケープ

p5.js の真価は、既存の音を再生・分析するだけに留まりません。アルゴリズムによって、無から音を生成し、時間とともにその姿を変化させていく ジェネラティブサウンド の世界を切り拓きます。これは、静的な絵画を描くことと、生命を持つ生態系を育むことの違いに似ています。私たちは音の設計者となり、ルールを与えるだけで、あとはシステムが自律的に音響風景(サウンドスケープ)を織りなしていくのです。

その基本的な構成要素となるのが p5.Oscillator (オシレーター) です。これは指定された波形(サイン波、三角波、矩形波など)を、指定された周波数と振幅で生成する音の源です。例えば、マウスの X 座標を周波数に、Y 座標を振幅にマッピングすれば、画面上をなぞるだけでテルミンのような電子楽器を奏でることができます。

しかし、ただ音が鳴り続けるだけでは、音楽的な表情に欠けます。そこで重要になるのが p5.Envelope (エンベロープ) です。エンベロープは、音の時間的な輪郭、すなわち音量の変化を制御します。具体的には、Attack (音が最大音量に達するまでの時間)、Decay (Sustainレベルまで減衰する時間)、Sustain (持続する音量)、Release (音が消えるまでの時間) という、いわゆる ADSR を設定できます。これにより、打楽器のような短い音から、ゆっくりと立ち上がって消えていく持続音まで、多彩な音のキャラクターを生み出すことが可能になります。

let osc, envelope;

function setup() {
  createCanvas(windowWidth, windowHeight);
  
  osc = new p5.Oscillator('sine');
  
  // ADSRエンベロープを設定
  envelope = new p5.Envelope();
  envelope.setADSR(0.01, 0.2, 0.5, 1.0);
  envelope.setRange(0.8, 0); // アタック時の音量とリリース後の音量

  osc.start();
  osc.amp(0); // 最初は音量を0にしておく
}

function mousePressed() {
  // マウスの位置で周波数を決定
  let freqValue = map(mouseY, 0, height, 600, 200);
  osc.freq(freqValue);
  
  // エンベロープをトリガーして音を鳴らす
  envelope.play(osc);
}

このスケッチでは、マウスクリックのたびに、エンベロープによって制御された柔らかな輪郭を持つ音が生成されます。このようなジェネラティブなアプローチは、固定された楽曲を再生するのとは全く異なる体験をもたらします。それは、予測不能性と偶発性を許容し、一瞬ごとに移ろいゆく、二度とは再現できない音響の庭を育む試みです。

インタラクティブな音響表現:鑑賞者との対話が生み出す共振

音と視覚の探求をさらに深めるのは、鑑賞者の存在です。マウスの動き、キーボードの打鍵、マイクから拾う声。これらの入力をトリガーとして音とグラフィックがリアルタイムに変化するインタラクティブアートにおいて、音は極めて重要な役割を果たします。なぜなら、音は視覚以上に直接的に私たちの身体感覚に訴えかけ、アクションに対する即時的なフィードバックとして機能するからです。

マウスカーソルが特定の領域に入ったときに環境音が変化する。キーを押すたびに、異なる音階の音と、それに対応する色の粒子が画面に生まれる。マイクに向かって囁いた声の大きさに応じて、描かれる線の揺らぎが変化する。これらはすべて、鑑賞者の振る舞いをシステムの内部状態に変換し、それを聴覚と視覚の両方で出力する「対話」のループを形成しています。

この対話が豊かであるほど、作品は単なる鑑賞の対象から、鑑賞者が参加し、共創する「場」へと変化します。もはや作品は作者の手を離れ、鑑賞者の存在によってその都度、一回性の体験として生成されるのです。このプロセスにおいて、p5.js は鑑賞者と作品システムとの間の媒介者として機能します。mouseXkeyIsPressedmic.getLevel() といったシンプルな入力検知の仕組みが、音と視覚を操るための複雑なアルゴリズムへと接続されることで、深い没入感と、システムと一体になるような感覚が生まれます。それは、鑑賞者と作品との間に生まれる一種の「共振」と呼べるかもしれません。

音と視覚の融合が拓く、新たな表現の地平

p5.js を手に、音の可視化、生成、そしてインタラクションを探求する旅は、単に二つの異なるメディアを並置する行為ではありません。それは、音の構造が視覚の論理を決定し、視覚のパターンが音響のテクスチャを生み出すような、より深く、分かちがたく結びついた「共感覚的 (Synesthetic)」な体験を創造する試みです。例えば、音の持つ倍音構成の複雑さをフラクタルの自己相似性として視覚化したり、画面上のエージェントたちの動きが作り出すリズム・パターンをそのまま MIDI ノートとして出力したり、といった表現が考えられます。

この領域では、音と視覚はもはや主従の関係にはありません。それらは互いに影響を与え合い、一つの統合された表現システムの異なる側面として現れます。コードという極めて論理的な言語を用いて、私たちは「音が色を持つ」「形が響きを持つ」という、詩人や神秘主義者が語ってきたような世界のビジョンに、ささやかながらも具体的な形で触れることができるのです。

この探求に終わりはありません。なぜなら、聴覚と視覚の関係性をどのように「翻訳」し、どのように「共鳴」させるかという問いの答えは、アーティストの数だけ存在するからです。p5.js と p5.sound.js は、その無限の問いかけを始めるための、静かで力強い出発点を与えてくれます。キャンバスの上で、そして静寂の中で、あなたのコードがどのような響きを奏でるのか。その音に耳を澄ませてみてください。

関連記事