Web Audio APIによるモーター音再現

概要

 BVEでのモーター音再現方式である、モーター音サンプリング音源のピッチと音量を変化させながら再生する手法をWeb Audio APIを使って実現した実例を紹介します。

 ここではパラメーターをピッチと音量のみと必要最小限にしましたが、例えば、さらにBiquadFilterNodeを接続すれば、特定のモーター音成分を強調したり、完全に取り除くことなどのモーター音の加工が実現できます。

デモ

 Stopボタンを押して音声を停止した後に再び音声を再生することはできません。再び音声を再生するにはページの再読み込みを行ってください。これは、AudioBufferSourceNodeの仕様によるものです。

 実際にモーター音の再現をWeb Audio APIで実装するときには、再生をやめるときには音量を0にするか、あるいは再生時に都度AudioBufferSourceNodeを作り直すかのいずれかでの実装を行います。

Pitch: 1
Volume: 1

ソース

HTML

<div>
    <button class="play-button">Play</button>
    <button class="stop-button">Stop</button>
</div>
<div>
    Pitch:
    <input class="pitch-range" type="range" min="0" max="2" value="1" step="0.01">
    <span class="pitch-span">1</span>
</div>
<div>
    Volume:
    <input class="volume-range" type="range" min="0" max="2" value="1" step="0.01">
    <span class="volume-span">1</span>
</div>

JavaScript

// 音声コンテキストの作成
const audioContext = new AudioContext();

// 音声ファイルのダウンロード要求
const request = new XMLHttpRequest();
request.open('GET', 'motor.wav', true);
request.responseType = 'arraybuffer';
request.onload = function () {
    // ダウンロード完了後に、取得した音声ファイルを波形データへデコード
    audioContext.decodeAudioData(request.response, function (buffer) {
        // ノード作成
        const bufferSourceNode = audioContext.createBufferSource();
        const gainNode = audioContext.createGain();

        // デコード済み波形データのバッファ登録とループ再生設定
        bufferSourceNode.buffer = buffer;
        bufferSourceNode.loop = true;

        // ノード接続
        bufferSourceNode.connect(gainNode);
        gainNode.connect(audioContext.destination);

        // ---------- イベント ----------

        // 再生開始
        document.querySelector('.play-button').onclick = function () {
            bufferSourceNode.start();
        };

        // 再生停止
        document.querySelector('.stop-button').onclick = function () {
            bufferSourceNode.stop();
        };

        // ピッチ変更
        document.querySelector('.pitch-range').onchange = function (event) {
            bufferSourceNode.playbackRate.value = event.target.value;
            document.querySelector('.pitch-span').textContent = event.target.value;
        };

        // 音量変更
        document.querySelector('.volume-range').onchange = function (event) {
            gainNode.gain.value = event.target.value;
            document.querySelector('.volume-span').textContent = event.target.value;
        };
    }, function (error) {
    });
};
request.send();