EDIT : we are at the Web Audio conference 2017, and it appears that the way we currently extend the ScripProcessorNode with Faust code is not the Right Way… Part of the post concerning the exposed API will probably change a bit in the near future…
Using latest developments done for the Web (the new WebAssembly backends and libfaust library compiled in WebAssembly with Emscripten), statically and dynamically Faust generated WebAudio nodes can be easily produced and deployed on the Web.
Deploying statically compiled Faust WebAudio nodes
This will generate a foo.wasm file with the WebAssembly module as binary code, as well as a foo.js wrapper file containing the code needed to turn the Faust DSP in a fully working WebAudio node (using an extended ScriptProcessor node). The name of the Faust DSP code file is used to define the final ScriptProcessorNode constructor name. So for instance if osc.dsp file is compiled, the following faust.createosc function will be generated:
var paths = node.getParams(); // get the set of paths to read/write input control parameters
Then knowing the path for a given parameter, the following function is used to change the parameter value:
A full JSON description of the node with the complete UI, can be retrieved with:
var json = node.getJSON();
A simple example Web page
A simple Web page using the files generated by faust2wasm on the noise.dsp file can be defined with the following parts:
<!-- Load 'faust2wasm' script generated .js file --> <script src="noise.js"></script>
A slider to control the noise volume parameter is defined with:
<P> Noise volume: <input type="range" oninput="changeVolume(event) "min="0" max="1" value="0.5" step="0.01"/>
The WebAudio context is created and the noise slide hander is defined with:
A startnoise function which creates the Faust WebAudio node is defined with:
An finally the load handler is defined to activate the code:
Note that pages loading an additional .wasm file cannot directly be loaded in Chrome. You’ll have to start a local server (using the python -m SimpleHTTPServer command for instance) and access them with their http:// based URL.
Generating Polyphonic WebAudio nodes
Assuming that the compiled Faust DSP file is polyphonic ready, a polyphonic ready WebAudio node can be created with the -poly parameter, and will generate the following constructor for the node (where the mydsp part will be replaced by the actual DSP name):
Polyphonic nodes have an extended API to be controled with MIDI messages:
Extended control with -comb parameter
Generating fully working self-contained HTML pages
The faust2webaudiowasm script can be used to generate a fully working self-contained HTML page, with a SVG/CSS a Graphical User Interface. From the osc.dsp Faust DSP source file, it will generate an osc.html file:
Assuming that the compiled Faust DSP file is polyphonic ready, the -poly parameter can be used to generate a polyphonic MIDI controlable instrument, to be used with a MIDI application or device.
The -links generates the DSP processor SVG representation, and links to the original DSP file as well as generated SVG files, so that the HTML page can possibly be deployed as a reusable Faust DSP resource.
Several pages generetd with the faust2webaudiowasm tool can be seen here.
WebAssembly module optimization
Assuming that you have Binaryen tools installed on your machine, the faust2wasm and faust2webaudiowasm scripts can take an additional -opt parameter to allow WebAssembly module optimization.
Deploying dynamically compiled Faust WebAudio nodes
Since the libfaust library is available for the Web, it becomes possible to embed the complete dynamic compilation chain in a Web page, from the Faust DSP source to the executable WebAudio node. First the following resources (located on the Faust GitHub in architecture/webaudio folder) have to be loaded in the page:
<!-- Load 'libfaust' library and wrapper code --> <script src="libfaust-wasm.js"></script> <script src="webaudio-wasm-wrapper.js"></script>
Then the two following functions are used to generate factories, creating later on monophonic or polyphonic instances (this is necessary because of the way internal WebAssembly memory is managed):
The two following functions are used to generate monophonic or polyphonic Faust WebAudio nodes:
The resulting nodes have the same API as statically compiled nodes described in the first section, so can be controlled the same way, including the polyphonic ones. Here is a code example using faust.createDSPFactory and faust.createDSPInstance:
The Dynamic OSC page demonstrates the dynamic OSC complete code (based on the example seen before). The Dynamic Organ page demonstrates a polyphonic organ instrument, which loads a DSP from an url, and ready to be controlled with a MIDI device or application. Look at the Dynamic Faust compiler page for a more complete use-case of the dynamic compiler.
Float denormal handling
A specific problem occurs when audio computation produces denormal float values, which is quite common with recursive filters, and can be extremely costly to compute on some processors like the Intel family for instance. A Flush To Zero (FTZ) mode for denormals can usually be set at hardware level, but it not yet available in the WebAssembly MVP version, which strictly conform to the IEEE 754 norm 8.
Thus an automatic software strategy which consists in adding FTZ code in all recursive loops has been implemented in the Faust compiler. To activate it, the -ftz compilation parameter must be used at compilation time.
The -ftz 1 mode adds a test in each recursive loop which uses the fabs function and a threshold to detect subnormal samples (slower). The -ftz 2 mode adds a test in each recursive loop which uses a mask to detect subnormal samples (faster).
Use for example the following line to active software denormal handing when using faust2wasm tool:
faust2wasm -ftz 2 foo.dsp
The same for the faust2webaudiowasm tool:
faust2webaudiowasm -ftz 2 foo.dsp
For dynamic compilation, the -ftz v flag will have to be added in the argv parameter in faust.createDSPFactory or faust.createPolyDSPFactory, like for instance:
faust.createPolyFactory(dsp_code, ['-ftz', '2'], callback);