Event Types
Identifying Event Types
Section titled “Identifying Event Types”Event types are not strings. Each type is an opaque Lua light userdata value. To
compare against a type you read it from the global sys_event_types table:
if event.type == sys_event_types.noteOn then -- handle note onendThe full set of keys in sys_event_types:
sys_event_types = { none, -- sentinel / untyped noteOn, noteOff, controller, timer, script,}Never compare against string literals — always use sys_event_types.
Common Fields
Section titled “Common Fields”Every event sub-table has these two fields regardless of type:
| Field | Type | Description |
|---|---|---|
id | opaque | Unique event handle; passed to all manipulate/dispose functions |
type | opaque | Event type; compare against sys_event_types |
offset | number | Position of the event within the current render block (seconds) |
noteOn
Section titled “noteOn”Fired when a key is pressed or a note is triggered programmatically.
| Field | Type | Description |
|---|---|---|
channel | number | MIDI channel (1–16) |
note | number | MIDI note number (0–127) |
velocity | number | Note velocity (0–127) |
function onProcessEvents(blockLen, events) for i, event in ipairs(events) do if event.type == sys_event_types.noteOn then local ch = event.channel local nn = event.note local vel = event.velocity end endendnoteOff
Section titled “noteOff”Fired when a key is released.
| Field | Type | Description |
|---|---|---|
channel | number | MIDI channel (1–16) |
note | number | MIDI note number (0–127) |
velocity | number | Release velocity (0–127) |
controller
Section titled “controller”Represents an instantaneous controller state change: a CC message, pitch bend, or aftertouch.
| Field | Type | Description |
|---|---|---|
channel | number | MIDI channel (1–16) |
controller | number | Controller number (CC number, or system-defined index) |
value | number | Controller value |
A timer event is generated by the script itself, not from incoming MIDI. It
carries no additional fields beyond type and offset. The ID of the event is
the same handle used to create and cancel the timer.
Timer creation and management are covered in Timers and Envelopes.
script
Section titled “script”A script event is created by an upstream script to carry an arbitrary payload to downstream processors. It travels through the event queue like any other event.
| Field | Type | Description |
|---|---|---|
data | any | The payload passed to sys_create_script_event |
-- Upstream script: tag the stream with articulation contextsys_create_script_event(event.offset, { isLegato = true })
-- Downstream script: read the payloadif event.type == sys_event_types.script then local payload = event.dataendSee Script Events for the full usage pattern.
The Event Table
Section titled “The Event Table”onProcessEvents receives a sequence table (indices 1..n). Each entry is an
event sub-table that includes an id field carrying the event’s unique handle.
The id is the argument used by all functions that manipulate or emit events.
Iterate with ipairs:
function onProcessEvents(blockLen, events) for i, event in ipairs(events) do -- event.id : unique event handle -- event.type : compare against sys_event_types -- event.offset: block-relative time (seconds) -- ...type-specific fields endendnoteOn and noteOff share an ID
Section titled “noteOn and noteOff share an ID”A noteOn and its matching noteOff carry the same event.id because they
refer to the same underlying engine event. This is intentional — it is the
mechanism used to finalize a note’s length when the release arrives (see
Your First Script for a worked example).