サークル燃えないゴミ仮拠点

サークル代表師路射地の連絡所代わりのブログ

WEB_AUDIO_API (JavaScript) で 音声ファイルのシームレスループを実現する方法

どうもこんにちは、シャチです。
今回は皆さんお待ちかね、音声ファイルのシームレスループの解説です。

WEB_AUDIO_API (JavaScript) でシームレスループを実現するには何が必要か?


極端なことを言ってしまうと、「AudioBufferSourceNodeクラス」を使うだけでシームレスループは実装可能です。


このクラスには、音声ファイルのどこから(loopStart)、どこまで(loopEnd)がループ範囲なのかを設定するプロパティがあります。
それを設定した状態でループ再生をオンにすると、自然な流れで loopStart ~ loopEnd の区間を延々と再生し続けます。
(再生開始位置がファイルの先頭の場合、先頭から再生されていき、loopEnd の地点に差し掛かったときに loopStart の地点に戻ります。stop 命令を出すまで止まりません)


意外と簡単だと思いませんか?
しかし、これには1つ大きな落とし穴があります。

loopStart と loopEnd の値は人間が入力しなければならない!


結論から言ってしまうと、適切な loopStart と loopEnd を設定しなければシームレスなループにはなりません。
ここだけは人力でどうにかしなければならないのです。


そして、この適切な値を見つけるのが意外と面倒くさいのです。
複数のソフトをハシゴして音声ファイルの波形を見る必要があります。
(しかし、やり方を覚えてしまえば比較的簡単かも? 私は十数回やっている内に慣れました)


一度に全てを解説すると理解が難しくなるのでその方法については触れません。(解説は別の記事に回します)
今回は loopStart(ループ範囲の始点)と loopEnd(終点)の値を設定して、ループ範囲の自由なループをするための解説に留めます。


WEB_AUDIO_API (JavaScript) を使ったループ範囲の自由なループ再生のサンプル


では、今回の内容を踏まえてループ範囲の自由なループ再生のサンプルを載っけておきます。

用意するもの

  • ティラノスクリプトの新しいゲームプロジェクト
  • 少し長めの音声ファイル(少なくとも十秒以上。名前を「sample.ogg」にしておきます)

準備

「sample.ogg」をゲームプロジェクトの「data/bgm/」フォルダーに配置したら準備完了です。
それではサンプルコードを「data/scenario/」フォルダーの「first.ks」に書いていきます。

data/scenario/first.ks

[iscript]
// https://syachi.hatenablog.jp/entry/2019/07/04/051005 に載っけたサンプルを流用しています。
var context = new AudioContext();
var arrayBuffer;
var audioBuffer;
var source;

function getArrayBuffer(url){
  return new Promise(function(resolve){
    var request = new XMLHttpRequest();
    request.open('GET', url, true);
    request.responseType = 'arraybuffer';
    request.onload = function () {
      arrayBuffer = request.response;
      resolve();
    };
    request.send();
  });
}
function createAudioBuffer(){
  return new Promise(function(resolve){
    context.decodeAudioData(arrayBuffer, function (buf) {
      audioBuffer = buf;
      resolve();
    });
  });
}
function createBuffer(){
  return new Promise(function(resolve){
    source = context.createBufferSource();
    source.buffer = audioBuffer;
    source.connect(context.destination);
    resolve();
  });
}
function playOGG(){
  // ループ再生の設定
  source.loop = true;
  // ループ範囲開始位置 (今回は先頭から1秒の位置を指定)
  source.loopStart = 1;
  // ループ範囲終了位置 (今回は先頭から7秒の位置を指定)
  source.loopEnd = 7;
  // ループ再生開始
  source.start(0);
}

// ファイルのパス
var SOUND_URL = 'data/bgm/sample.ogg';
getArrayBuffer(SOUND_URL).then(createAudioBuffer).then(createBuffer).then(playOGG);
[endscript]


以上でシームレスではないですが、ループ範囲の自由なループ再生ができたはずです。
シームレスなループはこれを利用して実現させます。


次回はシームレスループにおける loopStart と loopEnd の値の探し方について説明しようと思います。
お楽しみに。それでは。

P.S.私が作った最新の動画です。シームレスなループも使われています。ぜひご覧ください。


【第十話】優しい騎士と小さな魔法使い【後編】―動画版