Detecting "is_recording" of Clip Slots - Max for Live
Hello All,
I'm having a problem with a Max for Live patch I'm working on. I'm trying to detect when a user begins recording a clip and when they stop recording. I've included a procedure on how to show the problem I'm having in the patch that I've attached.
Debugging procedure:
- load device on any track in Ableton Live
- start recording in the first clip slot ('clip slot 0')
- click 'path this_device" while recording
- watch status box change to indicate recording is taking place
- stop clip - watch status box change to indicate recording has completed
- delete clip
- record new clip - note status box does not change now when recording.
- ..!?
According to the LOM, I should be able to observe this property. I'm not sure where I'm going wrong. Any help would be greatly appreciated.
Thanks
Mike
When deleting the clip the previous path calculation (ID assignment) becomes invalid.
So I think for observing a new clip you may need to click 'path this_device' again.
Hi Guys,
I update this thread because it's kind of a continuation, but with the js point of view.
I setup an observer in a js object, but I don't understand why it doesn't react as the same action programmed with max object... .
With the max code provided on the first post of this thread, the observer "bang" a 1 message when the record starts in the clip slot, and a 0 message when the record stops.
Why does my js object doesn't post a message in the max window when the record starts and stops ?
Many thanks for your feedback.
{
"boxes" : [ {
"box" : {
"maxclass" : "newobj",
"text" : "s status",
"numoutlets" : 0,
"style" : "",
"patching_rect" : [ 286.0, 201.0, 51.0, 20.0 ],
"numinlets" : 1,
"fontsize" : 10.0,
"id" : "obj-20",
"fontname" : "Arial Bold"
}
}
, {
"box" : {
"maxclass" : "button",
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"style" : "",
"patching_rect" : [ 245.0, 198.0, 20.0, 20.0 ],
"numinlets" : 1,
"id" : "obj-23"
}
}
, {
"box" : {
"maxclass" : "number",
"parameter_enable" : 0,
"numoutlets" : 2,
"outlettype" : [ "", "bang" ],
"style" : "",
"patching_rect" : [ 245.0, 165.0, 50.0, 20.0 ],
"numinlets" : 1,
"fontsize" : 10.0,
"id" : "obj-27",
"fontname" : "Arial Bold"
}
}
, {
"box" : {
"maxclass" : "message",
"text" : "property is_recording",
"numoutlets" : 1,
"outlettype" : [ "" ],
"style" : "",
"patching_rect" : [ 245.0, 125.0, 114.0, 20.0 ],
"numinlets" : 2,
"fontsize" : 10.0,
"id" : "obj-28",
"fontname" : "Arial Bold"
}
}
, {
"box" : {
"maxclass" : "newobj",
"text" : "live.observer",
"numoutlets" : 2,
"outlettype" : [ "", "" ],
"style" : "",
"patching_rect" : [ 245.0, 144.0, 148.0, 20.0 ],
"numinlets" : 2,
"fontsize" : 10.0,
"id" : "obj-30",
"fontname" : "Arial Bold",
"saved_object_attributes" : {
"_persistence" : 1
}
}
}
, {
"box" : {
"maxclass" : "newobj",
"text" : "t b l",
"numoutlets" : 2,
"outlettype" : [ "bang", "" ],
"style" : "",
"patching_rect" : [ 245.0, 104.0, 147.5, 20.0 ],
"numinlets" : 1,
"fontsize" : 10.0,
"id" : "obj-31",
"fontname" : "Arial Bold"
}
}
, {
"box" : {
"maxclass" : "message",
"text" : "path live_set tracks 7 clip_slots 0 clip",
"numoutlets" : 1,
"outlettype" : [ "" ],
"style" : "",
"patching_rect" : [ 245.0, 25.0, 196.0, 20.0 ],
"numinlets" : 2,
"fontsize" : 10.0,
"id" : "obj-14",
"fontname" : "Arial Bold"
}
}
, {
"box" : {
"maxclass" : "newobj",
"text" : "live.path",
"numoutlets" : 3,
"outlettype" : [ "", "", "" ],
"style" : "",
"patching_rect" : [ 245.0, 59.0, 51.0, 20.0 ],
"numinlets" : 1,
"fontsize" : 10.0,
"id" : "obj-13",
"fontname" : "Arial Bold"
}
}
, {
"box" : {
"maxclass" : "button",
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"style" : "",
"patching_rect" : [ 49.0, 34.0, 24.0, 24.0 ],
"numinlets" : 1,
"id" : "obj-52"
}
}
, {
"box" : {
"maxclass" : "newobj",
"text" : "js clipobstest.js",
"numoutlets" : 2,
"outlettype" : [ "", "" ],
"style" : "",
"patching_rect" : [ 49.0, 77.0, 91.0, 22.0 ],
"numinlets" : 2,
"id" : "obj-51",
"saved_object_attributes" : {
"filename" : "clipobstest.js",
"parameter_enable" : 0
}
}
}
],
"lines" : [ {
"patchline" : {
"source" : [ "obj-14", 0 ],
"destination" : [ "obj-13", 0 ],
"hidden" : 0,
"disabled" : 0
}
}
, {
"patchline" : {
"source" : [ "obj-27", 0 ],
"destination" : [ "obj-20", 0 ],
"hidden" : 0,
"midpoints" : [ 254.5, 188.0, 295.5, 188.0 ],
"disabled" : 0
}
}
, {
"patchline" : {
"source" : [ "obj-27", 0 ],
"destination" : [ "obj-23", 0 ],
"hidden" : 0,
"disabled" : 0
}
}
, {
"patchline" : {
"source" : [ "obj-31", 1 ],
"destination" : [ "obj-30", 1 ],
"hidden" : 0,
"disabled" : 0
}
}
, {
"patchline" : {
"source" : [ "obj-30", 0 ],
"destination" : [ "obj-27", 0 ],
"hidden" : 0,
"disabled" : 0
}
}
, {
"patchline" : {
"source" : [ "obj-28", 0 ],
"destination" : [ "obj-30", 0 ],
"hidden" : 0,
"disabled" : 0
}
}
, {
"patchline" : {
"source" : [ "obj-31", 0 ],
"destination" : [ "obj-28", 0 ],
"hidden" : 0,
"disabled" : 0
}
}
, {
"patchline" : {
"source" : [ "obj-13", 1 ],
"destination" : [ "obj-31", 0 ],
"hidden" : 0,
"disabled" : 0
}
}
, {
"patchline" : {
"source" : [ "obj-52", 0 ],
"destination" : [ "obj-51", 0 ],
"hidden" : 0,
"disabled" : 0
}
}
],
"appversion" : {
"major" : 7,
"minor" : 3,
"revision" : 1,
"architecture" : "x64",
"modernui" : 1
}
}
It's generally a better idea - when you want to post a patch - to select the patch or part of the patch you want to copy, choose Edit > Copy Compressed, and paste that into your posting. It keeps things a lot more readable. :-)
Thanks for the tip! I didn't managed to edit my post, but here is the compressed copy :
Here's the solution I currently use. This follows the clip slot as the user records different clips.
Here's the same thing using Javascript.
/**
* @author Michael Gary Dean
* @link https://michaelgarydean.com
*/
/**
* Inlet is provided for the live.thisdevice object.
*/
inlets = 1
outlets = 1
/**
* Trigger the clip operations.
*/
function bang() {
get_playing_slot_index();
}
/**
* Observe the playing_slot_index property of the track this device is placed on.
*/
function get_playing_slot_index() {
//Create object to observe a property
var this_track = new LiveAPI(observe_property);
//Get the LiveObject of the track this device is placed on
this_track.path = "this_device canonical_parent";
//Observe the playing_slot_index property of this_track
this_track.property = "playing_slot_index";
}
/**
* Observe property changes.
*/
function observe_property(args) {
//Output the playing slot index each time the property is updated
outlet(0,args[1]);
}
Hi Mike,
Many thanks for your answer.
Can someone confirm this, to be sure I have understood well:
- a clip cannot be observe until it is created, which means I can't setup an "is_recording" observer before it's already recording or recorded ;
- if I want to detect a clip is recording, I need to observe the playing_slot_index property of a track, (or maybe the "is_triggered" property of a clip slot) and use this information to observe the clip itself after it has been created (even if not finished) ;
Looks correct, I would observe "has_clip" instead though, probably less variables involved.