2013年にもなって今更WebAudioAPIで喜ぶというのもなんとも言えない感じですが、触ってみると結構楽しかったのでブログします。
What's "Web Audio API"?
Web Audio APIはブラウザ向けのオーディオ再生機構としてW3Cによって規定されているAPIで、いわゆるHTML5に含めて扱われているAPIです。
現在はWebkit系ブラウザでしかマトモに動かないという制約はあるのですが、
- オーディオファイル再生
- ストリーミング再生
- フィルタリング
- スクリプトによる音声生成・編集
など、シンプルに音声を再生するという以上の能力を持っています。
W3Cによるドラフトによると、
The introduction of the audio element in HTML5 is very important, allowing for basic streaming audio playback. But, it is not powerful enough to handle more complex audio applications. For sophisticated web-based games or interactive applications, another solution is required
audioエレメント入れてさ、HTML5でストリーミング再生出来るようになったのはスゲー良かったよ。でもさ、もっとややこしい音声イジりには出来なくて、Webベースのゲームとかではもっと強力な奴が求められてるんよ(WebAudioスゲーだろ?) [注:僕の理解]
とあります。
要約すればaudio要素の機能不足面を補強するもの、という立ち位置のようです。
Modular Routing
大前提として、WebAudio APIはModular Routingという仕組みを持っています。
これはAudio Node(= オーディオのソース自体やフィルタなど、それぞれの一要素)を接続していくもので、シンプルな物からコンプレックスな構造まで同じ仕組みによって表現することができます。
W3Cのリファレンスから画像を借りてくると、
こういうシンプルな構成から
こういうややこしい構造までを表現可能です。
矢印がModular間の接続(Routing)です。前者が入力(source)から出力(destination)まで直結されているのに対して、後者はフィルターなどを経由してより複雑な構成になっているのがわかります。
このようにAudio Nodeを接続していくことで音声ソースから出力までの造りを変化させ、それぞれのNodeに処理させることで音色を操作するという設計ですね。
僕はリアルオーディオのケーブルのようなものだと理解していて、とても直感的で良い仕組みだと思いました。マイクからスピーカへ直挿しするか、あるいはマイクからミキサを経由してスピーカに接続するかみたいな感じですよね。
音を鳴らす
とりあえず正弦波を作って音を鳴らしてみます。
var context;
var init = function() {
// なにはともあれAudioContextを作る。役割はその名の通り。
// webkitの独自実装なのでプレフィックスがつく。
try{
context = new webkitAudioContext();
} catch(e) {
console.log(e);
}
context.samplingRate = 48000;
}
var audio = function(){
// Bufferを生成して、そこからChannelDataを取得する。
var buffer = context.createBuffer( 1, 48000, 48000 );
var channel = buffer.getChannelData(0);
// ChannelDataには1サンプルごとの音声データが入る。
// とりあえず正弦波作って入れる。
for( var i=0; i < channel.length; i++ )
{
channel[i] = Math.sin( i / 100 * Math.PI);
}
// Sourceを作る。これが入力になる。
// 入力にBufferを入れる。
var src = context.createBufferSource();
src.buffer = buffer;
// Modular Routing。Sourceをdest(出力)に直結する。
src.connect(context.destination);
// そして再生。
src.noteOn(context.currentTime);
}
document.querySelector("#play").addEventListener("click", function(){audio();}, false);
init();
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="audio.js" defer="defer"></script>
</head>
<body>
<button id="play">play sound!</button>
</body>
</html>
とりあえず[play sound!]をクリックすると240Hzの微妙な音が1秒間再生されるはずです。
(ちなみに、同じようなことをやるならOscillatorというもっと便利な仕組みもあるんですが、こっちのほうが面白いのでこうしています。)
フィルタする
音を出すことには満足したので、フィルターをかけてみます。
フィルタはLRC回路と同様に周波数とQを指定、20db/octで下に落ち込む特性になります。Modular Routingにこのフィルタを加えて、出力に突っ込みます。
今回はローパスフィルタを試してみました。
// 300Hzから利得が落ちていく特性のフィルタを定義する。
var filter = context.createBiquadFilter();
filter.type = "lowpass";
filter.frequency.value = 300;
filter.Q.value = 1;
// Modular Routingにフィルタを加える
src.connect(filter);
filter.connect(context.destination);
srcの周波数を変えてやると、利得が変化するのが感じられると思います。
なお、ローパスフィルタの他にもハイパスフィルタやバンドパスフィルタ、双二次フィルタやピークフィルタなどが利用できます。
パッと見はフィルタの特性を2段・3段にする機能は無さそうなので、ココらへんは普通の電気回路と同じ用に多段構成につなげていく必要がありそうです。
# というか、この回路のQって回路系やってない人にとっては結構馴染みのない概念だと思うんですが、オーディオの世界では良く使うんですか?
# 馴染みの無い人にとっては理解しづらい気がしますね。
その他
その他、色々出来るみたいですがそろそろ書くのに飽きてきたのでココらへんで筆を置きます。
気が向いたら続編を書きます。