WebAudioAPIとWebWorkerとの通信オーバーヘッド
Web Music Developers JPのアドベントカレンダー 21日目の記事です。
今日はWebAudioAPIのオーディオスレッドからWebWorkerを呼び出す際のオーバーヘッドについて書きます。ここでの内容はChrome限定で、Safariでは話が違ってきます。
オーディオスレッドとは?
まずは以下の実験を見てください。音量は絞ってますが音がなるのでご注意を。
- startでカウンターが回り始めます。
- alertでアラートダイアログが表示されます。
ここでおかしなことが起こります。ダイアログが表示されている間も音が鳴り、カウンターが回り続けてるんですね。Javascriptはシングルスレッドです。スレッドがダイアログによりブロックされているのに、いったい誰がカウンターを回しているのでしょう?
答えはオーディオスレッドです。具体的には下のようになっています。
var ctx = new webkitAudioContext(); var node = ctx.createJavaScriptNode(2048, 1, 1); node.onaudioprocess = function(){ // この中がオーディオスレッド }
WebAudioAPIにはこういう特殊なプロセスが存在しているようです。内部の実装が気になるところですね。ちなみにSafariではsetInterval()などでカウンターを回したときと同じような動作になります。
オーディオスレッドからのWebWorker呼び出し
では本題のオーディオスレッドとworkerの通信オーバーヘッドについて実験で計測してみましょう。
ここでの動作は上から順番に以下の通りです。
- onaudioprocess内で正弦波を合成する
- onaudioprocessからworkerにpostMessage()後、addEventListener()により正弦波を受け取る
- 2. のonaudioprocessの変わりにsetInterval()を使う
Chromeで実験するとレイテンシが3<1<2となります。つまりオーディオスレッドからworkerを呼ぶと、普通にworkerを呼ぶよりパフォーマンスが悪いようです。
WebAudioAPI仕様に関する議論
何でこんなことになるのでしょうか?興味深い議論をW3Cのメーリングリストで見つけたので抄訳して紹介しておきます。
a sample to use Web Worker with current JavaScriptAudioNode
JavaScriptAudioNodeとworkerを使ったサンプルを作ってみたよ。
Re: a sample to use Web Worker with current JavaScriptAudioNod
そのやり方は現状正しい。しかし良いパフォーマンスを得ようとすればworkerスレッドからコールバック関数(*1)を直接コールできるようにする必要がある。ここでの問題はメインスレッドからworkerスレッドを呼ぶという余計なスレッドホップにより遅延が発生してしまうことだ。
(*1) onaudioprocessに設定したコールバック関数
つまり現状はworkerスレッドからオーディオスレッドを呼べないのでパフォーマンス的にちょっとなぁ、と言うわけです。
それを実現しようという話もありました。
Re: Web Audio API and Web Workers
コールバック関数の代わりに、createJavaScriptProcessingNode関数にWeb Workerを食わせてみてはどうだろうか?
これはシンプルな解ですね。これが出来るようになると目の前がパーッと明るくなりそうです。
正直WebAudioはまだ実用の域に達していないと感じさせられる部分が多いのですが、その中でハックしていくのがWebAudioの面白みでもあると思います。何はともあれ今後の議論が楽しみですね。
以上、オーディオスレッドとWebWorkerにおける通信オーバーヘッドについてでした。同じWebkitでもSafariだと違う結果が得られるので、興味があれば試してみてください。
Web楽器のプラグイン規格を作りました
Web Music Developers JPのアドベントカレンダー 13日目の記事です。
現在Web上でDAWを作ろうとするといくつか壁がありますが、まずはVSTのような規格が欲しいですよね。そこで試しにWeb楽器向けのプラグイン規格をつくってWebWorker上で動かしてみたらうまくいったので、規格の仕様と実験ページを公開します。
規格はAudio Script Interface(以下ASI)と呼ぶことにして話を進めます。
どんな規格?
ASIはJavascript上ならどこでも動作すること、ホスト側でGUIやAudioAPIのインターフェースを吸収することを目的としています。今回はWebWorker上で動作させていますが、ASI規格自体はWebWorkerのインターフェースに依存させないように配慮しています。
規格があると
- 開発者は音源を合成するエンジンの開発に集中できる
- 利用者はASI規格の楽器を組み合わせて使うことが容易になる
- Javascriptが動けばどこでも動かせる
などなど便利なことが多々あります。将来的にはnode.js上で音源データを作成したり、Windows8のMetroアプリ上で楽器の演奏がたらいいなぁ、とか思っています。
逆にデメリットはというと、
- 思い通りのGUIコントロールパネルが作れない
- ホストがないと動かない
そのうち問題はいっぱい出てくると思いますが、今はこんなところでしょうか。
実験サイト
規格考えましたっていうだけじゃ面白くないので、ConnectSynth という実験サイトを作りました。Web Audio API対応ブラウザ(Chrome、Safari)を推奨しますが、Audio Data APIにも対応してあります。
このサイトで以下のようなことが出来ます。
- プラグインのファイルをサーバーにアップして起動
- プリセットの保存
- ソースコードの編集
- 人が公開したプラグインを自分の作業領域にコピーして編集(Fork)
- WebMidiLink に対応
Twitterアカウントでログインすれば、テストや公開も可能なので良かったら試してみてください。仕様はサイトにまとめてあります。ただし説明書がありません(汗)。なんとなく使えると思いますが、、作っておきます。
プラグインがどうやって動作しているのかも簡単にまとめました。
- ホストの動作
- プラグインの動作
- ボタンの配置情報などをホストに送信
- MIDIイベントの受信
- ボタンなどを通じてパラメータの変更イベントの受信
- 音波形データ(Float32Array)をホストに送信
今後
ConnectSynthはHeroku + S3で作ったんですが、米東海岸にサーバーがあるので結構遅いです。あんまり不便なようなら国内サーバーに移すか、ローカルでASIプラグインをデバグできるSDKみたいなものを作るかします。エフェクトの仕様やMIDIと連携させたシーケンサー辺りまで手が広がれば、ちょっとした打ち込み曲が作れるようになりそうでワクワクしますね。
現状は概念を説明するのに必要な仕様しかありません。ご指摘や要望、アドバイスなどがあれば是非WebMusicDevelopersJP に参加してポストしてみてください。では。
git-flowのgitコマンドを確認する方法
職場でgit-flowを使うことになったので、git-flowコマンドの際に投げられるgitコマンドを把握するためソースコードを眺めてました。
gitflow-commonファイルに以下の様な記述があり、show_commandsフラグを立てれば標準エラー出力にgitコマンドが出力されます。
- gitflow-common
git_do() { # equivalent to git, used to indicate actions that make modifications if flag show_commands; then echo "git $@" >&2 fi git "$@" }
このフラグはgit-flowファイルのmain関数内で設定されており、以下のように変更すれば常にgitコマンドが表示されるようになります。編集するファイルはぼくの環境では/usr/local/bin/git-flowでした。
- git-flow
#DEFINE_boolean show_commands false ’show actions taken (git commands)’ g DEFINE_boolean show_commands true ’show actions taken (git commands)’ g
オプション引数が使えない場合がある
上のソースコードを見るとgオプションをつければいいじゃないかと思ったのですが、動作がおかしくなる場合がありコードを追ってみました。結論だけ言うとgit-flowのバグによりオプション引数が有効にならない場合があります。すでにpull requestがあがっていたので参照しておきます。
https://github.com/nvie/gitflow/pull/232
従って以下のコマンドでオプション引数を使うことはこのsubmitが承認されるまでは控えたほうがよさそうです。(既に4ヶ月放置されているようですが、、)
- git flow feature start
- git flow hotfix start
- git flow release start
そのためデフォルトでshow_commandsをtrueにするやり方を採用することにしました。