In the previous installment we discussed locating and gathering information about loaded Control Surface scripts using M4l and the Live API. In this installment we will look at applying our session control to any Control Surface that has a SessionComponent. This will involve some iterations and checks, things which aren’t the cleanest in Max, but they can be done!
I am assuming that you have read the first article in this series and downloaded the Session_Scene_Launcher device. If we load that into an empty Live set, and open the device in the Max editor by clicking the edit button in the upper right we can take a look at how this is all done.
Once the device is opened you should double click on the [p control surface] sub patcher to expose the insides. This may seem daunting at first, but I have attempted to split it into digestible portions that take care of one specific task.
When setting up systems like this it is useful to describe what it is we are wanting to do in plain english, so we have a bit of a roadmap to follow as we go along. You can makes small pieces of code that do just one thing, and then cross it off the list. Thinking in smaller pieces is important in programming, and is something that I learned by doing it wrong in the beginning.
So we want to find the id of a SessionComponent in a script. First we need to find the id of the script. How do we do that? In the previous article we found that by sending a ‘path control_surfaces 0’ will get our first control script. That’s great but we want to do this by name, regardless of which slot the control script is loaded into. This becomes kind of convoluted:
– Find out how many control scripts we have loaded.
– Iterate through those until we get the name we are looking for.
– Figure out which control surface it is.
That is done in the two top left groups of objects in the patch, which you can see over to the left. . When this patch receives a symbol from the menu, (after deciding it it was Push or not, which we talk about in a bit), we get the number of control surfaces loaded by asking the Live to ‘getcount control_surfaces’. We then iterate over these control surfaces using the [uzi] and the [counter] object, and then send the paths into a live.path. The live.path then asks a live.object to get the type of control surface, which will be the name of the control surface in each slot in Live’s preferences. These names are output one by one, grouped with the [zl group] object, and then indexed and output one by one using the [listfunnel] object. We filter this list based on our input symbol, and finally output the path number to our selected control surface. This all seems like a lot of hassle for just getting the proper path of our control surface, but doing it programmatically like this, makes sure that no matter which slot our control surface is loaded into, we will calculate the correct path.
If you’ve been wondering why we route the Push script to a different section of code, it’s because the Push script doesn’t create the SessionComponent (or more accurately the SpecialSessionComponent) until we enter Session Mode on the controller. In order to make sure that this device doesn’t return errors, and works with the Push seamlessly, we store the control surface slot number in an [int], and then send that out once we enter Session Mode from the Push. Its a fairly simple construction on the lower left of the patch, which you can see to the right. This is done by assigning a live.observer to the value of the Session_Mode_Button on the Push, and when this button is pushed, it will then send out the appropriate number of the control script.
Now we can move onto to finding our SessionComponent.
– Iterate through all of the components of our Control Surface.
– If the name of the component is SessionComponent, or SpecialSessionComponent then output the number of the component.
– Combine that component number with the proper Control Surface path.
This group of objects starts with some message formatting based on the control surface we found in the first part. All of the components belong to the same control surface, so we just count up through all of the components, using the [counter] object and keep track of which number we are currently looking at using the [int] object. We call ‘gettype’ on each of these components in turn, and then send it to a [route] object to check the name. If the name matches SessionComponent, or SpecialSessionComponent, we send a bang to the [int] that is storing our component number. Finally we construct our path message using the [prepend] object and the [zl.join] object.
Now that our path is constructed, it gets spit out into the main patch that we worked on in the previous article. You might be wondering why we went through all of the trouble to find our control surface and session component paths, when we could have just hard-coded a message box. If you ever want to share work like this with other users, it’s important to make it easy to use and flexible. If you’re the only one using the device, then one message might be good enough. But if a friend dropped it in their set, unless they had the same exact setup as you, it wouldn’t work properly, without some adjustments. This elaborate system of checks and iterations, and message processing ensures smooth operation, as long as the user has one of the scripts activated in their preferences.
I tried to include all of the most common Live controllers that had SessionComponents in this device, but what if a user didn’t have one of the controllers? The Ableton sanctioned scripts will only display the Session Component, if the intended controller is connected, which means you can’t really use this without having one. I decided to code up a very simple dummy script that creates a session box, and allows you to navigate your session and launch scenes from this device. In the third part of this series, we will take a quick look at this script to learn some basics of coding remote scripts using python. As always, direct any questions, comments, or concerns, to firstname.lastname@example.org