ComplexAnalyserNode (WebAudio) を作った (IQ信号のFFT) | tech - 氾濫原 に続き、WebAssembly を使って複素 FIR Filter を行う AudioWorkletNode の実装を書いてみた。前回と同様 Rust と wasm_bindgen を使っている。Rust 側の実装はとても素朴。

Analyser と違うのは、直接信号に手を加える必要があるというところ。つまり AudioWorklet 内で wasm の実装を呼ぶ必要がある。

wasm_bindgen を使おうと思ったが…

wasm_bindgen の JS 側の実装は Uint8Array を文字列化するために TextEncoder を使っている。しかし TextEncoder は AudioWorkletGlobalScope には(今のところ)存在しておらず、エラーになってしまった。

自動生成されたコードに手を入れて使うのはあまりやりたくないのと、どっちにしろメモリ管理を自力でやる必要はあるので、wasm_bindgen の生成するJSコードは使わず、直接 wasm を呼びだすようにした。

なおエラーメッセージの転送などで、どうしても Uint8Array から文字列を生成したいケースはある。今回は ASCII 以外の文字が入ることは想定していないので TextEncoder の代わりに String.fromCharCode() でお茶を濁した。

wasm module を AudioWorkletGlobalScope に受け渡す

AudioWorkletGlobalScope にはそもそも fetch もないため、wasm のコードを AudioWorkletGlobalScope 内で直接読みこんでインスタンス化することができない。

どうするかというと、メインスレッド(など)で fetch を行い、wasm のモジュールを得てから、これを postMessage で transfer するという余計な手順が必要になる。

wasm module は postMessage ができるが、wasm の instance はできないので、instance 化は AudioWorkletGlobalScope 側でやる必要がある。

  1. トップ
  2. tech
  3. WebAudio ComplexFirFilterNode AudioWorklet

https://github.com/cho45/complex-analyser-node

WebAudio の AnalyserNode は実数計算しかしないタイプ (仕様でそう決まっている) ですが、IQの2ch入力の信号を FFT して表示したいので、ほぼ類似のAPIを持つComplexAnalyserNodeを作ってみました。

簡単な割に IQ 信号を WebAudio で処理する際のデバッグに便利です。

FFT部分はwasmにコンパイルしたrustfftを呼んでおり、自分では実装していません。

AudioWorkletNode と AudioWorkletProcessorの使いわけ

AudioWorkletNode と AudioWorkletProcessor をうまく使いわける必要があるのですが、今回は以下のようにしています

  • AudioWorkletProcessor (audio スレッドで動く)
    • 入力をそのまま出力にコピーするだけ
    • 入力をバッファとして貯めこみ、port 経由で AudioWorkletNode にそのまま転送する
  • AudioWorkletNode (メインスレッドで動く)
    • AudioWorkletProcessor からくるバッファを管理し、FFT 用のバッファを保持する
    • getFloatFrequencyData() に応じてバッファの内容をFFTして返す
    • 対数変換やUSB/LSBの並び換え(fftshift)も rust でやってます

こういう構成なので、wasm は普通にメインスレッドで読みこんでメインスレッドで使っています。Analyser の場合は audio スレッドで信号内容に手を加えるということはしないので、余計なことを audio スレッドでやらせたくないという気持ちがあります。

もともと WebAudio にある AnalyserNode とインターフェイスを似せようとすると同期的にしなくてはいけないので若干制約があります。全部非同期にすればもうちょいやりようがある気はします。

  1. トップ
  2. tech
  3. ComplexAnalyserNode (WebAudio) を作った (IQ信号のFFT)

習作としてFIR (Finite Impulse Response) フィルタの可視化をつくってみた。

FIRフィルタのcoefficient(係数)をJSONで張りつけると、係数のグラフと、その周波数特性を表示する。複素数対応

  1. トップ
  2. tech
  3. FIRフィルタの可視化