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)