31
24

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Web Audio APIで、簡単なシンセサイザーを作ってみる / 1: まずは音を鳴らす

Last updated at Posted at 2016-02-20

Web Audio APIを触ってみた

音楽好きとしては、やはり何か惹かれるWeb Audio API。
timbre.jsのような素晴らしいライブラリも公開されているので、そういうものを扱えば簡単に楽しめるとは思いますが、勉強も兼ねて、あえて素のWeb Audio APIを書いてみました。
偉そうなタイトルにしましたが、僕自身まったくの手探り状態なので、間違いやアドバイスがありましたら、ぜひコメントでご教示いただければ幸いです。

役に立ちそうなページ

まずは音を鳴らしてみる

キーボードを押すとサイン波が出てくる、簡単なピアノのようなものを作りました。
キーボードのZキー 〜 ,キーあたりを押すと、音が鳴ります。

実際の動作例はこちらで確認できます。

synth.app
'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エンベロープを作成してみようと思います。

次回!!!

Web Audio APIで、簡単なシンセサイザーを作ってみる / 2: 音をフェードアウトさせる

31
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
24

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?