Tzopilotl
Docs
GitHub

Writing SynthDefs

14. Compiling, Tagging, and Playing

defSynthX

defSynthX(synthFun, name) and defSynthX(synthFun, name, tags) (from synthc.compile) run your graph function, compile the graph with synthc — the Tzopilotl-hosted synthdef compiler — and load the resulting plugin into the engine under name. This is the production path.

defSynthX is async: the clang invocation that builds the .dylib runs on a background worker, so sequences that are already playing keep playing while a def compiles. The call returns a Future<String> holding the generated C++ source; when it resolves, the def has been compiled, loaded, and registered. A failed compile panics: the error prints and the script halts, so code never sails past a def that did not load. Two usage patterns:

Inside a non-real-time render script the compile runs synchronously (the render cannot proceed without the def), so the returned future is already resolved.

defSynthXChecked is the fallible form for code that must tolerate and report failures rather than halt (test harnesses that sweep many defs): it returns a Future<Result<String, String>>ok(cpp) on success, err(message) on a failed analysis, compile, or load — and prints nothing.

defSynth (in synthdef.x) is the legacy path through the C++ compiler via the S-expression serializer. It byte-matches defSynthX's output and is retained as the differential-test oracle; new code should use defSynthX. It is async in the same way, panics on failure the same way (with a defSynthChecked fallible form), and returns the synthdef's S-expression text.

Tags

Tags are free-form category strings attached to a def (defSynthX(f, "name", ["example"])) that the plugin browser uses for filtering. The TZPL_DEFAULT_TAGS environment variable (comma-separated) appends session-wide default tags to everything compiled — test harnesses set TZPL_DEFAULT_TAGS=test so their defs are born filtered out.

Playing

FunctionDescription
play(defName) / play(defName, nodeID)Create a node of the def, connect its output to audio out, return the node ID.
stop(nodeID)Free the node.
playFor(defName, seconds)Coroutine: play, yield for seconds, stop. Useful in scheduled/scripted contexts.

These are conveniences over the audio_engine bridge (begin/newNode/connect/sched); for full graph patching, silos, and scheduling see the Music Cookbook.

Inspecting graphs without compiling

FunctionDescription
makeGraph(synthFun)Run the function and return the in-memory SignalGraph (no compile).
toSynthSexpr(graph, name)The (Synth name ...) S-expression for a graph — the exchange format both compilers consume. Handy for debugging what your code actually built.
↑ Back to top