How to Add an Arpeggiator¶
Wire up the Stl.Steparp system to add a step arpeggiator and sequencer with configurable step tables, timing, and per-step modulation.
Prerequisites¶
- A working IVLS product with at least one flow and
Stl.PlayEvent - Familiarity with flows and voice fields
- UI controls for step table editing (optional, but needed for user interaction)
Steps¶
1. Add Stl.Steparp.Bundle to IVLS_NODES¶
The bundle includes all required steparp nodes: Stl.Steparp.Core (timing and helpers), Stl.Steparp.Data (parameter storage), Stl.Steparp.TableData (step table storage), Stl.Steparp.SnapWait (grid snap), Stl.Steparp.Arp (arpeggiator engine), Stl.Steparp.Seq (sequencer engine), and the step notify relay nodes.
2. Create arp and seq flows¶
Register separate flows for the arpeggiator and sequencer. Each flow starts with Stl.Steparp.SnapWait (which delays the note until the next grid boundary when snap-to-grid is enabled), followed by either Stl.Steparp.Arp or Stl.Steparp.Seq, then moves to your sound output flow:
node MyProduct.Flows:
cb Flows:
define FLOWS += my.arp_flow, my.seq_flow, my.sound_flow
{ Arpeggiator flow }
ivls.register_node(my.arp_flow, Stl.Steparp.SnapWait)
ivls.register_node(my.arp_flow, Stl.Steparp.Arp)
ivls.register_move(my.arp_flow, my.sound_flow)
{ Sequencer flow }
ivls.register_node(my.seq_flow, Stl.Steparp.SnapWait)
ivls.register_node(my.seq_flow, Stl.Steparp.Seq)
ivls.register_move(my.seq_flow, my.sound_flow)
{ Sound output flow }
ivls.register_node(my.sound_flow, Stl.PlayEvent)
end node3. Add a Divert node to route based on steparp mode¶
The steparp system stores its mode in steparp[thread].mode. Use a Divert node to send voices to the correct flow:
node MyProduct.Divert.StepArp:
cb NoteOn:
if my.arp_enabled = TRUE
if steparp[thread].mode = steparp.arp_mode.ARP
ivls.reflow_voice(self, my.arp_flow)
else
ivls.reflow_voice(self, my.seq_flow)
end if
else
ivls.reflow_voice(self, my.sound_flow)
end if
ivls.pass()
end nodeRegister the divert node in your base flow:
4. Set up engine box parameters for step table data¶
The steparp system uses two engine box data layers:
steparp-- global parameters (mode, speed, swing, steps, note order, loop mode, table enables)steparp_t-- per-step table data (trigger, volume, pan, length, pitch, wave, modulation)
Both are initialized automatically by Stl.Steparp.Data and Stl.Steparp.TableData (included in the bundle). The key parameters are:
| Parameter | Values | Purpose |
|---|---|---|
steparp[thread].mode |
steparp.arp_mode.ARP, steparp.arp_mode.SEQ |
Arpeggiator or sequencer mode |
steparp[thread].sync |
TRUE / FALSE | Sync to host tempo or free-running |
steparp[thread].sync_speed |
ticks.sync.* constants |
Step duration when synced |
steparp[thread].free_speed |
10--1000 | Step duration in ms when free |
steparp[thread].seq_steps |
2--32 | Number of active steps |
steparp[thread].note_order |
steparp.note_order.* |
Note ordering (Played, Up, Down, etc.) |
steparp[thread].octaves |
-4 to 4 | Octave range for arpeggiation |
steparp[thread].loop_mode |
steparp.loop_end.* |
Loop, Stop, or Hold |
steparp[thread].swing |
0--127 | Swing amount |
Per-step table values are accessed as steparp_t[thread].trigger[step], steparp_t[thread].volume[step], etc.
5. Wire step callbacks (optional)¶
If you need to react to each arp or seq step (for example, to update a UI step indicator), implement the step callback nodes:
node MyProduct.StepIndicator:
cb ArpStepOn:
{ Fired when the arpeggiator triggers a new step }
declare step := Voice[self].step_arp.table_idx
my.update_step_display(step)
cb SeqStepOn:
{ Fired when the sequencer triggers a new step }
declare step := Voice[self].step_arp.table_idx
my.update_step_display(step)
end nodeRegister this node in IVLS_NODES so its callbacks are included in the callback chain:
6. Control arp/seq state¶
To stop the arpeggiator or sequencer programmatically (for example, when switching sounds), use the state functions:
{ Stop the arpeggiator on a thread }
stl.arp.state(thread, OFF)
{ Stop the sequencer on a thread }
stl.seq.state(thread, OFF)Trigger modes¶
Each step in the table has a trigger mode that controls its behavior:
| Mode | Constant | Behavior |
|---|---|---|
| Off | steparp.trigger_mode.OFF |
No note plays on this step |
| Retrigger | steparp.trigger_mode.RETRIGGER |
A new note is triggered |
| Tie | steparp.trigger_mode.TIE |
The previous note continues, pitch-shifted to the new step's note |
Verify¶
- Enable arpeggiator mode, hold a chord, and verify that notes cycle through the held keys
- Switch to sequencer mode -- held notes should play the step pitch pattern
- Change
note_order-- verify that Up, Down, Up-Down patterns work correctly - Adjust
seq_steps-- the pattern length should change in real time - Enable tempo sync and change
sync_speed-- step rate should follow the DAW tempo - Set some steps to TIE -- verify that the previous note glides to the new pitch without retriggering
- Set some steps to OFF -- verify silence on those steps
Further reading¶
- Guide: Step Arpeggiator for the conceptual architecture
- Guide: Engine Boxes for understanding the
steparpandsteparp_tdata layers - Guide: Flows for how
ivls.register_movechains flows together