Skip to content

Compile-Time Code Generation

IVLS-KSP provides compile-time code generation via literate macros, callback injection, and voice logic generation. These directives are processed by the ivls-sksp compiler before conversion to native KSP.


Literate Macros

literate_macro(pattern) on LIST

Iterates over a comma-separated list and expands a pattern for each item.

Placeholder Description
#l# Current list item (literal value)
#n# Current index (0-based)
define IVLS_ALL_NODES := Ivls.NodeUI, Ivls.VoiceOps, Ivls.Flows

family ivls
    const node
        literate_macro(#l#) on IVLS_ALL_NODES
    end const
end family
define DEBUGS := Audio, MIDI, UI
literate_macro(debug.category_names[debug.category.#l#] := "#l#") on DEBUGS

When the pattern lacks #l#, it is called as a macro with the list item as argument:

literate_macro(Voice.WriteInitList) on Voice.INIT_LIST
// Expands to: Voice.WriteInitList(Voice.BASE_INIT), Voice.WriteInitList(Voice.ADD_INIT)

literate_post_macro(pattern) on LIST

Processed after regular macro expansion -- use when the list is itself defined by macros:

macro ivls.MakeArgs(#node#)
    const args
        literate_post_macro(#l#) on #node#.Args
    end const
end macro

Callback Injection

__RUN_CB__(CallbackName)

Injects code from all nodes that define the named callback:

on init
    __RUN_CB__(Init)
    __RUN_CB__(ICB)
    __RUN_CB__(PostInit)
    __RUN_CB__(Post_ICB)
end on

__VIRTUAL__(Name)

Defines an extension point in a base node that child nodes can override:

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

node Stl.PlayEvent from Stl.PlayEvent.Template:
    cb EventArgs:
        event.note := event.note + 12
    cb EventGroups:
        event.groups[0] := TRUE
end node

The compiler replaces each __VIRTUAL__(Name) with the corresponding cb Name: block from the child node.


Voice Logic Generation

__DECLARE_VOICE_LOGIC__ / __SELECT_VOICE_LOGIC__

Generates voice logic taskfuncs and dispatch case statements for all nodes with NoteOn/NoteOff callbacks:

// Generated pattern:
taskfunc ivls.NodeName.VoiceLogic(var self, var self_invalid, var user_continue, var passed_vo, nenv)
    if NodeEnv[nenv].input_type = ivls.input_type.VOICE_ON
        // NoteOn callback code
    else if NodeEnv[nenv].input_type = ivls.input_type.VOICE_OFF
        // NoteOff callback code
    end if
end taskfunc

select NodeEnv[nenv].node_id
    __SELECT_VOICE_LOGIC__
end select

__DECLARE_VOICE_PASS__ / __SELECT_VOICE_PASS__

Same pattern for nodes with NotePass callbacks.

__CACHE_PASSES__ / __CACHE_OFFS__

Generate lookup tables marking which nodes support pass-through or note-off behavior:

declare node_passes[ivls.node.SIZE] := (FALSE)
__CACHE_PASSES__
// Sets ivls.node_passes[ivls.node.NodeWithPass] := TRUE for each applicable node

Processing Order

  1. Define substitution -- define constants resolved
  2. Literate macro expansion -- literate_macro directives expanded
  3. Regular macro expansion -- standard macros expanded
  4. Post macro expansion -- literate_post_macro directives expanded
  5. Node assembly -- node callbacks parsed, inheritance resolved
  6. Callback injection -- __RUN_CB__ directives inject node code
  7. Voice logic generation -- __DECLARE_* / __SELECT_* generate dispatch code
  8. Caching -- __CACHE_* directives generate lookup tables

See Also

  • Macros - Standard macro system
  • Nodes - Node declaration and inheritance
  • Callbacks - Callback system overview
  • Defines - Define constant system