How to Add Round Robins¶
Set up round-robin sample cycling so that repeated notes play different samples, avoiding the machine-gun effect.
Prerequisites¶
- A working IVLS product with at least one flow and
Stl.PlayEvent Stl.RoundRobinsalready included viaIvls.STL(it is part of the standard library bundle)- Your sample groups organized with multiple round-robin layers per note
- Familiarity with round robin concepts
Steps¶
1. Confirm Stl.RoundRobins is in IVLS_NODES¶
Stl.RoundRobins ships inside Ivls.STL. If your product includes that bundle, the node is already available. Otherwise, add it explicitly:
2. Register Stl.RoundRobins in your flow¶
Place Stl.RoundRobins in the flow before Stl.PlayEvent. The node runs on cb NotePass, so it sets Voice[self].rr before the event is triggered.
node MyProduct.Flows:
cb Flows:
define FLOWS += my.sound_flow
ivls.register_node(my.sound_flow, Stl.RoundRobins)
ivls.register_node(my.sound_flow, Stl.PlayEvent)
end node3. Register RR dimension fields¶
In your product's cb FirstLoad, tell the round-robin system which voice fields form the RR index. Each field is a dimension -- the system combines them into a composite index to track independent RR counters per combination.
The most common case is note-only RR (each MIDI note has its own counter):
node MyProduct.Setup:
cb FirstLoad:
ivls.RoundRobins.register_field(Voice.field.note, 128)
end nodeFor multi-articulation products, register multiple fields to get independent RR cycling per articulation per note:
cb FirstLoad:
ivls.RoundRobins.register_field(Voice.field.my_artic, NUM_ARTICS)
ivls.RoundRobins.register_field(Voice.field.note, 128)4. Implement the get_max_rr hook¶
Override ivls.RoundRobins.hooks.get_max_rr() to return the number of available round robins for the given voice. The system uses this to index into its pre-shuffled seed table.
node MyProduct.Product:
cb Functions:
function ivls.RoundRobins.hooks.get_max_rr(vo) -> rr_max override
{ Return the number of RR samples for this voice's group }
rr_max := my.num_rr_for_group(Voice[vo].my_group)
end function
end nodeIf all your groups have the same RR count, this can be a simple constant:
function ivls.RoundRobins.hooks.get_max_rr(vo) -> rr_max override
rr_max := 4
end function5. Use Voice[self].rr in EventGroups¶
After Stl.RoundRobins runs, Voice[self].rr contains the selected round-robin index (zero-based). Use it in your cb EventGroups to allow the correct sample group:
node MyProduct.PlayEvent from Stl.PlayEvent:
cb EventGroups:
declare rr := Voice[event_vo].rr
declare grp := my.get_group_for_rr(Voice[event_vo].note, rr)
event.groups[grp] := TRUE
end nodeComplete example¶
Here is a minimal product setup with 4-way round robins indexed by note:
node MyProduct.RRSetup:
cb FirstLoad:
ivls.RoundRobins.register_field(Voice.field.note, 128)
cb Functions:
function ivls.RoundRobins.hooks.get_max_rr(vo) -> rr_max override
rr_max := 4
end function
end node
node MyProduct.Flows:
cb Flows:
define FLOWS += my.sound_flow
ivls.register_node(my.sound_flow, Stl.RoundRobins)
ivls.register_node(my.sound_flow, MyProduct.PlayEvent)
end node
node MyProduct.PlayEvent from Stl.PlayEvent:
cb EventGroups:
{ Select the correct group based on note and RR position }
declare rr := Voice[event_vo].rr
declare base_group := Voice[event_vo].note * 4
event.groups[base_group + rr] := TRUE
end nodeVerify¶
- Play the same note repeatedly -- each hit should trigger a different sample (check via Kontakt's group monitor or
message()) - Verify that RR counters reset on transport start (DAW stop/play)
- If using multiple dimensions, confirm that different articulations cycle independently
Further reading¶
- Guide: Round Robins for the conceptual architecture and seed table details
- Guide: Voice Fields for understanding
Voice.field.*accessors