女子小学生と××したい

Webフロントエンド界のゴミクソメンヘラであり続けたい

web audio APIを用いたiOS6 safari対応の仮想音源位置の移動があんまり上手くいかなかった話

こんなん作りました。以上です。





ではなく。ちゃんと解説します。
ざっくり言うと、「chromeとiOS6 safariで動く、仮想音源位置の移動体験」です。
使い方はれあどめ読んでくださいな。
web audio API使ってます。日本語記事少ないしリファレンス読めないし大変だったー。

Web Audio API
Web Audio API のスペック (日本語訳) - miura off

説明のためにこのアプリのjsを部分要素に分解しますと

  1. 音源位置の移動
  2. タッチ位置の検出
  3. selectの選択値から仮想音源位置の操作を行う面(水平面、正中面、冠状面)を変更する
  4. 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軸です。この値をタッチまたはクリック位置によって操作して、仮想的に音源位置を動かしています。

まとめ

  1. web audio APIで用意されているnodeの中から必要なものをwebkitAudioContextから生成する。
  2. 音源を作る
  3. 各種nodeをconnectでつなぎ、最後をcontext.destinationにconnectする
  4. context.noteOn()で再生する
  5. pannerNodeのsetPositionで仮想音源位置を簡単に操作できる

あんまりまとまってないな…。でもこれに関してはまだまだ書きたいこと(iOS6 safari対応時のつまずき、対応してみて分かったこと、pannerNode自体に考えられる問題)があるので別記事にします。

お腹減った…