WEB_AUDIO_API (JavaScript) で AudioBufferSourceNode を利用する際の注意点
少しご無沙汰しておりました。シャチです。
早速、前回の続きから書いていきたいと思います。
ちなみに前回↓
ティラノスクリプトで WEB_AUDIO_API (JavaScript) を利用する - ティラノスクリプトで小説動画を作る
BGMのシームレスなループは「 AudioBufferSourceNodeクラス 」一択!
WEB_AUDIO_APIには3種類の利用方法があり、
その中でシームレスなループ再生が可能なのは
「AudioBufferSourceNodeクラス」を利用する方法だけ
というのが、前回の結論でした。
ただし、この「AudioBufferSourceNodeクラス」というのがなかなかに曲者なのです。
「AudioBufferSourceNodeクラス」は、短い音声ファイル用
前回のサンプルの後に私はこう書きました。
もしうまく行かないようなら「sample.ogg」をもっと軽いファイルにして試してみてください。
(短い効果音のようなものがオススメです)
その理由は「AudioBufferSourceNodeクラス」が短い音声ファイル用のクラスだからです。
このクラスはファイルの読み込みが終わるまで、再生命令を実行できません。
(したところで、命令が空振りに終わるだけです)
ですから、読み込みの完了を待って再生命令を実行するなどの工夫が必要になってきます。
そして、実際に再生するタイミングで読み込みを始めたのでは間に合わないため、事前に読み込んでおく処理も必要になるでしょう。
「AudioBufferSourceNodeクラス」は、再生命令を一回しか受け付けない
困ったことに、「AudioBufferSourceNodeクラス」は再生開始命令を一回しか受け付けません。
一度再生されたデータはメモリから削除されてしまいます。
(公式のリファレンスでは「撃ちっぱなし」と表現していました)
そのため、同じファイルをもう一度再生したいと思った場合、再び同じファイルからAudioBufferSourceNodeを作る必要があります。
(大変面倒です)
この手間を抑えるために、一度読み込んだファイルのArrayBufferを別で取っておき、再生命令に応じてAudioBufferSourceNodeを生成する仕組みが必要になります。
(とっても面倒です)
私の目的としては、ティラノスクリプトの[playbgm]や[playse]と変わらない使用感でシームレスなループ再生を使えるようにすることだったので、これらの実装は不可欠なものでした。
ティラノスクリプトで「AudioBufferSourceNodeクラス」を利用するサンプル
では今回の内容を踏まえて、AudioBufferSourceNodeクラスを使って音声ファイルを再生するサンプルを載せておきます。
準備
「sample.ogg」をゲームプロジェクトの「data/bgm/」フォルダーに配置したら準備完了です。
それではサンプルコードを「data/scenario/」フォルダーの「first.ks」に書いていきます。
data/scenario/first.ks
[iscript] // 使い回した方が良い AudioContext var context = new AudioContext(); // 以下、判りやすくするため事前に変数宣言しておきます。 var arrayBuffer; // 読み込んだファイルの ArrayBuffer ・・・(1) var audioBuffer; // (1) を AudioBufferSourceNode に変換したもの var source; // BufferSource // url から音声ファイルの arrayBuffer を読み込む function getArrayBuffer(url){ // 同期処理を Promise を使って実装する return new Promise(function(resolve){ // XMLHttpRequest で sample.ogg を読み込む var request = new XMLHttpRequest(); request.open('GET', url, true); // データを arraybuffer 形式で読み込む設定 request.responseType = 'arraybuffer'; // 読み込みが終わったときに行われる処理 request.onload = function () { // 読み込んだデータを arrayBuffer に入れて保管 arrayBuffer = request.response; // 終わったら次の処理へ resolve(); }; // 読み込み開始 request.send(); }); } // 読み込んだ arrayBuffer から audioBuffer を作る function createAudioBuffer(){ return new Promise(function(resolve){ // arrayBuffer を audioBuffer に変換する context.decodeAudioData(arrayBuffer, function (buf) { // 変換したものを audioBuffer に入れて保管 audioBuffer = buf; // 終わったら次の処理へ resolve(); }); }); } // 作った audioBuffer を BufferSource にオーディオソースとして登録する function createBuffer(){ return new Promise(function(resolve){ // 新しい BufferSource を作る source = context.createBufferSource(); // audioBuffer を BufferSource に登録する source.buffer = audioBuffer; // AudioContext と BufferSource を接続 source.connect(context.destination); // 終わったら次の処理へ resolve(); }); } // 再生する function playOGG(){ source.start(0); } // ファイルのパス var SOUND_URL = 'data/bgm/sample.ogg'; // Promise を使って順番に処理していく (今回の重要ポイント) getArrayBuffer(SOUND_URL).then(createAudioBuffer).then(createBuffer).then(playOGG); [endscript]
これで、長めの音声ファイルも再生することができるはずです。
次回は音量操作の方法について解説します。
お楽しみに。それでは。