公開後1年の記事に書いたのをきっかけに、改めて反響音(リバーブ処理)の追加に取り組んだ。
しかし、元々のWeb Audio APIを使ったコードが「コピペコーディング」で、どうにか動くようにしたものなので、リバーブの処理をやはり参考のサイトからコピペしても、うまく動かず。
参考サイト:
- WEB SOUNDER - Web Audio API 解説
- Web Audio API 解説 - 16.コンボルバーの使い方 - g200kg
- ブラウザで動くアゲアゲなシンセサイザーをWeb Audio ... - Qiita
どうやら非同期処理の影響らしい、ということはなんとなくわかる。インパルス応答のwavファイルをAudioBufferとして読み込んで、Conbolverノードを原音とミックスして出力する、というときに、wavファイルをAudioBufferに読み込む処理が時間がかかるので飛ばされて、先に他の処理が走ってしまう。
このように時間のかかる処理の終了を待ってから次に進む、というのがJavascriptで言うところのコールバック、Promise、Async/Awaitなどで、関数が結果を返すまで実行を待機する。
と、教科書的なことはなんとなくわかるんだけど、実装するとうまく動かない。参考にしたコードでは、AudioBufferの読み込みにAsync/Awaitを使っているので、コピペしてみたところ、確かにエラーは出ないけれど、iPhone/iPad環境で、1回目の再生で音が鳴らない。パソコン環境だと動く、という微妙な状況。
結局3週間ほど週末に集中的にデバッグとリファクタリングに取り組んで、ようやくテストしたすべてのデバイスでエラーなく1回目で音が出るようになった。テストした環境は下記。
- Windows10 Chrome
- Windows10 Edge
- MacOS Monterey Chrome
- MacOS Monterey Safari
- Android Chrome
- Kindle Silk
- iPad Safari
- iPad Chrome
- iPhone Safari
一番のキーポイントは、window: loadイベントをasyncにしてAudio Context関係の処理をすべて囲んで、loadイベントの最初にawaitでインパルス応答の読み込み処理を済ませてしまうことだった。これはつまり参考サイトの構成そのまま。やっぱり独自にヘンなことをするのではなくて、基本に忠実にするのが結局一番確実ということだった。
処理はできるようになったんだけど、インパルス応答(IR)のwavファイルをどうするかが問題。理想的には総合通信士の試験会場でインパルス応答を測定できれば良いけれどそれは無理だし、似たような会場で測定しようにも機材がない。ネットでフリーで使える素材も限られている、というのが今回わかった。幸い、非商用に限りフリー、というコンサートホールのIRがあったので、これを使わせていただいた。
- Concert Hall Impulse Responses - Pori, Finland:(非商用の場合に限ってフリー)
重い腰を上げてリファクタリングに取り組んだので、ついでに気になっていたCSSも全面的に修正。pure.cssというフレームワークを使わせていただいているけれど、その親要素で縛られているところがなかなかわからず、cssの指定が効かないと思ってデバッグに時間がかかった。Chromeのデベロッパーツールの要素タブを睨みながらなんとか親要素を部分的にオーバーライドして、所望の動作をするようになった。
これまでの一時停止機能、反響音機能を通してまだまだ汚いながらもリファクタリングはできたと思うし、自分自身のJavascript、CSSの勉強になった。
あとはPWA対応が残っているけれど、日替わりでデータを読み込む必要性があるので、ネイティブアプリっぽくしてもあまりメリットはないかも、と思って優先度は下げている。