WebAudioを使って音を鳴らす
===============
## はじめに
この文書は,WebAudioAPIの簡単なintroductionです.
## 音を鳴らす最低限のプログラム
あれこれ言う前に,まずは音を鳴らしてみましょう.パソコンの音量を下げ気味にして,以下のコードの下にあるRunボタンをクリックしてください.PCとWebブラウザが対応していれば1秒間音が鳴ります.
注意点として,WebブラウザによってAudioContextの初期化回数が制限されていることです.つまり,以下のコードを何回も実行するとエラーで止まります.
```javascript runnable editable
// 音を出す
window.AudioContext = window.webkitAudioContext || window.AudioContext;
let audioCtx = new AudioContext();
let oscNode = audioCtx.createOscillator();
oscNode.connect( audioCtx.destination );
oscNode.start();
setTimeout( () => { oscNode.stop() }, 1000 );
```
## 基本的な文法
それでは順番にソースコードを見ながら実行していきましょう.ソースコードの下にあるOnceやRunボタンを押すと実行できます.なお,Runボタンは何回でも実行できる箇所で,Onceボタンは1回のみ実行できる箇所です.
WebAudioAPIを使用して音を鳴らすためには,まずAudioContextを作成します.コンテキストとは,元々**文脈**という意味を持っていますが,プログラム用語では**状況によって異なる動作を行うもの**が転じて**制御するための情報**という意味を持ちます.
このAudioContextですが,Webブラウザによって名称が若干異なります.元々はWebブラウザごとに暫定的な仕様に基いて実装されていた際の名残で,将来的に統一されると思われます.現在では,通常のWebブラウザでは「AudioContext」が用いられ,iOSでは「webkitAudioContext」が用いられています.その違いを吸収するコードが1行目で,どちらか実装されている方をAudioContextとする方法です.また,windowという単語は,グローバル変数を表します.
以下を実行すると,作成されたコンテキストを表示しています.
```javascript once editable console
// WebAudioの初期化
window.AudioContext = window.webkitAudioContext || window.AudioContext;
var audioCtx = new AudioContext();
console.log( audioCtx );
```
次にオシレータ(発振回路)を初期化し,変数oscNodeに代入します.ノードとは,WebAudioAPIで使用される,機能を持った部品のことです.WebAudioAPIでは音源としてオシレータや配列の内容(サンプリングした波形や合成した波形)を使用することができます.
```javascript once editable console
// オシレータの初期化
var oscNode = audioCtx.createOscillator();
console.log( oscNode );
```
続いて,下図のようにオシレータを出力先(destination)に接続します.ハードウェアを配線することをイメージしてください.
```mermaid
graph LR
oscNode -- connect --> destination
```
```javascript once editable console
oscNode.connect(audioCtx.destination);
console.log( oscNode );
```
オシレータの発振を開始すると音が鳴ります.
```javascript runnable editable
oscNode.start();
```
放っておくとずっと音が鳴ります.以下のようにしてオシレータを止めましょう.
```javascript runnable editable
oscNode.stop();
```
最初に示したソースコードでは,1秒後にオシレータの発振を止めるようにしていました.その部分を抜き出すと以下のようになります.
```javascript hl
setTimeout(
() => {
oscNode.stop();
}, 1000
);
```
ここで```setTimeout```の文法は,```setTimeout( 関数, 時間 );```となっており,第2パラメータで指定された時間経過後に,第1パラメータで指定された関数を実行します.第1パラメータは,直接関数名を指定するか,```function```で定義した関数を与えることができます.
## sin波以外の波形の取り扱い
オシレータノードはsin波以外に矩形波や三角波,ノコギリ波などの波形を扱うことも可能です.オシレータノードは内部的に```type```というパラメータを持っているので,この値を変更することで矩形波などを鳴らすことができます.
type | 波形
--|--
sine | 正弦波
square | 矩形波
triangle | 三角波
sawtooth | ノコギリ波
```javascript runnable editable
// コメントの位置を変えることで矩形波,三角波,ノコギリ波を鳴らす
// 音量が大き目になっています.コンピュータの音量を下げてから実行してください.
let audioCtx = new AudioContext();
let oscNode = audioCtx.createOscillator();
oscNode.connect( audioCtx.destination );
oscNode.type = "square"; // 矩形波
// oscNode.type = "triangle"; // 三角波
// oscNode.type = "sawtooth"; // ノコギリ波
oscNode.start();
setTimeout( () => { oscNode.stop() }, 2000 );
```
## 音量を変更するプログラム
WebAudioAPIでは,音に様々な加工を施すことができます.まずは**音量を変更する**加工を施してみましょう.音量を調整するためには```gainNode```を使用します.具体的には,oscNodeからdestinationに直接接続するのではなく,oscNodeからgainNodeに接続し,その後destinationに接続します.
```mermaid
graph LR
oscNode -- connect --> gainNode
gainNode -- connect --> destination
```
以下の例では,音を鳴らし始めて1秒後に音量を1/2にして,さらに1秒後に音を止めます.
```javascript runnable editable
// Max音量:1秒間,1/2音量:1秒間
window.AudioContext = window.webkitAudioContext || window.AudioContext;
let audioCtx = new AudioContext();
let oscNode = audioCtx.createOscillator();
let gainNode = audioCtx.createGain();
oscNode.connect( gainNode );
gainNode.connect( audioCtx.destination );
// タイミングを合わせて音量調整
oscNode.start();
setTimeout( () => {
gainNode.gain.value = 0.5;
}, 1000 );
setTimeout( () => {
oscNode.stop();
}, 2000 );
```
## 音量を変更する方法
音量を変更するためには,ゲインノードを使用します.WebAudioの各ノードは,ソースノードを除いて接続することができます.ここでは,オシレータノード→ゲインノード→出力という順で接続していきます.
それではプログラムを見ていきましょう.まずはコンテキスト,オシレータノード,ゲインノードを初期化します.ゲインノードはgainNodeという変数に格納しています.
```javascript runnable editable
// コンテクスト,オシレータノード,ゲインノードの初期化
window.AudioContext = window.webkitAudioContext || window.AudioContext;
var audioCtx = new AudioContext();
var oscNode = audioCtx.createOscillator();
var gainNode = audioCtx.createGain();
```
続いて,各ノードを接続していきます.
```javascript runnable editable
// オシレータノード → ゲインノード → 出力
oscNode.connect( gainNode );
gainNode.connect( audioCtx.destination );
oscNode.start();
```
音量を変更したい所で,ゲインノードの持つパラメータ**gain**の**value**を変更します.ここでは0.5にしています.
```javascript runnable editable
// 音量を1/2に
gainNode.gain.value = 0.5;
```
放っておくとずっと音が鳴ります.以下のようにしてオシレータを止めましょう.
```javascript runnable editable
oscNode.stop();
```