Skip to content

API Reference

This chapter is the complete reference for every function and global available in an RT script’s Lua environment.

The following Lua standard libraries are available:

LibraryNotes
baseprint, pairs, ipairs, type, …
tabletable.insert, table.remove, …
stringstring.format, string.find, …
mathmath.floor, math.random, …
utf8UTF-8 aware string utilities

No file I/O, OS, or debug libraries are available.


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_BLOCK

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.value

Do not read .value at top-level script load time — it is only valid inside callbacks.

TypeContinuousTypical range / notes
volumeyesdB scale
timeMsyesmilliseconds
tuneStyessemitones (float)
frequencyHzyesHz
percentyes0–100
panyes−1 to +1 or similar
genericIntyesarbitrary integer range
intervalyessemitone interval (integer)
noteyesMIDI note number range
genericFloatyesarbitrary float range
onOffnoboolean; no min/max
genericStringnostring value; no min/max

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.

ParameterTypeDescription
blockLennumberDuration of the current render block (seconds)
eventstableAll 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
end
end

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.

ParameterTypeDescription
blockLennumberDuration of the current render block (seconds)
function onProcessBlock(blockLen)
-- called every block, with or without events
end

onProcessEvents and onProcessBlock are independent. Defining one does not affect whether the other is called.


Global table of opaque type constants. Always use these for type comparisons — never compare against string literals.

sys_event_types.none
sys_event_types.noteOn
sys_event_types.noteOff
sys_event_types.controller
sys_event_types.timer
sys_event_types.script

Removes an event from the queue. The event will not be forwarded to the next processor. Also used to stop a recurring timer.

ParameterTypeDescription
eventIdopaqueID returned by a create function, or the id key from the events table
sys_dispose_event(event.id)

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 emit
end

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.

ParameterTypeDescription
offsetnumberBlock-relative end position of the note (seconds)
eventIdopaqueID of the note event to finalize (returned by sys_create_note_event)
sys_set_note_length(event.offset, createdNoteId)

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.

ParameterTypeDescription
eventIdopaqueID 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.).

ParameterTypeDescription
eventIdopaqueID of the note event to redirect
zoneMapUidstringUID 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
end
end

The zone map UID is copied from the editor’s zone map view.


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.

ParameterTypeDescription
offsetnumberBlock-relative time of the event (seconds)
channelnumberMIDI channel (1–16)
notenumberMIDI note number (0–127)
velocitynumberVelocity (0–127)
lengthnumber or nilDuration 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 long
local 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.

ParameterTypeDescription
offsetnumberBlock-relative time of the event (seconds)
channelnumberMIDI channel (1–16)
controllernumberCC number (0–127) or special value (see below)
valuenumberController value

Special controller values:

ConstantValueNotes
Standard CC0–127Standard MIDI CC number
pitchBend128Value range 0–16383; neutral position is 8192
afterTouch129
channelPressure130
-- CC 74 (brightness)
sys_create_control_event(event.offset, 1, 74, 64)
-- pitch bend to neutral
sys_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.

ParameterTypeDescription
offsetnumberBlock-relative time of the first firing (seconds)
intervalnumberTime between firings (seconds)
numIterationsnumber or nilNumber 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 seconds
local timerId = sys_create_timer_event(0, 0.5, 1)
-- fire every 0.25 seconds indefinitely
local timerId = sys_create_timer_event(0, 0.25, nil)
-- stop the timer later
sys_dispose_event(timerId)

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 table
sys_log(scriptInfo) -- inspect all parameters and their current values

Returns a table describing the current state of the host transport.

FieldTypeDescription
sampleRatenumberCurrent sample rate (Hz)
isPlayingbooleanHost transport is playing
isRecordingbooleanHost is recording
isLoopingbooleanLoop mode is active
playPositionnumberCurrent playhead position (seconds)
songTemponumberCurrent tempo (BPM)
signatureNumnumberTime signature numerator
signatureDenomnumberTime signature denominator
local host = sys_get_host_info()
if host.isPlaying then
sys_log("tempo: " .. host.songTempo .. " BPM")
end

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 beat
local timerId = sys_create_timer_event(0, qn, nil)

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.

ParameterTypeDescription
offsetnumberBlock-relative time coordinate of the breakpoint (seconds)
linkedEventIdopaqueID of the note event this envelope is attached to
targetUidstringModulation target — a sys_default_target_uids value or a script modulator component UID
valuenumberEnvelope 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 duration
local 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)

Global table of built-in modulation target UIDs for use with sys_create_custom_control_event.

KeyTarget
sourceVolumeVolume of the PCM source
sourceTuneTuning of the PCM source

For other modulation targets, pass the component UID of a script modulator configured in the layer.

sys_default_target_uids.sourceVolume
sys_default_target_uids.sourceTune

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.

ParameterTypeDescription
parameterUidstringUID of the parameter to write, or its name if it has one
valueanyNew 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 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).

ParameterTypeDescription
namestringParameter 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.

ParameterTypeDescription
parameterUidstringUID of the parameter to watch, or its name if it has one
callbackfunctionCalled 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 parameter
local 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 call
local function sync(value) sys_log("mode: " .. tostring(value)) end
sync(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.

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.

ParameterTypeDescription
parameterUidstringUID 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/onProcessBlock
local startupValue = sys_get_parameter_value(uid)

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.

Creates a new event of type script and adds it to the queue.

ParameterTypeDescription
offsetnumberBlock-relative time of the event (seconds)
payloadanyLua value to carry (number, boolean, string, table, …)

Returns the event ID of the created event.

-- Flag the next note as legato
sys_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
end
end

Script events have the same common fields as all other events (id, type, offset) plus one extra:

FieldTypeDescription
dataanyThe value passed as payload at create time

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.

ParameterTypeDescription
componentUidstringUID of the target processor component (from layer editor)
presetUidstringUID 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")

Loads a MIDI file from the instrument’s custom assets. Returns an index-based table with one entry per MIDI track.

ParameterTypeDescription
assetNamestringName of the MIDI asset to load

Each entry in the returned table:

FieldTypeDescription
trackHandleopaqueHandle passed to the query functions
durationnumberTrack duration (seconds)
numNoteEventsnumberTotal note events in the track
numControllerEventsnumberTotal controller events in the track
local tracks = sys_load_midi_file("my_sequence.mid")
local track = tracks[1].trackHandle
local trackLen = tracks[1].duration

Call 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.

ParameterTypeDescription
trackHandleopaqueHandle from sys_load_midi_file
fromnumberWindow start (seconds, MIDI-file-absolute)
tonumberWindow end (seconds, MIDI-file-absolute)

Each entry in the returned table:

FieldTypeDescription
secondsnumberNote start time within the MIDI file
durationnumberNote duration (seconds)
channelnumberMIDI channel
notenumberMIDI note number
velonumberNote-on velocity
releaseVelonumberNote-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)
end

sys_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.

ParameterTypeDescription
trackHandleopaqueHandle from sys_load_midi_file
fromnumberWindow start (seconds, MIDI-file-absolute)
tonumberWindow end (seconds, MIDI-file-absolute)

Each entry in the returned table:

FieldTypeDescription
secondsnumberEvent time in the MIDI file
channelnumberMIDI channel
controllernumberCC number or special value (same range as sys_create_control_event)
valuenumberController 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