pulp

Skode Scheduled Opcodes

Architecture: Logical vs Realtime

The Skode ISA features a strict separation between logical and realtime opcodes:

This structural invariant ensures that opcode_event_t, event_t, and event_program_t memory layouts remain compact and optimized for the audio thread. Opcodes outside the 0-255 range will be categorically rejected at compilation time when attempting to push them to a sequence, queue, or defer block.

Scheduled work executed by the audio callback consists only of fixed-size numeric opcode events. Skode text is parsed and compiled on a command or UDP thread before it enters a queue, defer, repeat, or sequence.

Numeric Opcode Escape (EXEC)

Skode supports direct, backward-compatible invocation of numeric opcodes via the x escape command (e.g. EXEC 3 -6.0 to set the amplitude using SKODE_OP_AMP). The x command parses the opcode number, strictly validates it against the realtime 0-255 bounds and feature support list, and seamlessly routes the remaining arguments into the existing compilation and execution pathways. This allows numeric debugging, cross-toolchain interactions, and testing without requiring mnemonic strings.

Commands that require a string, data array, parser-owned memory, file access, or other control-thread state are immediate-only. Compilation rejects the entire scheduled program instead of retaining text as a fallback.

Literal external macro calls such as e!12 are expanded on the control thread while the containing pattern, defer, repeat, or execute-string is compiled. The resulting program is a snapshot: later changes to external buffer 12 do not alter already compiled or queued events. Nested macros are supported, but undefined buffers, recursive cycles, runtime-selected e!$n calls, and expansions beyond SEQ_PROGRAM_OP_MAX are rejected.

eR macro,count,seconds[,tag] and eRR macro,count,beats[,tag] copy and compile the selected external macro once on the control thread, then queue repeated invocations of that snapshot. Repetition does not duplicate the program’s opcodes, so SEQ_PROGRAM_OP_MAX applies to each invocation rather than to the total number of repeats.

Compiled Commands

The base voice command set includes:

Feature-dependent commands compile only when their synth feature is enabled. Ksynth commands, status/printing commands, and commands using strings or data tables remain immediate-only.

=slot,value is also supported so sequence programs can update registers used by later voice opcodes. Other administrative variable commands remain immediate-only.

Programs

An event_program_t contains at most SEQ_PROGRAM_OP_MAX (32) operations. It can include + tempo-relative and ~ seconds-relative delay markers. Executing a program runs due operations directly and queues future operations as typed events.

$n operands remain register references in the compiled representation. They are resolved when each opcode executes, including deferred events and variable-selected voices. The explicit - default sentinel is retained for commands such as n- and N-.

Sequence steps retain their source text for display and editing, but playback uses the compiled program stored alongside it. Voice selection is persistent per pattern and resets to voice 0 when the pattern is cleared. Empty steps and the - stop marker do not require a compiled program. Comment-only steps such as # compile to a zero-operation program, preserving their sequence position without invoking the parser during playback.

Repeat, conditional execute, explicit execute-string, defer, and sequence-edit commands all compile before scheduling. A compile failure leaves the queue or sequence step unchanged and reports that the command is not schedulable.

Real-Time Boundary

The queue contains event_t values only:

There are no command strings, data arrays, borrowed parser pointers, parser calls, allocations, or string formatting in queued event execution. The compiler itself allocates an ands parser and therefore must remain on the control thread.

Future scheduled resource commands should carry a stable engine resource ID, not a string or pointer to parser-owned storage.

Diagnostics

Pattern diagnostics include the original source and render register operands as $n, default sentinels as -, delays with + or ~, and comment-only steps as (no-op).