JavaScript

オフラインでWebAudio APIを再生する

More than 1 year has passed since last update.

Javascriptで音を鳴らすにはどうしたらいいかなぁと
色々調べてみました
いくつか方法がありますが

①audioタグをJavaScriptで制御する
②WebAudio APIで再生する

今回はローカルの音を鳴らすにはどうしたらいいか考えました。
①はローカルのリソースをaudioタグのsrcに指定すれば鳴らせます
②はXHRもしくはinputタグのfile属性からのファイル取得(File API)限定なため、
ブラウザの仕様上結構難しい

①でいいじゃないかという声が上がってくると思いますが
iPhoneやAndroidではaudioタグの複数同時再生ができなかったりします
逆にWebAudio APIなら複数音同時再生できます。
(上記とは別にスマホブラウザでは①、②ともに
ユーザアクションがないと再生できないという制限があります)
ちなみに②のinputタグから取得する方法だと、ページ表示時に鳴らせないため
別の方法を使います。
あっ、HTML5前提です。

パクry・・・参考元
(英語わかる人はこっち見た方が早いかも)
http://html5doctor.com/taking-web-audio-offline-in-ios-6-safari/

流れとしては次のように行います
・opensslでオーディオファイルをbase64化
・base64データをArrayBuffer化
・後はWebAudioAPIにロードさせる

MacOSX 前提ですが次のOpenSSLコマンドでオーディオファイルをbase64ファイル化します

openssl base64 -in [infile] -out [outfile]

今回はjump.wavでやってみました
(適当なオーディオファイルをご準備ください)

openssl base64 -in jump.wav -out jump.txt

base64に変換でき・・・んん?改行入っているぞ
ということで、改行も次のコマンドで除外します(※ここ重要)

cat jump.txt | tr -d '\n' > out.txt

base64→ArrayBuffer変換ですが
base64-binary.jsを使います

https://github.com/danguer/blog-examples/blob/master/js/base64-binary.js

使い方は下みたいに使います

var sound = "base64データ";
var arrayBuff = Base64Binary.decodeArrayBuffer(sound);

後はArrayBufferからデータを取得してWebAudio APIで鳴らすだけです。

全ソースコードです。

offline_webaudio.html
<!DOCTYPE html>
<html lang="en" manifest="web.appcache"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<title>Offline Audio Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./js/jump.js"></script>
<script src="./js/base64-binary.js"></script>
<script type="text/javascript">

var myAudioContext, mySource, myBuffer;

if ('AudioContext' in window) {
    myAudioContext = new AudioContext();
} else if ('webkitAudioContext' in window) {
    myAudioContext = new webkitAudioContext();
} else {
    alert('Your browser does not support yet Web Audio API');
}

function play () {

    mySource = myAudioContext.createBufferSource();
    mySource.buffer = myBuffer;
    mySource.connect(myAudioContext.destination);

    if ('AudioContext' in window) {
        mySource.start(0);
    } else if ('webkitAudioContext' in window) {
        mySource.noteOn(0);
    } 

}


window.onload = function(){

    var arrayBuff = Base64Binary.decodeArrayBuffer(sound);

    myAudioContext.decodeAudioData(arrayBuff, function(audioData) {
        // データ取得
        myBuffer = audioData;

        // 再生
        play();
    });

};

</script>
</head>

<body>
<h1>Offline Web Audio Demo</h1>
<button onclick="play();" style="height: 44px; width: 75px;">Play</button>

</body>
</html>

base64データが長いので別ファイルにしてます。
今回はjump.jsに分離しました
jump.jsにはout.txtで出力したbase64データをコピペします

 var sound="base64データ(out.txtの中身)";