3:サウンドの再生 p5.sound.js サウンド

以降のサンプルはp5.jsの「Examples」ページの[Sound]項からのものです。基本的に、サンプルコードはそのまま使用し、その下に実行結果と解説を示しています。

サウンドの読み込みと再生

preload()関数でサウンドを読み込み、キャンバスがクリックされたらサウンドを再生します。このサンプルをローカルで実行するには、p5.soundライブラリとサウンドファイルを用意し、ローカルサーバーで実行します。

let song;

function setup() {
    song = loadSound('assets/lucky_dragons_-_power_melody.mp3');
    createCanvas(720, 200);
    background(255, 0, 0);
}

function mousePressed() {
    if (song.isPlaying()) {
        // .isPlaying()はブール値を返す
        song.stop();
        background(255, 0, 0);
    }
    else {
        song.play();
        background(0, 255, 0);
    }
}

キャンバスのクリックで、サウンドの再生のオンとオフを切り替えます。

解説
リファレンスメモ

loadSound()

説明

loadSound()は、指定されたパスから新しいp5.SoundFileを返す。preload()中に呼び出された場合、そのp5.SoundFileは、setup()やdraw()での使用に間に合うように再生の準備を整える。preload()の外で呼び出された場合には、p5.SoundFileは即座に準備できないので、第2パラメータとしてコールバックを受け取る。外部ファイルをロードするときにはローカルサーバーの使用が推奨される。

この関数はp5.soundライブラリを必要とするので、index.htmlファイルの<head>部には、次のコードを追加する。

<script src="path/to/p5.sound.js"></script>
シンタックス

loadSound(path, [successCallback], [errorCallback], [whileLoading])

パラメータ

path 文字列|配列: サウンドファイルへのパスか、複数の形式のサウンドファイルへのパスを含む配列。例:[‘sound.ogg’, ‘sound.mp3’]。代替法として、HTML5 File APIかp5.Fileからのオブジェクトを渡す方法もある。
successCallback 関数: ファイルが読み込まれたときに呼び出す関数の名前(オプション)
errorCallback 関数: ファイルの読み込み中、エラーが発生した場合に呼び出す関数の名前(オプション)
whileLoading 関数: ファイルの読み込み中に呼び出す関数の名前。この関数は0.0から1.0までの読み込んだパーセンテージを受け取る(オプション)

戻り

SoundFile: p5.SoundFileを返す

p5.SoundFile

説明

ファイルへのパスを持つSoundFileオブジェクト。
p5.SoundFileは、ファイル情報を非同期で読み込むので、即座に使用できない可能性がある。
読み込んですぐサウンドで何かするには、第2パラメータとして関数の名前を渡す。
ファイルへのパスは1つでよいが、オーディオファイル形式(mp3, ogg, wav, m4a/aacなど)はすべてのWebブラウザでサポートされているわけではない。互換性を確保したい場合には、1ファイルへのパスでなく、複数のファイルへのパスを含んだ配列を渡すこともできる。するとブラウザは動作する形式を選択する。

この関数はp5.soundライブラリを必要とするので、index.htmlファイルの<head>部には、次のコードを追加する。

<script src="path/to/p5.sound.js"></script>
シンタックス

new p5.SoundFile(path, [successCallback], [errorCallback], [whileLoadingCallback])

パラメータ

path 文字列|配列: サウンドファイルへのパス(文字列)。複数のファイル形式を配列に入れて指定することもできる。また、GTML5 File APIやp5.Fileからのオブジェクトも受け取る。
successCallback 関数: ファイルが読み込まれたときに呼び出す関数の名前(オプション)
errorCallback 関数: ファイルの読み込みに失敗した場合に呼び出す関数の名前。この関数は、エラー、つまり何が問題であったかに関する情報を持ったXMLHttpRequestオブジェクトを受け取る(オプション)
whileLoadingCallback 関数: ファイルの読み込み中に呼び出す関数の名前。この関数は、第1パラメータとして、サウンドファイルの読み込みリクエストの進捗度(0と1の間)で受け取る。この進捗度には、オーディオデータのでコードに必要な追加時間は考慮されない(オプション)

isPlaying()

説明

p5.SoundFileが再生中ならtrueを返し、そうでない(一時停止か停止)ならfalseを返す。

stop()

説明

サウンドファイルの再生を停止する。

シンタックス

stop([startTime])

パラメータ

startTime 数値: 今から何秒後にこの出来事を発生させるか(オプション)

play()

説明

p5.SoundFileを再生する。

シンタックス

play([startTime], [rate], [amp], [cueStart], [duration])

パラメータ

startTime 数値: (今から何秒後に)再生を開始するか(オプション)
rate 数値: (任意の)再生レート(オプション)
amp 数値: (任意の)再生の振幅(音量)(オプション)
cueStart 数値: 秒単位の(任意の)キュー開始時間(オプション)
duration 数値: 秒単位の再生の(任意の)継続時間(オプション)

サウンドファイルの事前読み込み(プリロード)

setup()が呼び出される前にサウンドを完全に読み込んでおくには、preload()中にloadSound()を呼び出します。loadSound()をpreload()内でつねに呼び出すようにするのが最も良い方法です。そうしない場合、サウンドは必ずしも、再生したいときまでにスケッチに読み込まれるとは限りません。

let song;
let isUserStarted = false;

function preload() {
    song = loadSound('assets/lucky_dragons_-_power_melody.mp3');
}

function setup() {
    const canvas = createCanvas(710, 200);
    // キャンバスのマウスプレスでtogglePlay()を呼び出す
    canvas.mousePressed(togglePlay);
    // 無音時は緑
    background(0, 255, 0);
}

// マウスプレスで再生/一時停止を切り替える
function togglePlay() {
    print('mouse');
    if (!song.isPlaying()) {
        // .play()は.pause()位置から再開する
        song.play();
        // 再生中は赤
        background(255, 0, 0);
    }
    else {
        song.pause();
        // 無音時は赤
        background(0, 255, 0);
    }
}

function touchStarted() {
    if (!isUserStarted) {
        // touchStarted()を1回だけ呼び出されるようにする
        print('touch');
        userStartAudio();
        isUserStarted = true;
    }
}
解説

このサンプルをChromeブラウザで開くと、[デベロッパーツール]の[Console]画面に、「The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page. https://goo.gl/7K7WLu」という注意が表示されます。

これは、”AudioContextの開始は許可されない、ページへのユーザージェスチャ後に再開(または作成)しなければならない”という、Chromeブラウザの自動再生ポリシーによるものです。このポリシーは簡単に言うと、サウンドやビデオの再生は、開発者が勝手に開始するのではなく、ボタンのクリックなど、ユーザーからの何らかの積極的なアクションによって開始すべきものだ、とする考えです。

p5.sound.jsでは、このポリシーに対処できるuserStartAudio()という関数が提供されています。あらかじめユーザーに対し、マウスクリックなどでサウンドの再生が始まることを伝えておき、ユーザーのクリックという積極的なアクションからuserStartAudio()を呼び出して、AudioContextを開始します。

リファレンスメモ

loop()

説明

p5.SoundFileを繰り返す。再生レートや音量、ループの開始、終了を設定するオプションのパラメータを受け取る。

シンタックス

loop([startTime], [rate], [amp], [cueLoopStart], [duration])

パラメータ

startTime 数値: 今から何秒後にこの出来事を発生させるか(オプション)
rate 数値: (任意の)再生レート(オプション)
amp 数値: (任意の)再生音量(オプション)
cueLoopStart 数値: (任意の) 秒単位のstartTime(オプション)
duration 数値: (任意の)秒単位のループ継続時間(オプション)

pause()

説明

現在再生中のファイルを一時停止する。再生中でない場合には、何も起こらない。
一時停止した後、.play()は、一時停止した位置から再生を再開する。p5.SoundFileが、一時停止する前に、ループするよう設定されている場合には、.play()によって一時停止が解除された後、ループを継続する。

シンタックス

pause([startTime])

パラメータ

startTime 数値: 今から何秒後にこの出来事を発生させるか(オプション)

userStartAudio()

説明

ユーザーに音声再生開始への制御を与えるのは優れたプラクティス(慣習)。このプラクティスは、Google Chromeのr70バージョンでの自動再生ポリシー(情報)とiOS Safari、そのほかのブラウザに強要される。

userStartAudio()はユーザージェスチャでAudioContextを開始する。この関数は、Yotam MannのStartAudioContextライブラリ(MIT Licence, 2016)を利用している。詳細はこちら(https://github.com/tambien/StartAudioContext)

ユーザージェスチャによるオーディオコンテキストの開始はuserStartAudio()を使えば簡単。オプションのパラメータを使用すると、オーディオコンテキストを開始する特定の要素を決めたり、オーディオコンテキストが開始された後に関数を呼び出すことができる。

シンタックス

userStartAudio([element(s)], [callback])

パラメータ

element(s) 要素|配列: この引数には、Element、Selector String、NodeList、p5.Element、jQuery Element、またはこれらを含む配列が指定できる(オプション)
callback 関数: AudioContextが開始したときに呼び出すコールバック(オプション)

戻り

Promise: AudioContextが’running’状態のときに解決されるPromiseを返す

soundFormats

厳密に言うと、特許の問題により、すべてのWebブラウザがサポートする単一のサウンド形式はありません。たとえばmp3は、OS XとWindowsの主要ブラウザの最新版でサポートされていますが、主流でないOSやブラウザでは利用できない場合があります。
*
完全な互換性を確保するには、同じサウンドファイルを複数の形式で、たとえば’sound.mp3’と’sound.ogg’のように用意します(Oggはmp3の代替となるオープンソースです)。オーディオファイルはmedia.ioを使うと、無料かつオンラインで、Webで扱いやすい形式に変換できます。
*
soundFormats()関数はloadSound()に、スケッチに含めた形式を伝えます。するとloadSound()は、クライアントのWebブラウザがサポートする最初の形式を読み込もうとします。

let song;

function preload() {
    // サウンド形式に.oggファイルと.mp3ファイル両方を含める
    soundFormats('ogg', 'mp3');

    // このブラウザがmp3をサポートしない場合、
    // loadSound()は、スケッチに含めておいたoggファイルを読み込む
    song = loadSound('assets/lucky_dragons_-_power_melody.mp3');
}

function setup() {
    createCanvas(710, 200);
    background(0, 255, 0);

    // ボタン
    const button = setButton('PLAY', {
        x: 40,
        y: 180
    });

    button.mousePressed(() => {
        // 再生中なら
        if (song.isPlaying()) {
            // 一時停止
            song.pause();
            // ボタンのラベルを変更
            button.html('PLAY');
            // 背景色を変更
            background(255, 0, 0);
            // 再生中でないなら
        }
        else {
            // 再生
            song.play();
            button.html('PAUSE');
            background(0, 255, 0);
        }
    });
}

function mousePressed() {
    // サンプルから変更
}

function setButton(label, pos) {
    const button = createButton(label);
    button.size(100, 30);
    button.position(pos.x, pos.y);
    return button;
}
解説

このサンプルでは、Chromeブラウザの自動再生ポリシーに抵触しないように、ボタンのクリックによって開始するように変更しています。なお、ボタンのラベルの変更に使用しているhtml()関数はp5.domライブラリの関数です。

リファレンスメモ

soundFormats()

説明

含めるSoundFile形式をリストアップする。loadSound()はディレクトリでこれらの拡張子を検索し、クライアントのWebブラウザと互換性のある形式を選択します。これはフリーのオンラインファイルコンバーターです。

シンタックス

soundFormats([formats])

パラメータ

formats 文字列: たとえば’mp3′, ‘wav’, ‘ogg'(オプション)

プレイモード

‘sustain’モードでは、サウンドはそれ自体と重なり、’restart’モードでは、一度停止してから最初からスタートします。 ページをクリックするとサウンドファイルが再生されます。何度もクリックすると多くのサウンドを一度に再生できます。いずれかのキーを押すと、プレイモードを切り替えることができます。

let playMode = 'sustain';
let sample;

function setup() {
    createCanvas(710, 50);
    soundFormats('mp3', 'ogg');
    sample = loadSound('assets/Damscray_-_Dancing_Tiger_02.mp3');
}

function draw() {
    background(255, 255, 0);
    let str = 'ここをクリックして再生、キーを押してプレイモードを切り替え';
    str += ' 現在のプレイモード: ' + playMode + '.';
    text(str, 10, height / 2);
}

function mouseClicked() {
    sample.play();
}

function keyPressed(k) {
    togglePlayMode();
}

function togglePlayMode() {
    if (playMode === 'sustain') {
        playMode = 'restart';
    }
    else {
        playMode = 'sustain';
    }
    sample.playMode(playMode);
}
解説

sustainは維持する、という意味です。

リファレンスメモ

playMode()

説明

p5.SoundFileは、restartとsustainという2つのプレイモード(再生モード)を持っている。プレイモードは、再生が再生途中に引き起こされた場合のp5.SoundFileの動作を決める。sustainモードでは新しい再生と同時に継続され、restartモードではplay()が再生を止め最初からスタートする。untilDoneを指定すると、まだ再生されていない場合のみ再生される。デフォルトのモードはsustain。

シンタックス

playMode(str)

パラメータ

str 文字列: ‘restart’か’sustain’または’untilDone’

サウンドのパン

マウスクリックでサウンドを再生します。ボールの位置はマウスに付随し、サウンドのパンにも関係します。

let ball = {};
const soundFile;

function preload() {
    soundFormats('mp3', 'ogg');
    soundFile = loadSound('assets/beatbox.ogg');
}

function setup() {
    createCanvas(710, 100);
}

function draw() {
    background(0);
    ball.x = constrain(mouseX, 0, width);
    ellipse(ball.x, height / 2, 100, 100);
}

function mousePressed() {
    // ボールのx位置を、-1(左)と1(右)の間のパンの度合いにマッピングする
    let panning = map(ball.x, 0, width, -1.0, 1.0);
    soundFile.pan(panning);
    soundFile.play();
}
解説

パンは通常、カメラの左右への振りを表す用語ですが、サウンドをステレオで再生する場合の、左と右のスピーカーへの音の振り分けも意味します(「パンニング (音響)」)。

サウンドのパン設定を-1にすると、サウンドは全部左のスピーカーから聞こえ、1にすると全部右のスピーカーから聞こえ、0にすると左右スピーカーの間から聞こえます。

サンプルでは、draw()関数内の次のコードによって、mouseXが0とキャンバスの幅の間に制限されます。これにより、円はキャンバスの外に出なくなります。constrain()関数については「7_4:ランダム p5.js JavaScript」で述べています。

ball.x = constrain(mouseX, 0, width);

ページをクリックすると。次のmousePressed()関数が呼び出されます。このmap()関数は、0とキャンバス幅の間にあるball.xの値を、-1と1の間の数値に対応付けします。つまり、ボールが左端にあると変数panning は-1になり、右端にあると1になります。map()関数については「4_7:マッピング(対応付け) p5.js JavaScript」で述べています。soundFile.pan()はこの数値を使ってサウンドのパン設定を行います。

function mousePressed() {
    let panning = map(ball.x, 0, width, -1.0, 1.0);
    soundFile.pan(panning);
    soundFile.play();
}
リファレンスメモ

pan()

説明

p5.soundオブジェクトのステレオパンニングを、-1.0(左)と1.0(右)の間の浮動小数点数に設定する。デフォルトは0.0(センター)。

シンタックス

pan([panValue], [timeFromNow])

パラメータ

panValue 数値: ステレオパンナーを設定する(オプション)
timeFromNow 数値: 今から何秒後にこの出来事を発生させるか(オプション)

効果音

マウスが円の中でクリックされると、効果音を再生します。

sketch.js

// Adapted from Learning Processing by Daniel Shiffman
// http://www.learningprocessing.com
// Doorbell sample by Corsica_S via freesound.org,
// Creative Commons BY 3.0

// p5.SoundFileオブジェクト
let dingdong;

// Doorbellオブジェクト(サウンドを鳴らすきっかけとなる)
let doorbell;

function setup() {
    createCanvas(200, 200);
    // MP#とOGGの両バージョンを用意する
    soundFormats('mp3', 'ogg');
    dingdong = loadSound('assets/doorbell.mp3');
    // Doorbellオブジェクトを作成
    doorbell = new Doorbell(width / 2, height / 2, 64);
}

function draw() {
    background(255);
    // Doorbellオブジェクトを描画
    doorbell.display(mouseX, mouseY);
}

function mousePressed() {
    // ドアベルがクリックされたら、サウンドを再生する
    if (doorbell.contains(mouseX, mouseY)) {
        dingdong.play();
    }
}

Doorbell.js

// ドアベル(実際にはボタン)を表すクラス
class Doorbell {
    constructor(x_, y_, r_) {
            // 位置とサイズ
            this.x = x_;
            this.y = y_;
            this.r = r_;
        }
        // (mx, my)がドアベル内にあるかどうか(マウスのロールオーバーに使用)
    contains(mx, my) {
        return dist(mx, my, this.x, this.y) < this.r;
    }

    // ドアベルを表示。カラーをハードコーディングしている。改善できる
    display(mx, my) {
        if (this.contains(mx, my)) {
            fill(100);
        }
        else {
            fill(175);
        }
        stroke(0);
        strokeWeight(4);
        ellipse(this.x, this.y, this.r, this.r);
    }
}
解説

このサンプルのポイントは、マウスカーソルが円の中にあってそこでクリックされたときにだけ、音が鳴ることです。これは、sketch.jsのmousePressed()関数で行われています。

function mousePressed() {
    if (doorbell.contains(mouseX, mouseY)) {
        dingdong.play();
    }
}

mousePressed()はキャンバスだけでなく、HTMLページのどこかがクリックされたときに呼び出されます。それを円内に限っているのは、Doorbellクラスのcontains()メソッドです。

contains(mx, my) {
    return dist(mx, my, this.x, this.y) < this.r;
}

動作が1行で書かれているので分かりにくいかも知れません。その場合には分けて書き直すのが一番です。

contains(mx, my) {
    // return dist(mx, my, this.x, this.y) < this.r;
    // (mouseX,mouseY)と(100,100)間の距離
    const distance = dist(mx, my, this.x, this.y);
    // その距離より64の方が大きいかどうか => 大きければマウスカーソルは円の中にあることになる
    const isInside = distance < this.r;
    // その結果をtrueかfalseで返す
    return isInside;
}

再生レート

SoundFileを読み込み、その再生レートをmouseYにマッピングします。再生レートは、Webオーディオコンテキストがサウンドファイルの情報を処理するスピードです。レートを遅くすると、そのサウンドの持続時間が増加するだけでなく、より低い周波数で再生されるので、ピッチが減少します。

// p5.SoundFileオブジェクト
let song;

function preload() {
    // サウンドファイルの読み込み
    song = loadSound('assets/Damscray_DancingTiger.mp3');
}

function setup() {
    createCanvas(710, 400);

    // Chromeの自動再生ポリシーに沿うため、ここでsong.loop()は実行しない

    // 代わりにボタンのクリックでループ再生と停止を切り替える
    const button = setButton('LOOP', {
        x: 600,
        y: 350
    });
    button.mousePressed(() => {
        if (song.isPlaying()) {
            song.stop();
            button.html('LOOP');
        }
        else {
            // ループ再生
            song.loop();
            button.html('STOP');
        }
    });
}

function draw() {
    background(200);

    // 音量を0と1の範囲におさめる
    let volume = map(mouseX, 0, width, 0, 1);
    volume = constrain(volume, 0, 1);
    song.amp(volume);

    // レートを0.01と4の範囲におさめる
    // レートの変更によってピッチが変わる
    let speed = map(mouseY, 0.1, height, 0, 2);
    speed = constrain(speed, 0.01, 4);
    song.rate(speed);

    // mouseXとmouseYの変化を円の位置で示す
    stroke(0);
    fill(51, 100);
    ellipse(mouseX, 100, 48, 48);
    stroke(0);
    fill(51, 100);
    ellipse(100, mouseY, 48, 48);
}

function setButton(label, pos) {
    const button = createButton(label);
    button.size(100, 30);
    button.position(pos.x, pos.y);
    return button;
}
解説

このサンプルでもChromeの自動再生ポリシーに沿うように、ボタンのクリックでサウンドのループ再生と停止を切り替えています。このサンプルでは、マウスのmouseXで音量を、mouseYで音程を変えているので、変化が同時に起こります。変化を明確に聞くようにするために、次のどちらかにコメントをつけて、一方だけ有効にして実行する方がよいでしょう。

song.amp(volume);
song.rate(speed);

音の仕組み(参考:「01. 音の仕組み」)

音は音の波(音波)として下図のように表されます。波形変化の1回分を周期、波の高さを振幅と言います。これはサインやコサインの波と同じです(「8:数学(Math)」参照)。

音程(音の高低)は振動の回数で決まります。下図では、同じ時間内で青い波形の方が多く振動しているので、高い音になります。周波数はこの回数を示すもので、1秒間の周期の繰り返し回数を言います。

音量(音の大小)は振幅の大きさで決まります。下図では青い波形の振幅の方が赤い波形の振幅より大きいので、大きな音になります。

増幅とピッチ

ではこの波形変化を、Audacityというフリーのオーディオエディタで見てみましょう。

下図は前のドアベルの音として使用したdoorbell.mp3をAudacityで開いて表示される波形です。下のコントロールで波形の音が再生できます。


このdoorbell.mp3をAudacityの[エフェクト]→[増幅]機能を使って、増幅、つまり振幅を大きくしたのが下図です。その下のコントロールで再生すると分かりますが、ベル音が鳴った後、少しして不自然に残音が大きく聞こえるのが分かります。


次はピッチを下げてみます。これにはAudacityの[エフェクト]→[変更:ピッチの変更]機能を使用します。

ピッチを下げるということは振動回数を減らす、周波数を下げるということで、下図に示すように、波形の波の数が減り、音が低くなります。

下のコントロールで再生すると、ドアベルの音が低くなったことが分かります。

音量を操作する、つまり波形の振幅を変化させているのは、draw()関数内の次のコードです。変数volumeの値は0と1の間に制限され、これをSoundFileオブジェクトのamp()メソッドに渡します。

let volume = map(mouseX, 0, width, 0, 1);
volume = constrain(volume, 0, 1);
song.amp(volume);

また音程を操作する、つまり振動回数を変化させている(=周波数を変化させている、ピッチを変えている)のは、draw()関数内の次のコードです。変数speedの値は0.01と4の間に制限され、これをSoundFileオブジェクトのrate()メソッドに渡します。。

let speed = map(mouseY, 0.1, height, 0, 2);
speed = constrain(speed, 0.01, 4);
song.rate(speed);

変数speedには再生速度の意味が含まれていると思われます。スピードを速くするとピッチが上がり、音が高くなる、という感覚です。今はほとんど使われなくなった音楽テープの早送りや、DVDの倍速再生でも、早送りすると音が高くなるので、イメージできると思います。

リファレンスメモ

amp() setVolume()
*p5.SoundFile.amp()はp5.SoundFile.setVolume()と同じ

説明

サウンドファイルの出力音量(振幅)を、0.0(無音)と1.0(フルボリューム)の間の数値と乗算する。1.0はデジタルサウンドの最大振幅なので、1.0より大きな値を掛けると、デジタルディストーション(歪み)の原因になる。フェードするには、rampTimeパラメータを与える。複雑なフェードについては、Envelopeクラスを参照。

また別の方法として、オシレーター(発振器)などの信号ソースを渡して、オーディオ信号で振幅を変調することもできる。

シンタックス

amp([vol], [rampTime], [tFromNow])

パラメータ

vol 数値: 0と1.0の間の振幅(オプション)
rampTime 数値: rampTimeまでつづくフェードを作成する(オプション)
tFromNow 数値: 今から何秒後にこの出来事を発生させるか(オプション)

rate()

説明

サウンドファイルの再生レートを設定する。これによりスピードとピッチが変わる。0未満の値はオーディオバッファを反転させる。

シンタックス

rate([playbackRate])

パラメータ

playbackRate 数値: 再生レートを設定する。1.0はノーマル、.5は1/2倍速、2.0は倍速再生。0未満の値は逆方向の再生となる(オプション)

振幅の計測

サウンドの振幅をp5.Amplitudeで分析します。
*
振幅は振動の大きさです。サウンドは振動なので、その振幅は音量やラウドネス(音の大きさ)に密接に関係します。
*
getLevel()メソッドは、ごく短時間で収集した振幅値の配列を取り(1024サンプル)、それらの値の二乗平均平方根(RMS)を返します。
*
デジタルオーディオの元の振幅値は-1.0と1.0の間の値ですが、RMSは2乗なのでつねに正になります。また、1秒当たり44.100回の頻度でサンプリングする瞬時の振幅読み取り値でなく、時間経過のともなう平均(今の場合は1024サンプル)のRMSを使用するので、人間が聞いている振幅がより適切に表現できます。

let song, analyzer;

function preload() {
    song = loadSound('assets/lucky_dragons_-_power_melody.mp3');
}

function setup() {
    createCanvas(710, 200);
    // 新しいAmplitudeアナライザーを作成する
    analyzer = new p5.Amplitude();

    // ボタン
    const button = setButton('START', {
        x: 40,
        y: 180
    });

    button.mousePressed(() => {
        if (song.isPlaying()) {
            song.pause();
            button.html('LOOP');
        }
        else {
            song.loop();
            // 入力を音量アナライザーにあてがう
            analyzer.setInput(song);
            button.html('PAUSE');
        }
    });
}

function draw() {
    background(255);

    // 平均振幅(二乗平均平方根、RMS)を得る
    let rms = analyzer.getLevel();
    fill(127);
    stroke(0);

    // 音量にもとづいたサイズの円を描く
    ellipse(width / 2, height / 2, 10 + rms * 200, 10 + rms * 200);
}

function setButton(label, pos) {
    const button = createButton(label);
    button.size(100, 30);
    button.position(pos.x, pos.y);
    return button;
}
解説

音の原理に関するサンプルなので、きちんと理解するには相応の学習が必要になるでしょうが、ここで行っているのは、p5.Amplitudeオブジェクトの機能を使って、サウンドの瞬間瞬間の音量を調べ、それを円の大きさに変換して表示する、ということです。

p5.Amplitudeを使って、音量を計測するには次の3つの手順を取ります。

  1. Amplitudeオブジェクトを作成する
    analyzer = new p5.Amplitude();
  2. AmplitudeオブジェクトのsetInput()メソッドに音源を設定する
    analyzer.setInput(song);
  3. AmplitudeオブジェクトのgetLevel()メソッドで音量の値を得る
    let rms = analyzer.getLevel();

AmplitudeのgetLevel()メソッドが返すのは、瞬間瞬間で収集した振幅値の二乗平均平方根で、これは単なる平均値よりも実効性が高いと見なすことのできる値です(「二乗平均平方根」)

リファレンスメモ

p5.Amplitude

説明

p5.Amplitudeは0.0と1.0の間の音量を計測する。デフォルトではすべてのp5soundを対象にするが、setInput()を使って特定の音源を対象にすることもできる。オプションの平滑化値(デフォルトは0)も受け取る。

シンタックス

new p5.Amplitude([smoothing])

パラメータ

smoothing 数値: 振幅の読み取りを平滑化する0.0と.999の間の数値(デフォルトは0)(オプション)

setInput()

説明

デフォルトではp5soundインスタンス(マスター出力)に接続する。オプションで、特定のソース(つまりsoundfile)を渡すこともできる。

シンタックス

setInput([snd], [smoothing])

パラメータ

snd SoundObject|undefined: (任意の)音源を設定する(デフォルトはマスター出力)(オプション)
smoothing 数値|undefined: 振幅の読み取りを平滑化する0.0と.999の範囲(オプション)

getLevel()

説明

呼び出された瞬間での、単一のAmplitude読み取り値を返す。連続して読み取る場合には、draw()ループで実行する。

シンタックス

getLevel([channel])

パラメータ

channel 数値: チャンネルの0(左)または1(右)を選択して返す(オプション)

戻り

数値: 0.0と1.0の間の数値としての振幅

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA