AudioContext

Web Audio APIを利用するために必ず必要な処理があります. それは, AudioContextクラスのコンストラクタを呼び出して, AudioContextクラスのインスタンスを生成することです.

なぜなら, AudioContextインスタンスがWeb Audio APIで定義される処理の起点になるからです. 言い換えれば, AudioContextインスタンスを生成することで, Web Audio APIが定義するプロパティやメソッドにアクセス可能になるわけです.

…いきなり抽象的な事を説明したので, よくわからなかったかもしれませんが, コードにすると簡潔になります. Web Audio APIを利用するには, とりあえず以下のコードが必要ということです.

サンプルコード 01


// Create the instance of AudioContext
var context = new AudioContext();

ビルトインオブジェクトのコンストラクタ呼び出し (DateやRegExpなど) と同じです. ただし, 現状のブラウザの実装ではベンダープレフィックスを追加する必要があるので, サンプルコード 01を以下のように修正します.

サンプルコード 02


// Create the instance of AudioContext
var context = new webkitAudioContext();

将来的なことまで考慮すると, サンプルコード 03がベターでしょう.

サンプルコード 03


window.AudioContext = window.AudioContext || window.webkitAudioContext;

// Create the instance of AudioContext
var context = new AudioContext();

ちなみに, Firefoxではプレフィックスなし, Operaではwebkitのプレフィックスに対応しています.

デモ 01

このサイトでは, Web Audio APIの仕様で定義されているオブジェクトをクラスと表現します. そして, その実体をインスタンスと表現することにします. 定義されているオブジェクトを, クラスとその実体であるインスタンスと考えても, 理解のうえで大きな問題はありません.

もう1つこのサイトの用語定義として, それらのオブジェクトを文脈によっては現実世界の音響機器の構成要素と見なして, ノードと表現することもあります. もっとも, 表現を変えているだけで本質的には同じことです.

JavaScriptの言語仕様上, C++やJavaのようなクラスは存在しません (ECMAScript the 6th editionからは存在します). しかし,クラスに相当するモノ (new式で呼び出すことを想定した関数. すなわち, コンストラクタ) は存在します. それらをクラスと考えても, 理解のうえで大きな問題はありません.

とりあえずサウンドを生成する

サウンドの入出力

AudioContextインスタンスで, 最も重要なのは以下の2点でしょう.

  • サウンド入力のためのノードとそれを生成するメソッド
  • サウンド出力のためのdestinationプロパティ

現実世界の音響機器に例えると, 楽器 (の振動) やCD (のオーディオデータ) などのサウンドの入力点と, スピーカやイヤホンなどのサウンドの出力点にあたります.

サウンドの出力点の役割を担うのは, AudioDestinationNodeインスタンスであるdestinationプロパティのみですが, サウンドの入力点の役割を担うノードとそれを生成するメソッドは複数あります. 表1 - 1 - aにそれらを簡単にまとめます. これらのメソッドと生成されるノードは後ほど詳しく解説します.

表1 - 1 - a. サウンド入力のためのノードとメソッド
InputMethod
AudioBufferSourceNodecreateBufferSource
OscillatorNodecreateOscillator
ScriptProcessorNodecreateScriptProcessor
(createJavaScriptNode)
MediaElementAudioSourceNodecreateMediaElementSource
MediaStreamAudioSourceNodecreateMediaStreamSource

ノードの接続

現実世界の音響機器では, 何らかの入力と出力は接続することで, その機能を果たします. 例えば, エレキギターであれば, サウンド入力を担うギターとサウンド出力を担うアンプ (厳密にはスピーカー) は, 単体では本来の機能を発揮できません. シールド線などで接続することによって機能します.

音響機器の接続

図1 - 1 - a. 音響機器の接続

このことは, Web Audio APIの世界も同じです. AudioContextインスタンスを生成して, サウンド入力点となるノードを生成するメソッドとサウンド出力点となるAudioDestinationNodeインスタンスが使える状態になっただけではその機能を果たしません. まずは, サウンド入力点と出力点を接続する処理が必要となります. さらに, Web Audio APIが定義する様々なノードと接続することで, 高度なサウンド処理を実現するAPIとして真価を発揮します.

Web Audio APIの真価

図1 - 1 - b. Web Audio APIの真価

Web Audio APIのアーキテクチャは, 現実世界における音響機器のアーキテクチャと似ています. このことは, Web Audio APIの理解を進めていくとなんとなく実感できるようになると思います.

Web Audio APIにおいて「接続」の役割を担うのが, connectメソッドです. 具体的に解説するために, 入力点となるノードにOscillatorNodeクラス (表1 - 1 - a) を利用します. OscillatorNodeクラスのインスタンスを生成するには, new式を利用するのではなく, createOscillatorメソッドを利用します.

OscillatorNodeインスタンスはconnectメソッドを呼び出せます. connectメソッドを利用して, サウンド入力点であるOscillatorNodeインスタンスを, サウンド出力点であるAudioDestinationNodeインスタンスに接続するコードは, サンプルコード 04のようになります.

サンプルコード 04


/*
 * Add code to sample code 03
 */

// ....

// Create the instance of OscillatorNode
var oscillator = context.createOscillator();

// OscillatorNode (Input) -> AudioDestinationNode (Output)
oscillator.connect(context.destination);

少し話が細かくなってしまいますが, connectメソッドは, OscillatorNodeクラスが定義するメソッドではなく, AudioNodeクラスが定義するメソッドです. ではなぜ, OscillatorNodeインスタンスから呼び出せるのかというと, OscillatorNodeクラスがAudioNodeクラスを (プロトタイプ) 継承したクラスだからです.

connectメソッドとAudioNode

図1 - 1 - c. connectメソッドとAudioNode

Web Audio APIでは, AudioNodeクラスを (プロトタイプ) 継承したクラスが多くあります. サンプルコード 04のように, AudioNodeクラスを (プロトタイプ) 継承したサブクラスのインスタンスから, プロトタイプチェーンをたどって, AudioNodeクラスにおいて定義されているプロパティやメソッドにアクセスします. もっとも, API内部の詳細を知らなくても, connectメソッドを呼び出すにあたって支障になることはほとんどありません.

詳細はともかく, サウンドの入力点と出力点を接続し, 最小の構成を実装できました. しかし, まだ音は出せません. なぜなら, サウンドを開始するための音源スイッチをONにしていないからです. 現実世界の音響機器も同じです. もっとも, 現実世界がそうであるように, Web Audio APIにおいても, 音源のスイッチをON / OFFにする方法は簡単です. OscillatorNodeインスタンスのstart / stopメソッドを呼び出すだけです.

サンプルコード 05


/*
 * Add code to sample code 05
 */

// ....

// Start sound
oscillator.start(0);

// Stop sound (after 5 sec)
window.setTimeout(function() {
    oscillator.stop(0);
}, 5000);

start / stopメソッドの引数に0を指定していますが, これはメソッドが呼ばれたら, 即時にサウンドを開始 / 停止することを意味しています.

また, 初期の仕様では, start / stopメソッドは定義されておらず, それらの代わりにnoteOn / noteOffメソッドを利用していました. したがって, ブラウザによってはnoteOn / noteOffメソッドしか実装されていない可能性があります. そこで, サンプルコード 06のようにフォールバックを記述しておきます.

サンプルコード 06


/*
 * Add code to sample code 05
 */

// ....

// for legacy browsers
oscillator.start = oscillator.start || oscillator.noteOn;
oscillator.stop  = oscillator.stop  || oscillator.noteOff;

// Start sound
oscillator.start(0);

// Stop sound (after 5 sec)
window.setTimeout(function() {
    oscillator.stop(0);
}, 5000);

これでとりあえずサウンドを生成することができます.

デモ 02

ボリュームコントローラ

次にステップアップとして, ボリュームコントローラ機能を追加したいと思います.

GainNode

ボリュームコントローラ機能の実装は簡単です. GainNodeクラスのインスタンスを利用することによって作成できる機能です. また, GainNodeインスタンスの生成は, AudioContextインスタンスのcreateGainメソッドの呼び出しで可能です.

ちなみに, 初期の仕様では, createGainメソッドは定義されておらず, その代わりにcreateGainNodeメソッドを利用していました. したがって, サンプルコード 07のようにフォールバックを記述するほうが安全です.

サンプルコード 07


/*
 * Add code to sample code 03
 */

// ....

// for legacy browsers
context.createGain = context.createGain || context.createGainNode;

// Create the instance of GainNode
var gain = context.createGain();

現実世界の音響機器でも, ボリュームコントローラは他のデバイスに接続されてその機能を果たします. これは, Web Audio APIも同じです. つまり, GainNodeインスタンスも他のノードに接続することによって, その機能を果たします. GainNodeクラスもAudioNodeクラスをプロトタイプ継承したクラスなので, プロトタイプチェーンをたどり, connectメソッドを呼び出すことができます.

ノード接続

図1 - 1 - d. ノード接続

サンプルコード 08


/*
 * Add code to sample code 07
 */

// ....

// Create the instance of OscillatorNode
var oscillator = context.createOscillator();

// for legacy browsers
oscillator.start = oscillator.start || oscillator.noteOn;
oscillator.stop  = oscillator.stop  || oscillator.noteOff;

// OscillatorNode (Input) -> GainNode (Volume Controller) -> AudioDestinationNode (Output)
oscillator.connect(gain);
gain.connect(context.destination);

これで, ボリュームコントローラを入力点と出力点に接続することができました.

あとは, ボリュームの設定方法です. GainNodeインスタンスには, gainプロパティが定義されています. そして, gainプロパティには, valueプロパティがあり, この値を操作することでボリュームのコントロールが可能になります. ややこしくなりましたが, コードにすると非常に簡潔に記述できます.

サンプルコード 10


/*
 * Add code to sample code 09
 */

// ....

gain.gain.value = 0.5;  // Set volume at 0.5

また, この値はデフォルトで1, 最小値が0, 最大値が1と定義されています. そして, 実際のアプリケーションでは, イベント処理において, この範囲で値を設定することになるでしょう.

しかし, この範囲外の値に設定することも可能で, 例外は発生しません. 負数を設定すると, 位相が反転すると仕様では定義されています. エフェクターの実装に, この特性を活かすことが可能です.

話が細かくなりますが, GainNodeインスタンスのgainプロパティは, AudioParamクラスのインスタンスです. Web Audio APIにおいては, これ以外にもAudioParamインスタンスであるプロパティが多く定義されています. それらはすべて, 音響指標 (ゲイン・周波数・ディレイタイム・フィルタのパラメータ…) にアクセスするためのインスタンスとなっています. ちなみに, AudioParamクラスに関しては, エンベロープジェネレータのページで詳しく解説します.

長くなりましたが, これまでのまとめとしてデモ 03を実行してみてください.

デモ 03

Web Audio APIの概要 まとめ

このページでは, Web Audio APIを利用するための最小限の処理を解説しました. そして, とりあえずサウンドを生成することまで実装しました. そのステップをまとめます.

  1. AudioContextクラスのインスタンスを生成 (コンストラクタ呼び出し)
  2. 入力ノードを生成
  3. AudioDestinationNodeインスタンスに接続 (connectメソッド)
  4. 音源のスイッチをON (startメソッド)
  5. +α ボリュームコントローラ機能の追加 (createGainメソッド)

ところで, サウンド出力点の役割を担うのはAudioDestinationNodeインスタンスのただ1つでしたが, サウンド入力点の役割を担うノード (とそれを生成するメソッド) は複数ありました (表1 - 1 - a) .

Web Audio APIの基本処理では, MediaStreamAudioSourceNodeクラス以外, すなわち, デバイス以外の入力をサウンド入力点とするノードにフォーカスして解説します.