ジンジャー研究室

長めのつぶやき。難しいことは書きません。

関数型言語 Faust で wasm な AudioWorkletNode を一瞬で作るサンプル

Faust って何

faust.grame.fr

音声信号処理に特化した言語というか DSL です。次のような短い記述でサクッとシンセ が作れます。

import("stdfaust.lib");
freq = hslider("freq",200,50,1000,0.01);
gain = hslider("gain",0.5,0,0.5,0.01);
gate = button("gate");
process = os.sawtooth(freq) * gain * gate;

簡潔、素晴らしい。 UI も定義できますが十分に抽象的なので見た目は完全にカスタマイズできます。

Faust については次の記事が詳しいです。 qiita.com

AudioNode を吐き出す

コンパイルターゲットの一つに wasm があり Web Audio API の AudioNode を作ってくれます。 例えば Hello.dsp というファイルを作って faust2wasm というコマンド(実体は shell )を叩くと、次の3点セットが出てきます。

  • Hello.js: AudioWokletNode ( main thread 側)
  • Hello-processor.js: AudioWorkletProcessor ( audio thread 側)
  • Hello-processor.wasm: 信号処理部分

ミニマルなサンプルを作った

言語そのものに関しては公式サイトがかなり詳しく解説しているので、上から順にやっていくと一通り作れるようになります。 が、個別のターゲットに関する情報は少ないので、 wasm 向けにすぐに音を出せるサンプルを作りました。

動作確認は2020/3/4 時点( FAUST Version 2.23.1

github.com

Web Audio API との相性

AudioWorklet の想定としては「ノード毎に processor を実装して組み合わせてね」ということなんですが、 Faust でなんでも出来てしまうので、ぶっちゃけ1ノードで済みます。 1ノードになんでもやらせるか、多数のノードを個別に作って組み合わせるのは Web Audio API でやるかは悩みどころ。

ちなみに現時点で吐き出されるコードは AudioParam のオートメーションが実装されていないので setTargetAt() などが効かないはず。ということは OfflineContext を使ったミックスダウンも上手く動かないんじゃないかと予想。気軽にコントリビュートするには重い課題な気がしますが、どうなんでしょうね。

github.com