Controlling Live using Max for Live (Tutorial)
- Live Versions: 9-10
- Operating System: All
- How Can I Access Live's API In Max for Live?
- The Live Object Model
- How Can I Control Live's API In Max for Live?
- Volume Control
- Select Clip Slot
- API Functions
- Additional reading
How can I access Live's API in Max for Live?
Everything in Live's API that is accessible to Max for Live is illustrated in the Live Object Model (LOM).
The key to controlling Live this way is in understanding the LOM and the different paths that can be taken to each parameter.
The Live Object Model
The LOM is essentially a roadmap to each of Live's parameters that are accessible via Max for Live.
Not all parameters are available in Live's API, so this diagram should give you an idea of what can and can't be done via Max for Live.
Live Object Model
In the LOM, we can see that each route begins with live_app, live_set or control_surfaces. As the names indicate, each control their respective areas in Ableton Live.
- live_app: allows you to access controls of the Live application itself. This can be useful if you want to toggle the browser view, zoom or scroll features in Live.
- live_set: allows you to access various parameters within Live, for example Track Volume, Clip parameters (including launching Clips), etc.
- control_surfaces: allows you to access various control surface features (depending on your controller).
The items in boxes are objects belonging to these classes. For example, in live_set you will find Track, Device, Clip, etc.
The text written on the interconnecting lines represents a way to navigate down a path, to a certain object.
Note that there is usually more than one route to a given object.
For this lesson, we will focus mainly on the live_set class.
The live_set class and its objects
In order to control parameters in Live, you will need to work out the best route in the LOM.
The easiest way to understand the LOM is to imagine that objects such as Clip, Track, etc. are buildings and the interconnecting lines are roads.
For example, starting at live_set:
Q. How can I get to the volume control of the MixerDevice?
A. Continue down live_set, turn left onto tracks, then turn again onto mixer_device.
Path to the volume parameter
So what do these directions look like in Max-speak?
path live_set tracks 0 mixer_device volume
We begin with the word "path" to indicate that this is a set of directions.
Starting at live_set, we then access tracks (in this case the first one - note that this is 0, not 1). Next, the mixer_device and inside this we can access the volume parameter.
Similarly, to access the fourth clip on Track 3, the path would be:
path live_set tracks 2 clip_slots 3
Again, notice here that as we are counting from 0, the third track is written as track 2, the fourth clips is written as clip_slots 3.
Now that we know how to access parameters in Live's API, let's have a look at how to observe and control these via Max for Live.
How can I control Live's API in Max for Live?
Having learned how to find the path to a parameter in Live's API, this article will now demonstrate how to observe and control these parameters.
As you might remember from the last lesson, the path we provide Max for Live to direct it to the volume parameter of track 1's volume is:
path live_set tracks 0 mixer_device volume
We send this using a message to a live.path object as follows:
The live.path object takes the directions we give it and returns a unique ID number (out of its second outlet) for the parameter: track 1, mixer volume. We can now use this ID (in this case id 3) to control or observe the volume.
If you hover your mouse over the first and second outlets of live.path, you will notice that the first one "follows object", while the second "follows path".
Generally, it makes more sense to choose the first one. Why? If you build a Max for Live device that follows the path and drop this on a Track in Live, it will work as expected the first time. However if you then change the Set in any way, for example dropping another device before the Max for Live device or adding a Track before it, the ID will no longer address this parameter.
Obtaining the ID from the "follows object" outlet overcomes this issue as the ID will always be linked to that device, regardless of where you move it or what you change in your Live Set.
Once provided with a valid ID (as above), live.object can be used to control the accessed parameter (in this case, track 1’s volume). We can test this by hooking up a simple slider object to it.
The slider, in conjunction with a set value message, tells Max what value to send to the parameter:
Note that in Max for Live, we often deal with changing values. Using $1 means that the slider value, which is an arbitrary number (known as a replaceable argument), is passed through.
$1 means the first input to the message ($2 would be the second input, etc).
If the slider outputs a value of 25, this message will become "set value 25".
We can see that controlling Live from Max for Live is made very easy.
In some cases, we may not wish to alter the values of a parameter, it might only be necessary to listen to them so we can then do something with their values.
Take the slider for example. We can now use Max for Live to change the value of the volume of Track 1, however when we change the volume of Track 1 in Live, it doesn’t affect the slider in Max for Live.
It would be nice if Live controlled the slider in Max for Live and vice versa, to give us some visual feedback of what's happening.
For these cases, we would use live.observer which actively monitors any change in values of Live objects.
live.observer works quite like before, passing it a valid ID (obtained from live.path) directs it to the parameter you want to listen to.
After we have configured live.observer with the object ID from live.path (so that it is focused on a parameter) we can send it the message property value to tell it to output the value of the parameter it is focused on.
Below is a patch that uses a combination of all these objects to allow a slider in Max for Live to control a Track's volume in Live (and vice versa). We can see that we have it set in such a way that we can both control Live from the slider in Max for Live, as well as represent any changes made in Live.
The first step in our patch generates the parameter ID using live.path, and is then fed to a trigger object, t for short.
In Max talk t b l l is a short way to say Trigger Bang List List
In the real-world this means:
Take the incoming message and send it to 3 outputs, in the form of 2 lists and a bang!
The trigger object takes any input, and sends it to many outputs, formatted according to the object-argument specified, in this case a list, another list, and a bang.
This allows us to do a few things at one time. Let's begin by looking at the list outlets.
The incoming message is our parameter ID. As before, this ID number addresses the parameter we have provided the path to. Since we want to both control the parameter in Max for Live, and to check if anything has been changed from Live, we can save ourselves some time by sending the same ID to both live.observer and live.object.
Max executes messages from right to left, so the order in which the messages arrive allows everything to work in the correct sequence.
Timing is a very important factor to consider when creating patches. If you want to learn more about Max message ordering, have a look at this dedicated tutorial on the Cycling '74 website.
Let's run through the cycle to see what's happening:
Step 1: Using the LOM, we worked out the path to the parameter we want to use. We then send this as a message to live.path.
Step 2: Our live.path object creates a unique ID number from this path message, and sends it on to the trigger object.
Step 3: The trigger takes this ID and sends it as a list out of the right outlet, down to our live.object, below, pointing it to the parameter we want to deal with.
Step 4: The trigger next sends the same ID from the middle outlet, to live.observer, also making this aware of the parameter we want to 'listen' to.
Step 5: Finally, the trigger sends a bang, triggering the property value message. This sends the message to the live.observerobject. The message property value tells live.observer to output the current value of the parameter it is listening to.
Now we have learned how to use the LOM and the related Live API Max for Live objects.
We will now take a look at API functions.
So far, we have seen how to navigate the LOM to find our way to a parameter.
Next, we saw how we can use these directions to ask for a unique parameter ID from live.path.
We then saw how to use this ID to control the parameter using live.object and to listen to it using live.observer.
There is still a final point in the LOM that we have not covered, namely function calls to the API.
We will use these combined with what we have learned so far to build our second patch, a Max for Live Clip Launcher.
Select Clip Slot
As in the previous lessons, we will consult the LOM to work out a path to theclip_slot.
The only difference is that this time, we wish to be able to select which Clip to launch.
To achieve this, we will use replaceable arguments again as in Lesson 2. Just to briefly recap, this means instead of tracks 0 clip_slots 0, we will use tracks $1 clip_slots $2. Thus, by sending values to the messages, $1 will be replaced by the first value we send and $2 will be replaced by the second value.
This is a good moment to remind ourselves about the indexing with Live's API. The first Track will be tracks 0, the second, tracks 1 and so on.
This works out to be the following path message:
path live_set tracks $1 clip_slots $2
By using $1 and $2 instead of numbers in the message, we can hook up controls that will allow us to choose which clip_slot to trigger.
The pack object simply bundles the track and clip slot numbers and feeds them together as a list into the message.
When looking at the Live Object Model, you may have noticed that there is a functions section further down the page.
These functions allow you to easily implement a number of operations, for example launching clips, inserting tracks, re-sizing the grid, inserting devices, etc.
For this patch, we will use the Clip object's fire function.
Once we have set the live.object with a valid ID, we can call the associated functions for the addressed object by sending a message to it.
In this case, we will send the message call fire, where fire is the name of the function.
Exactly as in the last lesson, we pass the ID generated by live.path to live.object. We can now call the fire function by sending the message call fire to the live.object. This will trigger the clip slot.
If there is a clip in this slot, it will be launched. If the slot is empty and the track-record armed, a clip will be created and recording will begin, otherwise it stops the playing clip in that track.
Note: Looking to the right side of the patch, we notice something useful. When we feed a path message into live.path that doesn’t exist (for example track 5 where there are only 4 tracks in the project), live.path returns ID 0.
In this 3-part lesson, we have covered:
- How to use the Live Object Model to obtain a path to parameters in Live
- How to use this path in the live.path, live.object and live.observer objects to get an ID for the desired parameter and thus to control and observe this parameter.
- How to use function calls to the API (in this case, we used this to "fire" Clips)
- How Max message ordering works
This knowledge will allow you to start building Max for Live devices to control elements in Live.
To learn more about Max for Live, we highly recommend this series of Max for Live tutorials.
The Max for Live forum is also a great place to share ideas and get help from the Max community with your patches.
Max Object References