Introduction¶
Installation¶
Faustax needs Python 3.11 or later. The base install runs on CPU JAX and needs no Faust compiler:
pip install faustax # or: uv add faustax
Each extra adds the dependencies of one optional feature:
pip install "faustax[audiotree]" # the audiotree transform adapter
pip install "faustax[realtime]" # sounddevice, for the duplex stream
pip install "faustax[viz]" # matplotlib, for the example plots
pip install "faustax[vst-datasets]" # the faustax-vst-* dataset commands
pip install "faustax[realtime,viz]" # several at the same time
The CUDA wheels of JAX are not an extra, because the wheel to install depends on your CUDA version. Install them next to Faustax:
pip install faustax "jax[cuda13]"
To work on Faustax itself, use uv:
uv sync # project + dev dependencies (CPU JAX)
uv sync --group gpu # additionally installs jax[cuda13]
uv sync --extra audiotree # the audiotree transform adapter
Processors¶
Each effect is a Processor that wraps a Faust-compiled NNX module.
Audio always has the shape (batch, channels, samples).
You address each parameter with the slider label that the Faust source declares:
gain = Gain(sample_rate=44100)
x = jax.random.normal(jax.random.key(0), (2, 1, 1000)) * 0.5
y = gain.process(x, gain_db=-6.0)
expected = x * 10 ** (-6.0 / 20.0)
print(jnp.allclose(y, expected, atol=1e-6))
True
A parameter accepts a scalar or a (batch,) array.
A scalar broadcasts over the batch.
A (batch,) array gives one value for each batch item.
Each processor reads its parameters from the Faust slider declarations.
You do not maintain the parameter data by hand:
compressor = Compressor(sample_rate=44100)
print(compressor.param_names)
print(compressor.param_ranges["threshold_db"])
('attack_ms', 'knee_db', 'makeup_gain_db', 'ratio', 'release_ms', 'threshold_db')
(-60.0, 0.0)
Normalized parameters¶
process_normalized takes a (batch, num_params) matrix with values on [0, 1].
The columns follow the order of param_names.
A neural network controller or an RL policy produces this matrix format:
params = jax.random.uniform(jax.random.key(1), (2, compressor.num_params))
y = compressor.process_normalized(x, params)
print(y.shape)
(2, 1, 1000)
JAX computes gradients through the exact per-sample recurrence:
def loss(params):
return jnp.mean(compressor.process_normalized(x, params) ** 2)
grads = jax.grad(loss)(jnp.full((2, compressor.num_params), 0.6))
print(bool(jnp.isfinite(grads).all()))
True
The underlying module¶
processor.module is the generated nnx.Module.
Use this module for streaming and for NNX-native training workflows.
The documentation for the Faust NNX backend describes initialize_carry() and process_block().
It also describes parameter save and load with safetensors, and polyphony with jax.vmap:
module = compressor.module
carry = module.initialize_carry()
carry, out_block = module.process_block(carry, input_block)