Web Audio APIを使ってブラウザで音楽や音声にエフェクトをかけられるツールを作りました。(2) サウンドフォント



[前回の記事](http://qiita.com/hiruberuto/items/72236dfb8476cd490e01)の続きです。MIDI接続のキーボードなどを接続して、電子キーボードのように楽器の演奏ができるようになりました。今のところ、ピアノやヴァイオリンなどのオーケストラ楽器を中心に、数十種類の音色が用意されています。

* [Soundknot @ Bitbucket](http://hiruberuto.bitbucket.org/soundknot/)
* [Soundknot @ Github](https://aratama.github.io/soundknot/)

# つかいかた

MIDIメッセージの入力を扱うMIDIInputノード、MIDIメッセージをオーディオ信号に変換するInstrumentノードが新たに追加されています。つぎのように、MIDIInputノード、Instrumentノード、Compressorノード、Destinationノードを接続してください。

![midi.png](https://qiita-image-store.s3.amazonaws.com/0/64695/fac4af43-f2b4-4814-a6a2-8ddc53530d1f.png)


それから、Instrumentノードのドロップダウンリストで任意の音色を選択してください。ドロップボックスで音色を選択すると、音色のデータのダウンロードとデコードが開始され、デコードが完了した音から発音可能になります。Instrumentノード下部のバーが音源の読み込みの状況を表していて、暗いグレーの部分が音が割り当てられていない部分、明るいグレーが読み込み未完了の部分、白がロードとデコードが完了して発音可能になった部分を表しています。白い部分がいっぱいになれば発音可能になり、その白い部分をマウスで押すと、選択された楽器の音が発音されると思います。

また、MIDIキーボードからの入力にも対応しています。キーボードが接続されると、MidiInputノードにそのキーボードのベンダ名や製品名が表示されると思います。上の画像では筆者が使っている[Korg microKey USB Keyboard](http://www.korg.co.jp/Product/Controller/microKEY/)の製品名が表示されています。もし表示されない場合は、MidiInputノードのドロップダウンリストを使ってデバイスを選択してください。キーボードが認識された状態で鍵盤を叩くと、そのMidiInputノードに接続しているInstrumentノードで選択された音がなると思います。

ひとつのMIDIInputノードに複数のInstrumentノードを接続することもできます。その場合、キーボードを叩くと２種類の音色が同時になります。また、Instrumnetノードで出力される音はもちろん他のどのノードとでも組み合わせることができます。Convolverノードでリバーブを掛けてみたり、Analyserノードで波形を確認してみてもいいでしょう。

なお、InstrumentノードとDestinationノードの間にコンプレッサが挟まっているのは、複数の音を同時に鳴らすとあっさり音割れしてしまうからです。複数の音が同時になる場合には、Destinationノードの直前につねにCompressorノードが必要になるはずです。現時点の実装では、読み込んだオーディオファイルはすべてメモリ内に溜め込むことにも注意してください。調子にのっていろんな楽器を読み込むと、もりもりメモリを消費していくので気をつけましょう。最悪ページごとクラッシュする可能性があります。

#### WebMidiLink

[WebMidiLink](http://www.g200kg.com/en/docs/webmidilink/)にも対応してみました。ページをまたがって異なるウェブアプリケーション同士で連携することができます。以下のページに行って、WebMidiLinkのゲストとしてSoundknotを起動してください。

* http://www.g200kg.com/en/docs/webmidilink/

それから、次の画像のようにWebMidiLinkノードを接続します。それからWebMidiLinkのホストの方のキーボードを叩くと、ゲストであるSoundknotの方で音が鳴ると思います。ホストの方で「MML Play」ボタンを押すとMMLの再生もできます。SoundknotのほうではMMLには対応していませんが、このように他のアプリケーション同士で連携することでMMLの演奏にも使うことができるわけです。

![link.png](https://qiita-image-store.s3.amazonaws.com/0/64695/fb00d0d8-2f66-05e6-6889-e2a5fe2ff0e5.png)





----

使い方の紹介だけだと知識が増えなくて面白くないでしょうし、この機能に関連して、オーディオプログラミング周りの解説をもう少し加えておきます。

# MIDI

MIDIは電子機器どうしで演奏情報を交換するための規格です。MIDIはハードウェアの規格も含んでいて、MIDIケーブルというMIDIメッセージを送受信する専用のケーブルもあったのですが、現代ではほとんどUSBに取って代わられているので目にする機会は少なくなりました。USB接続でも各機器が送受信するメッセージは同じで、簡単なバイト列を送り合っているだけです。

このツールではWeb Midi APIを通じてMIDIメッセージを受け取っています。たとえば、MIDIキーボードの中央の「ド」のキーを押すと、その瞬間に`[144, 60, 70]`というような単なる数値の配列がイベントを使って渡されます。この３つの数字の先頭の数はメッセージの種類を表していて、`144`というのはチャンネル`0`に対する「キーが押された」というメッセージであることを意味しています。次の数`60`はこの場合は音程で、`0`から`127`のいずれかの数が渡されます。最後の数値は「ベロシティ」と呼ばれる音の強さの情報で、鍵盤を勢い良く叩くと大きな値、そっと押し下げると小さな値になり、この値が大きいほど大きな音がなることになります。このようにMIDIがやりとりしているメッセージはとてもシンプルで、MIDIプログラミングもとても簡単です。手順としては次のようになります。

1. `navigator.requestMIDIAccess`を呼んで`MIDIAccess`オブジェクトを取得
2. `MIDIAccess`オブジェクトの`inputs`プロパティは現在利用可能なMIDI入力を表しているので、そのひとつを選択
3. `MIDIInput`オブジェクトの`onmidimessage`プロパティにイベントハンドラを設定する

これだけでMIDIメッセージを受け取る事が可能になります。

```js
navigator.requestMIDIAccess().then(function(midiAccess){
    midiAccess.inputs.get(0).onmidimessage = function(e){
        console.log(e.data);  // 「ド」を押すと [144, 60, 64]が出力
    };
});
```
https://jsfiddle.net/qkhvaqqu/

ほかに「MIDI」と呼ばれるものには、`.smf`という拡張子のファイルもあります。これは正式には"Standard MIDI File"といい、MIDIメッセージを元にした演奏情報を記録しておくためのファイルです。SMFは軽量なので、ネットワークが低速な時代にはウェブページにBGMをつけたりしたいときにはよく使われましたし、ゲームのBGMなんかもSMFで配布されることもよくありました。しかし現代のネットワークは高速なのでもはやこの程度の節約などあまり意味はないし、SMFには具体的な音の波形は入っておらず、それを読み込んだソフトウェアがそれぞれの解釈で波形にレンダリングするため再現性がなく、目にする機会はもうほとんどありません。異なるデジタルオーディオワークステーションでのデータ交換で使われる程度です。




# サウンドフォント

サウンドフォントは要するに、音色ごと、音程ごとに録音された多数のオーディオファイルをまとめたものです。サウンドフォントのファイルは`.sf` あるいは `.sfz`という拡張子がついたもので、このツールではそのうちテキスト形式で扱いやすい`.sfz`のほうを読み込んで使っています。これらのサウンドフォントのオーディオファイルをMIDIメッセージの内容に合わせてオーディオファイルを選択して再生します。もっとも、このツールではこのツールではネットワーク越しに読み込むという都合上、オーディオファイルをすべてMP3にエンコードしているなど、元のサウンドフォントの内容を多少調整しています。

このツールではクリエイティブ・コモンズライセンスで公開されている[Sonatina Symphonic Orchestra](http://sso.mattiaswestlund.net/)というサウンドフォントを使っています。このサウンドフォントはフリーな割にとてもクオリティが高いので重宝しています。