p5.sound

p5.soundは、Web上で音響処理を手軽に行えるp5.jsの拡張ライブラリです。
基本的なサウンド生成からエフェクト、フィルター、音量といった音響属性の制御、さらには高度な音響分析までを実現する多数の機能が備わっています。

目次
  1. Reference
  2. 基礎知識
  3. 環境設定
  4. p5.domとは
  5. p5.Amplitude
  6. p5.FFT
  7. 音を作成する
    1. p5.Oscillator
    2. p5.Envelope
  8. 課題

Reference

  • Envelope: 音の持続時間と振幅を制御するための設定。
  • SoundFile: オーディオファイルを読み込んで再生や編集ができるクラス。
  • Amplitude: 音の大きさ(振幅)を測定する。
  • FFT: 音の周波数成分を解析するツール。
  • Oscillator: 音波を生成するためのコンポーネント。
  • SoundRecorder: オーディオを録音する。
  • Distortion: 音波を歪ませるエフェクト。
  • Gain: 音量を制御する。
  • AudioVoice: 単一の音源(ボイス)を表す。
  • MonoSynth: 単一の音色で音を生成するシンセサイザー。
  • PolySynth: 複数の音色で音を生成するシンセサイザー。
  • Noise: ノイズ(白、ピンク、ブラウンなど)を生成する。
  • Pulse: 矩形波で音を生成する。
  • AudioIn: マイク入力などの外部オーディオソース。
  • Effect: 音に様々なエフェクトを加える基底クラス。
  • Filter: 音の特定の周波数範囲をカットまたは強調する。
  • EQ: 特定の周波数帯域の振幅を調整する。
  • Panner3D: 3D空間内での音の位置を制御する。
  • Delay: 音を遅延させるエフェクト。
  • Reverb: 残響(反響)を作成するエフェクト。
  • Convolver: 畳み込みを使用して音に複雑なエフェクトを加える。
  • Phrase: 一連の音符とリズムパターン。
  • Part: 複数のフレーズを組み合わせる。
  • Score: 複数のパートを時系列で管理する。
  • SoundLoop: オーディオループを作成と制御。
  • Compressor: 音のダイナミクスを制御するエフェクト。
  • PeakDetect: 音のピーク(最高振幅)を検出する。

基礎知識

振幅 (Amplitude): 音の大きさを表す。通常、0から1の間で設定されます
周波数 (Frequency): 音の高さを表す。単位はヘルツ(Hz)
デュレーション (Duration): 音が鳴っている時間。単位は秒

エフェクト関連
リバーブ (Reverb): 音に反響を加える効果。長さや湿度などをパラメータとして持つ
ディレイ (Delay): 音を遅延させる効果。遅延時間やフィードバックが主なパラメータ

フィルタリング
Low-pass Filter: 高周波成分をカットするフィルタ
High-pass Filter: 低周波成分をカットするフィルタ

波形関連
Sinewave: サイン波。自然界の音に近い
Squarewave: 矩形波。電子音に使われる
Trianglwave: 三角波。弦楽器に似た音

ステレオとモノラル
Stereo: 左右独立した音
Mono: 単一の音源から出る音

タイミングとテンポ
BPM (Beats Per Minute): 曲のテンポを表す
Beat: 曲のリズムの基本単位

音色とシンセサイザー
Oscillator Types: オシレータ(振動子)の種類(サイン、ソー、スクエアなど)
ADSR (Attack, Decay, Sustain, Release): 音のエンベロープを形成する4つのステージ

環境設定

p5.soundはp5.js本体に含まれているコアライブラリです

HTMLファイルにライブラリを追加する場合
p5.js本体の後に追加する必要があります

<!doctype html>
<html>
<head>
  <script src="p5.js"></script>  
  <script src="p5.sound.js"></script>  
  <script src="main.js"></script>  
</head>
<body>
</body>
</html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/addons/p5.sound.min.js"></script>

p5をインストールしてインポートする場合

import p5 from 'p5';
import 'p5/lib/addons/p5.sound';

とりあえず、音楽を流してみる

let song;

//サウンドファイルをロード
function preload() {
song = loadSound('./file.mp3');
}

function setup() {
createCanvas(windowWidth, windowHeight);
//サウンド再生
song.play();
}

注意点: draw関数内での音楽の再生
draw関数は毎フレームごとに呼び出されるので何度も音楽が再生されてしまいます

//draw関数内で状態変数を使用して曲が既に再生されているかどうかをチェックする
let isSongPlaying = false;
//マウスが押されたときに
const draw = (p5) => {
  if (!isSongPlaying) {
    song.play();
    isSongPlaying = true;
  }
};
function mousePressed() {
  // マウスが押されたら一度だけ音楽を再生する
  song.play();
}

p5.domとは

p5.domは、かつてはp5.jsの拡張ライブラリとして提供されていたが、現在はp5.jsのコアに統合されています。
この機能はを使いHTML DOM要素とのインタラクションを容易にすることです

例えば以下のようなものを簡単に作成・操作できます

  • テキストボックス(createInput)
  • スライダー(createSlider)
  • ボタン(createButton)
  • ドロップダウンメニュー(createSelect)
  • チェックボックス(createCheckbox)
  • テキストエリア(createTextarea)

ウンドファイルを再生・停止するための2つのボタンを生成し、それぞれのボタンにスタイルを適用しています

let sound; // サウンドオブジェクトを格納する変数
let playButton, stopButton; // プレイとストップのボタン用の変数

// preload関数でサウンドファイルを読み込む
function preload() {
  sound = loadSound('path/to/sound.mp3');
}

// setup関数でキャンバスとUIを作成する
function setup() {
  createCanvas(400, 400); // キャンバスを作成

  // プレイボタンを作成
  playButton = createButton('Play');
  playButton.position(20, 20);
  playButton.style('background-color', '#00FF00'); // 背景色を緑に設定
  playButton.style('color', '#FFFFFF'); // 文字色を白に設定
//addClassメソッドを使用してクラスを追加することもできます
  //playButton.addClass('my-class');
  // プレイボタンがクリックされたらサウンドを再生
  playButton.mousePressed(() => {
    sound.play();
  });

  // ストップボタンを作成
  stopButton = createButton('Stop');
  stopButton.position(20, 50);
  stopButton.style('background-color', '#FF0000'); // 背景色を赤に設定
  stopButton.style('color', '#FFFFFF'); // 文字色を白に設定
  // ストップボタンがクリックされたらサウンドを停止
  stopButton.mousePressed(() => {
    sound.stop();
  });
}

p5.Element

p5.js の create* 関数(例:createCanvas, createButton など)を使用して DOM 要素を生成すると、その要素を表す 「p5.Element オブジェクト」が返されます。このオブジェクトに対して、各種メソッド(.position(), .style() など)を適用することで、要素を操作できます

https://p5js.org/reference/#/p5.Element

p5.Amplitude

オーディオ信号の振幅(音量の強さ)を分析するために用いられます。
このクラスを使うことで、実行中のオーディオ信号(例えば、音楽や話し声など)の振幅をリアルタイムで取得することができます
音量が大きい瞬間や小さい瞬間をプログラムで検出し、それに応じてグラフィックの変更や他のイベントをトリガーするなどの操作が可能になります

音楽ファイルの振幅に応じて、画面中央の円の大きさが動的に変わります

let amplitude;

function setup() {
  let cnv = createCanvas(400, 400);
  cnv.mouseClicked(togglePlay);
  soundFile = loadSound('song.mp3'); // 音楽ファイルの読み込み
  amplitude = new p5.Amplitude();
}

function draw() {
  background(200);
  let level = amplitude.getLevel(); // 振幅(音量レベル)を取得
  let size = map(level, 0, 1, 0, 200); // 振幅に応じて円の大きさを変える
  ellipse(width/2, height/2, size, size);
}

function togglePlay() {
  if (soundFile.isPlaying()) {
    soundFile.pause();
  } else {
    soundFile.loop();
  }
}

余談 map関数の基本的な形

map(value, start1, stop1, start2, stop2)

value(値):マッピングする値。この値はstart1とstop1の間にあるとされます。
start1(開始1):元の範囲の最小値。
stop1(終了1):元の範囲の最大値。
start2(開始2):新しい範囲の最小値。
stop2(終了2):新しい範囲の最大値。

level(amplitude) は0から1の範囲の値なので、上記のコードでは
この level 値を0から200の範囲にマッピングします。
具体的には、level が0の場合、size も0になります。level が1の場合、size は200になります

p5.FFT

FFT(Fast Fourier Transform)とは、ディジタル信号処理でよく用いられる高速フーリエ変換のアルゴリズムです
p5.FFTは、音声信号を周波数領域に変換する役割を果たします

  • 周波数解析:analyze()メソッドを使用して、特定の時点での周波数領域のデータを取得できます。このデータは通常、配列として返されます。
  • 波形解析:waveform()メソッドで、波形(時間領域)のデータを取得できます。
  • ビジュアル化:p5.jsのrect()やellipse()などの描画関数を用いて、周波数や波形のデータをビジュアル化できます。

周波数スペクトルを解析し、それを矩形でビジュアル化しています

// 音声ファイルとFFTオブジェクトをグローバル変数として定義
let soundFile;
let fft;

// プリロード関数で音声ファイルを読み込む
//preload関数内で指定されたファイルの読み込みが完了するまで、他の関数は実行されません
function preload() {
  soundFile = loadSound('./sound.mp3');
}

// セットアップ関数で初期設定を行う
function setup() {
  // キャンバスを生成し、クリックイベントを設定
  let cnv = createCanvas(400, 200);
  cnv.mouseClicked(togglePlay);

  // 音声ファイルを再生
  soundFile.play();

  // FFTオブジェクトを生成
  fft = new p5.FFT();
}

// 描画関数でFFT解析と可視化を行う
function draw() {
  // 背景を白に設定
  background(255);

  // FFT解析の結果を取得
  let spectrum = fft.analyze();

  // FFT解析の結果を用いて可視化
  for (let i = 0; i < spectrum.length; i++) {
    let x = map(i, 0, spectrum.length, 0, width); // X座標を計算
    let h = map(spectrum[i], 0, 255, 0, height);  // 高さを計算
    fill(0,0,0); 
    rect(x, height, width / spectrum.length, -h); // 長方形を描画
  }
}

// キャンバスがクリックされたときの処理
function togglePlay() {
  // 音声が再生中であれば一時停止、それ以外なら再生
  if (soundFile.isPlaying()) {
    soundFile.pause();
  } else {
    soundFile.loop();
  }
}

音を作成する

p5.Oscillator

p5.Oscillatorはp5.jsの音声ライブラリに含まれており、基本的な正弦波(sine)、三角波(triangle)、方形波(square)、鋸歯波(sawtooth)を生成するためのオブジェクトです。これにより音をプログラムで生成することができます。

let osc;

function setup() {
  osc = new p5.Oscillator('sine');  // 正弦波のオシレーターを生成
}

function draw() {
  osc.freq(440);  // 周波数を440Hzに設定
  osc.amp(0.5);  // 振幅(音量)を0.5に設定
  osc.start();  // 音を再生
}

p5.Envelope

音のエンベロープ(包絡線)を簡単に生成・操作できるクラスです。基本的にはADSR(Attack, Decay, Sustain, Release)モデルを使って、音の形状や動きを設定できます

  • Attack(アタック): 音が始まってから最大音量になるまでの速さ。
    短い = 速く音が大きくなる
    長い = ゆっくり音が大きくなる
  • Decay(ディケイ): 最大音量から安定した音量(サステインレベル)まで落ちる速さ。
    短い = 速く音が小さくなる
    長い = ゆっくり音が小さくなる
  • Sustain(サステイン): 安定した音量を保つ力。
    キーを押している間はこの音量が保たれる。
  • Release(リリース): 音が完全に消えるまでの速さ。
    短い = 速く音が消える
    長い = ゆっくり音が消える

要するに、ADSRは音が「どれくらい速く大きくなるか」、「どれくらい速く小さくなるか」、「どれくらいの音量で続くか」、「どれくらい速く消えるか」を決めるものです。

osc.amp(env)
エンベロープを継続的に適用します。
手動で音の開始と停止を制御可能。

let env, osc;

function setup() {
  env = new p5.Envelope();
  osc = new p5.Oscillator('sine');
  osc.amp(env);  // エンベロープを継続的に適用
  osc.start();
}

function mousePressed() {
  env.setADSR(0.1, 0.2, 0.5, 1); // Attack, Decay, Sustain, Release
  env.triggerAttack();  // 手動でアタックフェーズを開始
}

function mouseReleased() {
  env.triggerRelease();  // 手動でリリースフェーズを開始
}

env.play(osc)
エンベロープを一度「プレイ」して、その後自動で停止します。
単発の音に便利。

let env, osc;

function setup() {
  env = new p5.Envelope();
  osc = new p5.Oscillator('sine');
}

function mousePressed() {
  env.setADSR(0.1, 0.2, 0.5, 1); // Attack, Decay, Sustain, Release
  osc.start();
  env.play(osc); // エンベロープを一度「プレイ」
}

function mouseReleased() {
  // env.play()を使うと、自動で音が停止する
}

課題

Uncaught TypeError: Cannot read properties of undefined (reading ‘length’)
at RingBuffer.push
このようなエラーが発生します。