Edited at

WebAudioAPIで遊べるようになった

More than 5 years have passed since last update.

音楽の覚えがあるエンジニアとしては、触らなきゃダメだろーと思いつつ、なかなか手を付けられていなかったWebAudioAPI、

先日のハッカソンでようやく着手できました。

その過程でわかったこと・つくったものなどまとめました。


登場人物

HTML5のAudio要素を使う時と違って、

WebAudioAPIの場合は、使っているオブジェクトがけっこう多い。

そのあたりを把握するのが、WebAudioAPIのマスターの第一歩っぽい。


context (AudioContext)

音をとりまとめるcontext。

音の再生先(destination)なんかも、このcontextが握っているみたい。

WebAudioAPIに対応しているブラウザは、

window.AudioContext (window.WebkitAudioContext)というのが生えてるので、

これをインスタンス化すると作れる。

var context = new window.AudioContext();


buffer

再生する音のデータ。

.wavなど外部のファイルを使う場合は、


  • XMLHttpRequest(responseType: arraybuffer で!)で読み込む

  • 読み込んだものを、contextにdecodeしてもらう (context.decodeAudioData)

という流れでできる。

// ここにbufferを格納したい

var buffer;

// ファイルを取得 (arraybufferとして)
var request = new XMLHttpRequest();
request.open('GET', '/sounds/sample.wav', true);
request.responseType = 'arraybuffer';

request.send();
request.onload = function () {
// 読み込みが終わったら、decodeしてbufferにいれておく
var res = request.response;
context.decodeAudioData(res, function (buf) {
buffer = buf;
});
};


source

こうして作ったbufferを再生するためには、sourceというものを作る。

これもcontextに生えているメソッドを使う。(context.createBufferSource)

// source作成

var source = context.createBufferSource();

// さきほど作ったbufferを、ここにセット
source.buffer = buffer;

// 再生準備。contextの持っている再生先に接続
source.connect(context.destination);

// 再生 (引数はtimeout)
source.noteOn(0);


たとえば、できること


音の高さを変える

厳密にはピッチ変更ではないけれど、

単発の音を鳴らすのであれば、sourceのplaybackRate.valueをいじればおk。


気をつけること


sourceは使い捨て

sourceは、 再生するたびに生成して、使い捨てるというかたち になっている。

最初は、つくったsourceに対して何度も .noteOn したりできるのかと思ってた。


一度は、ユーザーアクションをトリガーにして、音再生させないとだめ。

逆に言えば、1度タップのタイミングなどで再生をさせてしまえば、 その後は好きなタイミングで鳴らし放題 なもよう。

その辺の挙動から、「ユーザーアクションで再生許可」は、おそらくcontextに紐付いてるんじゃないかなぁという印象。

(source単位での許可だとすると、sourceは再生のたびに使い捨ててるので、再生のたびに許可が必要なはず)

ちゃんとしらべてないけど。

ちなみに、ユーザアクションから間接的に音再生呼んだ場合、

(clickのlistenerでsetTimeout通して音再生、とか)

なんかときどき再生できちゃってたけれど、

確実に鳴らしたいなら、やっぱり1度は直接再生呼び出しした方がいいみたい。


つくったもの


DripMetro

先日のハッカソンで作ったもの。

ぴちょんぴちょん言うメトロノーム。

いちおうBPMを上げるほど、音も高くなるようにしてます。


ToneMap

↑のDripMetroを作る過程でできた、WebAudioAPIのwrapper。

(wrapperとはいえ、もうすこし機能追加するつもり)

複数の音源を使う場合でも、やりやすくなる…はず。

デモでは、

画面タッチで音再生→スワイプのスピードに応じて音を高く

っていうのやってます。


まとめ


  • たのしい

  • ↓のデモなど見ても思うけれど、iOSは十分にWebAudioAPIつかえるっぽい

  • 音をばしばしつかったスマホサイトなんかも、挑戦したいなぁ


参考とかっこいいデモ