HTML5のゲームで音を再生する場合、従来はAudio要素を使用していました。例えば、次のようにするとurlで指定した音を再生することができます。

var audio=new Audio(url);
audio.play()

この方法はPCだと問題なく動作しますが、iOSの場合、ユーザのタッチイベントの中でしかplayを受け付けないという問題があります。回避策として、ユーザのタッチイベントでaudio.load()しておいてplayする方法もありますが、1回のタッチイベントで1つのAudioファイルしかloadすることはできないため、効果音を全てプリロードすることはできません。複数の効果音を1つのファイルに結合してプリロードする、オーディオスプライトという方法もありますが、同時に1つの効果音しか再生できません。

これらの問題を解決するためには、Audio要素ではなく、WebAudio APIを使用する必要があります。WebAudio APIの場合、iOSでも、ユーザのタッチイベントで何か1つ音を再生すると、以降は自由に音を再生できるようになります。プリロードはXmlHttpRequestで行うため、タッチイベント外で、全ての効果音をまとめて行うことができます。

WebAudio APIを使用するには、まず、AudioContextを作成します。

try {
	window.AudioContext = window.AudioContext || window.webkitAudioContext;
	context = new AudioContext();
}
catch(e) {
	onerror('Web Audio API is not supported in this browser');
}

次に、XMLHttpRequestで音声ファイルを読み込みます。iOSとAndroidの場合、wavとmp3の両方を再生することができます。ファイルを読み込んだら、decodeAudioDataでデコードします。Audioタグのストリーミングとは異なり、事前に全てデコードするので、BGMなど長い曲では処理に時間がかかります。

var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onload = function() {
	context.decodeAudioData(request.response, function(buffer) {
		audio_buffer = buffer;
	}, function(){
		//エラー
	}
	);
};
request.send();

再生するには、BufferSourceを作成して、startを実行します。効果音を再生するたびにBufferSourceを作成しても、パフォーマンス的な問題は起きませんでした。

var source = context.createBufferSource();
source.buffer = audio_buffer;
source.connect(context.destination);
source.start(0);

ループ再生するには、BufferSourceのloop属性にtrueを入れます。

source.loop=true;
source.start(0);

ループ再生を停止するには、startしたBufferSourceでstopを実行します。仕様上はstopの引数は任意ですが、iOSの場合はstopの引数は必須となっており、設定しないと例外が飛びます。playで引数を指定しない場合は例外が飛ばないので、不思議な挙動です。

source.stop(0);

音量を調整するには、gainNodeを使用します。

var gainNode = context.createGain();
gainNode.gain.value=gain;
source.connect(gainNode);
gainNode.connect(context.destination);
source.start(0);

WebAudio APIを使うと、iOSのMobile Safariでも、ネイティブゲーム並みの音声操作ができてオススメです。Androidは標準ブラウザは未対応で、Chromeでは対応しています。