Duplex - Build_App() Using Array For Many Buttons?

Hi all,

Had some fun with Duplex tonight - wrote a controller map from scratch (it only has two buttons so far, but hey…it’s a start), and as I couldn’t find the pattern sequence triggering I needed I wrote a small Application to do the work.

It’s hacked together but seems to work, button 1 instantly triggers pattern sequence index 2 and button 2 instantly triggers pattern sequence index 3, which was my goal as a first step.

So, next goal - I want to map a lot more than 2 buttons to instant-trigger various patterns. I’ve created the buttons in build_app individually (see below) but when I come to create 16, 32 or more is there a smarter approach?

function LW_Triggers:_build_app()  
  
 local c = UIToggleButton(self.display)  
 c.group_name = self.mappings.boggle.group_name  
 c:set_pos(self.mappings.boggle.index)  
 c.on_change = function(obj)  
 if not self.active then  
 return false  
 end  
 -- instantly switch position:  
 renoise.song().transport:trigger_sequence(2)  
 end  
 self:_add_component(c)  
 self._boggle = c  
  
 local d = UIToggleButton(self.display)  
 d.group_name = self.mappings.zoggle.group_name  
 d:set_pos(self.mappings.zoggle.index)  
 d.on_change = function(obj)  
 if not self.active then  
 return false  
 end  
 -- instantly switch position:  
 renoise.song().transport:trigger_sequence(3)  
 end  
 self:_add_component(d)  
 self._zoggle = d  
  
 -- attach to song at first run  
 self:_attach_to_song()  
  
 return true  
  
end  

Hi LamptonWorm,

here’s how to create 16 buttons within a for… loop:

  
  
-- remember my buttons   
self._boggles = table.create()  
  
for i = 1,16 do  
  
 local c = UIToggleButton(self.display)  
 c.group_name = self.mappings.boggle.group_name  
 c:set_pos(self.mappings.boggle.index+i)  
 c.on_change = function(obj)  
 if not self.active then return false end  
 renoise.song().transport:trigger_sequence(i)  
 end  
 self:_add_component(c)  
 self._boggles:insert(c)  
  
end  
  

Once the loop has run, you should have 16 buttons next to each other, triggering patterns 1-16.
To access the 4th button, simply state self._boggles[4] and you will get a reference to that particular UIToggleButton
Notice that local variable, “i”, is used for setting the position and specifying which pattern to trigger.
The local variable “c” is also just temporary, while anything that is regarded as important, stuff that we need to remember is stored in application variables (those that are prefixed with “self.”)

A lot more than 2. 16, 32 … eventually, you’ll run out of buttons or screen space - you don’t see this as a problem?

I suggest you check out the Matrix application. It has a lot of features that deal with the pattern-sequence, including support for an unlimited number of patterns (via “pages”).
For instance, to make 4 buttons control the pattern-sequence, open your device configuration and add the following to the “applications” branch:

Matrix = {  
mappings = {  
 triggers = {  
 group_name = "SeqTriggers" -- this will use all buttons in that group  
 }  
}  
}  

Assuming that you have an empty group in your control-map called “SeqTriggers” (any name will do, it’s just a name), which contain four buttons, you should be good to go, with each button able to trigger an individual pattern. Toggling song-follow will cause the patterns to follow your position in the pattern sequence, or to stay fixed at the current position.

For extra control, you would add the next and previous buttons. This is done by adding a single mapping called “sequence”

Matrix = {  
mappings = {  
 triggers = {  
 group_name = "SeqTriggers" -- this will use all buttons in that group  
 },  
 sequence= {  
 group_name = "SeqNav" -- this will occupy two buttons next to each other  
 }  
}  
}  

This will allow you to navigate through the pattern sequence with a specific “step size”. For example, if the step size is set to 4, pressing next will take us 4 patterns further down in the sequence. The actual page size can be changed in the settings dialog. This sort of “paged navigation scheme” is implemented in most Duplex applications, btw.

Finally, it’s worth mentioning that the trigger buttons we just set up can also be used for looping patterns within the sequence. If your controller transmit release events, simply select “Pattern-trigger: Position + PatternLoop” in the settings dialog

Thanks for the help and information.

When I get some time I’ll try the Matrix again, the UISlider threw me last time because I was expecting it to be a button (it seems so obvious now!) for some reason. I have to keep remembering it is easier than I’m expecting ;)

I have 2 quick questions…

  • With regards to

, if I’m only using Duplex plus a custom control map, where do I specify per button which point in the index it should jump to, or perhaps it is hardwired and I don’t need to worry, e.g. using matrix>trigger, button 1 always sets sequence index to 1, button 2 to index 2 etc.

  • Just to confirm, I want part of my grid to use “instance trigger” and another part of the grid to use “schedule” all in the same map/config, is this ok? Assume I’d just use different groups when mapping and set switch mode differently in each group.

Learning more each day!

Cheers,
LW.

Device-configurations are simple to work with, once you understand them. Observe this configuration:

  
  
duplex_configurations:insert {  
 name = "Matrix + Navigator + Transport",  
 pinned = true,  
 device = {  
 class_name = "Launchpad",  
 display_name = "Launchpad",  
 device_port_in = "Launchpad",  
 device_port_out = "Launchpad",  
 control_map = "Controllers/Launchpad/Controlmaps/Launchpad_Matrix.xml",  
 thumbnail = "Controllers/Launchpad/Launchpad.bmp",  
 protocol = DEVICE_MIDI_PROTOCOL,  
 },  
 applications = {  
 Matrix = {  
 mappings = {  
 matrix = {  
 group_name = "Grid",  
 },  
 triggers = {  
 group_name = "Triggers",  
 },  
 sequence = {  
 group_name = "Controls",  
 index = 1,  
 },  
 track = {  
 group_name = "Controls",  
 index = 3,  
 }  
 },  
 options = {  
 sequence_mode = 2,  
 }  
 },  
 Navigator = {  
 mappings = {  
 blockpos = {  
 group_name = "Navigator",  
 }  
 }  
 },  
 Transport = {  
 mappings = {  
 edit_mode = {  
 group_name = "Controls",  
 index = 5,  
 },  
 start_playback = {  
 group_name = "Controls",  
 index = 6,  
 },  
 loop_pattern = {  
 group_name = "Controls",  
 index = 7,  
 },  
 follow_player = {  
 group_name= "Controls",  
 index = 8,  
 },  
 },  
 options = {  
 pattern_play = 3,  
 }  
 },  
  
 }  
}  
  
  

The result

Thanks, this is really useful stuff. I’ve used the matrix>triggers to get a vertical list of buttons that control the sequence, cool. Is it possible to use a horizontal (or grid) layout for matrix>triggers? I added orientation=“horizontal” to the xml which sorts the GUI out, but when I do that only the first button works (the others are blank).

Cheers,
LW.

Sure, you just need to add this to the configuration:

Matrix = {  
 mappings = {  
 triggers = {  
 group_name = "Grid1",  
 orientation = HORIZONTAL  
 },  
}  
  

In case you’re wondering - the orientation of the group itself (in the control-map) is describing the layout of the controller.
But the device configuration is describing the “software” running on that layout. So they’re slightly different things…

And while not all mappings can be flipped, most can. It really is up to each application how to deal with this.

Thanks. I must be missing something obvious as I can’t get that working just yet.

Here is a snip of the xml…

  
<row><br>
       <group name="Triggers" orientation="horizontal"> <br>
            <param value="CC#70" type="button" name="1,1" maximum="127" minimum="0">
<br>
            <param value="CC#71" type="button" name="1,2" maximum="127" minimum="0">
<br>
            <param value="CC#72" type="button" name="1,3" maximum="127" minimum="0">
<br>
            <param value="CC#73" type="button" name="1,4" maximum="127" minimum="0">
<br>
       </group><br>
    </row>  
  

…and the .lua

  
 applications = {  
  
 Matrix = {  
 mappings = {  
 triggers = {  
 group_name = "Triggers",  
 orientation = HORIZONTAL,  
 }  
 }   
 }  
  
 }  
  

Ps - thanks for your time and effort helping me out here.

Cheers,
LW.