Skip to content

Nodes

Nodes are the fundamental organizational unit in IVLS. They encapsulate state, callbacks, functions, and macros into modules that are registered and dispatched by the IVLS system.

Declaration

node NodeName:
    cb CallbackName:
        // code
end node

Callbacks end implicitly when the next cb begins or end node is reached.

Minimal Example

{{ MyNode }}

node MyNode:
    cb Init:
        family mn
            declare value := 0
        end family
    cb NoteOn:
        ivls.SendSelf()
    cb Functions:
        function mn.process(x) -> result
            result := x * mn.value
        end function
end node

Inheritance

Nodes inherit from parent nodes using from. The child can override or extend virtual callbacks.

node ChildNode from ParentNode:
    // child body
end node

Virtual Callbacks (__VIRTUAL__, __PARENT__)

The parent defines extension points with __VIRTUAL__(). The child provides implementations:

node Stl.PlayEvent.Template:
    cb NoteOn:
        declare event.note := Voice[self].note
        declare event.vel := Voice[self].vel
        __VIRTUAL__(EventArgs)
        Voice[self].event := play_note(event.note, event.vel, 0, 0)
        __VIRTUAL__(EventGroups)

    cb NoteOff:
        __VIRTUAL__(EventDismiss)
end node

node Stl.PlayEvent from Stl.PlayEvent.Template:
    cb Init:
        family event
            declare groups[10000] := (FALSE)
        end family
    cb EventArgs:
        __RUN_CB__(EventArgs)
    cb EventGroups:
        __RUN_CB__(EventGroups)
    cb EventDismiss:
        __RUN_CB__(EventDismiss)
end node

The compiler replaces __VIRTUAL__(EventArgs) in the template with the child's cb EventArgs: body.


Callback Blocks

Category Callbacks
Lifecycle Init, ICB, PostInit, Post_ICB
Persistence FirstLoad, Pre_PCCB/PreReload, PCCB/Reload, Post_PCCB/PostReload
Voice NoteOn, NoteOff, NotePass
Events KNCB, KRCB, CC, PolyAT
Timers LCB, TimerMsTick, TimerBeatTick, TransportStart, TransportStop
UI KUI/KUICB, UICBS, UIOpen, UIClose
Async ACCB/AsyncResponse, PGS
Codegen Functions, Macros, Flows, Keymaps
Lifecycle hooks VoiceConstructor, VoiceDestructor, VoiceCopyConstructor, PathCancellation
node Stl.Midi:
    cb Init:
        family midi
            declare const NOTES := 128
            declare last_note
            declare last_vel
        end family
    cb CC:
        midi.cc[MIDI_CHANNEL, CC_NUM] := CC[CC_NUM]
    cb KNCB:
        midi.last_note := EVENT_NOTE
        midi.last_vel := EVENT_VELOCITY
    cb Functions:
        function midi.get_note_octave(note) -> oct
            oct := (note / 12)
        end function
end node

Namespacing

IVLS uses dot-notation for node names. At compilation, dots become double underscores.

Namespace Purpose
Ivls.* Core IVLS framework
Stl.* Standard Library
Ext.* Extended Library
Custom Application-specific

Template Pattern

node Stl.PlayEvent.Template:
    cb NoteOn:
        // base implementation with __VIRTUAL__() hooks
end node

node Stl.PlayEvent from Stl.PlayEvent.Template:
    cb EventArgs:
        // override virtual callback
end node

The {{ NodeName }} Comment Convention

A visual delimiter placed before node declarations for navigation:

{{ Stl.Lib }}

node Stl.Lib:
    cb Init:
        set_ui_color(0666666h)
        declare bool_validator
    cb Functions:
        function lib.is_dev_mode() -> result
            result := dev_mode[0]
        end function
end node

{{ Stl.Lib_Post }}

node Stl.Lib_Post:
    cb Init:
        if use_ram_report = TRUE
            message("Object RAM Load: " & TO_MB(lib_mem) & " MB")
        end if
end node

Node Registration

Nodes must be registered via the IVLS_ALL_NODES define to participate in callback dispatch:

define IVLS_BASE_NODES := Ivls.NodeUI, Ivls.STL, Ivls.VoiceOps, ...
define IVLS_NODES := MyApp.Core, MyApp.Synth, MyApp.UI
define IVLS_ALL_NODES := IVLS_BASE_NODES, IVLS_NODES, Stl.Lib_Post

Registration generates:

// Node ID constants
family ivls
    const node
        literate_macro(#l#) on IVLS_ALL_NODES
    end const
end family

// Node name strings
declare !node_names[ivls.node.SIZE]
literate_macro(ivls.node_names[ivls.node.#l#] := "#l#") on IVLS_ALL_NODES

Registration order determines callback execution order and node IDs.


See Also