Callbacks
General Information
A callback is a section within a script that is being "called" (i.e. executed) at certain times.
All callbacks start with
on <callback-name>and end withend on.Callbacks can be stopped by using the
exitcommand.Each callback has a unique ID number which can be retrieved with
$NI_CALLBACK_ID.You can query which callback triggered a function with
$NI_CALLBACK_TYPEand the corresponding built-in constants.You can query which UI widget triggered a UI callback with
$NI_UI_IDand the corresponding built-in constants.
Examples
function show_callback_type()
if ($NI_CALLBACK_TYPE = $NI_CB_TYPE_NOTE)
message("Function was called from note callback!")
end if
if ($NI_CALLBACK_TYPE = $NI_CB_TYPE_CONTROLLER)
message("Function was called from controller callback!")
end if
end function
on note
call show_callback_type()
end on
on controller
call show_callback_type()
end onQuery the callback type in a function.
See Also
on async_complete
|
|---|
Async complete callback, triggered after the execution of any command that is executed asynchronously, for example various loading or saving related commands. |
Remarks
To resolve synchronization issues, the commands listed in the "See Also" section below return unique IDs when being used.
Upon completion of the command’s action, the
on async_completecallback gets triggered and the built-in variable$NI_ASYNC_IDis updated with the ID of the command that triggered the callback.If the command was completed successfully (for example if the file was found and successfully loaded), the internal value of
$NI_ASYNC_EXIT_STATUSis set to 1, otherwise it is 0.
Examples
on init
declare $load_midi_file_id
declare ui_button $load_midi_file
end on
on ui_control ($load_midi_file)
$load_midi_file_id := load_midi_file(<midi-file-path>)
while ($load_midi_file_id # -1)
wait(1)
end while
message("MIDI file loaded!")
end on
on async_complete
if ($NI_ASYNC_ID = $load_midi_file_id)
$load_midi_file_id := -1
end if
end onExample that pauses the ui_control callback until the file is loaded.
See Also
Music Information Retrieval: MIR Commands
Built-in Variables and Constants: $NI_ASYNC_EXIT_STATUS, $NI_ASYNC_ID
Module Types and Subtypes: $ENGINE_PAR_EFFECT_TYPE, $ENGINE_PAR_EFFECT_SUBTYPE
on controller
|
|---|
MIDI controller callback, executed whenever a MIDI CC, Pitch Bend or Channel Pressure message is received. |
Examples
on controller
if (in_range($CC_NUM, 0, 127))
message("CC Number: " & $CC_NUM & " - Value: " & %CC[$CC_NUM])
else
if ($CC_NUM = $VCC_PITCH_BEND)
message("Pitch Bend - Value: " & %CC[$CC_NUM])
end if
if ($CC_NUM = $VCC_MONO_AT)
message("Channel Pressure - Value: " & %CC[$CC_NUM])
end if
end if
end onQuery MIDI CC, Pitch Bend and Channel Pressure data.
See Also
Events and MIDI: %CC[], $CC_NUM, $VCC_PITCH_BEND, $VCC_MONO_AT
on init
|
|---|
Initialization callback, executed when the script was successfully compiled without warnings or errors. |
Remarks
The on init callback will be executed when:
The "Apply" button is clicked in Script Editor.
Script preset or an instrument are loaded.
Kontakt's audio engine is restarted by clicking the "Restart Engine" button in the Monitor > Engine tab, or "!" button in Kontakt's header.
Snapshot is loaded with
set_snapshot_type()set to 0 or 2Creator Tools is connected to a Kontakt instance, and GUI Designer's performance view file is resaved. In this case, the scripts are reinitialized automatically in order to update the performance view with most recent changes.
Examples
on init
declare ui_button $Sync
declare ui_menu $Time
add_menu_item($Time, "16th", 0)
add_menu_item($Time, "8th", 1)
$Sync := 0 { sync is off by default, so hide menu }
move_control($Time, 0, 0)
move_control($Sync, 1, 1)
make_persistent($Sync)
make_persistent($Time)
read_persistent_var ($Sync)
if ($Sync = 1)
move_control($time, 2, 1)
else
move_control($Time, 0, 0)
end if
end on
on ui_control ($Sync)
if ($Sync = 1)
move_control($Time, 2, 1)
else
move_control($Time, 0, 0)
end if
end oninit callback with read_persistent_var().
on init
declare ui_button $Sync
declare ui_menu $Time
move_control($Sync, 1, 1)
add_menu_item($Time, "16th", 0)
add_menu_item($Time, "8th", 1)
make_persistent($Sync)
make_persistent($Time)
end on
function show_menu()
if ($Sync = 1)
move_control($Time, 2, 1)
else
move_control($Time, 0, 0)
end if
end function
on persistence_changed
call show_menu()
end on
on ui_control ($Sync)
call show_menu()
end onThe same script functionality, now with persistence_changed callback. This is the preferred method to use, especially when utilizing snapshots!
See Also
on listener
|
|---|
Listener callback, executed at definable time intervals or whenever a transport command is received. |
Remarks
The listener callback is executed at time intervals defined with the
set_listener()command. It can also react to the host's transport start and stop commands. This makes it the ideal callback for anything tempo-synced, like sequencers, arpeggiators, MIDI file players etc.In some situations (like tempo changes within the host), ticks can be occasionally left out.
Examples
on init
declare ui_knob $Test (0, 99, 1)
declare $direction
declare $tick_counter
set_listener($NI_SIGNAL_TIMER_MS, 10000)
end on
on listener
if ($NI_SIGNAL_TYPE = $NI_SIGNAL_TIMER_MS)
if ($direction = 0)
inc($tick_counter)
else
dec($tick_counter)
end if
$Test := $tick_counter
if ($tick_counter = 99)
$direction := 1
end if
if ($tick_counter = 0)
$direction := 0
end if
end if
end onNot useful as such, but nice to look at.
See Also
Callbacks and UI: $NI_SIGNAL_TYPE, $NI_SONG_POSITION
on note
|
|---|
Note callback, executed whenever a MIDI Note On message is received. |
Examples
on note
message("Note Number: " & $EVENT_NOTE & " - Velocity: " & $EVENT_VELOCITY)
end onQuery note properties.
See Also
Events and MIDI: $EVENT_NOTE, $EVENT_VELOCITY, $EVENT_ID
on note_controller
|
|---|
MIDI 2.0 per-note controller callback, executed whenever a MIDI 2.0 Registered Per-Note Controller, MIDI 2.0 Assignable Per-Note Controller, or MIDI 2.0 Per-Note Pitch Bend message is received. |
Remarks
Currently, these messages can only be generated internally by KSP in one script slot, then acted upon in another script slot. Kontakt does not yet receive MIDI 2.0 messages from the outside.
Examples
on init
set_ui_height(3)
declare $i
declare %black[5] := (1, 3, 6, 8, 10)
declare %key_id[128]
declare ui_label $L (1, 1)
declare ui_table %Active[61] (6, 1, 1)
declare ui_table %BG[61] (6, 1, 1)
declare ui_table %KB[61] (6, 1, -8191)
set_control_par(get_ui_id(%KB), $CONTROL_PAR_HIDE, $HIDE_PART_BG .or. $HIDE_PART_VALUE)
set_control_par(get_ui_id(%KB), $CONTROL_PAR_WIDTH, 555)
set_control_par(get_ui_id(%KB), $CONTROL_PAR_HEIGHT, 110)
set_control_par(get_ui_id(%BG), $CONTROL_PAR_HIDE, $HIDE_PART_BG)
set_control_par(get_ui_id(%BG), $CONTROL_PAR_WIDTH, 555)
set_control_par(get_ui_id(%BG), $CONTROL_PAR_HEIGHT, 110)
set_control_par(get_ui_id(%BG), $CONTROL_PAR_BAR_COLOR, 0777777H)
set_control_par(get_ui_id(%Active), $CONTROL_PAR_WIDTH, 555)
set_control_par(get_ui_id(%Active), $CONTROL_PAR_HEIGHT, 110)
set_control_par(get_ui_id(%Active), $CONTROL_PAR_BAR_COLOR, 0AAAAAAH)
set_control_par(get_ui_id($L), $CONTROL_PAR_HIDE, $HIDE_PART_BG)
set_control_par(get_ui_id($L), $CONTROL_PAR_WIDTH, 560)
set_control_par(get_ui_id($L), $CONTROL_PAR_FONT_TYPE, 19)
set_text($L, "C1 " & ...
"C2 " & ...
"C3 " & ...
"C4 " & ...
"C5 " & ...
"C6")
while ($i < num_elements(%BG))
if (search(%black, $i mod 12) # -1)
%BG[$i] := 1
end if
inc($i)
end while
move_control_px($L, 55, 0)
move_control_px(%BG, 62, 15)
move_control_px(%Active, 62, 15)
move_control_px(%KB, 62, 15)
end on
on note
{ make sure we only have one event per key }
if (event_status(%key_id[$EVENT_NOTE]) = $EVENT_STATUS_NOTE_QUEUE)
fade_out(%key_id[$EVENT_NOTE], 1000, 1)
end if
%key_id[$EVENT_NOTE] := $EVENT_ID
set_note_controller($VNC_PITCH_BEND, $EVENT_NOTE, %KB[$EVENT_NOTE - 36])
if (in_range($EVENT_NOTE, 36, 96))
%Active[$EVENT_NOTE - 36] := 1
end if
end on
on release
if (in_range($EVENT_NOTE, 36, 96))
%Active[$EVENT_NOTE - 36] := 0
end if
end on
on ui_control (%KB)
set_note_controller($VNC_PITCH_BEND, 36 + $NI_CONTROL_PAR_IDX, %KB[$NI_CONTROL_PAR_IDX])
end onon init
declare const $BEND_RANGE := 2
declare $i
declare %events[128]
end on
on note
%events[$EVENT_NOTE] := $EVENT_ID
end on
on note_controller
if ($NC_NUM = $VNC_PITCH_BEND and in_range($NC_NOTE, 36, 96))
change_tune(%events[$NC_NOTE], int(real($NC_VALUE) * 12.208522) * $BEND_RANGE, 0)
end if
end onAn example of MIDI 2.0 Per-Note Pitch Bend communication between two script slots.
See Also
Events and MIDI: $VNC_PITCH_BEND
on persistence_changed
|
|---|
Executed after the |
Remarks
This callback is called whenever the persistent variables change in an instrument, i.e. it is always executed after the
on initcallback, and/or upon loading a snapshot.
Examples
on init
set_snapshot_type(1) { init callback not executed upon snapshot loading }
reset_ksp_timer
declare $init_flag { 1 if init callback has been executed, 0 otherwise }
$init_flag := 1
declare ui_label $label (2, 2)
set_text($label, "Init callback " & $KSP_TIMER)
end on
function add_text()
add_text_line($label, "Persistence changed callback " & $KSP_TIMER)
end function
on persistence_changed
if ($init_flag = 1) { instrument has been loaded }
call add_text()
else { snapshot has been loaded }
set_text($label, "Snapshot loaded!")
end if
$init_flag := 0
end onQuery if a snapshot or instrument has been loaded. This also demonstrates the ability to call functions upon initialization, i.e. the persistence callback acts as an extension to the init callback.
See Also
on pgs_changed
|
|---|
Executed whenever any |
Remarks
PGS stands for Program Global Storage and is a means of communication between script slots. See the chapter on PGS for more details.
Examples
on init
pgs_create_key(FIRST_KEY, 1) { defines a key with 1 element }
pgs_create_key(NEXT_KEY, 128) { defines a key with 128 elements }
declare ui_button $Push
end on
on ui_control($Push)
pgs_set_key_val(FIRST_KEY, 0, 70 * $Push)
pgs_set_key_val(NEXT_KEY, 0, 50 * $Push)
pgs_set_key_val(NEXT_KEY, 127, 60 * $Push)
end onPressing the button...
on init
declare ui_knob $First (0, 100, 1)
declare ui_table %Next[128] (5, 2, 100)
end on
on pgs_changed
{ checks if FIRST_KEY and NEXT_KEY have been declared }
if (pgs_key_exists(FIRST_KEY) and pgs_key_exists(NEXT_KEY))
$First := pgs_get_key_val(FIRST_KEY, 0)
%Next[0] := pgs_get_key_val(NEXT_KEY, 0)
%Next[127] := pgs_get_key_val(NEXT_KEY, 127)
end if
end on…will change the controls in this example, regardless of the script slot order.
See Also
PGS: pgs_create_key(), pgs_set_key_val(), pgs_get_key_val()
on poly_at
|
|---|
Polyphonic aftertouch callback, executed whenever a MIDI Polyphonic Aftertouch message is received. |
Examples
on init
declare %note_id[128]
end on
on note
%note_id[$EVENT_NOTE] := $EVENT_ID
end on
on poly_at
change_tune(%note_id[$POLY_AT_NUM], %POLY_AT[$POLY_AT_NUM] * 1000, 0)
end onA simple poly aftertouch to pitch implementation.
See Also
Events and MIDI: %POLY_AT[], $POLY_AT_NUM, $VCC_MONO_AT
on release
|
|---|
Release callback, executed whenever a MIDI Note Off message is received. |
Examples
on init
declare polyphonic $new_id
end on
on release
wait(1000)
$new_id := play_note($EVENT_NOTE, $EVENT_VELOCITY, 0, 100000)
change_vol($new_id, -24000, 1)
end onCreating an artificial release triggered noise.
See Also
get_event_par(): $EVENT_PAR_REL_VELOCITY
on rpn/nrpn
|
|---|
RPN and NRPN callbacks, executed whenever a MIDI RPN or NRPN (registered/non-registered parameter number) message is received. |
Examples
on rpn
select ($RPN_ADDRESS)
case 0
message("Pitch Bend Sensitivity" & " - Value: " & $RPN_VALUE)
case 1
message("Fine Tuning" & " - Value: " & $RPN_VALUE)
case 2
message("Coarse Tuning" & " - Value: " & $RPN_VALUE)
end select
end onQuery standard RPN messages.
See Also
Events and MIDI: $RPN_ADDRESS, $RPN_VALUE
on ui_control
|
|---|
UI callback, executed whenever the user interacts with a particular UI widget. |
Examples
on init
declare ui_knob $Knob (0, 100, 1)
declare ui_button $Button
declare ui_switch $Switch
declare ui_table %Table[10] (2, 2, 100)
declare ui_menu $Menu
declare ui_value_edit $VEdit (0, 127, 1)
declare ui_slider $Slider (0, 100)
add_menu_item($Menu, "Entry 1", 0)
add_menu_item($Menu, "Entry 2", 1)
end on
on ui_control ($Knob)
message("Knob" & " (" & $ENGINE_UPTIME & ")")
end on
on ui_control ($Button)
message("Button" & " (" & $ENGINE_UPTIME & ")")
end on
on ui_control ($Switch)
message("Switch" & " (" & $ENGINE_UPTIME & ")")
end on
on ui_control (%Table)
message("Table" & " (" & $ENGINE_UPTIME & ")")
end on
on ui_control ($Menu)
message("Menu" & " (" & $ENGINE_UPTIME & ")")
end on
on ui_control ($VEdit)
message("Value Edit" & " (" & $ENGINE_UPTIME & ")")
end on
on ui_control ($Slider)
message("Slider" & " (" & $ENGINE_UPTIME & ")")
end onVarious UI controls and their corresponding UI callbacks.
See Also
Callbacks And UI: $NI_UI_ID
Control Parameters: $CONTROL_PAR_CUSTOM_ID, $CONTROL_PAR_TYPE
on ui_controls
|
|---|
Global UI callback, executed whenever the user interacts with any particular UI widget. |
Remarks
When interacting with a particular UI widget, this callback will always be executed first, then the individually declared
on ui_controlcallback (if it exists).Intended use of this callback type is to provide a more general approach of dealing with UI widgets, and also allowing for a sort of separation between the UI widgets (the Controller) and actual parameter data (the Model), according to MVC methodology (where UI widget covers the Controller and View parts). This results in UI widgets generally not needing to be made persistent, instead all parameter data could be held in a single persistent array (or two, in case of mixing integer and real values in the Model). As a consequence of not requiring persistence, variable names of UI widgets - and even widget types themselves - can change without affecting the state of the data in the script.
Examples
on init
message("")
set_snapshot_type(3)
declare const $NUM_PARAMS := 4
declare const $FILT_SLOT := 0
declare $i
declare $param_idx
declare @str
{ this array actually holds our parameter values, not the widgets,
and it's the only persistent variable! }
declare %params[$NUM_PARAMS] := (1000000, 0, 630000, 500000)
make_persistent(%params)
declare const $FILT_CUT := 0
declare const $FILT_RES := 1
declare const $OUT_VOL := 2
declare const $OUT_PAN := 3
declare ui_slider $Cut (0, 1000000)
declare ui_slider $Res (0, 1000000)
declare ui_slider $Vol (0, 1000000)
declare ui_slider $Pan (0, 1000000)
{ link between parameter indices and UI IDs }
declare %pidx_to_uid[$NUM_PARAMS]
%pidx_to_uid[$FILT_CUT] := get_ui_id($Cut)
%pidx_to_uid[$FILT_RES] := get_ui_id($Res)
%pidx_to_uid[$OUT_VOL] := get_ui_id($Vol)
%pidx_to_uid[$OUT_PAN] := get_ui_id($Pan)
{ this is a quick example of course, but you can easily see how this can be used
to scale up to larger instruments, since UI IDs can get out of order, but this
doesn't matter when $CONTROL_PAR_CUSTOM_ID holds the "pointer" to the actual
parameter index }
$i := 0
while ($i < $NUM_PARAMS)
set_control_par(%pidx_to_uid[$i], $CONTROL_PAR_CUSTOM_ID, $i)
{ set the default values for first time script apply case, optionally }
set_control_par(%pidx_to_uid[$i], $CONTROL_PAR_VALUE, %params[$i])
inc($i)
end while
{ set up a filter in group 1 so that we have something to work with }
set_engine_par($ENGINE_PAR_EFFECT_TYPE, $EFFECT_TYPE_FILTER, 0, $FILT_SLOT, -1)
end on
function SetParam()
select ($param_idx)
case $FILT_CUT
set_engine_par($ENGINE_PAR_CUTOFF, %params[$param_idx], 0, $FILT_SLOT, -1)
case $FILT_RES
set_engine_par($ENGINE_PAR_RESONANCE, %params[$param_idx], 0, $FILT_SLOT, -1)
case $OUT_VOL
set_engine_par($ENGINE_PAR_VOLUME, %params[$param_idx], 0, -1, -1)
case $OUT_PAN
set_engine_par($ENGINE_PAR_PAN, %params[$param_idx], 0, -1, -1)
end select
end function
function SetLabel()
select ($param_idx)
case $FILT_CUT
@str := get_engine_par_disp($ENGINE_PAR_CUTOFF, 0, $FILT_SLOT, -1) & " Hz"
case $FILT_RES
@str := get_engine_par_disp($ENGINE_PAR_RESONANCE, 0, $FILT_SLOT, -1) & " %"
case $OUT_VOL
@str := get_engine_par_disp($ENGINE_PAR_VOLUME, 0, -1, -1) & " dB"
case $OUT_PAN
@str := get_engine_par_disp($ENGINE_PAR_PAN, 0, -1, -1)
end select
set_control_par_str(%pidx_to_uid[$param_idx], $CONTROL_PAR_LABEL, @str)
end function
on persistence_changed
{ easy refreshing of parameter values and automation labels! }
$i := 0
while ($i < $NUM_PARAMS)
$param_idx := $i
call SetParam()
call SetLabel()
set_control_par(%pidx_to_uid[$i], $CONTROL_PAR_VALUE, %params[$i])
inc($i)
end while
end on
{ that's all you need, no need to write individual callbacks anymore! }
on ui_controls
$param_idx := get_control_par($NI_UI_ID, $CONTROL_PAR_CUSTOM_ID)
%params[$param_idx] := get_control_par($NI_UI_ID, $CONTROL_PAR_VALUE)
call SetParam()
call SetLabel()
end onA small showcase of benefits provided by the on ui_controlscallback.
See Also
Callbacks And UI: $NI_UI_ID
Control Parameters: $CONTROL_PAR_CUSTOM_ID, $CONTROL_PAR_TYPE
on ui_update
|
|---|
UI update callback, executed with every GUI change in Kontakt. |
Remarks
This callback can be executed very often in Kontakt, so use it with caution!
Examples
on init
declare ui_knob $Volume (0, 1000000, 1)
set_knob_unit($Volume, $KNOB_UNIT_DB)
set_knob_defval($Volume, 630000)
$Volume := get_engine_par($ENGINE_PAR_VOLUME, -1, -1, -1)
set_knob_label($Volume, get_engine_par_disp($ENGINE_PAR_VOLUME, -1, -1, -1))
end on
on ui_update
$Volume := get_engine_par($ENGINE_PAR_VOLUME, -1, -1, -1)
set_knob_label($Volume, get_engine_par_disp($ENGINE_PAR_VOLUME, -1, -1, -1))
end on
on ui_control ($Volume)
set_engine_par($ENGINE_PAR_VOLUME, $Volume, -1, -1, -1)
set_knob_label($Volume, get_engine_par_disp($ENGINE_PAR_VOLUME, -1, -1, -1))
end onMirroring instrument volume with a KSP control.