<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:series="http://organizeseries.com/"
	>

<channel>
	<title>Web Audio API &#8211; HTML5Experts.jp</title>
	<atom:link href="/tag/web-audio-api/feed/" rel="self" type="application/rss+xml" />
	<link>https://html5experts.jp</link>
	<description>日本に、もっとエキスパートを。</description>
	<lastBuildDate>Sat, 07 Jul 2018 03:14:05 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.7.19</generator>
	<item>
		<title>【Web Audio API + Web MIDI API】ブラウザで電子楽器を作ってみよう！</title>
		<link>/ryoyakawai/12569/</link>
		<pubDate>Mon, 23 Mar 2015 04:01:41 +0000</pubDate>
		<dc:creator><![CDATA[河合良哉]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[Web Audio API]]></category>
		<category><![CDATA[Web MIDI API]]></category>
		<category><![CDATA[ブラウザ]]></category>

		<guid isPermaLink="false">/?p=12569</guid>
		<description><![CDATA[連載： HTML5 Conference 2015 特集 (3)ブラウザ上で音を扱うというと、直接音を加工できるWeb Audio API、ブラウザから直接MIDIデバイスと接続できるWeb MIDI APIの2つがここ...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/h5conf2015/" class="series-257" title="HTML5 Conference 2015 特集" data-wpel-link="internal">HTML5 Conference 2015 特集</a> (3)</div><p>ブラウザ上で音を扱うというと、直接音を加工できるWeb Audio API、ブラウザから直接MIDIデバイスと接続できるWeb MIDI APIの2つがここ数年の間に利用可能になり、実際のWebサイトでも使われるようになりました。<br>
今回は「ハンズオンだともっとよかった」というお声をいただきましたHTML5 Conference 2015での講演内容を元に、2つのAPIの説明と、実際にブラウザ上に電子楽器の1つであるシンセサイザーを作ってしまうという記事です。</p>

<p>記事中のサンプルは<a href="https://github.com/ryoyakawai/html5conference2015" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">GitHub</a>に公開していますので、そちらも合わせてご参照ください。</p>

<h2>利用するAPIの説明</h2>

<h3>Web Audio API</h3>

<p style="margin-bottom:8px">短く一言で説明すると<b>「ブラウザ上で音を直接作ったり、いじったりすることのできるAPI」</b>です。もう少し難しく言うと「ブラウザ上で波形処理を可能にしたAPI」となります。<br>
Web Audio APIの理解を深めるためにまず「音」とは何かを考えてみたいと思います。Wikipediaには以下のように書かれています。
</p>

<div style="border:solid 1px #cccccc;margin-bottom:8px">
<blockquote>
<ul style="margin-left:20px;margin:10px 0px 10px 20px">
 <li style="margin-top:2px">物の<b>響き</b>や人や鳥獣の声</li>
 <li style="margin-top:2px">（物体の振動が空気などの<b>振動</b>（音波）として伝わって起す）聴覚の内容</li>
 <li style="margin-top:2px">またはそのもととなる<b>音波</b></li>
</ul>
</blockquote>
<div style="margin:10px 0px 10px 80px;border-left:3px solid #aaaaaa;padding-left:10px">
「引用」『フリー百科事典　ウィキペディア日本語版』より。<br>
2015年3月16日 8:30 UTC<br>
<a href="http://ja.wikipedia.org/wiki/%E9%9F%B3" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">http://ja.wikipedia.org/wiki/%E9%9F%B3</a><br>
</div>
</div>

<p>
<b>響き</b>、<b>振動</b>、<b>音波</b>と出てきました。実は、音を目に見える形にすると<b>波</b>になるのです。Web Audio APIも原理は同じで、波を与えて音として出力しています。そして、その波の形（波形）をいじる（処理）して様々な音を作り出すとご理解いただけばよいと思います。</p>

<p style="margin-bottom:8px">原理の説明はここまでにして、最初に声を取得して、その声をWeb Audioでピッチシフト（音を高くしたり、低くしたりする効果）、Delay（音を遅らせる効果）の加工を行うデモをご紹介いたします。（できるだけマイクとヘッドホンをご用意ください）<a href="http://ryoyakawai.github.io/html5conference2015/audio/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ピッチシフト＆Delayのライブデモ</a></p>

<div class="aligncenter" style="clear:both;width:568px">
<div style="float:left;width:283px"><a href="http://ryoyakawai.github.io/html5conference2015/audio/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2015/02/Screen-Shot-2015-02-15-at-9.54.14-AM.png" alt="PitchShift&amp;Delay" width="281" height="289" class="alignnone size-full wp-image-12827" srcset="/wp-content/uploads/2015/02/Screen-Shot-2015-02-15-at-9.54.14-AM.png 281w, /wp-content/uploads/2015/02/Screen-Shot-2015-02-15-at-9.54.14-AM-201x207.png 201w" sizes="(max-width: 281px) 100vw, 281px" /></a></div>
<div style="float:left;width:283px">
 <div style="text-align:left;padding:40px 0px 0px 20px">
  <p style="margin-bottom:2px;font-weight:bold">ノブとボタンの説明▼</p>
  <div style="padding:4px">
   <p style="margin-bottom:2px"><b>(1)</b> PitchShift ON/OFF</p>
   <p style="margin-bottom:2px"><b>(2)</b> Shiftの種類：(上:高い、下：低い)</p>
   <p style="margin-bottom:2px"><b>(3)</b> Delay ON/OFF</p>
   <p style="margin-bottom:2px"><b>(4)</b> Delayの種類：並列/直列</p>
   <p style="margin-bottom:2px"><b>(5)</b> Feedback量</p>
   <p style="margin-bottom:2px"><b>(6)</b> Delay時間</p>
  </div>
 </div>
</div>
</div>

<div style="clear:both"></div>

<p><br></p>

<div class="aligncenter">
<img src="/wp-content/uploads/2015/02/delay-parallel.png" alt="delay-parallel" width="70%" class="alignnone wp-image-12849" srcset="/wp-content/uploads/2015/02/delay-parallel.png 631w, /wp-content/uploads/2015/02/delay-parallel-300x85.png 300w, /wp-content/uploads/2015/02/delay-parallel-207x59.png 207w" sizes="(max-width: 631px) 100vw, 631px" /></div>

<p><br>
ノードグラフ（Web Audioでは処理をする1つ1つをノードと呼び、それらをつなぎ合わせて1つのグラフにします）は上図のようになっています。ピッチシフト＆DelayのライブデモのDelayをONにして、種類を直列にする（（4）のスイッチを下にする）と<a href="https://html5experts.jp/wp-content/uploads/2015/02/delay-direct.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">このような接続</a>になります。直列につなげると、マイクで拾った音が(6)Delay時間だけ遅れてスピーカから出るようになります。<br>
このノードグラフをWeb Audio APIで書くとこうなります。（ピッチシフト部分、Delay部分をObjectにしてまとめている関係上、ゼロから書くともう少し長く、複雑になります）（<a href="http://ryoyakawai.github.io/html5conference2015/audio/sample01.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ライブデモ</a>）</p>
<pre class="crayon-plain-tag">var ctx=new AudioContext();
var mic;
var psin=ctx.createGain(), psout=ctx.createGain();
var delayin=ctx.createGain(), delayout=ctx.createGain();

navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
navigator.getUserMedia({audio : true}, successCallback, errorCallback);
function successCallback(stream) {
    mic = ctx.createMediaStreamSource(stream);
    mic.connect(psin);
}
function errorCallback(msg) {
    console.log(msg);
}
var pshift=new pitchShift(ctx);
psin.connect(pshift.getSrc());
pshift.connect(psout);

var delay=new delayProcess(ctx);
delayin.connect(delay.getSrc());
delay.connect(delayout);

psout.connect(delayin);
delayout.connect(ctx.destination);</pre></p>

<p>このように、Web Audio APIを使うと、今まではプラグインを使う以外に方法がなかったWebブラウザ上でのリアルタイムな波形処理を、比較的簡単に行うことが可能です。</p>

<h3>Web MIDI API</h3>

<p>短く一言で説明すると<b>「ブラウザとデバイス間でMIDIメッセージを送受信するためのAPI 」</b>です。MIDIとは <b>M</b>usical <b>I</b>nstrument <b>D</b>igital <b>I</b>nterface の略で、電子楽器の演奏データをデバイス間でデジタル転送するための世界共通規格であり、物理的な送受信回路・インタフェース、通信プロトコル、ファイルフォーマットなど複数の規定からなっています。Web MIDI APIは特にこの中の通信プロトコルをWebブラウザへの実装したAPIです。</p>

<p style="margin-bottom: 8px">Web MIDI APIの特徴は外付けのMIDIデバイス<a href="#footnote0" style="vertical-align: top;color: red;font-size:10px" data-wpel-link="internal">※0</a>とWebブラウザが直接接続できるところです。ですのでWeb Audio APIのようにそれ単体で音が鳴ったりする訳ではなく、MIDIデバイスからWebブラウザで動くアプリケーションをコントロールしたり、またWebブラウザからMIDIデバイスコントロールするために利用します。よって本記事では最初にWeb Audio APIを使った電子楽器アプリケーションを作り、それをWeb MIDI APIを使って外付けのMIDIデバイスからコントロールするというシナリオで進めさせていただきます。</p>

<div style="border:solid 1px #cccccc;margin-bottom:25px">
  <a name="footnote0" data-wpel-link="internal"></a>
  <div style="margin:10px 5px 10px 10px;border-left:3px solid #aaaaaa;padding-left:10px">
    <a name="footnote0" data-wpel-link="internal"></a>
    <span style="vertical-align: top;color: red;font-size:10px">※0</span> <b>MIDIデバイス</b>： 楽器関連では鍵盤をはじめ、ドラムパッド、スライダー、ノブ等があり、楽器以外ですと、ステージ上のセットを楽器等と一緒にMIDIでコントロールしてしまおうという発想で照明機器、その他噴水、爆破、炎の制御に使われていることもあります。<br>
  </div>
</div>

<p>なお、やや長い記事になってしまいましたので、ソースコードの量の少なさを体感していただき、その解釈は後回しにしてデモを触っていただくのがよいと思います。「電子楽器を実装する」というと難しそうに聞こえるかもしれませんが、そこまで難しくもありませんので実装に挑戦していただけるとうれしいです。</p>

<h2>Web Audio API で電子楽器を実装する</h2>

<p>電子楽器と言ってもその種類は複数あります。今回はその中からアナログシンセサイザーとFMシンセサイザーを実装してみます。</p>

<h3>Web Audio API でアナログ・シンセサイザー</h3>

<p>アナログ・シンセザイザーはアナログ回路を用いて信号処理を行うことで音を出す方式のシンセサイザーです。そのアナログ回路をWeb Audio APIを使って実装していきます。まずはどんな音が出るか<a href="http://ryoyakawai.github.io/html5conference2015/analog/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">完成形のデモ</a>で試してみてください。
</p>

<p><a href="http://ryoyakawai.github.io/html5conference2015/analog/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2015/02/Screen-Shot-2015-02-19-at-12.49.31-AM.png" alt="AnalogSynthApp" width="60%" class="aligncenter size-full wp-image-12998" srcset="/wp-content/uploads/2015/02/Screen-Shot-2015-02-19-at-12.49.31-AM.png 640w, /wp-content/uploads/2015/02/Screen-Shot-2015-02-19-at-12.49.31-AM-300x248.png 300w, /wp-content/uploads/2015/02/Screen-Shot-2015-02-19-at-12.49.31-AM-207x171.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>
画面上にある２つのスライダを動かすと音色を大きく変化させることができると思います。それでは原理を見てみましょう。
</p>

<p style="margin-bottom:8px">
このシンセサイザーは以下の3つの部品を使っています。
</p>

<ul style="margin-bottom:14px">
  <li style="margin-bottom:2px">基本の信号・波形を作り出す発振機<a href="#footnote1" style="vertical-align: top;color: red;font-size:10px" data-wpel-link="internal">※1</a> （VCO0、VCO1）</li>
  <li style="margin-bottom:2px">波形を加工するフィルタ（VCF）</li>
  <li style="margin-bottom:2px">低い周波数の制御信号を発振機から発生させて送ることで周期的な変化を与える（LFO）</li>
</ul>

<p>
これらを接続して下図のノードグラフを作ります。
<img src="/wp-content/uploads/2015/02/analogsynth.png" alt="AnalogSynthNodeGraph" width="60%" class="aligncenter size-full wp-image-13003" srcset="/wp-content/uploads/2015/02/analogsynth.png 527w, /wp-content/uploads/2015/02/analogsynth-300x225.png 300w, /wp-content/uploads/2015/02/analogsynth-207x155.png 207w" sizes="(max-width: 527px) 100vw, 527px" />


<div style="border:solid 1px #cccccc;margin-bottom:8px">
  <div style="margin:10px 5px 10px 10px;border-left:3px solid #aaaaaa;padding-left:10px">
    <a name="footnote1" data-wpel-link="internal"></a>
    <span style="vertical-align: top;color: red;font-size:10px">※1</span> <b>発振機</b>： 波を発生させる部品で、オシレータ（Oscillator）とも呼びます。<br>
  </div>
</div>



</p>

<p>ソースコードは以下のようになります。（<a href="http://ryoyakawai.github.io/html5conference2015/analog/sample02.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ライブデモ</a>、<a href="https://github.com/ryoyakawai/html5conference2015/tree/master/analog/sample02.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ソースコード</a>）</p>

<p></p><pre class="crayon-plain-tag">var ctx=new AudioContext();
var vco0, vco1, lfo, vcf;

vco0=ctx.createOscillator();   // VCO0を作成
vco1=ctx.createOscillator();   // VCO1を作成
lfo=ctx.createOscillator();    // LFOを作成
vcf=ctx.createBiquadFilter();  // VCFを作成

vco0.connect(vcf);             // (1)の接続
vco1.connect(vcf);             // (2)の接続
lfo.connect(vco0.frequency);   // (3)の接続
lfo.connect(vco1.frequency);   // (4)の接続
lfo.connect(vcf.detune);       // (5)の接続
vcf.connect(ctx.destination);  // (6)の接続

// 値を変更
//vco0.type="sawtooth";
//vco1.detune.value=-35;
//lfo.frequency.value=2;
//vcf.frequency.value=10000;

// Oscillator（発振機）を動作させて発音
vco0.start(0);
vco1.start(0);
lfo.start(0);

// 音階を変える
vco0.frequency.value=440;
vco0.frequency.value=440;</pre><p></p>

<p style="margin-bottom:12px">これで発音されます。が、このままですとそのままの音が出るだけですので面白くありません。そこで、それぞれのノードのパラメータを変更してみます。コメント化していた「値を変更」の以下4行を生かしてみます。（<a href="http://ryoyakawai.github.io/html5conference2015/analog/sample03.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ライブデモ</a>、<a href="https://github.com/ryoyakawai/html5conference2015/tree/master/analog/sample03.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ソースコード</a>）<br>
先程より音色が明るくなったと思います。<a href="http://ryoyakawai.github.io/html5conference2015/analog/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">完成形のデモ</a>のVCFのスライダを右に動かしたのと同様な値の変更を行いました。VCFは設定値より低い周波数を通す（ローパス）フィルタになっていて、そのパラメータを大きくしてより多くの明るい部分を通して明るい音色を出しています。</p>

<p>さらにシンセサイザーっぽい音にするべく、音量や音高などを時間で変化させる<a href="http://ja.wikipedia.org/wiki/ADSR" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ADSR</a><a href="#footnote2" style="vertical-align: top;color: red;font-size:10px" data-wpel-link="internal">※2</a> と呼ばれてるエンベロープ<a href="#footnote3" style="vertical-align: top;color: red;font-size:10px" data-wpel-link="internal">※3</a> の機能実装します。ここではこのエンベロープを発振機（Oscillator）の音量（VCO0、VCO1）に適応しますので音量を調節するGainNodeを(1)、(2)へ追加します。そのソースコードは以下のようになります。（ノード作成、接続部分のみ抜粋）

<div style="border:solid 1px #cccccc;margin-bottom:8px">
  <div style="margin:10px 5px 10px 10px;border-left:3px solid #aaaaaa;padding-left:10px">
    <a name="footnote2" data-wpel-link="internal"></a>
    <span style="vertical-align: top;color: red;font-size:10px">※2</span> <b>ADSR</b>：下図のように波形を処理する場合のそれぞれも部分を指しています。<br>
<img src="/wp-content/uploads/2015/02/Screen-Shot-2015-02-20-at-12.14.23-AM.png" alt="ADSR-DIAGRAM" width="60%" class="aligncenter size-full wp-image-13025" srcset="/wp-content/uploads/2015/02/Screen-Shot-2015-02-20-at-12.14.23-AM.png 473w, /wp-content/uploads/2015/02/Screen-Shot-2015-02-20-at-12.14.23-AM-300x157.png 300w, /wp-content/uploads/2015/02/Screen-Shot-2015-02-20-at-12.14.23-AM-207x108.png 207w" sizes="(max-width: 473px) 100vw, 473px" />
    <ul style="margin-bottom:14px;padding-left:5px">
      <li style="margin-bottom:2px"><b style="color:#ff0303">A</b> (Attack) :音の出始め（例えば鍵盤を押した瞬間）から最大音量に到達する時間</li>
      <li style="margin-bottom:2px"><b style="color:#3c78d8">D</b> (Decay) : Attackで到達した音量最大からSustainに到達するまでの時間</li>
      <li style="margin-bottom:2px"><b style="color:#6aa84f">S</b> (Sustain) : Decayから音が出続けている間保つ音量</li>
      <li style="margin-bottom:2px"><b style="color:#ffd966">R</b> (Release) : 演奏終了（例えば鍵盤を離した瞬間）から音量ゼロまで到達する時間</li>
    </ul>

  </div>

    <a name="footnote3" data-wpel-link="internal"></a>
  <div style="margin:10px 5px 10px 10px;border-left:3px solid #aaaaaa;padding-left:10px">
    <span style="vertical-align: top;color: red;font-size:10px">※3</span> <b>エンベロープ</b>： ピーク（最大値）を描いた曲線。特にここでは音量のピークを描く曲線のことを指しています。<br>
  </div>


</div>
</p>

<p></p><pre class="crayon-plain-tag">var ctx=new AudioContext();
var vco0, vco1, lfo, vcf;

vco0=ctx.createOscillator();
vco1=ctx.createOscillator();
lfo=ctx.createOscillator();
vcf=ctx.createBiquadFilter();

// GainNodeを追加
vco0gain=ctx.createGain();
vco1gain=ctx.createGain();

vco0.connect(vco0gain); // vco0の接続先を変更
vco1.connect(vco1gain); // vco1の接続先を変更
vco0gain.connect(vcf);  // vco0gainからvcfへ接続
vco1gain.connect(vcf);  // vco1gainからvcfへ接続
lfo.connect(vco0.frequency);
lfo.connect(vco1.frequency);
lfo.connect(vcf.detune);
vcf.connect(ctx.destination);

// Oscillator（発振機）を動作させて発音
vco0.start(0);
vco1.start(0);
lfo.start(0);</pre><p></p>

<p>続いて、実際にエンベロープを適応していきます。Web Audioには今回のエンベロープのような時間と目標値を指定して、その間を連続的に値を変化させるオートメーションの機能も提供されており、非常に簡単に実装することが可能です。今回は「指定した値まで直線的に連続して値を変化させる」linearRampToValueAtTime()を使いオートメーションを行います。
ソースコードは以下になります。（エンベロープ部分のみ抜粋）
</p><pre class="crayon-plain-tag">var now=ctx.currentTime;
var attack=0.5, decay=0.5, sustain=0.5, release=0.5;

var rootValue0=0.8; // Attackの目標値を0.8
vco0gain.gain.cancelScheduledValues(0);  // スケジュールを全て解除
vco0gain.gain.setValueAtTime(0.0, now);  // 今時点を音の出始めとする
vco0gain.gain.linearRampToValueAtTime(rootValue0, now + attack);  
// ▲ rootValue0までattack秒かけて直線的に変化
vco0gain.gain.linearRampToValueAtTime(sustain * rootValue0, now + attack + decay);
// ▲ sustain * rootValue0までattack+decay秒かけて直線的に変化

var rootValue1=0.8;
vco1gain.gain.cancelScheduledValues(0);
vco1gain.gain.setValueAtTime(0.0, now);
vco1gain.gain.linearRampToValueAtTime(rootValue0, now + attack);
vco1gain.gain.linearRampToValueAtTime(sustain * rootValue0, now + attack + decay);</pre><p>
<a href="http://ryoyakawai.github.io/html5conference2015/analog/sample03.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">1つ前のライブデモ</a>にエンベロープを適応させた<a href="http://ryoyakawai.github.io/html5conference2015/analog/sample04.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ライブデモはこちら</a>になります。（<a href="https://github.com/ryoyakawai/html5conference2015/tree/master/analog/sample04.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ソースコード</a>）
</p>

<p>以上でアナログ・シンセサイザーの骨格が完成しました。楽器にするためには、パラメータをコントロールするスライダー、ノブ、VCOの周波数を変えて音階決める鍵盤を取り付ける作業を残すのみとなります。より個性的な音を作る場合、例えばノードグラフにVCOをもう1つ並列に追加したりすることで、更に多彩な音色を作ることが可能になりますので試してみてはいかがでしょうか。</p>

<p>ちなみに<a href="http://ryoyakawai.github.io/html5conference2015/analog/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">完成形のデモ</a>で使っているノブ、鍵盤は楽器、Audio系のアプリケーションには欠かせないカッコイイノブが簡単に取り付けられるスゴク便利なツール<a href="https://github.com/g200kg/webaudio-controls" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">webaudio-controls</a>というPolymerエレメント（<a href="https://html5experts.jp/1000ch/11905/" target="_blank" data-wpel-link="internal">詳しくはこちらをご覧ください</a>）を利用して実装しています。</p>

<p>アナログ・シンセサイザーの実装の説明は以上になります。</p>

<h3>Web Audio API でFMシンセサイザー</h3>

<p>FMシンセサイザーのFMはFrequency Modulationの頭文字を取っていて、その名の通り周波数を変調して音を作り出す方法で、周波数変調と呼んでいます。（しかしながら、Web Audio APIに用意されている発振機では周波数変調ができません。よって、ここでは複数の波を掛け合わせFMシンセサイザーっぽい音を作っていることにご注意ください。本当のFMシンセサイザーを作るためには周波数変調可能な発振機の作成が必要です）<br>
それでは、どんな音が出るか<a href="http://ryoyakawai.github.io/html5conference2015/fm/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">完成形のデモ</a>を試してみてください。
<a href="http://ryoyakawai.github.io/html5conference2015/fm/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2015/02/Screen-Shot-2015-02-20-at-1.23.53-AM.png" alt="AnalogSynthApp" width="60%" class="aligncenter size-full wp-image-12998" /></a>
</p>

<p>
アナログ・シンセサイザーよりももう少し金属音的な音が出ていると思います。画面右上のプルダウンメニューにて音色も変更することができるようになっていますので、ぜひお試しください。
</p>

<p>
さて、実装に関してですが複数の発振機（Oscillator）を接続していきます。ここで、掛け合わせる側の発振機（Oscillator）をモジュレータ、その影響を受けて掛け合わされる側の発振機（Oscillator）をキャリアと呼びます。今回の実装はモジュレータとキャリアを1つづつ直列に接続し、更にモジュレータを自身にFeedbackしするような接続にします。ノードグラフに表すと以下のようになります。
<img src="/wp-content/uploads/2015/02/fmsynth00.png" alt="fmsynthnodegraph" width="60%" class="aligncenter size-full wp-image-13095" />
少し余談ですが、モジュレータの数が増やすと接続の組み合わせによって複数の接続方法が考えられます。その接続方法の1つ1つをアルゴリズムと呼んでいます。
</p>

<p>ソースコードをみてみましょう。（<a href="http://ryoyakawai.github.io/html5conference2015/fm/sample05.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ライブデモ</a>、<a href="https://github.com/ryoyakawai/html5conference2015/tree/master/fm/sample05.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ソースコード</a>）</p>

<p></p><pre class="crayon-plain-tag">var ctx=new AudioContext();
var modulator, carrier;
var modulatorGain, carrierGain, feedbackGain;

modulator=ctx.createOscillator();  // モジュレータを作成
carrier=ctx.createOscillator();    // キャリアを作成
modulatorGain=ctx.createGain();    // モジュレータの振幅を制御するためのGainの作成 (1)の途中にある
carrierGain=ctx.createGain();      // キャリアの振幅を制御するためのGainの作成 (2)の途中にある
feedbackGain=ctx.createGain();     // フィードバックの振幅を制御するためのGainの作成

// 接続
modulator.connect(modulatorGain);          // モジュレータとモジュレータGainの接続
modulatorGain.connect(carrier.frequency);  // モジュレータGainとキャリアの接続
carrier.connect(carrierGain);              // キャリアとキャリアGainの接続
carrierGain.connect(ctx.destination);      // キャリアGainとDestinationの接続
modulator.connect(feedbackGain);           // モジュレータとフィードバックGainの接続
feedbackGain.connect(modulator.frequency); // フィードバックGainとモジュレータの接続

carrier.frequency.value=440;

// 値を変更
//var presetList={ "name":"Elec.Piano1", "freqRatio":[1,9], "feedback":"0", "outRatio":[99,55]};
//var freq=540;
//modulator.frequency.value=presetList.freqRatio[1]*freq;
//carrier.frequency.value=presetList.freqRatio[0]*freq; // 音階を変える
//feedbackGain.gain.value=presetList.feedback;
//modulatorGain.gain.value=(presetList.outRatio[1]/100)*1024;
//carrierGain.gain.value=(presetList.outRatio[0]/100);

// 発振機（Oscillator）を動作させて発音
modulator.start(0);
carrier.start(0);</pre><p></p>

<p>これで発音されます。が、アナログ・シンセサイザーの時と同様にそのままの音が出るだけで面白くないので、ここでもパラメータを変更してみます。コメント化されている「値を変更」の以下7行を生かしてみます。（<a href="http://ryoyakawai.github.io/html5conference2015/fm/sample06.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ライブデモ</a>、<a href="https://github.com/ryoyakawai/html5conference2015/tree/master/fm/sample06.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ソースコード</a>）<br>
なんと、音がキラキラしてきました。さて、ではアナログ・シンセサイザーのときと同じようにエンベロープを適応してみます。ソースコードは以下になります。（エンベロープ部分のみ抜粋）
</p><pre class="crayon-plain-tag">var now=ctx.currentTime;
var m_attack=0, m_decay=0.5, m_sustain=0.3, m_release=0.5;
var c_attack=0.4, c_decay=0.3, c_sustain=0.7, c_release=0.4;

var modulatorRootValue=modulatorGain.gain.value;  // Attackの目標値をセット
modulatorGain.gain.cancelScheduledValues(0);      // スケジュールを全て解除
modulatorGain.gain.setValueAtTime(0.0, now);      // 今時点を音の出始めとする
modulatorGain.gain.linearRampToValueAtTime(modulatorRootValue, now + m_attack);
// ▲ rootValue0までm_attack秒かけて直線的に変化
modulatorGain.gain.linearRampToValueAtTime(m_sustain * modulatorRootValue, now + m_attack + m_decay);
// ▲ m_sustain * modulatorRootValueまでm_attack+m_decay秒かけて直線的に変化

var carrierRootValue=carrierGain.gain.value;      // Attackの目標値をセット
carrierGain.gain.cancelScheduledValues(0);        // スケジュールを全て解除
carrierGain.gain.setValueAtTime(0.0, now);        // 今時点を音の出始めとする
carrierGain.gain.linearRampToValueAtTime(carrierRootValue, now + c_attack);
// ▲ rootValue0までc_attack秒かけて直線的に変化
carrierGain.gain.linearRampToValueAtTime(c_sustain * carrierRootValue, now + c_attack + c_decay);
// ▲ c_sustain * carrierRootValueまでc_attack+c_decay秒かけて直線的に変化</pre><p>
<a href="http://ryoyakawai.github.io/html5conference2015/fm/sample06.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">1つ前のライブデモ</a>にエンベロープを適応させた<a href="http://ryoyakawai.github.io/html5conference2015/fm/sample07.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ライブデモはこちら</a>になります。（<a href="https://github.com/ryoyakawai/html5conference2015/tree/master/fm/sample07.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ソースコード</a>）
</p>

<p>FMシンセサイザーの骨格もこれで完成しました。<a href="http://ryoyakawai.github.io/html5conference2015/fm/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">完成形のデモ</a>ではパラメータの集合に音色名をつけて選択できるようにしていますが、アナログ・シンセサイザーのときのように、ノブやスライダでパラメータをコントロールするという方法も実現可能ですので、いろいろとお試しいただくと楽しいと思います。</p>

<p>アナログ・シンセサイザーとFMシンセサイザーの実装を通して「Web Audio APIで電子楽器を作ってみる」をやってきましたが、印象はどうでしょう。「Web Audio APIって簡単で楽しいな〜」と感じていただけているととても嬉しいのです！</p>

<p>さて、それでは次のセクションでは作成した電子楽器を本物の楽器のように鍵盤から演奏できるように、MIDIの接続を説明します。</p>

<h2>Web MIDI APIを使う</h2>

<p>
先ほど少しだけMIDIとWeb MIDI APIについてご説明させていただきました。さらに理解したいという方はDTM界隈で著名な藤本健さんの&#8221;DTMステーション&#8221;に<a href="http://www.dtmstation.com/archives/51930656.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">「今さら聞けない、「MIDIって何？」「MIDIって古いの？」」</a>というMIDIを理解するのにドンピシャな記事が公開されましたので、詳細はそちらにお任せするとしてここでは粛々と実装を行っていきたいと思います。</p>

<p>ちなみに2015年3月現在でWeb MIDI APIが動作するブラウザは<a href="https://www.google.co.jp/chrome/browser/desktop/index.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Google Chrome</a>だけとなっています。また、その使用には<a href="https://plus.google.com/u/0/+RyoyaKAWAI/posts/8QeU6ss4dHM" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">フラグの変更（Web MIDI APIを有効にする方法）</a>が必要ですので、お試しになる前にフラグの変更を忘れないようにお願い致します。（MIDIデバイスがお手元になく、Macをお使いの場合は<a href="https://itunes.apple.com/jp/app/easy-midi-free-turn-your-mac/id614043075?l=en&amp;mt=12" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Easy MIDI Free</a>をお使いいただくと演奏できるはずです）
</p>

<p>
コンピュータに接続されているMIDIデバイスをブラウザで取得するには以下のコードを書き、MIDI InputとOutputのデバイスリストを取得します。
</p>

<p></p><pre class="crayon-plain-tag">var inputs, outputs;
navigator.requestMIDIAccess.then({sysex:true})(successCallback, errorCallback);
function successCallback(midiAccess) {
  var inputIterator=midiAccess.inputs.values();
  for(var o=inputIterator.next(); !o.done; o = inputIterator.next()) {
    inputs.push(o.value);
  }
  var outputIterator=midiAccess.outputs.values();
  for(var o=outputIterator.next(); !o.done; o = outputIterator.next()) {
    outputs.push(o.value);
  }
}</pre><p></p>

<p>
MIDI Inputを使う場合、例えば使いたいMIDI Inputデバイスがinputsの先頭にリストされた（index=0）とします。その場合は以下のようにイベントハンドラをつけてあげます。
</p><pre class="crayon-plain-tag">inputs[0]=function(event) {
  console.log("[MIDI Message] " + event.data + " [Timestamp] " + event.timestamp);
}</pre><p>
こうすることで、inputsの先頭にリストされている外部MIDIデバイスからMIDIメッセージが飛んできた場合にMIDIメッセージとタイムスタンプをコンソールに出力するようになります。
</p>

<p>
MIDI Outputを使う場合、例えば使いたいMIDI Outputデバイスがoutputsの先頭にリストされた（index=0）にあったとします。
</p><pre class="crayon-plain-tag">outputs[0].send([0x90, 0x45, 0x3f], performance.now()+0);</pre><p>
とすると、outputsの先頭にリストされたMIDIデバイスに対して0x90, 0x45, 0x3fというMIDIメッセージを今すぐ(第２引数)送信します。MIDIメッセージ0x90, 0x45, 0x3fは、A4の音（0x45）を、50%の音量（0x3f）でチャンネル1を音を鳴らしなさい(0x90)、です。
</p>

<p>といっても、MIDIに慣れ親しんでいない場合は実装のハードルが高いと思っています。そこでWeb MIDI APIの実装を簡単にするPolymerエレメントを公開しています。それが、 <a href="https://github.com/ryoyakawai/x-webmidi" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">x-webmidi</a>です。x-webmidiを使うとHTMLタグを5つ追加する（そのうち1つはWeb ComponentsのPolyfill）だけで、コンピュータに接続されているMIDIデバイスを取得して、セレクトボックスを生成して表示する、までを行ってくれます。MIDI InputデバイスからのメッセージはEventハンドラを、またMIDI Outputデバイスへのメッセージの送信は.sendRawMessage()を使い生のMIDIメッセージを、.sendHRMessage()を使いMIDIに慣れていない方でも分かるようにメッセージを送信できるようになっています。コードにするとこうなります。</p>

<p></p><pre class="crayon-plain-tag">&lt;script src="path/to/webcomponents.js"&gt;&lt;/script&gt;
&lt;link rel="import" href="x-webmidirequestaccess.html"&gt;
&lt;x-webmidirequestaccess sysex="true" input="true" output="true"&gt;&lt;/x-webmidirequestaccess&gt;
&lt;x-webmidiinput id="midi-input"&gt;&lt;/x-webmidiinput&gt; 　　// MIDI Inputデバイスのセレクトボックスを表示 
&lt;x-webmidioutput id="midi-output"&gt;&lt;/x-webmidioutput&gt; // MIDI Inputデバイスのセレクトボックスを表示

// MIDIメッセージを受信する
window.addEventListener("midiin-event:midi-input", function(event){
    // MIDIノートナンバーと、対応する周波数をConsoleに出力
    console.log("[noteNumber] "+event.property.noteNumber+" [frequency] "+event.property.frequency);
});

// outputsの先頭にリストされたデバイスにMIDIメッセージを送信する
var outputs=documenet.getElementById("midi-output");
outputs[0].sendHRMessage("noteon", 0, ["d4", 127], performance.now()+0);</pre><p></p>

<p>それでは、Web Audio APIで作ったシンセサイザーを、MIDIデバイスから操作できるように実装していきます。演奏するためには、音階を変えるのですが、そのためには発振機（Oscillator）の周波数を変更する必要があります。MIDIの鍵盤は1つ1つに連番の番号がついていてこれを<a href="http://ja.wikipedia.org/wiki/MIDI" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">MIDIノートナンバー（ノートナンバーでページ内を検索）</a>と言いますが、そのMIDIノートナンバーから周波数に変換する必要がありますが、それをコードにすると以下のようになります。
</p>

<p></p><pre class="crayon-plain-tag">var freq=440.0 * Math.pow(2.0, (noteNo - 69.0) / 12.0); // noteNoはMIDI鍵盤の鍵盤番号</pre><p></p>

<p style="margin-bottom:8px">しかし、x-webmidiを使うとEventの引数として演奏した鍵盤の番号とそれに対応する周波数が取得することができるので、MIDIノートナンバーから周波数の変更をする必要はありません。これらをアナログ・シンセサイザーとFMシンセサイザーに実装をするとこのように実装できます。</p>

<ul>
<li style="margin-bottom:2px">（単音）アナログ・シンセサイザー：<a href="http://ryoyakawai.github.io/html5conference2015/analog/sample08.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ライブデモ</a>（<a href="https://github.com/ryoyakawai/html5conference2015/tree/master/analog/sample08.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ソースコード</a>）</li>
<li style="margin-bottom:2px">（単音）FMシンセサイザー：<a href="http://ryoyakawai.github.io/html5conference2015/fm/sample09.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ライブデモ</a>（<a href="https://github.com/ryoyakawai/html5conference2015/tree/master/fm/sample09.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ソースコード</a>）</li>
</ul>

<p style="margin-bottom:8px">
でもこのままだと単音しか出なくて楽しくないので、和音も出せるようにしちゃいます。そうするとこうなります。
</p>

<ul style="margin-bottom:14px">
  <li style="margin-bottom:2px">（和音可）アナログ・シンセサイザー：<a href="http://ryoyakawai.github.io/html5conference2015/analog/sample10.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ライブデモ</a>（<a href="https://github.com/ryoyakawai/html5conference2015/tree/master/analog/sample10.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ソースコード</a>）</li>
  <li style="margin-bottom:2px">（和音可）FMシンセサイザー：<a href="http://ryoyakawai.github.io/html5conference2015/fm/sample11.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ライブデモ</a>（<a href="https://github.com/ryoyakawai/html5conference2015/tree/master/fm/sample11.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ソースコード</a>）</li>
</ul>

<p>自作した楽器を両手で演奏できちゃいますよね。立派な楽器のできあがりです！「Web Audio APIとWeb MIDI APIを接続するのって簡単で楽しいな～」と感じていただけているととても嬉しいのです！</p>

<h2>番外編</h2>

<p style="margin-bottom:8px">2015年3月13日（金）にWeb MIDI APIはGoogle Chromeにおいて実験的APIから標準のAPIとなることが承認されました。これによって、フラグを変更することなく（これが不要になる ▶ <a href="https://plus.google.com/u/0/+RyoyaKAWAI/posts/8QeU6ss4dHM" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Web MIDI APIを有効にする方法</a>）、Web MIDI APIを利用することが可能になります。この変更がChromeに適応されるまでにはもう少し時間がかかりますが、実現するとWeb MIDI APIがChrome APPsでの利用も可能になります。（<a href="https://developer.chrome.com/apps/about_apps" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Chrome Appsとは：英語</a>）Chrome Appsにしてしまえばオフラインでも利用可能<a href="#footnote4" style="vertical-align: top;color: red;font-size:10px" data-wpel-link="internal">※4</a>になります。ですので、ユースケースとして例えばライブでWeb Audio API、Web MIDI APIを使った自作楽器でパフォーマンスを行いたい、という場合に活躍してくれることでしょう。</p>

<p style="margin-bottom:8px">そこで、今回ご紹介した2つのシンセサイザーをChrome Appsにして公開してみました。（Web MIDI API部分の動作はしません：2015年3月14日現在）</p>

<ul style="margin-bottom:14px">
  <li style="margin-bottom:2px"><a href="https://chrome.google.com/webstore/detail/analog-synthesizer2-oscil/fpgbjodpjjmmjmoeiddbbmlkonmkjnhf" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">アナログ・シンセサイザー</a></li>
  <li style="margin-bottom:2px"><a href="https://chrome.google.com/webstore/detail/fm-synthesizer1-operator/okaomknpndkkiieohhibkfkbiniijpoe?utm_source=chrome-ntp-icon" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">FMシンセサイザー</a></li>
</ul>

<p style="margin-bottom:8px">細かいところですが、Chrome AppsはCSP（Contents Security Policy）によってスクリプト（JavaScript等）をHTMLファイルへインラインで書くことが禁止されていますが、これら2つのアプリにはPolymerエレメントを使っています（インラインJavaScirptが書かれたHTMLファイルです）のでちょっと困ったことになります。それを解決してくれるBuildツールに<a href="https://github.com/polymer/vulcanize" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">vulcanize</a>があります。&#8221;csp&#8221;オプションをつけてツールを実行することでHTML部分ととスクリプトを分けてくれますので、ソースコードの変更なしにCSPに合致したソースコードを生成することが可能なのです。
</p>

<p><code>
$ vulcanize --csp -o build.html index.html
</code></p>

<p style="margin-bottom:8px">Google Chromeのフラグの変更なしにWeb MIDI APIの利用が可能になることで、Web Audio API、Web MIDI APIを使ったブラウザで作った電子楽器の使えるシーンがより拡大されることを期待しています。manifest.jsonとバックグランドで動作させるJavaScriptの2つのファイルを用意することで簡単に実現できますので、ぜひ試してみてください。</p>

<div style="border:solid 1px #cccccc;margin-bottom:25px">
  <div style="margin:10px 5px 10px 10px;border-left:3px solid #aaaaaa;padding-left:10px">
    <a name="footnote4" data-wpel-link="internal"></a>
    <span style="vertical-align: top;color: red;font-size:10px">※4</span> <b>オフラインでも利用可能</b>：Webアプリは大きく分けて以下の2つの種類があります。<br>
    <ul style="margin-bottom:14px;padding-left:5px">
      <li style="margin-bottom:2px"><b>Hosted App</b>: HTML、CSS、JavaScript等の全てのリソースファイルがWebサーバに保存されているWebアプリのことです。URLにアクセスしてアプリを起動する所謂従来からよく知られているWebアプリです。</li>
      <li style="margin-bottom:2px"><b>Packaged App</b>: Hosted Appとは違い、HTML、CSS、JavaScript等のリソースファイルがzip等で1つになっており、Webブラウザにインストールします。Webブラウザにインストールされたリソースから起動します。そのため、オフラインでも動作が可能になっています。Chrome Appsはこの方式のWebアプリです。</li>
    </ul>
  </div>
</div>

<h2>おわりに</h2>

<p>いかがでしたでしょうか？Web Audio APIで用意されている発振機（Oscillator）は正弦波、ノコギリ波、矩形波、三角波の基本的な波形しかなく、それ単体では単調な音しか出なかったのが、少し波形処理をしてあげることで楽器らしい音にすることができたと思います。さらにはWebブラウザに鍵盤をつなげると、和音まで演奏できるようになってしまいました。
</p>

<p>さて、自作で楽器が開発ができるのはWebブラウザが初めてでしょうか？いえ、そんなことはありません。Windows、Mac、Android、iOS等の所謂Nativeな環境でも開発することは可能でした。では、Webブラウザで開発できるようになった利点はなんでしょう。それは楽器を開発するということに対するハードルが一段と低くなったところです。WebアプリケーションはWeb標準言語で開発します。Web標準言語の開発はブラウザとテキストエディタで行います。ですのでコンピュータを買ってきたその日から開発が可能です。さらにご説明させていただいた通り、こんなにも簡単に楽器を開発することができるのです。</p>

<p>今までは難しそうなイメージがあった音楽を使ったアプリケーション。しかしWeb Audio APIを使うと音を作ることができます。またWeb MIDI APIを使うと外部のMIDIデバイスとの双方向の操作が可能です。開発するWebアプリケーションに音を鳴らす要素を追加してみる、または遊び心でMIDIデバイスからWebアプリケーションを操作してみる等、ほんの少しの遊び心があなたのWebアプリケーションをより面白くする可能性があります。これを機会にいろいろなとことで試してみてはいかがでしょうか？
</p>

<h2>セッションの資料と動画</h2>

<p>2015年1月25日に行われたHTML5 Conference 2015の当日の資料と動画へのリンクです。こちらも合わせて御覧ください。</p>

<h3>動画</h3>

<div class="aligncenter">
<iframe width="315" height="177" src="https://www.youtube.com/embed/sRHhclavETY?feature=oembed&#038;wmode=opaque" frameborder="0" allowfullscreen></iframe>
</div>

<h3>スライド</h3>

<div class="aligncenter">
<iframe src="https://www.slideshare.net/slideshow/embed_code/key/6s8QuVndYhqe7U" width="427" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="https://www.slideshare.net/ryoyakawai/web-audi-oapi-web-midi-api-2015-html5-conference" title="Web Audio API, Web MIDI API - 2015 html5 conference" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Web Audio API, Web MIDI API &#8211; 2015 html5 conference</a> </strong> from <strong><a href="http://www.slideshare.net/ryoyakawai" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Kawai Ryoya</a></strong> </div>
</div>
]]></content:encoded>
		
		<series:name><![CDATA[HTML5 Conference 2015 特集]]></series:name>
	</item>
	</channel>
</rss>
