# FAUST Primer

A concise reference for the FAUST language, distilled from
[Audio Signal Processing in Faust](https://ccrma.stanford.edu/~jos/aspf/)
by Julius O. Smith III, CCRMA, Stanford University.

---

## 1. What is FAUST?

FAUST (**F**unctional **AU**dio **ST**ream) is a functional programming
language for defining block diagrams whose input and output signals all
operate at a single, uniform sampling rate.  Every FAUST program must
define a `process` function (analogous to `main` in C):

```faust
process = faust_expression;
```

The FAUST compiler translates `.dsp` source to C++ (and many other
targets), applying aggressive optimizations: constant sub-expressions
are computed once at init, slowly-varying GUI parameters are sampled
once per block (typically 64 samples), and only full-rate signals
appear in the inner loop.

---

## 2. Elementary Signal-Processing Blocks

These are the primitive operations on signals:

| Block | Meaning |
|-------|---------|
| `_` | Wire (identity: one input passed to one output) |
| `!` | Cut (absorb one input, produce no output) |
| `+` `-` `*` `/` | Arithmetic (two inputs, one output) |
| `%` | Modulo |
| `^` | Exponentiation |
| `mem` | One-sample delay (equivalent to `@(1)`) |
| `@` | Variable delay: `x @ n` delays signal `x` by integer `n` samples |
| `int(x)` | Truncate toward zero (magnitude truncation) |
| `float(x)` | Treat signal as float |

### Constants as signals

A bare number is a block with zero inputs and one output that produces
a constant stream:

```faust
process = 0;   // stream of zeros
process = 1;   // stream of ones (unit step)
```

### The one-sample delay (postfix `'`)

The tick operator delays a signal by one sample:

```faust
impulse = 1 - 1';   // unit impulse: 1 at n=0, then 0
```

---

## 3. Block-Diagram Composition Operators

Five operators combine block diagrams:

| Operator | Name | Description |
|----------|------|-------------|
| `A : B` | **Series** (sequential) | Outputs of A feed inputs of B |
| `A , B` | **Parallel** | A and B side by side; inputs and outputs concatenated |
| `A <: B` | **Split** (fan-out) | Distribute A's outputs to B's inputs |
| `A :> B` | **Merge** (fan-in) | Sum groups of A's outputs into B's inputs |
| `A ~ B` | **Recursive** (feedback) | Feed B's outputs back to A's inputs (with implicit one-sample delay) |

### Precedence (lowest to highest)

```
~  <  :  <  ,  <  arithmetic
```

### Examples

```faust
// Series: stereo input summed to mono
process = +;            // equivalent to: _,_ : +

// Parallel: stereo pass-through
process = _,_;

// Split: mono to stereo
process = _ <: _,_;

// Merge: stereo to mono (sum)
process = _,_ :> _;

// Recursive: one-pole integrator  y(n) = x(n) + y(n-1)
process = + ~ _;
```

---

## 4. Infix Notation and Rewriting

FAUST recognizes conventional infix math and rewrites it into
Block-Diagram Normal Form (BDNF):

| Infix form | BDNF equivalent |
|------------|-----------------|
| `x + y` | `x,y : +` |
| `x * y` | `x,y : *` |
| `x / y` | `x,y : /` |
| `x ^ y` | `x,y : ^` |
| `x @ n` | `x,n : @` |
| `x'` | `x : mem` |
| `f(x)` | `x : f` |
| `f(x,y)` | `x,y : f` |

---

## 5. Functional Notation for Operators

All elementary blocks can be written in functional notation with
partial application:

```faust
+(x)   -->  _,x : +     // add x to the input
*(x)   -->  _,x : *     // multiply input by x
/(x)   -->  _,x : /     // divide input by x
-(x)   -->  _,x : -     // subtract x from input
```

---

## 6. Four Notation Styles

The same function `f(x,y) = x + 2*y` can be written as:

| Style | Example |
|-------|---------|
| **Core** | `x,y : f` |
| **Applicative** | `f(x,y)` |
| **Partial application** | `y : f(x)` |
| **Infix** | `x + 2*y` |

Yann Orlarey recommends mixing styles: core notation for overall
structure, partial application for slowly-varying parameters, and infix
for math expressions.

---

## 7. Statements

FAUST has four statement types:

1. **Definition** -- define a function (`f(x) = ...;`)
2. **File import** -- `import("stdfaust.lib");`
3. **Declaration** -- metadata: `declare author "JOS";`
4. **Documentation** -- XML-style tags for in-source documentation

Only definitions are required.  Every program must have a `process`
definition.

---

## 8. Function Definition

```faust
f(x, y, z) = expression_using_x_y_z;
```

- Definitions may appear in any order (except when pattern-matching
  order matters).
- Unused definitions are removed by dead-code elimination.
- To preserve a side-effect (e.g., a level meter), use `attach`:

```faust
process = _ <: attach(levelmeter);
```

---

## 9. Partial Function Application

Call a function with fewer arguments than it declares; remaining
arguments become unnamed input wires:

```faust
general(mode, x, y) = ...;
special = general(1);          // only 'mode' is bound
// special now has two inputs (x, y)
```

---

## 10. Naming Input and Output Signals

### Inputs

Function parameters name the inputs:

```faust
foo(x, y) = x + y;
```

### Outputs

Comma-separated expressions name multiple outputs:

```faust
process(x) = x, -x;           // stereo: original + inverted
```

### Fixing signal counts explicitly

```faust
foo = _,_ : faust_expression : _,_;   // guarantee stereo in/out
```

This helps catch wiring errors at compile time.

---

## 11. Signal Types

| Type | Precision |
|------|-----------|
| `int` | Always 32-bit |
| `float` | 32-bit by default; use `-double` or `-quad` compiler flags |

- `int(x)` truncates toward zero (preserves feedback-loop stability).
- Integer expressions auto-promote to float when needed:

```faust
process = 1/2;         // outputs 0.5  (auto-promoted)
process = int(1/2);    // outputs 0    (truncated)
```

---

## 12. Comparison and Bitwise Operators

### Comparison (sample-by-sample, output is 0 or 1)

```
<  <=  >  >=  ==  !=
```

```faust
process(L, R) = L > R;    // 1 when L > R, else 0
```

### Bitwise (for integer signals)

```
&  |  xor  <<  >>
```

---

## 13. Unary Minus

`-x` rewrites to `0,x : -` (a signal: the negation of `x`).

`-(expr)` is a **block diagram** with one input that subtracts `expr`
from that input.  Be aware of the distinction:

```faust
-1 - cos(w)       // a signal (no inputs)
-(1 + cos(w))     // a block diagram (one input)
```

---

## 14. Iteration Constructs

### `par` -- parallel iteration

```faust
par(i, N, f(i))    // f(0) , f(1) , ... , f(N-1)

bus(n) = par(i, n, _);            // n-wire bus
process = bus(4) <: bus(12);      // 4 inputs fanned to 12 outputs
```

### `seq` -- sequential iteration

```faust
seq(i, N, f(i))    // f(0) : f(1) : ... : f(N-1)
```

### `sum` -- additive iteration

```faust
sum(i, N, f(i))    // f(0) + f(1) + ... + f(N-1)
```

(Often unnecessary because `:>` already sums.)

### `prod` -- multiplicative iteration

```faust
prod(i, N, f(i))   // f(0) * f(1) * ... * f(N-1)
```

---

## 15. Foreign Constants, Variables, and Functions

### Foreign constant (set once at init)

```faust
SR = fconstant(int fSamplingFreq, <math.h>);
```

### Foreign variable (may change per block)

```faust
BS = fvariable(int count, <math.h>);
```

### Foreign function

```faust
tanh = ffunction(float tanhf(float), <math.h>, "");
```

Syntax: `ffunction(<return-type> <name>(<arg-types>), <header>, <lib>)`

Types are restricted to `int` and `float`.

---

## 16. Pattern Matching

Pattern matching enables recursive definitions:

```faust
fact(0) = 1;
fact(n) = n * fact(n - 1);
```

**Order matters**: more specific patterns must precede general ones
(evaluated top to bottom; reversing the factorial patterns causes an
infinite compile-time loop).

Patterns can match structural elements of block diagrams, enabling
meta-programming over signal-processing topologies (e.g., Hadamard
matrices, feedback delay networks, FFT butterflies).

---

## 17. Scope Rules

### Local definitions with `with`

```faust
process = out
with {
    a = 0.9;
    out = + ~ *(a);
};
```

### Libraries and namespaces

```faust
f = library("foo.lib");
process = f.myFilter;          // dot-notation access
```

### Environments

```faust
e = environment {
    Phi = 0.5 * (1.0 + sqrt(5));
};
golden_ratio = e.Phi;
```

### Components

```faust
process = component("other.dsp");   // shorthand for library("other.dsp").process
```

---

## 18. White Noise Generator

A classic example using the feedback (`~`) operator with the linear
congruential method:

```faust
random  = +(12345) ~ *(1103515245);   // overflowing multiply & offset
RANDMAX = 2147483647.0;
noise   = random / RANDMAX;
process = noise;
```

---

## 19. A Complete Example: Constant-Peak-Gain Resonator

```faust
import("stdfaust.lib");

fr = nentry("frequency (Hz)", 1000, 20, 20000, 1);
bw = nentry("bandwidth (Hz)", 100,  20, 20000, 1);
g  = hslider("peak gain", 1, 0, 10, 0.01);

R  = exp(-ma.PI * bw / ma.SR);
RR = R * R;
A  = 2.0 * ma.PI * fr / ma.SR;

// FIR part
fir(x) = (x - x'') * g * (1 - RR) / 2;

// Feedback (recursive) part
fbk(x) = 0 + 2*R*cos(A)*x - RR*x';

process = fir : fbk;
```

---

## 20. GUI Primitives

| Widget | Syntax |
|--------|--------|
| Numeric entry | `nentry("label", init, min, max, step)` |
| Horizontal slider | `hslider("label", init, min, max, step)` |
| Vertical slider | `vslider("label", init, min, max, step)` |
| Button | `button("label")` |
| Checkbox | `checkbox("label")` |
| Horizontal bar graph | `hbargraph("label", min, max)` |
| Vertical bar graph | `vbargraph("label", min, max)` |

GUI widgets produce **slow** output signals (updated once per audio
block).  The compiler automatically hoists GUI-dependent expressions
out of the inner loop.

### Grouping

```faust
hgroup("name", layout)     // horizontal group
vgroup("name", layout)     // vertical group
tgroup("name", layout)     // tab group
```

---

## 21. Verifying and Testing

### Generate block diagrams (SVG)

```bash
faust -svg myfile.dsp
```

Creates `myfile-svg/` with one SVG per block-diagram expression.
Diagram conventions:
- A **dot** marks standard block orientation (like IC pin 1)
- A **small open square** marks a unit-sample delay in a feedback loop

### Inspect generated C++

```bash
faust myfile.dsp           # prints C++ to stdout
faust -cn MyClass myfile.dsp   # set generated class name
```

The generated class has:
- `init()` / `instanceInit()` -- initialization
- `compute(int count, float** input, float** output)` -- the inner loop
- `buildUserInterface()` -- GUI wiring

### Plot output signals

```bash
faust2plot myfile.dsp      # generate and plot output
faust2octave myfile.dsp    # export for Octave/Matlab inspection
```

---

## 22. Generating Applications and Plugins

The FAUST distribution includes `faust2*` scripts for many targets:

| Script | Target |
|--------|--------|
| `faust2jaqt` | JACK + Qt GUI |
| `faust2jack` | JACK console |
| `faust2juce` | JUCE plugin (VST/AU/standalone) |
| `faust2ladspa` | LADSPA plugin |
| `faust2lv2` | LV2 plugin |
| `faust2vst` | VST plugin |
| `faust2au` | AudioUnit |
| `faust2max6` | Max/MSP external |
| `faust2puredata` | Pure Data external |
| `faust2supercollider` | SuperCollider UGen |
| `faust2csound` | Csound opcode |
| `faust2faustvst` | Faust VST |
| `faust2ios` | iOS app |
| `faust2android` | Android app |
| `faust2bela` | Bela board |
| `faust2esp32` | ESP32 |
| `faust2teensy` | Teensy |
| `faust2wasm` | WebAudio (WASM) |
| `faust2plot` | Plot output |
| `faust2octave` | Octave/Matlab |

Run any script with `-h` for options.

---

## 23. Standard Libraries

```faust
import("stdfaust.lib");
```

This single import gives access to all standard FAUST libraries, whose
symbols are accessed via namespace prefixes:

| Prefix | Library | Contents |
|--------|---------|----------|
| `ma.` | `maths.lib` | Math constants and functions (`ma.PI`, `ma.SR`) |
| `ba.` | `basics.lib` | Utilities (`ba.count`, `ba.take`, `ba.if`) |
| `fi.` | `filters.lib` | Filters (`fi.lowpass`, `fi.highpass`, `fi.resonbp`) |
| `os.` | `oscillators.lib` | Oscillators (`os.osc`, `os.sawtooth`, `os.square`) |
| `no.` | `noises.lib` | Noise generators (`no.noise`) |
| `ef.` | `effects.lib` | Effects |
| `de.` | `delays.lib` | Delay lines |
| `en.` | `envelopes.lib` | Envelopes (`en.adsr`) |
| `an.` | `analyzers.lib` | Analysis tools |
| `si.` | `signals.lib` | Signal utilities (`si.bus`, `si.smooth`) |
| `sp.` | `spats.lib` | Spatialization |
| `ve.` | `vaeffects.lib` | Virtual-analog effects |
| `re.` | `reverbs.lib` | Reverbs |
| `co.` | `compressors.lib` | Dynamics |
| `ro.` | `routes.lib` | Signal routing |

---

## References

- Full tutorial: <https://ccrma.stanford.edu/~jos/aspf/>
- FAUST homepage: <https://faust.grame.fr/>
- FAUST libraries: <https://faustlibraries.grame.fr/>
- FAUST Quick Reference (GitHub): <https://github.com/grame-cncm/faust>
- Online IDE: <https://faustide.grame.fr/>
