# Audio-Rate Modulation

Any parameter can be modulated continuously using modulation words. Instead of a fixed value, these words produce a modulation string that the engine interprets as a moving signal.

All time values are in **steps**, just like `attack`, `decay`, and `release`. At 120 BPM with speed 1, one step is 0.125 seconds. Writing `4 lfo` means a 4-step period.

## LFOs

Oscillate a parameter between two values.

```forth
saw snd 200 4000 4 lfo lpf .         ( sweep filter over 4 steps )
saw snd 0.3 0.7 2 tlfo pan .         ( triangle pan over 2 steps )
```

| Word | Shape | Output |
|------|-------|--------|
| `lfo` | Sine | `min~max:period` |
| `tlfo` | Triangle | `min~max:periodt` |
| `wlfo` | Sawtooth | `min~max:periodw` |
| `qlfo` | Square | `min~max:periodq` |

Stack effect: `( min max period -- str )`

## Slides

Transition from one value to another over a duration.

```forth
saw snd 0 1 0.5 slide gain .         ( fade in over half a step )
saw snd 200 4000 8 sslide lpf .      ( smooth sweep over 8 steps )
```

| Word | Curve | Output |
|------|-------|--------|
| `slide` | Linear | `start>end:dur` |
| `expslide` | Exponential | `start>end:dure` |
| `sslide` | Smooth (S-curve) | `start>end:durs` |

Stack effect: `( start end dur -- str )`

## Random

Randomize a parameter within a range, retriggering at a given period.

```forth
saw snd 200 4000 2 jit lpf .         ( new random value every 2 steps )
saw snd 200 4000 2 sjit lpf .        ( same but smoothly interpolated )
saw snd 200 4000 1 drunk lpf .       ( random walk, each step )
```

| Word | Behavior | Output |
|------|----------|--------|
| `jit` | Sample & hold | `min?max:period` |
| `sjit` | Smooth interpolation | `min?max:periods` |
| `drunk` | Random walk | `min?max:periodd` |

Stack effect: `( min max period -- str )`

## Envelope Modulation

Apply an envelope to any parameter. The `env` word is the complete form: it sweeps from `min` to `max` following a full attack, decay, sustain, release shape. All times are in steps.

```forth
saw snd 200 8000 0.01 0.1 0.5 0.3 env lpf .
```

Stack effect: `( min max attack decay sustain release -- str )`

This is the building block. From it, three shorthands drop the parameters you don't need:

| Word | Stack | What it does |
|------|-------|-------------|
| `env` | `( min max a d s r -- str )` | Full envelope (attack, decay, sustain, release) |
| `eadr` | `( min max a d r -- str )` | No sustain (sustain = 0) |
| `ead` | `( min max a d -- str )` | Percussive (sustain = 0, release = 0) |

`eadsr` is an alias for `env`.

```forth
saw snd 200 8000 0.01 0.3 ead lpf .              ( percussive filter pluck )
saw snd 0 5 0.01 0.1 0.3 eadr fm .               ( FM depth with release tail )
saw snd 200 8000 0.01 0.1 0.5 0.3 env lpf .      ( full ADSR on filter )
```

These work on any parameter — `lpf`, `fm`, `gain`, `pan`, `freq`, anything that accepts a value.

## Low Pass Gate

The `lpg` word couples the amplitude envelope with a lowpass filter. Set your amp envelope first with `ad` or `adsr`, then `lpg` mirrors it to `lpf`.

```forth
saw snd 0.01 0.1 ad 200 8000 1 lpg .        ( percussive LPG )
saw snd 0.01 0.1 0.5 0.3 adsr 200 4000 1 lpg .  ( sustained LPG )
```

Stack effect: `( min max depth -- )`

- `min`/`max` — filter frequency range in Hz
- `depth` — 0 to 1, scales the filter range (1 = full, 0.5 = halfway)

```forth
saw snd 0.01 0.5 ad 200 8000 0.3 lpg .      ( subtle LPG, filter barely opens )
```

`lpg` reads `attack`, `decay`, `sustain`, and `release` from the current sound. If none are set, it defaults to a short percussive shape.

## Combining

Modulation words return strings, so they compose naturally with the rest of the language. Use them anywhere a parameter value is expected.

```forth
saw snd
  200 4000 4 lfo lpf
  0.3 0.7 8 tlfo pan
  0 1 0.01 0.1 ead gain
.
```
