$TZPL_HOME; see the module search path in the language docs). General-purpose modules live under the std.* namespace (import std.strings.*;). Audio-domain modules (synthdef, common_ugens, filters, dsp_math, complex_signal) and host bindings (audio_engine, ui, osc, nats, clock, bundles) keep their flat names.
Functions marked NRT perform blocking syscalls and cannot be called from real-time code; each module's RT-safety is stated in its section. Built-in (C++-implemented) functions are documented separately in the Built-in Functions Reference.
String utilities beyond the built-ins. Pure and RT-safe. String offsets and length are byte-based, matching substring and indexOf.
| Function | Description |
|---|---|
parens(s) / brackets(s) / braces(s) / quotes(s) | Wrap in (), [], {}, "". |
separatedString([String], sep = " ") | Join with a separator. |
repeatString(s, n) | s repeated n times. |
padStart(s, width, pad = " ") / padEnd(s, width, pad = " ") | Pad to at least width. |
splitLines(s) / lines(s) | Split into lines; \r\n normalized, no empty last line from a trailing newline. |
capitalize(s) | Uppercase the first character (ASCII). |
stripPrefix(s, p) / stripSuffix(s, p) | Remove a prefix/suffix if present, else unchanged. |
equalsIgnoreCase(a, b) | ASCII case-insensitive comparison. |
glob(s, pattern) | Whole-string glob match: *, ?, [abc], [a-z], [!abc]. |
import std.strings.*;
"7" padStart(3, "0") -- "007"
"a\r\nb\nc\n" splitLines -- [a, b, c]
"snare_04.wav" glob("snare_*.wav") -- true
"beat7" glob("beat[0-9]") -- true
↑ Back to top
Pure path-string manipulation — no syscalls, RT-safe. Paths are byte strings with / separators. The filesystem itself lives in std.fs.
| Function | Description |
|---|---|
basename(p) | Final component: basename("/a/b/c.txt") → "c.txt". |
dirname(p) | Everything before the last /; "." for bare names. |
extension(p) | The basename's extension including the dot ("" if none; dotfiles have none). |
withExtension(p, ext) | Replace (or add) the extension. |
joinPath(a, b) | Join with exactly one separator; an absolute b wins. |
splitPath(p) | Components, empty ones dropped: "/a//b" → [a, b]. |
isAbsolute(p) | True if the path starts with /. |
import std.path.*;
"/a/b/c.txt" basename -- "c.txt"
"/a/b/c.txt" dirname -- "/a/b"
"take1.wav" withExtension(".aif") -- "take1.aif"
joinPath("samples", "kick.wav") -- "samples/kick.wav"
↑ Back to top
Ergonomic wrappers over the NRT file built-ins (readFile, writeFile, listDir, …). Nothing here is real-time safe: the plain wrappers block on syscalls, and the Async wrappers — non-blocking, built on the readFileAsync-family built-ins — are still rejected in real-time code. The Result variants carry a path-bearing error message via std.result.
| Function | Description |
|---|---|
readFileOr(path, default) | Contents, or default if unreadable. |
readLines(path) → Option[[String]] | Contents split into lines. |
writeLines(path, [String]) → Bool | Write lines joined with \n, trailing newline. |
readFileResult(path) → Result[String, String] | readFile with an error message. |
readFileBytesResult(path) → Result[Bytes, String] | readFileBytes with an error message. |
writeFileResult(path, s) → Result[Bool, String] | writeFile with an error message. |
listDirResult(path) → Result[[String], String] | listDir with an error message. |
readFileAsyncResult(path) → Future[Result[String, String]] | Async readFileResult; await it, then try composes. |
readFileBytesAsyncResult(path) → Future[Result[Bytes, String]] | Async readFileBytesResult. |
writeFileAsyncResult(path, s) → Future[Result[Bool, String]] | Async writeFileResult. |
import std.fs.*;
readLines("setlist.txt") unwrapOr(["(empty)"]) println;
writeLines("/tmp/out.txt", ["one", "two"]);
readFileResult("missing") errOption unwrap println;
-- cannot read file: missing
↑ Back to top
Result<T, E> is a success-or-error sum type. Convention: built-ins that can fail return Option; stdlib .x APIs that want an error message return Result<T, String>.
| Function | Description |
|---|---|
Result<T, E>.ok(v) / Result<T, E>.err(e) | Constructors. |
isOk(r) / isErr(r) | Case tests. |
okOption(r) / errOption(r) | Either side as an Option. |
unwrapResult(r) | The ok value; traps on err. |
unwrapOr(r, default) | The ok value or a default. |
unwrapOrElse(r, f) | The ok value or f(err). |
mapOk(r, f) / mapErr(r, f) | Transform one side, pass the other through. |
import std.result.*;
fn half(x Int) Result<Int, String> {
x % 2 == 0 ? Result<Int, String>.ok(x / 2)
: Result<Int, String>.err("odd: " $ x toString)
}
half(8) unwrapOr(0) println; -- 4
half(7) errOption unwrap println; -- odd: 7
The postfix try operator propagates errors without boilerplate: expr try unwraps ok/some, and on err/none early-returns it from the enclosing function (whose return type must be a Result with the same error type, or an Option). It chains mid-pipeline like await.
fn quarter(x Int) Result<Int, String> {
let h = half(x) try; -- err propagates out of quarter
let q = half(h) try;
Result<Int, String>.ok(q)
}
quarter(8) unwrapOr(0) println; -- 2
quarter(6) errOption unwrap println; -- odd: 3
↑ Back to top
Assertion helpers with stable one-line output (PASS label / FAIL label: expected X got Y), designed to compose with the golden-file test runner and read well in the app's output panel. Each assertion returns its outcome as a Bool and updates shared counters.
| Function | Description |
|---|---|
assertEq<T>(actual, expected, label) | Structural equality. |
assertTrue(cond, label) / assertFalse(cond, label) | Boolean conditions. |
assertNear(actual, expected, eps, label) | Float comparison within a tolerance. |
check(label, f () Bool) | Run a named check function. |
testSummary() → Int | Print N passed, M failed; return the failure count. |
import std.test.*;
assertEq(2 + 2, 4, "ints add"); -- PASS ints add
assertNear(0.1 + 0.2, 0.3, 1e-9, "float near");
let failures = testSummary(); -- 2 passed, 0 failed
↑ Back to top
Memoized lazy values: a Thunk<T> wraps a deferred computation that runs at most once; force evaluates it on first use and caches the result in place.
| Function | Description |
|---|---|
thunk<T>(f () T) → Thunk<T> | Wrap a deferred computation. |
force<T>(t Thunk<T>) → T | Evaluate on first force, then return the cached value. |
import std.thunk.*;
let t = thunk(fn() Int { expensive() });
t force println; -- computed now
t force println; -- cached
↑ Back to top
Combinators over Future<T> from the async/await core.
| Function | Description |
|---|---|
awaitAll<T>(fs [Future<T>]) → Void | Barrier: wait for every future to resolve. |
gather<T>(fs [Future<T>]) → [T] | Await all and collect results in input order. |
The Json value enum (null, bool, number, string, array, object) and toString rendering. A parser returning Result<Json, String> is planned (see the roadmap in devplans/LANG_IMPLEMENTATION_PLAN.md). For fast binary interchange, prefer std.message's TZB codec.
Msg is the dynamic message value type (bool/int/float/symbol/string/vec) with asMsg constructors; std.messageEncoding provides the TZB binary codec: encode(Msg) → Bytes, decode(Bytes) → Msg, isMessage, and a zero-copy Reader with O(1) child access for columnar vectors. Used by the actor system and the NATS bridge. The TZB format itself — the wire layout and the matching C++ API — is documented in FFI Guide §15, Binary Messages.
Builds the app's .tzd notebook documents (Live Controls & Notebooks) programmatically — a .tzd file is a TZB-encoded Msg tree, so this module assembles the document records and hands them to std.messageEncoding. Cells are described with NotebookCell values, normally via the constructors below. Generated documents contain no widget records — give the notebook a run-on-load code cell and its ui constructors recreate the widgets on open — and no undo history, so the file opens with a fresh history tree.
| Function | Description |
|---|---|
proseCell(text) | A prose (text) cell. |
codeCell(text, runOnLoad = false, name = "") | A code cell; name is the optional header label. |
panelCell(name, height = 240.0) | A panel cell claiming widget panel name. |
presetsCell(name = "") | An empty presets cell; slots are captured in the GUI. |
saveNotebook(path, [NotebookCell]) → Bool | Encode and write the document to path. |
notebookBytes([NotebookCell]) → Bytes | The encoded document, without writing a file. |
notebookMsg([NotebookCell]) → Msg | The document as a Msg tree, for inspection. |
import std.notebook.*;
saveNotebook("demo.tzd", [
proseCell("# Sine demo"),
panelCell("main"),
codeCell("import ui.*;\npanel(\"main\");\nslider(\"freq\", 20.0, 2000.0, 440.0);", true),
]);
↑ Back to top