API Reference
This chapter is the complete reference for every function and global available in an RT script’s Lua environment.
Lua Standard Libraries
Section titled “Lua Standard Libraries”The following Lua standard libraries are available:
| Library | Notes |
|---|---|
base | print, pairs, ipairs, type, … |
table | table.insert, table.remove, … |
string | string.format, string.find, … |
math | math.floor, math.random, … |
utf8 | UTF-8 aware string utilities |
No file I/O, OS, or debug libraries are available.
Script Info Header
Section titled “Script Info Header”Every script must contain a script info block delimited by the two comment markers shown below. Nothing else may appear between them.
-- BEGIN_INFO_BLOCK
scriptInfo = { scope = 'event-processor', -- required; only valid value for now parameters = { -- parameter definitions (optional) }}
-- END_INFO_BLOCKScript Parameters
Section titled “Script Parameters”Parameters declared in scriptInfo.parameters are created as engine parameters
owned by this script instance. They can be bound to UI controls, automated by
the host, and saved with the patch.
Each entry is a named table:
parameters = { ParamName = { type = '<type>', -- required; see table below defaultValue = <value>, -- required minValue = <number>, -- required for continuous types maxValue = <number>, -- required for continuous types },}Read a parameter’s current value inside any callback:
scriptInfo.parameters.ParamName.valueDo not read .value at top-level script load time — it is only valid inside
callbacks.
Parameter Types
Section titled “Parameter Types”| Type | Continuous | Typical range / notes |
|---|---|---|
volume | yes | dB scale |
timeMs | yes | milliseconds |
tuneSt | yes | semitones (float) |
frequencyHz | yes | Hz |
percent | yes | 0–100 |
pan | yes | −1 to +1 or similar |
genericInt | yes | arbitrary integer range |
interval | yes | semitone interval (integer) |
note | yes | MIDI note number range |
genericFloat | yes | arbitrary float range |
onOff | no | boolean; no min/max |
genericString | no | string value; no min/max |
Event Callbacks
Section titled “Event Callbacks”onProcessEvents(blockLen, events)
Section titled “onProcessEvents(blockLen, events)”The main entry point for a script. Define this function at the top level of your script; the engine calls it once per render block.
| Parameter | Type | Description |
|---|---|---|
| blockLen | number | Duration of the current render block (seconds) |
| events | table | All events falling into this block, keyed by event ID |
Each value in events is a sub-table with at minimum type and offset
fields. See Event Types for the full field listing per
type.
function onProcessEvents(blockLen, events) for i, event in ipairs(events) do -- event.id holds the unique handle for this event endendonProcessBlock(blockLen)
Section titled “onProcessBlock(blockLen)”Called once per render block regardless of whether any events fall in that block. Define this only when you need per-block processing that does not stem from incoming events — continuously running sequencers, pattern playback, LFO generation, and similar tasks. Avoid defining it when you don’t need it: the callback has overhead proportional to how small the host’s buffer size is.
| Parameter | Type | Description |
|---|---|---|
| blockLen | number | Duration of the current render block (seconds) |
function onProcessBlock(blockLen) -- called every block, with or without eventsendonProcessEvents and onProcessBlock are independent. Defining one does not
affect whether the other is called.
sys_event_types
Section titled “sys_event_types”Global table of opaque type constants. Always use these for type comparisons — never compare against string literals.
sys_event_types.nonesys_event_types.noteOnsys_event_types.noteOffsys_event_types.controllersys_event_types.timersys_event_types.scriptEvent Management
Section titled “Event Management”sys_dispose_event(eventId)
Section titled “sys_dispose_event(eventId)”Removes an event from the queue. The event will not be forwarded to the next processor. Also used to stop a recurring timer.
| Parameter | Type | Description |
|---|---|---|
| eventId | opaque | ID returned by a create function, or the id key from the events table |
sys_dispose_event(event.id)sys_dispose_all_events()
Section titled “sys_dispose_all_events()”Removes all events currently in the queue. Nothing will be forwarded unless the script creates new events afterwards. Useful as the first line of a script that rebuilds the event stream from scratch.
function onProcessEvents(blockLen, events) sys_dispose_all_events() -- queue is now empty; create whatever you want to emitendManipulating Note Events
Section titled “Manipulating Note Events”sys_set_note_length(offset, eventId)
Section titled “sys_set_note_length(offset, eventId)”Finalizes the length of a previously created note event. The typical use is handling a noteOff: when the release arrives, call this with the noteOff’s block-relative offset to close the note at the correct time.
| Parameter | Type | Description |
|---|---|---|
| offset | number | Block-relative end position of the note (seconds) |
| eventId | opaque | ID of the note event to finalize (returned by sys_create_note_event) |
sys_set_note_length(event.offset, createdNoteId)sys_set_note_length_to_infinite(eventId)
Section titled “sys_set_note_length_to_infinite(eventId)”Resets a note’s length back to infinite. Useful for sustain pedal logic where a note that would have ended needs to be held open until the pedal is released.
| Parameter | Type | Description |
|---|---|---|
| eventId | opaque | ID of the note event to modify |
sys_set_note_length_to_infinite(heldNoteId)sys_force_note_event_to_zone_map(eventId, zoneMapUid)
Section titled “sys_force_note_event_to_zone_map(eventId, zoneMapUid)”Forces a note event to use a specific zone map, bypassing the engine’s normal selection logic (note range, velocity range, round robin, etc.).
| Parameter | Type | Description |
|---|---|---|
| eventId | opaque | ID of the note event to redirect |
| zoneMapUid | string | UID of the target zone map (copied from the editor’s zone map view) |
The primary use case is triggering samples that are intentionally unreachable through normal playback. Set the zone map’s selection criterion to “never” so it is invisible to normal key/velocity mapping, then call this function to reach it explicitly from a script.
A common pattern is emitting a noise or articulation sample in response to a controller event — for example, a pedal-down thump or a pedal-up release noise:
function onProcessEvents(blockLen, events) for i, event in ipairs(events) do if event.type == sys_event_types.controller and event.controller == 64 then -- sustain pedal
-- Emit a short noise sample regardless of what keys are held local id = sys_create_note_event(event.offset, event.channel, 60, 100, 0.1) sys_force_note_event_to_zone_map(id, "uid-of-pedal-noise-zone-map") end endendThe zone map UID is copied from the editor’s zone map view.
Creating Events
Section titled “Creating Events”sys_create_note_event(offset, channel, note, velocity, length)
Section titled “sys_create_note_event(offset, channel, note, velocity, length)”Creates a new note event and adds it to the queue.
| Parameter | Type | Description |
|---|---|---|
| offset | number | Block-relative time of the event (seconds) |
| channel | number | MIDI channel (1–16) |
| note | number | MIDI note number (0–127) |
| velocity | number | Velocity (0–127) |
| length | number or nil | Duration of the note (seconds); nil creates an infinite note |
Returns the event ID of the newly created event.
-- finite note: middle C, 0.5 seconds longlocal id = sys_create_note_event(event.offset, 1, 60, 100, 0.5)
-- infinite note (key-down from live keyboard)local id = sys_create_note_event(event.offset, 1, 60, 100, nil)sys_create_control_event(offset, channel, controller, value)
Section titled “sys_create_control_event(offset, channel, controller, value)”Creates a controller event and adds it to the queue.
| Parameter | Type | Description |
|---|---|---|
| offset | number | Block-relative time of the event (seconds) |
| channel | number | MIDI channel (1–16) |
| controller | number | CC number (0–127) or special value (see below) |
| value | number | Controller value |
Special controller values:
| Constant | Value | Notes |
|---|---|---|
| Standard CC | 0–127 | Standard MIDI CC number |
pitchBend | 128 | Value range 0–16383; neutral position is 8192 |
afterTouch | 129 | |
channelPressure | 130 |
-- CC 74 (brightness)sys_create_control_event(event.offset, 1, 74, 64)
-- pitch bend to neutralsys_create_control_event(event.offset, 1, 128, 8192)sys_create_timer_event(offset, interval, numIterations)
Section titled “sys_create_timer_event(offset, interval, numIterations)”Creates a timer event and adds it to the queue.
| Parameter | Type | Description |
|---|---|---|
| offset | number | Block-relative time of the first firing (seconds) |
| interval | number | Time between firings (seconds) |
| numIterations | number or nil | Number of times to fire; nil fires indefinitely; 0 is treated as 1 |
Returns the event ID of the timer. Pass this ID to sys_dispose_event to stop
an indefinite timer.
-- fire exactly once after 0.5 secondslocal timerId = sys_create_timer_event(0, 0.5, 1)
-- fire every 0.25 seconds indefinitelylocal timerId = sys_create_timer_event(0, 0.25, nil)
-- stop the timer latersys_dispose_event(timerId)Utility
Section titled “Utility”sys_log(object)
Section titled “sys_log(object)”Writes a value to the script console in the editor. Tables are expanded recursively for inspection.
sys_log("note received: " .. event.note)sys_log(event) -- prints the full event tablesys_log(scriptInfo) -- inspect all parameters and their current valuessys_get_host_info()
Section titled “sys_get_host_info()”Returns a table describing the current state of the host transport.
| Field | Type | Description |
|---|---|---|
sampleRate | number | Current sample rate (Hz) |
isPlaying | boolean | Host transport is playing |
isRecording | boolean | Host is recording |
isLooping | boolean | Loop mode is active |
playPosition | number | Current playhead position (seconds) |
songTempo | number | Current tempo (BPM) |
signatureNum | number | Time signature numerator |
signatureDenom | number | Time signature denominator |
local host = sys_get_host_info()if host.isPlaying then sys_log("tempo: " .. host.songTempo .. " BPM")endsys_get_quarter_note_length()
Section titled “sys_get_quarter_note_length()”Returns the duration of one quarter note at the current song tempo, in seconds.
Equivalent to 60 / host.songTempo but more convenient for scheduling
tempo-synced timers.
local qn = sys_get_quarter_note_length()-- fire a timer every beatlocal timerId = sys_create_timer_event(0, qn, nil)Custom Control Events
Section titled “Custom Control Events”sys_create_custom_control_event(offset, linkedEventId, targetUid, value)
Section titled “sys_create_custom_control_event(offset, linkedEventId, targetUid, value)”Inserts a single breakpoint into the custom control envelope that is attached to a note event. The envelope is piecewise linear: the engine draws a straight ramp from the previous breakpoint (or the envelope’s start) to this one. Add as many breakpoints as needed to describe the desired shape.
| Parameter | Type | Description |
|---|---|---|
| offset | number | Block-relative time coordinate of the breakpoint (seconds) |
| linkedEventId | opaque | ID of the note event this envelope is attached to |
| targetUid | string | Modulation target — a sys_default_target_uids value or a script modulator component UID |
| value | number | Envelope value at this breakpoint |
Custom control events are not received by scripts — they are output-only. They are forwarded to the engine alongside the linked note event.
-- Fade a note from full volume to silence over its 0.5-second durationlocal id = sys_create_note_event(event.offset, event.channel, event.note, event.velocity, 0.5)sys_create_custom_control_event( event.offset + 0.5, id, sys_default_target_uids.sourceVolume, 0)sys_default_target_uids
Section titled “sys_default_target_uids”Global table of built-in modulation target UIDs for use with
sys_create_custom_control_event.
| Key | Target |
|---|---|
sourceVolume | Volume of the PCM source |
sourceTune | Tuning of the PCM source |
For other modulation targets, pass the component UID of a script modulator configured in the layer.
sys_default_target_uids.sourceVolumesys_default_target_uids.sourceTuneParameters
Section titled “Parameters”sys_set_parameter_value(parameterUid, value)
Section titled “sys_set_parameter_value(parameterUid, value)”Sets a parameter to a new value. Works for any addressable parameter: own (script-defined), global, or engine.
| Parameter | Type | Description |
|---|---|---|
| parameterUid | string | UID of the parameter to write, or its name if it has one |
| value | any | New value; type must match the parameter’s declared type |
parameterUid accepts a name in place of the UID for parameters that have
one — in practice this means global parameters, since own and engine
parameters generally don’t have a user-visible name. Engine parameter UIDs are
copied from the layer editor. For own parameters, use sys_get_own_parameter_uid
to retrieve the UID at runtime.
sys_set_parameter_value(uid, 0.5)sys_set_parameter_value("tab-index", 1) -- global parameter, by namesys_get_own_parameter_uid(name)
Section titled “sys_get_own_parameter_uid(name)”Returns the UID of a parameter declared in this script’s scriptInfo.parameters
block. Use the returned UID wherever a parameter UID string is required (e.g.
sys_set_parameter_value, sys_subscribe_to_parameter).
| Parameter | Type | Description |
|---|---|---|
| name | string | Parameter name as declared in the info block |
Returns a string UID.
local transposeUid = sys_get_own_parameter_uid("Transpose")Note that scriptInfo.parameters.Transpose.value is a convenient shorthand for
reading an own parameter’s current value inside a callback — no UID lookup
required. sys_get_own_parameter_uid is needed when you want to pass the UID to
another function such as sys_subscribe_to_parameter.
sys_subscribe_to_parameter(parameterUid, callback)
Section titled “sys_subscribe_to_parameter(parameterUid, callback)”Registers a function to be called whenever a parameter’s value changes, and
returns the parameter’s current value at the time of subscription. Works for
own, global, and engine parameters. parameterUid accepts a name in place of
the UID under the same rule as sys_set_parameter_value above.
| Parameter | Type | Description |
|---|---|---|
| parameterUid | string | UID of the parameter to watch, or its name if it has one |
| callback | function | Called with the new value as its only argument |
Returns: the parameter’s current value at the time of subscription.
-- Subscribe to an engine parameter (UID from layer editor)sys_subscribe_to_parameter("uid-filter-cutoff", function(value) sys_log("cutoff changed: " .. value)end)
-- Subscribe to an own parameterlocal uid = sys_get_own_parameter_uid("Transpose")sys_subscribe_to_parameter(uid, function(value) sys_log("transpose: " .. value)end)
-- Read the current value and react to changes in one calllocal function sync(value) sys_log("mode: " .. tostring(value)) endsync(sys_subscribe_to_parameter("mode-name", sync))Subscriptions are typically set up at top level (outside any callback) so they are registered once when the script loads.
sys_get_parameter_value(parameterUid)
Section titled “sys_get_parameter_value(parameterUid)”Returns a parameter’s current value immediately, without subscribing. Works for
own, global, and engine parameters; parameterUid follows the same UID-or-name
rule as the other parameter functions.
| Parameter | Type | Description |
|---|---|---|
| parameterUid | string | UID of the parameter to read, or its name if it has one |
Only callable from top-level script code — the code that runs once when the
script loads, outside onProcessEvents, onProcessBlock, and any subscription
callback. This is the inverse restriction of the scriptInfo.parameters.X.value
shorthand, which only works inside a callback.
Its use is discouraged: it gives you a one-time snapshot at load time, with no
way to react to later changes. Prefer sys_subscribe_to_parameter, whose return
value already gives you the current value, plus a callback for every future
change.
-- Top level only — fine here, invalid inside onProcessEvents/onProcessBlocklocal startupValue = sys_get_parameter_value(uid)Script Events
Section titled “Script Events”Script events are the mechanism for passing information from one RT script
processor to the next. A script creates a script event with an arbitrary
payload; downstream processors receive it through the normal onProcessEvents
callback, just like any other event.
sys_create_script_event(offset, payload)
Section titled “sys_create_script_event(offset, payload)”Creates a new event of type script and adds it to the queue.
| Parameter | Type | Description |
|---|---|---|
| offset | number | Block-relative time of the event (seconds) |
| payload | any | Lua value to carry (number, boolean, string, table, …) |
Returns the event ID of the created event.
-- Flag the next note as legatosys_create_script_event(event.offset, { isLegato = true, originalVelocity = vel })Script events travel downstream with the rest of the event queue. A downstream
script reads the payload from the event’s data field:
function onProcessEvents(blockLen, events) for i, event in ipairs(events) do if event.type == sys_event_types.script then local payload = event.data if payload.isLegato then -- act on the flag end end endendScript events have the same common fields as all other events (id, type,
offset) plus one extra:
| Field | Type | Description |
|---|---|---|
data | any | The value passed as payload at create time |
Components
Section titled “Components”sys_apply_component_preset(componentUid, presetUid)
Section titled “sys_apply_component_preset(componentUid, presetUid)”Applies a named component preset to a processor. A component preset is a saved set of parameter values for a specific processor, created in the editor GUI.
| Parameter | Type | Description |
|---|---|---|
| componentUid | string | UID of the target processor component (from layer editor) |
| presetUid | string | UID of the preset to apply (from editor) |
A typical use case is switching a processor’s entire parameter state in one call in response to an event — for example, loading a different reverb or convolution configuration when a program change arrives.
sys_apply_component_preset("uid-of-reverb", "uid-of-preset-hall")Cross-Script Messaging
Section titled “Cross-Script Messaging”MIDI Files
Section titled “MIDI Files”sys_load_midi_file(assetName)
Section titled “sys_load_midi_file(assetName)”Loads a MIDI file from the instrument’s custom assets. Returns an index-based table with one entry per MIDI track.
| Parameter | Type | Description |
|---|---|---|
| assetName | string | Name of the MIDI asset to load |
Each entry in the returned table:
| Field | Type | Description |
|---|---|---|
trackHandle | opaque | Handle passed to the query functions |
duration | number | Track duration (seconds) |
numNoteEvents | number | Total note events in the track |
numControllerEvents | number | Total controller events in the track |
local tracks = sys_load_midi_file("my_sequence.mid")local track = tracks[1].trackHandlelocal trackLen = tracks[1].durationCall sys_load_midi_file at top level (script load time), not inside a
callback. Loading a file every block would be extremely wasteful.
sys_get_midi_note_events(trackHandle, from, to)
Section titled “sys_get_midi_note_events(trackHandle, from, to)”Returns all note events whose start time falls in the half-open window
[from, to). Times are absolute seconds within the MIDI file.
| Parameter | Type | Description |
|---|---|---|
| trackHandle | opaque | Handle from sys_load_midi_file |
| from | number | Window start (seconds, MIDI-file-absolute) |
| to | number | Window end (seconds, MIDI-file-absolute) |
Each entry in the returned table:
| Field | Type | Description |
|---|---|---|
seconds | number | Note start time within the MIDI file |
duration | number | Note duration (seconds) |
channel | number | MIDI channel |
note | number | MIDI note number |
velo | number | Note-on velocity |
releaseVelo | number | Note-off velocity |
local notes = sys_get_midi_note_events(track, playbackPos, playbackPos + blockLen)for i, note in ipairs(notes) do -- note.seconds is the file-absolute time; convert to block-relative: sys_create_note_event(note.seconds - playbackPos, note.channel, note.note, note.velo, note.duration)endsys_get_midi_controller_events(trackHandle, from, to)
Section titled “sys_get_midi_controller_events(trackHandle, from, to)”Returns all controller events whose time falls in [from, to). Same time
conventions as sys_get_midi_note_events.
| Parameter | Type | Description |
|---|---|---|
| trackHandle | opaque | Handle from sys_load_midi_file |
| from | number | Window start (seconds, MIDI-file-absolute) |
| to | number | Window end (seconds, MIDI-file-absolute) |
Each entry in the returned table:
| Field | Type | Description |
|---|---|---|
seconds | number | Event time in the MIDI file |
channel | number | MIDI channel |
controller | number | CC number or special value (same range as sys_create_control_event) |
value | number | Controller value |
local ccs = sys_get_midi_controller_events(track, playbackPos, playbackPos + blockLen)for i, cc in ipairs(ccs) do sys_create_control_event(cc.seconds - playbackPos, cc.channel, cc.controller, cc.value)end