Tzopilotl
Docs
GitHub

Writing SynthDefs

11. Control Flow

Two kinds of conditional exist, and choosing between them matters:

FunctionDescription
select2(test, ifOne, ifZero)Per-channel: ifOne where test is nonzero, else ifZero. All three evaluate every sample.
select(test, exprs)Per-channel N-way select: exprs[test]. All inputs evaluate every sample.
if_(test, thenFn, elseFn?)Branching conditional. The branches are zero-argument functions (fn() S { ... }) built as subgraphs; only the taken branch executes. Missing else yields 0. An overload on a plain Bool test resolves at graph-build time.
switch(test, funs)N-way branching conditional over an array of subgraph functions, indexed by test.
for_(varname, count, bodyFn)A loop in the generated code: the body subgraph (a fn(S) S receiving the loop variable) runs count times per sample. Prefer ordinary Tzopilotl loops (which unroll into the graph) unless you specifically need a runtime loop.
-- select2: per-sample, both sides always computed
fn divz(numer, denom, otherwise) = select2(denom == 0.0, otherwise, numer / denom);

-- switch: only the chosen oscillator chain runs
fn multiOsc() S {
    let f = control("freq", ControlSpec { lo: 20.0, hi: 5000.0, init: 220.0, warp: ControlWarp.exponential });
    let w = choice("wave", 3);
    switch(w, [
        fn() S { f sinosc },
        fn() S { f smoothSaw(4) },
        fn() S { f lfbpulse(0.5) },
    ]) * 0.2 |> outlet
}
↑ Back to top