web audio APIを用いたiOS6 safari対応の仮想音源位置の移動があんまり上手くいかなかった話
こんなん作りました。以上です。
ではなく。ちゃんと解説します。
ざっくり言うと、「chromeとiOS6 safariで動く、仮想音源位置の移動体験」です。
使い方はれあどめ読んでくださいな。
web audio API使ってます。日本語記事少ないしリファレンス読めないし大変だったー。
Web Audio API
Web Audio API のスペック (日本語訳) - miura off
説明のためにこのアプリのjsを部分要素に分解しますと
- 音源位置の移動
- タッチ位置の検出
- selectの選択値から仮想音源位置の操作を行う面(水平面、正中面、冠状面)を変更する
- canvasに人の頭アイコンを描画する
になります。で、今回1.しか説明しません。他はそんなに面白くないので。
ざっくり言うと、web audio APIってのは、nodeを繋ぎ合わせて音に色んな効果とかをつけるもんだ、っていう解釈してます。やり始めたの最近なんで違ってるかも知れないですが。
Web Audio API 解説 - 01.前説 | g200kg Music & Software
ここが非常に詳しかったです。オシレーターやゲイン操作、オーディオバッファやパナーのnodeをwebkitAudioContextから作って順番にconnectしていって、最後はcontext.destinationにconnectしてnoteOnすると音が鳴る、と。言ってしまえばそれだけです。僕の現時点での知識では。
実際のコードで言うと
var ctx = new webkitAudioContext(), src = ctx.createBufferSource(), pnr = ctx.createPanner(), node = ctx.createJavaScriptNode(1024, 1, 1);
でnode作って
src.noteOn(0); src.connect(node); node.connect(pnr); pnr.connect(ctx.destination);
でつないで、noteOnで再生。各nodeのメソッドなりメンバいじって聴こえを変える、と。
ちなみに止めるときは
src.disconnect(); node.disconnect(); pnr.disconnect();
ってやってる。noteOffってメソッドあるし、そっちでもできそうな気はしている。
で、肝心の音を作ってる部分
node.onaudioprocess = function(e) { var out = e.outputBuffer.getChannelData(0), rslt = [], len = out.length; for (var i=0;i<len;i++) { rslt.push(out[i] = Math.random()); } return rslt; };
forの中で、返り値の配列の中に乱数入れてホワイトノイズ作ってます。ただ、ちなみにこの部分
iOS6 の Web Audio API を使う - 音の鳴るブログ
こちらを参考にしていてまだ調査中という酷い状況に…
ちゃんと調べてここで報告しますすみません
で、仮想音源位置を動かしてる部分ですが、web audio APIのpannerNode(コード中ではpnr)にsetPositionというなんともそのまんまなメソッドが用意されています。
このメソッド、引数が3つ(x,y,z)で、値域は-∞から+∞です。(0,0,0)が聴取者の位置で、3次元座標をイメージすると分かりやすいと思います。
ちなみに両耳を貫く左右がx軸、頭部を脳天から首に向かって貫く上下がy軸、後頭部から鼻を貫く前後がz軸です。この値をタッチまたはクリック位置によって操作して、仮想的に音源位置を動かしています。
まとめ
- web audio APIで用意されているnodeの中から必要なものをwebkitAudioContextから生成する。
- 音源を作る
- 各種nodeをconnectでつなぎ、最後をcontext.destinationにconnectする
- context.noteOn()で再生する
- pannerNodeのsetPositionで仮想音源位置を簡単に操作できる
あんまりまとまってないな…。でもこれに関してはまだまだ書きたいこと(iOS6 safari対応時のつまずき、対応してみて分かったこと、pannerNode自体に考えられる問題)があるので別記事にします。
お腹減った…