LiveCoding#

Static façade over the engine’s embedded-CPython script API (yse_python.h). Submit scripts with LiveCoding.run() and observe uncaught Python errors through the LiveCoding.errors broadcast Stream.

What live coding is#

A live-coding script is a chunk of Python source you hand to the engine at runtime. Inside the interpreter the script drives the audio engine through the yse Python DSL — a small module of scheduling verbs that the embedded interpreter exposes:

  • yse.send — push an event into the engine immediately.

  • yse.on — register a callback to fire on a named engine event.

  • yse.schedule — queue an action to run at a future beat / time.

  • yse.tick — advance the script’s logical clock by one step.

  • yse.cancel_all — clear every pending scheduled action.

  • yse.fresh_scope — reset the script namespace, discarding state accumulated by earlier submissions.

A script is submitted with LiveCoding.run(), which returns immediately — the engine takes its own copy of the source and evaluates it on its script thread. See example/demo18_live_coding.dart for an end-to-end submit-and-pump loop.

The full Python-side DSL is owned by the upstream engine; this wrapper only marshals the source string in and the error text out. For the complete verb reference see the upstream live-coding epic, yvanvds/yse-soundengine#119.

Build-dependent behaviour#

The CPython interpreter is a compile-time option. Full functionality requires a library built with YSE_ENABLE_PYTHON=ON; LiveCoding.enabled reports which build you are running against and is safe to query regardless of engine state.

On an OFF build the API stays callable — LiveCoding.run() does not throw. Instead the engine synchronously emits the sentinel string "YSE compiled without YSE_ENABLE_PYTHON" through LiveCoding.errors from inside the run call itself. Subscribe to errors before calling run if you want to observe that sentinel.

Error-delivery model#

Uncaught Python exceptions and syntax errors do not surface from LiveCoding.run() (which has already returned). Instead the engine formats the traceback and delivers it on the thread that drives System.update() — the same isolate that called System.init(). Pump the update loop to receive queued tracebacks, which arrive as strings on the LiveCoding.errors broadcast stream. The OFF-build sentinel above is the one exception: it fires synchronously during run rather than on a later update.

LiveCoding#

class LiveCoding

Live-coding façade over the engine’s embedded-CPython script API.

The C surface (yse_python.h) is a set of stateless globals — there is no native handle — so this is a thin static façade rather than a fetched singleton. Scripts are submitted with [run] and uncaught Python errors surface through the [errors] stream.

The interpreter is only present on a YSE_ENABLE_PYTHON=ON build; query [enabled] to tell. On an OFF build [run] is still safe to call — the engine reports the missing feature through [errors] with a sentinel “compiled without” message.

Static accessors#

static bool get enabled

Compile-time feature query. True only when the library was built with YSE_ENABLE_PYTHON=ON. Safe to call regardless of engine state.

static Stream<String> get errors

Broadcast stream of formatted tracebacks from uncaught Python exceptions and syntax errors. The first subscription installs the engine error callback; the bridge is torn down when the last subscriber cancels (or the engine closes).

Unlike [Log.messages], the traceback string is owned by the engine and valid only for the duration of the call — there is no free function. A NativeCallable.listener would copy the pointer and read it later, by which point it dangles. So this uses NativeCallable.isolateLocal: the closure runs synchronously inside the C call and copies the string with toDartString() before returning. Safe because the engine fires this callback on the thread that drives yse_system_update() — the main isolate.

Static methods#

static void run(String src)

Submit a UTF-8 [src] script for evaluation on the engine’s script thread. Returns immediately; the engine takes its own copy, so the marshalled buffer is freed on return. Uncaught errors arrive later through [errors] (during [System].`update()`).

static Stream<BusFrame> bus(String prefix)

Prefix tap on the global named bus.

The bus is no longer live-coding specific: use [Bus.tap] (or [Bus.subscribe] for one exact address, [Bus.publish] to send).

Host bus access#

Publishing to, subscribing to and tapping the engine’s global named bus — the plane a script’s yse.send / yse.on talk over — lives on its own page: see Bus. LiveCoding.bus remains as a deprecated forwarder to Bus.tap().