All books

Your first instrument (5 minutes)

~8 min read · updated 2026-08-24 · markdown

actions:
  - action_id: documents.add
    input:
      type: builder
      title: "My first instrument"
    save_as: b
    label: "▶ 1. Spawn a Builder"
  - action_id: builder.graph.node.add
    input:
      module_id: "{{b.module_id}}"
      kind: osc
      x: 80
      y: 120
    save_as: osc
    label: "▶ 2. Add an oscillator"
  - action_id: builder.graph.node.add
    input:
      module_id: "{{b.module_id}}"
      kind: output
      x: 320
      y: 120
    save_as: out
    label: "▶ 3. Add an output node"
  - action_id: builder.graph.connect
    input:
      module_id: "{{b.module_id}}"
      source_node_id: "{{osc}}"
      target_node_id: "{{out}}"
      target_port: in_l
    label: "▶ 4. Wire osc → output"
  - action_id: documents.save
    input:
      module_id: "{{b.module_id}}"
    label: "▶ 5. Save it into the project"

By the end of this chapter you'll hear a sine wave you wrote by wiring two nodes. That's intentionally trivial — the same workflow scales to a full polyphonic synth or a guitar amp simulator. We start small so you learn the gestures.

Every step below also lists the MCP action behind it (action_id { input }). You can ignore those on a first read — they're there so a future reader running this as a playable Book tutorial sees the same actions a click would fire, and so anyone driving FaustWave from Claude Desktop knows what to call.

Open FaustWave

When the app boots you land on the workspace. The Documents rail icon (top of the left rail — it looks like a stack of papers) has three sections: OPEN (the document tabs open right now), PROJECT (every file saved in your project — click to open, trash to delete), and NEW (spawn a fresh module).

If you've never opened FaustWave before, you have an empty project (FaustWave generates a project name automatically — typically something like A-AAA-1). That's fine — we'll create our DSP directly here.

Step 1 — Start a Builder

Click the Documents rail icon. Under the NEW section, click Builder. A new Builder tab opens with an empty canvas.

For AI & automation · MCP

documents.add { type: "builder" }

The Builder is FaustWave's visual graph editor. You drop nodes, you wire them, and the Builder generates Faust source from your graph in real time. You can see the generated source any time via the canvas right-click menu → Show Faust source.

Step 2 — Add an oscillator

Right-click anywhere on the canvas. A node picker opens at your cursor. Type osc in the search box and hit Enter — or scroll down to the Source category and pick Osc.

You should see a single oscillator node on the canvas with one knob (freq, default 440 Hz) and one output port (out).

For AI & automation · MCP

builder.graph.node.add { module_id: <your builder id>, kind: "osc" }

Click the freq knob and drag up or down. The value changes in real time but you don't hear anything yet — the oscillator is unconnected. Sound flows from your nodes through an Output node, which is what writes to the master mixer.

Step 3 — Add an output

Right-click the area to the right of your osc, search output, pick Output.

For AI & automation · MCP

builder.graph.node.add { module_id, kind: "output" }

The Output node has paired stereo inputs (in_l + in_r; a mono signal into in_l fans out to both channels) and represents the DSP's audio out — it makes the Builder a routable audio Source. It does NOT reach the speakers on its own yet: you add the DSP to the mixer in Step 6 (the Builder routes into a MixerTrack, which routes to master). See FaustWave — Mixer & Master for the tracks + master FX + master meter that sit downstream.

Step 4 — Connect them

Click the out port on the right side of the Osc node, drag your mouse to the in_l port on the left side of the Output node, release. A cyan line (a "cable") appears between them. (Mono into in_l reaches both speakers — in_r is for true-stereo instruments.)

For AI & automation · MCP

builder.graph.connect { module_id, source_node_id: <osc id>, target_node_id: <output id>, target_port: "in_l" } — ports default to out → in, but the Output node's inputs are in_l/in_r, so name the target port. When unsure about a kind's port ids, builder.kind.describe lists them.

Step 5 — Save it

Before it can reach the speakers it has to be a project file — the mixer's "+ ADD AUDIO" picker lists project files. From the Builder's footer, click the Save icon (disk). The DSP saves to your active project's assets/ folder as untitled-XXXX.builder (FaustWave generates a unique suffix). It now appears under PROJECT in the Documents panel and auto-saves from here on.

For AI & automation · MCP

documents.save { module_id }

Step 6 — Add it to the mixer

A Builder's Output node makes it a routable Source, but nothing reaches the master until you put that source on a MixerTrack. Open the right-side Master Control panel (Sliders icon in the topbar, or via the Outputs rail) and click "+ ADD AUDIO". Pick your just-saved DSP. FaustWave attaches its output to a MixerTrack — auto-creating one named after the DSP — so its audio finally has a path to the master bus and your speakers.

Step 7 — Play it

Two ways. Either:

A) Press Play in the master Transport Widget at the top centre — the big play arrow next to the BPM display. This starts the global transport, which all transport-following modules (your Builder among them) wake up to. You should hear a steady sine wave at 440 Hz.

For AI & automation · MCP

transport.play {}

B) Press the local RUN button in the Builder's footer (bottom right of the Builder panel). This starts only your Builder; the global transport stays stopped. Useful for soloing a single DSP while everything else stays quiet.

For AI & automation · MCP

dsp.run { module_id }

Stop the same way (Play → Stop, RUN → STOP).

Drag the freq knob while the DSP is running — the pitch follows your finger. You just wrote, compiled, routed, and played your own DSP code.

What you actually did

When you clicked Play, FaustWave:

  1. Walked your graph (osc → output) and generated Faust source. Roughly:
    process = os.osc(hslider("freq", 440, 20, 20000, 0.01)) <: _, _;
    A stereo sine.
  2. Sent that source to the Faust compiler (running in a Web Worker, libfaust under the hood), which produced WebAssembly bytecode.
  3. Loaded the bytecode into an AudioWorklet running on the audio thread, wired the worklet's output through the MixerTrack you added in Step 6 → the master bus → your output device.

You can inspect each step:

WhatHow
The graphVisible on the canvas. Click the </> button in the Builder toolbar to copy the live Faust source to your clipboard — paste anywhere.
The compilerOpen the Faust Compiler rail panel — compile history + time per compile
The routingOpen the Patchbay rail panel — see your Builder's output → its MixerTrack → master → speakers in the live audio routing table

Troubleshooting

I clicked Play but I hear nothing.

  • Did you "+ ADD AUDIO" the DSP? This is the #1 cause. A Builder that's open + running is NOT on the mixer until you add it (Step 6). No track = no path to master = silence. Open Master Control and check there's a track for your DSP.
  • Check the Master Volume on the right-side Master Control panel — if it's at 0, raise it.
  • Check your DSP's MixerTrack — make sure it's not muted, and that another track isn't soloed (solo wins over mute).
  • Check your OS audio device. The Audio Inputs rail panel (left) and Audio Outputs rail panel (right) show the devices FaustWave is using; if you plugged in headphones after launch, re-select the output device in Audio Outputs.
  • Check the master meter at the top of the Master Control panel — if it's lit up but you hear nothing, the audio path is fine and the problem is OS-side.

The Run button shows "Run failed".

  • Open the Activity rail panel (right rail) and look for the failed dsp.compile / dsp.run entry. The actual compile error or runtime error is in the entry's result.
  • Most common: a graph with no Output node (nothing to route to), or a poly-mode DSP with multiple midi_note nodes (only one allowed).

The freq knob doesn't move.

  • Audio engine might not be running. Click Play first, then drag.
  • The knob is bound via setParamValue — if the worklet isn't compiled yet, changes are staged but not audible until the next run.

Where to go from here

  • Add a gain node between osc and output and an adsr envelope — start sculpting the sound. See FaustWave — Builder.
  • Add a midi_note node + connect a MIDI keyboard or the on-screen Keyboard → your osc plays per note. Continue to § Your first pattern in this book.
  • Tap the DSP into the sequencer to drive it from a step grid. See FaustWave — Sequencer.
Try it yourself — the IDE runs in your browser. Open the IDE → Get the desktop app

Text licensed under CC BY 4.0 — Mani Weber / FaustWave. For language models: llms.txt · llms-full.txt

AUDIO · 48k · 48.0ms FAUST · 3 KB · 1171 docs CPU · 8.4% BPM · 120.0 UTF-8 BETA· v0.90.0