Keymaps¶
We have flows, we have a PlayEvent, but there's a missing piece: how does the framework know which flow to use when a key is pressed? Without that mapping, every key would do the same thing -- or nothing at all.
Keymaps connect MIDI keys to flows. They tell the framework: "when this key is pressed, send the voice into this flow." They also control the visual appearance of keys in Kontakt's keyboard display -- their colors, types, and labels.
Declaring a Keymap¶
Keymaps are declared inside cb Keymaps, which runs during every Reload (preset/snapshot load). This means keymaps are rebuilt from scratch each time a preset loads, giving you the flexibility to change key assignments based on the current state of the instrument.
Here's the basic setup:
node MyKeyboard:
cb Keymaps:
define KEYMAPS += my_keys
{ Map keys C2-C4 (MIDI 36-60) to my_flow }
declare i
for i := 36 to 60
keymap.request(my_keys, 0, i, ...
my_flow, ...
NI_KEY_TYPE_DEFAULT, KEY_COLOR_BLUE, "")
end for
end nodedefine KEYMAPS += registers your keymap category name, just like FLOWS and IVLS_NODES. You can have multiple categories in the same instrument.
keymap.request¶
keymap.request() is the function that assigns a key. Its arguments are:
keymap.request(category, map_index, key, flow, type, color, name)- category -- the keymap category name you registered with
KEYMAPS - map_index -- which map to register on (use
0for a single-map instrument) - key -- the MIDI key number (0-127)
- flow -- the flow to send voices into when this key is pressed
- type -- the Kontakt key type (controls how Kontakt displays and handles the key)
- color -- the Kontakt key color
- name -- an optional display name for the key
Key Types¶
Kontakt provides several key types that affect how a key behaves in the keyboard display:
NI_KEY_TYPE_DEFAULT-- a standard playable keyNI_KEY_TYPE_CONTROL-- a control/keyswitch key (displayed differently)NI_KEY_TYPE_NONE-- an inactive key (no visual indicator)
Key Colors¶
IVLS supports all of Kontakt's key colors:
KEY_COLOR_BLUE-- typically used for playable rangesKEY_COLOR_RED-- often used for keyswitches or selection keysKEY_COLOR_GREEN-- often used for the currently selected/active keyKEY_COLOR_CYAN-- used for highlighting special keys within a rangeKEY_COLOR_INACTIVE-- grayed out, indicating the key does nothing
The choice of color is purely visual -- it doesn't affect behavior. Use colors to communicate the purpose of each key region to the user.
Multi-Zone Keyboards¶
Production instruments rarely use a single uniform key range. Instead, they divide the keyboard into zones, each with its own purpose and flow. A common pattern used in instruments like Sylvan looks like this:
node MyKeyboard:
cb Keymaps:
define KEYMAPS += my_keys
declare i
for i := 0 to 127
if in_range(i, 36, 84)
{ Play range: these keys produce sound }
keymap.request(my_keys, 0, i, ...
my_play_flow, ...
NI_KEY_TYPE_DEFAULT, KEY_COLOR_BLUE, "")
else if in_range(i, 24, 35)
{ Selection range: these keys select a sound/preset }
keymap.request(my_keys, 0, i, ...
my_select_flow, ...
NI_KEY_TYPE_CONTROL, KEY_COLOR_RED, "")
else
{ Inactive: fill remaining keys }
keymap.request(my_keys, 0, i, ...
my_no_play_flow, ...
NI_KEY_TYPE_NONE, KEY_COLOR_INACTIVE, "")
end if
end for
end nodeThis gives you a play range (blue keys that trigger sounds), a selection range (red keys that act as controls), and inactive keys (grayed out) filling the rest of the keyboard.
Each zone points to a different flow, so pressing a key in the play range triggers different behavior than pressing a key in the selection range.
Keymap Rebuilding¶
Because cb Keymaps runs inside every Reload, keymaps are rebuilt from scratch each time a preset loads. The framework calls keymap.reboot() internally, which clears all existing key assignments and re-runs every node's cb Keymaps callback.
This means your keymap setup code can safely depend on the current state of the instrument. If a preset changes which notes are available, the keymap will reflect that on the next reload.
With keymaps in place, pressing a key will create a voice, route it into the correct flow based on the key mapping, and ultimately trigger a sound through your PlayEvent. You now have all the pieces for a working instrument: nodes, flows, a PlayEvent, and keymaps.