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




ブラウザで本格的なサウンドプログラミングが可能になるWeb Audio APIを使って、リアルタイムで音声にフィルタを掛けられるツールを作りました。コードを書くことなくマウスで操作するだけで、好きな動画や音楽にエコーを掛けたりフィルタを掛けたり、MP3ファイルへとエンコードしたりと、いろいろな実験ができます。Web Audio APIやサウンドプログラミングの入門教材にもどうぞ。Web Audio APIは使ってみると楽しいAPIです。以下のURLで実際にブラウザ上で実行することができます。

(追記: BitbucketとGithubの両方に設置してありますが、気まぐれにアップデートしているので両者の内容が異なる場合があります。だいたいはBitbucketに置いてある方が新しいです。ただし、ChromeではHTTPSで接続しないとUser Mediaを使うことができないため、パソコンのマイクからの入力を使いたい場合はGithub版のほうを使ってください)

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

動作環境は主にChromeで確認していています。FirefoxやOperaなどでも一応動いてはいるようですが、Chrome以外の環境への対応はまだ作業が足りていないので、できればChromeがいいと思います。Electronでも動くのは確認していますが、現時点ではElectronで動かすメリットがほとんどないのでElectronパッケージでの提供はありません。まだまったくのWork in Progressなので、もしいろいろ動かなくても気にしないでください。きっとそのうち動くようになります。きっと。




# つかいかた

## 低音だけを取り出すフィルタをかける

簡単に使い方を紹介しておきます。最初の実験として、まずは音声の低音部分だけを取り出して再生するようなフィルタリングをやってみます。

このツールはUnreal Engineの[Blueprint](https://docs.unrealengine.com/latest/JPN/Engine/Blueprints/index.html)や[Node-RED](http://nodered.org/)みたいなインターフェイスになっていて、ノード同士を繋ぎあわせて音声データの流れを表す「オーディオグラフ」をグラフィカルに作成していきます。でも筆者はBlueprintとかは使ったことがないので、筆者のなかではBlenderの[Node Editor](http://wiki.blender.org/index.php/Doc:JA/2.6/Manual/Composite_Nodes/Editor)が元ネタです。

左のパネルから中央のエリアにボタンをドラッグアンドドロップすると各種のノードが作成できますので、「Media Element」「Biquad Filter」「Destination」の３つのノードを作成し、下の図のようにノード同士を接続してみましょう。それぞれのノードの右端にある黄色い丸はオーディオの出力ポートを表していて、それを各ノードの左端の丸にドラッグアンドドロップするとノードどうしを接続することができます。また、接続した線をクリックすると接続を切断することができます。これらのノードは上のタイトルバーっぽいところをドラッグすると移動することもできます。また中央のエリアの背景部分をドラッグすると全体をスクロールできますし、マウスホイールで全体を拡大縮小して表示することができます。

Media Elementノードの「Open」ボタンを押すとファイルダイアログが開きますから、何か適当な音声ファイルや動画ファイルを開いてみてください。読み込み可能なファイル形式はブラウザにそのまま依存しており、WAV、MP3、Oggのようなオーディオファイルや、avi、mp4、WebMなどの動画ファイルが読み込めます。それからMedia Elementノードの左下の再生ボタンをクリックするとファイルが再生され、Biquad Filterノードでフィルタリングされた音が出力されます。

![filter.png](https://qiita-image-store.s3.amazonaws.com/0/64695/f1c6e728-2b00-f022-3f26-24774d028137.png)


ノードと接続はオーディオ信号の流れる経路を表していて、オーディオ機器どうしを音声ケーブルで接続するのによく似ています。Media Elementは動画や音声ファイルなどを再生するためのノードで、その音声情報がBiquad Filterノードに入力されます。Biquad Filterは各種の周波数に応じたフィルタを掛けることができ、デフォルトでは350Hz以下の低音だけを通すローパスフィルタになっています。そしてそのフィルタリングされた結果の信号がDestinationノードへ入力されると、スピーカーから実際の音声が出力されます。

ローパスフィルタをかけると、まるで映画館の上映室から漏れる映画の音声とか、ライブハウスの会場の外に漏れる音楽みたいになります。これは高音に比べて低音は建物の壁などを通して周囲に伝わりやすいからです。Biquad Filterノードの一番上のドロップダウンリストはフィルタリングの種類になっていて、ここで`highpass`を選ぶとハイパスフィルタに変更できます。これは文字通り高音だけを通すフィルタで、`frequency`インプットでしきい値となる値を上げていくと低音が削除されて高音だけが残り、イヤフォンから漏れるシャカシャカ音みたいになります。





## 音声を視覚的に確認する

Analyserノードを使うと、音声信号の内容を視覚的に表示することができます。使い方は適当なノードの出力をAnalyserノードに接続するだけです。線で描画されているほうが、音声の時間的な波形を示しています。音声とは空気を媒体にした密度の縦波ですが、ここではある時間間隔でのその波形が表示されているわけです。音楽や動画などの音声では多分ぐにゃぐにゃとした曲線が表示されるだけで、人間では波形の振幅が大きいと大きな音だなーくらいしか読み取れないでしょう。どちらかというと、次の周波数領域での解析のほうが人間にとって直感的です。



後ろの塗りつぶしがされているほうの図形が周波数領域に対するヒストグラムです。音はさまざまな周波数の音に分解できることが知られており、これはその瞬間にAnalyserノードに入力された音声信号の各周波数ごとの分布を表しています。左側が周波数の低いほうになっていて、低い音が鳴っているとか高い音が鳴っているというのが視覚的にわかるのです。次のようにBiquad Filterをかけた信号と元の信号を並べて比較すると、ローパスフィルタにどのような効果があるのか、視覚的にも理解しやすいと思います。

![analyser.png](https://qiita-image-store.s3.amazonaws.com/0/64695/c748728e-3d55-fe0f-3c49-e0825b154c64.png)

そういえば、周波数領域と時間領域のグラフが重なって表示されていますが、縦軸も横軸もまったく無関係です。重ねて表示してるのは、ただのスペースの節約です。こういうグラフ書くと怒られるので気をつけましょう。


## エコーをかける

やまびこは音が遠くの山や谷に反射して遅れて返ってくる現象ですが、信号を遅らせるDelayノードと信号の大きさを変えるGainノードを組み合わせると、これと同じような効果を生むことができます。左のパネルからDelayノードを作成し、スライダを動かして遅延時間を0.5秒くらいに設定してください。またGainノードを作成して0.5くらいの大きさに設定してください。Gainノードは平たく言うといわゆる「ボリューム」で、音の大きさを比率で調節します。0.5は振幅をちょうど半分にするということです。これで、音声を小さくしながら0.5秒ずつ遅らせて再生するということができます……できます……きます……ます……ます……



![delay.png](https://qiita-image-store.s3.amazonaws.com/0/64695/f6774d43-ca06-4595-68ca-70db31f68001.png)




## リバーブをかける

広くて閉鎖的な空間で音声を発すると、周囲のあらゆる場所で乱反射して緩やかに減衰していきます。リバーブはこの現象をシミュレートするもので、音楽に空間的な広がりを与える効果があります。素人っぽい歌でもリバーブがかかると人間はなぜかやけにうまく感じるもので、音を吸収するものが少ない風呂場では音が反響しやすく、妙に鼻歌がうまく聞こえるのもコレのせいです。

Convolverノードはリバーブを再現するのに適したノードで、音声データどうしの畳込みを行います。Convolverノードにはリバーブを掛けたい音声信号のほかに、環境のインパルス応答を計測した音声データを入力します。このインパルス応答は広い空間でパンッという瞬間的な音(インパルス)がどのように聞こえるかを録音したもので、大きな教会の建物やホールなどで計測したものが[The Open Acoustic Impulse Response Library](http://www.openairlib.net/)などで入手することができます。たとえば、

* [http://www.openairlib.net/auralizationdb/content/york-minster#impulse-responses](http://www.openairlib.net/auralizationdb/content/york-minster#impulse-responses)

から、`minster1_000_ortf_48k.wav`をダウンロードして保存しておきます。また、ConvolverノードとAudioBufferノードを作成し、次のように接続します。ノードのコネクタは同じ色どうしでしか接続できないことに注意してください。それから、AudioBufferノードのボタンを押して、先ほどのインパルス応答の音声ファイルを開きます。これで音声を再生すると、インパルス応答を録音した空間でその音を鳴らしている状態をシミュレーションすることができます。

![convolver.png](https://qiita-image-store.s3.amazonaws.com/0/64695/584d7a15-218f-4ec7-ff4b-06590a474313.png)



## 音を大きくする

音声を小さくすることは簡単なのですが、それに比べて音量を大きくするのは結構複雑な処理になります。というのも、単純に波形を大きくすれば確かに音は大きくなるのですが、表現できる振幅の大きさには限度があるので、限度を超えるとそこで振幅は頭打ちになってしまい、波形が平坦に潰れます。このような波形を再生しようとしても、波形が潰れた点でプチッというノイズが発生してしまい、音楽としてはとても聞けたものにはなりません。このようなクリッピングが継続的に起きると、ガリガリガガガガといういわゆる「音割れ」になって聞こえます。先ほどのDelayノードやConvolverノードを通した時にも音が大きくなった部分で音割れが起きることがよくあります。

音を大きくした時にクリッピングが起きないようにするには、音声信号をCompressorノードを通します。これは音を大きくするというよりは大きすぎてクリップしそうな音を押さえつけるという役割があり、小さくて聞こえにくかった音が底上げされる感じで大きく聞こえるようになります。すべての周波数で音がなるようにバランスよく楽器を配置しつつコンプレッサをうまくかけると、迫力のある音楽にすることができます。

人間は音量を大きくするだけで不思議と良い音楽に聞こえるもので、クラシックだと強弱を聞かせた表現力が大事ということで音が大きい部分と小さい部分の差があるのですが、ロックやポップスでは曲全体にわたって目一杯音を大きくするのが普通です。ライブでも音が大きいだけで何故か迫力を感じてしまうので、巨大なアンプを設置して耳がおかしくなりそうなほど大きな音量を出したりするようです。パソコンやオーディオプレイヤーでは音楽を聞かせる側が無理やり音量を上げることはできないので、波形を崩さずになるべく音を大きく聞かせるというマスタリングの差が最終的な印象に大きく影響します。




## ハウリング

カラオケなんかでマイクがキーンってなるハウリングがありますが、信号を増幅して再び入力するループを作ると同じような現象を再現することができます。たとえば、先ほどのエコーを掛けるノードの構成でGainのスライダを`1.0`をほんのちょっとでも超えて動かすと、一瞬で信号が繰り返し果てしなく増幅されるので大音量で耳があああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああとなります。

ヘッドホンや大型スピーカーなんかを使ってる人は特に危険なので気をつけてください。音楽を聞いているとボリュームを上げて迫力を求めたくなりますが、ソフトウェアである人間の知覚はそれを自動的に調節するのですぐに慣れてしまうのに対し、ハードウェアである耳は大きな音を聞き続けると不可逆的な損傷を受けるそうです。耳は大切に。



## オシレータ

Oscillatorノードを使うと周波数を指定して単純な音声信号を合成することができます。ファミコンやゲームボーイなどの昔のハードウェアでは波形データをまるごと載せて再生するだけの性能がなく、このような単純な波形をオーディオ専用のハードウェアで合成することであのピコピコとした音を作り出していました。現代ではハードウェアの性能が向上して汎用のCPUで任意の波形を再生できるようになったので、もはやこのような機構を使う必要はありませんが、こういう単純な波形をあえて表現として多用した音楽はChiptuneとして現代でも生き残っています。また音に様々なエフェクトをかけたいときにも役に立ちます。シンセサイザーなどではこれらの波形をもっと組み合わせて複雑な音を作り出しますが、現段階ではこのツールにそこまでの機能はありません。そのうちそういう機能も付けたいです。

オシレータノードをつなげると、ピーーーーーーーっという音がずっと鳴り続けます。結構耳をつんざく音なので、Gainノードをなどを予め設定して音を小さくしておくほうがいいと思います。デフォルトでは440Hzの正弦波になっていて、Frequencyインプットをいじると周波数が変更されて音が高くなったり低くなったりします。

音声はさまざまな周波数に分解できますが、正弦波はたったひとつの周波数からなる最も単純な音です。正弦波はポーとかピーというクセのない音として聞こえます。Analyserで見ると、正弦波の周波数のピークはひとつだけで、周波数を変えるとそれが左右に動いていくのが視覚的にもわかるはずです。矩形波や三角波がどのような波形や周波数成分からなるのかも実験してみると面白いと思います。


![oscillator.png](https://qiita-image-store.s3.amazonaws.com/0/64695/682561ee-b333-556c-699c-34acdea78854.png)



## その他の操作

User Mediaというボタンを使うと、パソコンの音声入力から直接音声を入力できます。このノードを作成すると、ブラウザがマイクへのアクセスを許可するかどうか尋ねてきますので許可してください。マイクを繋いでConvolverノードでリバーブをかければ、その場でカラオケ気分に浸れます。**(注意)Chrome(Chromium)ではいつの間にか`getUserMedia`みたいな強力な機能はHTTPSのような安全な接続でないと使用不能になったようです([参考](https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins))。User Mediaを使いたい場合は、Githubに設置してあるほうを使ってHTTPSで接続してください。**Firefoxではどちらに設置してある方でもマイクからの入力ができます。

タイムラインノードを使うと、正確にタイミングを制御しながら一連のオーディオ片を再生できます。いくつかの「トラック」が用意されていて、その上にオーディオファイルをドラッグアンドドロップすると配置でき、再生ボタンを押すと再生されます。が、いかんせんまったくの開発途中で、効かないボタンもありますが気にしないでください。そのうちオーディオ片をスライスしたりマージしたりの編集ができるようになる予定です。

なお、上にならんだボタンのうち、一番右のボタンを押すと、現在のタイムラインの内容をエフェクト付きでMP3ファイルとして書き出すことができます。音を聞くだけしかできないなら単なるおもちゃですが、ちゃんと結果をオーディオファイルに残せれば何か役に立つツールとして使えるわけです。このまま開発を進めていけば、さまざまな音楽制作がブラウザだけで完結できるようになりそうです。いつかシーケンサもつけてサウンドフォントを鳴らせるようになればいいですね(願望)。

![timeline.png](https://qiita-image-store.s3.amazonaws.com/0/64695/6f591026-4452-4c0a-a8d5-5ce509566791.png)


画面左上のボタンを押すと、作業内容を保存するためのダイアログが出てきます。ここで作業内容をブラウザのIndexedDBに保存できるので、ブラウザを閉じたりしても状態を保存できます。また、画面上部のボタンで自由に取り消しとやり直しができます。が、どのタイミングでどう履歴を重ねていくかは調整が必要なところで、そこも調整の手が回っていないので操作が結構飛ぶ時があります。



# さいごに

目標としては、[Audacity](http://audacityteam.org/)や[Reaper](http://www.reaper.fm/)なんかと同じような目的で使えるツールにできたらいいかなと思います。ひと通りの検証が終わって技術的な見通しは立ったんですが、そうなると何か逆に開発のモチベーション下がってきてしまって、完成を待ってるといつになっても公開できなさそうなので、モチベーション維持を兼ねて記事にしました。この後もまただらだらと開発を続けようと思います。

なお、このアプリケーションのコードの大半は[PureScript](http://www.purescript.org/)で書かれています。純粋関数型プログラミング言語でGUIアプリケーションをゴリゴリ書いているというのはかなりめずらしい例だとは思いますし、今回使ったライブラリの紹介などもしたいのですが、その辺りの説明を始めると長くなるのでまたいずれ別の記事にまとめようかと思います。PureScriptはいいぞ。



# 参考文献

* [Web Audio API (日本語訳)](http://g200kg.github.io/web-audio-api-ja/) 日本語訳が公開されています。ありがてぇありがてぇ
* [Web Audio API の基礎 - html5rocks](http://www.html5rocks.com/ja/tutorials/webaudio/intro/) - Web Audio APIの入門によさげ。
* [2つの時計のお話 - Web Audio の正確なスケジューリングについて - html5rocks](http://www.html5rocks.com/ja/tutorials/audio/scheduling/) 「音楽」をやりたいなら知らないと困るやつ

* [Web MIDI API (日本語訳)](http://g200kg.github.io/web-midi-api-ja/) こっちも
* [松嶋ダンス動画【うなぎの唄】](http://www.nicovideo.jp/watch/1446026835) - 100万再生も目前


# 続き

* [Web Audio APIを使ってブラウザで音楽や音声にエフェクトをかけられるツールを作りました。(2) サウンドフォント](http://qiita.com/hiruberuto/items/c8dc4880d5621cfad250)

----

<br>

<br>

<br>

<br>

<br>

<br>

\-\-\-\---------------- ここから筆者の自分用メモ ---------------------------------------------------------------

<br>

<br>

<br>

<br>

#### ウェブで音楽制作できるまとめ

* [Web Audio Editor - MDN](https://developer.mozilla.org/ja/docs/Tools/Web_Audio_Editor) - Firefoxでは「開発ツール」である程度WebAudioをいじれたりします。デバッグに便利。

* [WebAudio Designer](http://g200kg.github.io/WebAudioDesigner/) - 同じようなツールですが、筆者が作ったものよりもうちょっとシンセサイザー的な使い方ができます。
* [Web Audio Tool](http://www.webaudiotool.com/) - これも同じような感じのツール
* [Web Audio Playground](http://webaudioplayground.appspot.com/)　 - これも同じような感じのツール
* [hya.io](https://hya.io/) 
* [soundtrap](https://www.soundtrap.com/)　商業では一番大手っぽい気がする。ループ素材がたくさん提供されていて、適当に並べるだけでそれっぽくなる手軽さがとてもいい
* [Web Music Platform](http://yamaha-webmusic.github.io/webmusicplatform/app/) すごくPolmyer
* [wavepot](http://wavepot.com/) テキストベース

##### まとめ記事系

* [10 of the best ways to make music in your web browser](http://www.musicradar.com/news/tech/10-of-the-best-ways-to-make-music-in-your-web-browser-490608)
* [ブラウザだけで出来るWEBベースのDTM系アプリいろいろ](http://matome.naver.jp/odai/2127546037497232901)
* [ブラウザDTMができる画期的な無料webサイト9+2つ](http://dtmnews.snapmix.jp/online-dtm/browser-dtm/)




#### 金科玉条なコンセプト

* 各種の実験に使えるプラットフォームとして、Web Audio APIのすべての機能を直接扱えること。「プラグイン」での高レベルに覆い隠すより、ノード単位、パラメータ単位で低レベルに扱えるものであること。これは一見「使いやすいやすさ」「わかりやすさ」と相反するようにも思えるけど、アホみたいに大量のツマミが並んでいるよりはわかりやすいように思う
* インストール作業なし、ユーザ登録なしで、クリックひとつで製作を始められる、もっとも手軽なツールであること
* シーケンサへの打ち込みからMP3へのエンコードまで、これひとつで音楽編集作業を一貫して行えること。エンコードは別のツールが必要、みたいなことにはしない

#### そのほか検討したいコンセプトや機能とか方向性

類似のツールはすでに山のようにあるので、既存のツールとの違いを明確化したいです

* すっきりとして一見して使い方がわかるUI。既存のDAWでは大量のダイヤルやスライダが所狭しと並んでいて、どこをどういじったらいいのかわかりづらいし、知らない機能のコントロールをうっかりいじると初心者は元へ戻し方がわからなくなったりすることがある。**何もしてない**のに突然音が出なくなっちゃった！というのはよくあることで、そういう事故が少ない直感的でシンプルな構成。必要な機能は必要に応じて追加するようにし、むやみに機能を並べない
* サウンドフォントを中心とした生音系の音色を使いたい。既存のツールにピコピコシンセサイザ系が多いので差別化を図りたいというのもありますが、単に筆者が生々しい音のほうが好きというのも
* 自由にスクロールやズームが可能なUI。ここまでできるツールはわりと少ないので、こういう使い勝手を押し出していきたい
* プロジェクトの保存やRedo/UndoなどのUIの使い勝手
* 音声入力として動画を使える
* MP3へのエンコード。oggやwavも要る？
* Webアプリケーション、Chromeアプリ、Electronでのネイティブアプリなどのマルチなプラットフォームでの実行
* ユーザ同士でのオンラインでのコミュニケーションの方法。共同作業や制作データの共有
* 録音機能。一度実装したのですが、実装の都合上一旦外してます
* ~~仮想キーボード。ピアノの鍵盤が表示されて押すと音がなるやつ。これも一度実(略~~ シーケンサと統合するからやっぱりいらない
* Web MIDI APIによるMIDI入出力。MIDIキーボードを持ってる人は多くないでしょうけど、ブラウザでもMIDIキーボードで入力できるのは結構感動です。これも一度(略
* スクリプト。この辺りはスクリプトノードの仕様が大きく変わっていることもあって後回し
* マルチプラットフォーム。ブラウザ版、Chromeアプリ版、Electron版で三種類。ブラウザだと履歴を消すときにうっかり消してしまうこともありそうだし、ローカルにプロジェクトファイルを置けたほうが安全。
* Chromeアプリでも僅かな変更だけで普通に動いた。セキュリティ的にはChromeアプリのほうがちょっと安心かも
* パフォーマンスチューニング。タイムラインでの波形描画やアナライザでのアニメーションは重いのでもう少し調整が必要
* こういうツールは多少の心得がないと使えないので、音楽制作に馴染みがないひとでも遊びやすい工夫。サンプルプロジェクトの提供やプリセット素材
* オンラインでプロジェクトを共有できるといいね。他人の作ったものは参考になるし、誰かに観てもらうことでモチベーションも上がる
* アイコン作らなきゃ
* とりあえず「妙に高級っぽい系」「明るい色系」「暗い色系」の３種類のテーマ。可能ならスタイルのユーザ定義可能にもしたい。プロジェクトファイルを配布した時にUIの雰囲気もついて回ったらちょっと楽しい。
* 他の人が書いた「プラグイン」をグラフに組み入れることができたら。ただしセキュリティには要注意

###### 関連するサンプルコード

* [MediaRecorder API](https://developer.mozilla.org/ja/docs/Web/API/MediaRecorder_API) なんてあったんすか。使えれば使いたいですが、Chrome未実装なのでどうにもならないです。というかまあサードパーティのライブラリで録音もなんとかなることがわかってるので、別に必要ないといえば必要ないです
* [WebAudioとMediaRecorderで録音](https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/webrtc-integration.html)。まあまだ絵に描いた餅みたいな感じだとは思います
* [pitchdetect](https://github.com/cwilso/pitchdetect) 音声からピッチを推定する。アナライザに組み込んだらあっさり動きました