<input>からfile(Blob)を読み込んで、readAsArrayBufferで読み込んだら、WebSofaからSofaのオブジェクトとして入手できた。そこからフィルターを抜き出して、左右の”フィルター”を入手できた。128個のフロートの配列だった。
これは周波数領域のTransferFunctionなのか?時間領域のFIRなのか?あ、そうか、これは128/48000秒のインパルス応答のデータそのものか。なるほど。
入力の方のサンプリング周波数を合わせなくては行けないらしく、それはoffline context を使うらしい。
で、BufferはWebAudio API のconvolver(たたみ込み)ノードで扱えるということらしい。はて?
どうやらWebAudio APIに向き合うときがきたようだ。
あと、WebSofaの読み込みの段階でうまく行かないSofaファイルや、大きすぎて最初の読み込みの段階でつまずくことまある。
あと、出来上がったblobを保存する方法は?
////////////////////////////////////////////////////////////////////////////////////////
WebAudio は、Source, 中間node, DestinationというwebAudioNodeをつなげて処理するらしい。
ファイルはevent.target.files[0] or fp.files[0]でとること
WebSofaには不具合がある。
その1 複数のelevation angle, 複数のradiusが含まれるようなファイルは読み込めない。HRTFの意味とは
その2 Impulse Responseのデータ読み込みの際、指定座標から最寄りのデータを参照するところに不具合があるらしく、本来のフィルター読み込み機能が使えない。
もしかして、steam audioよりポンコツかもしれない。
ドキュメントもあまり整備されていない個人プロジェクトな上、ライブラリももともとはパスカルなので何が使えて何が使えないのかわから無い。
sofaGetImpulseresponses(handle);によってIRの一覧リストを得て、
IR[Index][0|1]でIRが手に入る。場所はsofaGetReceiverPositionList(handle,Spherical = true|false);で見つけよう。
これをWebAudioのConvolverに使える形にしようとしたが、ちゃっとgpt君の提案する方法でAudioBufferにしても、音が出ない。Convolverの問題か、それともつなぎ方に問題があるのか
いかんせん、グローバルなオブジェクトとしてAudioContextを置いておけないし、イベントリスナーの連続では関数の戻り値という形でデータの受け渡しもできないのでわけわかめ。いっそdoitみたいなボタンから一斉に処理を始めるほうがいいのかな。
音声を録音してダウンロードするのとか、マイクを使うのは、Mediaなんたらの仕事であるから別の話
さらに、convolverではリアルタイムの処理も無理だから、ScriptProcessorNodeをつかうことになるだろう。その場合IRは、普通のArrayのほうがつかいやすいんだろうな。
言うまでもないことだが、ブラウザというかWeb技術は音声をリアルタイムに処理するとか、ローカルファイルを読み書きするとか、そういうためには設計されていないということが嫌というほど理解できた。
成果:
Web上で音楽を再生できた
Sofaファイルを読み込み、分析することができた
webSofaの不具合がわかった
クライアントJavaScriptのオブジェクトの受け渡しは慎重に行う必要があると気づいた
これからどう、リアルタイムに処理していくか道筋が少し見えた
10/6 追記
なんとかconvolverNodeを使ったHRTFの適用ができた。
原因は、
1.IRのインデックスの指定を忘れていたこと。
2.AI産のコードにまかせて変なサンプリングレートになっていた(しかしそれでも動かない)
3.ceateConvolverは引数でバッファを指定するのではなく、プロパティで指定するようになったこと。2019年の記事を参考にしていたら仕様が変わっていた
4.メインの音源の方のaudioContextのサンプリングレートは環境により勝手に決定されて、多分変更はできないので、フィルター用のバッファのサンプリングレートをそっちに合わせる。webSofaのページにも書いてあった。本当にquick and dirty。IRの特性が変化しちゃうじゃんか。
fp.addEventListener(“click,function(event){GlobalVar = Foo(event);},false);
function Foo(event){event.target.files[0]…; return bar;}
とかにすればグローバル変数の暗黙の書き換えみたいのが減るか
あと、AudioContextはdoitみたいなボタンを作って、そこでctxつくって、他の要素はその中で読み込むようにすれば秩序立つな。
コメントを残す