# Anatomy of a DSP — and your first one

A minimal generator DSP is three lines:

```faust
import("stdfaust.lib");
level = hslider("level", 0.3, 0, 1, 0.001);
process = os.osc(440) * level;
```

- `import("stdfaust.lib")` mounts the standard library under its usual
  two-letter prefixes (`os.` oscillators, `fi.` filters, `en.` envelopes,
  `no.` noise, `ba.` basics, `ma.` math, …).
- Every `hslider` / `nentry` / `button` / `checkbox` becomes a live knob in
  the module's UI panel **and** a param path the AI can read and write.
- `process` is the DSP's signal function. **Generator shape** means no
  audio inputs: `process = <expression>;`. Mono output is fine — split to
  stereo with `<: _, _` when you want both channels.

Two shapes the editor treats differently:

| Shape | Example | Where it runs |
|---|---|---|
| **Generator** | `process = os.osc(f);` | A `.dsp` module (this book) |
| **FX** | `process = _ : fi.lowpass(1, fc);` | Master-FX or track-FX slots — a standalone `.dsp` module has no input source, so Run refuses it with a friendly error. Validate FX sources with `dsp.compile` instead. |

## Build one hands-free

```yaml
actions:
  - action_id: documents.add
    input: { type: "faust-dsp", title: "Tutorial Tone" }
    save_as: mod
    label: "▶ 1. Create a .dsp module (file lands in assets/)"
  - action_id: editor.source.set
    input: { module_id: "{{mod.module_id}}", source: "import(\"stdfaust.lib\"); level = hslider(\"level\", 0.2, 0, 1, 0.001); process = os.osc(440) * level <: _, _;" }
    label: "▶ 2. Write a sine-tone source into the buffer"
  - action_id: dsp.run
    input: { module_id: "{{mod.module_id}}" }
    label: "▶ 3. Compile + start the worklet"
  - action_id: mixer.tracks.input.set
    input: { module_id: "{{mod.module_id}}", source_title: "Tutorial Tone" }
    label: "▶ 4. Attach to a mixer track — now it is audible"
  - action_id: dsp.stop
    input: { module_id: "{{mod.module_id}}" }
    label: "▶ 5. Stop the tone (strip + file survive)"
```

> 🟦 **RUNNING ≠ AUDIBLE**: step 3 alone plays into silence — a module
> becomes audible when its output reaches the master, which is what the
> attach in step 4 wires up (and it gives you a fader strip for free).
> `dsp.run`'s result tells you: it lists `routed_to` targets and warns
> when there are none.
