Web Audio APIを触ってみた
音楽好きとしては、やはり何か惹かれるWeb Audio API。
timbre.jsのような素晴らしいライブラリも公開されているので、そういうものを扱えば簡単に楽しめるとは思いますが、勉強も兼ねて、あえて素のWeb Audio APIを書いてみました。
偉そうなタイトルにしましたが、僕自身まったくの手探り状態なので、間違いやアドバイスがありましたら、ぜひコメントでご教示いただければ幸いです。
役に立ちそうなページ
- Web Audio API - Web API インターフェイス | MDN - APIリファンレンス
-
Web Audio API の基礎 - HTML5 Rocks -
日本語訳されたチュートリアルページ - Web Audio API (日本語訳) - W3Cドキュメントの日本語翻訳版
まずは音を鳴らしてみる
キーボードを押すとサイン波が出てくる、簡単なピアノのようなものを作りました。
キーボードのZキー 〜 ,キーあたりを押すと、音が鳴ります。
実際の動作例はこちらで確認できます。
'use strict';
// Web Audio APIを利用するためのインスタンス生成
var audioContext = new AudioContext();
// キーごとにMIDIノートナンバーを割り振る
var keymap = {
// Zキー = C4
90: 60,
// Sキー = C#4
83: 61,
// Xキー = D4
88: 62,
// Dキー = D#4
68: 63,
// Cキー = E4
67: 64,
// Vキー = F4
86: 65,
// Gキー = F#4
71: 66,
// Bキー = G4
66: 67,
// Hキー = G#4
72: 68,
// Nキー = A4
78: 69,
// Jキー = A#4
74: 70,
// Mキー = B4
77: 71,
// ,キー = C5
188: 72
};
// キーダウンした際の処理
document.onkeydown = function(keyDownEvent) {
// キー押しっぱなしの状態で発火した場合は、動作を終了する
if (keyDownEvent.repeat === true) {
return;
}
// オシレーターを作成
var osciillatorNode = audioContext.createOscillator();
// MIDIノートナンバーを周波数に変換
var freq = 440.0 * Math.pow(2.0, (keymap[keyDownEvent.keyCode] - 69.0) / 12.0);
// オシレーターの周波数を決定
osciillatorNode.frequency.value = freq;
// オシレーターを最終出力に接続
osciillatorNode.connect(audioContext.destination);
// オシレーター動作
osciillatorNode.start();
// キーを離した際に音が止まるよう、イベントを登録する
document.addEventListener('keyup', checkKeyUp);
// キーを離したかどうかチェック
function checkKeyUp(keyUpEvent) {
// 離したキーが、押下したキーで無い場合は処理を行わない
if (keyUpEvent.keyCode !== keyDownEvent.keyCode) {
return;
}
// オシレーターを停止する
osciillatorNode.stop();
// 自身のイベントを削除
document.removeEventListener('keyup', checkKeyUp);
}
};
# 解説
上から順番に解説していきたいと思います。
// Web Audio APIを利用するためのインスタンス生成
var audioContext = new AudioContext();
Web Audio APIを利用するためには、まずはAudioContext
を作成する必要があります。
はじめの一歩。
// キーごとにMIDIノートナンバーを割り振る
var keymap = {
// Zキー = C4
90: 60,
// Sキー = C#4
83: 61,
....
...
キーボードのZキー 〜 ,キーあたりを鍵盤として使うため、キーごとにMIDIノートナンバーを割り振りました。
直接周波数を指定してもいいかなと思いましたが、業界の標準に従っといたほうが何かと後で楽そうです。
A = 441Hzとかへ変更するのも楽にできそうだし。
// キーダウンした際の処理
document.onkeydown = function(keyDownEvent) {
// キー押しっぱなしの状態で発火した場合は、動作を終了する
if (keyDownEvent.repeat === true) {
return;
}
キーボードのキーが押下された場合は、これ以降のイベントが発火します。
しかしキーを押しっぱなしにしていると、window.onkeydown
は押している間に何回も発火してしまうので、
発火させるのはキーを最初に押した一回だけに限定する必要があります。
keyDownEvent.repeat
で、押した初回の発火なのか、押しっぱなし発火なのか判定できますので、
押しっぱなし発火の場合は以降の処理を行わないようにします。
// オシレーターを作成
var osciillatorNode = audioContext.createOscillator();
// MIDIノートナンバーを周波数に変換
var freq = 440.0 * Math.pow(2.0, (keymap[keyDownEvent.keyCode] - 69.0) / 12.0);
// オシレーターの周波数を決定
osciillatorNode.frequency.value = freq;
最初に生成したaudioContext
から、createOscillator()
を実行して、オシレーター(音波の発生装置)を作成します。
また、押下されたキー番号から、対応するMIDIノートナンバーを周波数に変換し、frequency.value
に鳴らす周波数を指定します。
オシレーターの音は、ちゃんと周波数で指定する必要があるようです。
// オシレーターを最終出力に接続
osciillatorNode.connect(audioContext.destination);
// オシレーター動作
osciillatorNode.start();
ここで音がなります!
osciillatorNode.start()
でオシレーターを動作させることができますが、これ単体だけ実行しても音はなりません。
オシレーターの音が、どこへ向かっていくのか、きちんと指定する必要があります。
osciillatorNode.connect()
で、どこへ接続するのか、指定が可能です。
今回は、最終的な出力先である、audioContext.destination
を選びました。
実際の楽器でも、ギター→エフェクター→アンプ とつないでいくのと、同じような考え方ですね。
// キーを離した際に音が止まるよう、イベントを登録する
document.addEventListener('keyup', checkKeyUp);
// キーを離したかどうかチェック
function checkKeyUp(keyUpEvent) {
// 離したキーが、押下したキーで無い場合は処理を行わない
if (keyUpEvent.keyCode !== keyDownEvent.keyCode) {
return;
}
// オシレーターを停止する
osciillatorNode.stop();
// 自身のイベントを削除
document.removeEventListener('keyup', checkKeyUp);
}
キーを離した際に音を停止するように、キーのリリースを監視するイベントを登録します。
別のキーが離された時に、音が停止しないように、処理の前にきちんと離されたキーの照合を行います。
osciillatorNode.stop()
で音を止めることができます。
また、最後にキー停止イベントそのものを削除することを忘れないように。
# 次回は...
いきなりそれっぽいのがすぐできてしまいました。
いきなりポリフォニーで音が鳴らすことができて、ちょっとびっくりです。
次回は、キーをリリースした際にブツブツ言わないように、
また、多彩な音が出せるようにするため、ADSRエンベロープを作成してみようと思います。
次回!!!