音を作る

 前回は音声ファイルやマイクなど外部から音のデータを入力して音として出力しました。 今回はプログラムで音を作って鳴らしてみようと思います。

 今回もスクリプトは参考資料とほぼ同じなので、詳しい技術解説は参考資料のサイトの方を読んでください。 なお、今ご覧のこのページは、技術解説というより私個人の覚書とかメモといった位置づけの内容です。

正弦波を作って鳴らす

 前回のマイクを使うときとほとんど同じで、音源をマイク(createMediaStreamSource)から発振器(createOscillator)に変更するだけです。 付随する箇所は多少変更することにはなりますが、大筋は同じです。 発振器(createOscillator)をスピーカー(destination)にconnectプロパティでつなぐことで組み立てが完了します。

 start(0)を実行すると音がなり始め、stop()を実行すると音が止まります。 サンプルではcreateOscillatorは初期値で使用しているので、440Hzの正弦波(sin波、純音)を出します。 実行すると大きめの音が出るので、イヤホンやヘッドホンを使っている方はご注意ください。

なお、今回はこちらのサイトを参考にしました。というかほぼ丸写しです。詳細な解説はリンク先をご覧ください。
参考資料:Web Audio API 3.音を出してみる
https://webmusicdevelopers.appspot.com/codelabs/webaudio/index.html?ja-jp#3


<button id="play">Play</button>
<button id="stop">Stop</button>

<script>
  // AudioContext の互換性のため処理
  window.AudioContext = window.AudioContext || window.webkitAudioContext;  

  // AudioContextを作成
  //  音をとりまとめるcontext
  //  この処理はページ読み込み時に自動実行するようにしておくと、
  //  ブラウザの自動再生ポリシーに引っかかって動かなくなる可能性があります。
  //  ボタンクリックなどユーザー操作を受けてから実行されるようにしておく必要があります。
  var audioctx = new AudioContext();

  // 発振器(Oscillator)で作った音の元を AudioContext に接続
  //  設定:440 Hz 正弦波
  var source = audioctx.createOscillator();

  // 作った音を「音の再生先」に接続
  source.connect(audioctx.destination);

  // 接続イメージ
  //    source    -> destination
  // (Oscillator)

  // 再生
  document.getElementById('play').addEventListener('click', function(){
    // このサンプルでは2回以上再生できません。
    // もう一度再生するには、audioctx を設定し直す必要があります。
    source.start(0);
  });

  // 停止
  document.getElementById('stop').addEventListener('click', function(){
    source.stop();
  });
</script>

サンプル
前回のマイクよりも単純にしてあります。発振器から出た音はそのままスピーカーに接続されています。 接続のイメージとしてはこんな感じです。

   source    -> destination
(Oscillator)

※ 入力側 -> 出力側

周波数変調(FM変調)

 先程のは単純に初期設定の音を鳴らしただけでした。せめて周波数ぐらい変更したいですね。 ということで、次は周波数を変えながら音を鳴らしてみます。資料を参考(というか丸写し)に周波数変調をしてみようと思います。
参考資料:Web Audio API 4.オシレータを揺らしてみる
https://webmusicdevelopers.appspot.com/codelabs/webaudio/index.html?ja-jp#4

 周波数変調(→Wikipedia)とは、FMラジオなどで使われているものです。搬送波というベースとなる正弦波を常に出しておいて、その周波数を変調波(送信したい波形信号)の振幅に応じて変更するというものです。 変調波の振幅が大きいときは搬送波の周波数が高くなり、変調波の振幅が小さいときは搬送波の周波数は低くなります。 変調波は直接送信されるのではなく、搬送波の周波数として送信されます。


<table>
  <tr><td>LFO Freq(変調波 周波数) : </td><td><input type="text" size="10" id="lfofreq" value="5"/></td></tr>
  <tr><td>Depth(変化幅) : </td>   <td><input type="text" size="10" id="depth" value="10"/></td></tr>
  <tr><td>VCO Freq(搬送波 周波数) : </td><td><input type="text" size="10" id="vcofreq" value="440"/></td></tr>
</table>
<button id="play">Play</button>

<script>
  // AudioContextを作成
  window.AudioContext = window.AudioContext || window.webkitAudioContext;  
  var audioctx = new AudioContext();

  // 2回startを実行させないためのフラグ
  var play  = 0;

  // 発信周波数を制御する信号の素(搬送波)
  var vco   = audioctx.createOscillator();
  // 低い周波数のゆらぎを与える素(変調波)
  var lfo   = audioctx.createOscillator();
  // ゆらぎの幅を調整する Node
  var depth = audioctx.createGain();

  // vco -> destination
  vco.connect(audioctx.destination);
  // lfo -> depth
  lfo.connect(depth);
  // depth -> vcoの周波数
  depth.connect(vco.frequency);
  //
  // ノードグラフのイメージ
  //
  //                  搬送波  スピーカー
  //                   vco  -> destination
  //                   ‖
  //  lfo  -> depth -> vco.frequency
  // 変調波   増幅    搬送波の周波数
  //

  // play ボタンが押されたときの動作
  document.getElementById('play').addEventListener('click', function(){
    // 再生
    if(play == 0) {
      play = 1;
      vco.start(0);
      lfo.start(0);
    }
    // 設定を反映
    vco.frequency.value = parseFloat(document.getElementById("vcofreq").value);
    lfo.frequency.value = parseFloat(document.getElementById("lfofreq").value);
    depth.gain.value    = parseFloat(document.getElementById("depth").value);
  });

</script>

サンプル
 サンプルでは変調波として正弦波を利用しています。変調波として設定した周期で音が高くなったり低くなったり揺れているのが確認できると思います。 変調波 周波数を低くして、変化幅を大きくするとわかりやすくなります。

                 搬送波  スピーカー
                  vco  -> destination
                  ‖
 lfo  -> depth -> vco.frequency
変調波   増幅    搬送波の周波数

※ 入力側 -> 出力側

 接続のイメージはこんな感じです。変調波をアンプcreateGainに入れ、その出力を搬送波の周波数設定vco.frequencyに差し込んでいます。 こういう接続をして使用する音響機器って普段見かけないので違和感のあるつなぎ方ですが、プログラムなのでこのように手軽にできます。 しかし、私には馴染みはないですが、ラジオや無線方面の方にとっては馴染み深い接続なんでしょうね。

次回予告

 createGainだけでなく、Web Audio APIでは音声信号を加工するのに必要なノードがいくつか用意されています。 始めたばかりなので、どのくらいあるのか全く把握していませんが、おそらく基本的なものは一通り揃っていると思います。 詳細については検索すると詳しいサイトが見つかります。日本語サイトも多数あるので調べてみてください。

 今回は、音の加工ができるようになりました。次回は音の可視化をやっていきます。