Detecting "is_recording" of Clip Slots - Max for Live

Michael Gary Dean's icon

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

Max Patch
Copy patch and select New From Clipboard in Max.

broc's icon

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.

brunal2496's icon

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
    }

}

clipobstest.js
js
Max Gardener's icon

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. :-)

brunal2496's icon

Thanks for the tip! I didn't managed to edit my post, but here is the compressed copy :

Max Patch
Copy patch and select New From Clipboard in Max.

Michael Gary Dean's icon

Here's the solution I currently use. This follows the clip slot as the user records different clips.

Max Patch
Copy patch and select New From Clipboard in Max.

Michael Gary Dean's icon

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]);
}

brunal2496's icon

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) ;

Jdudeo's icon

Looks correct, I would observe "has_clip" instead though, probably less variables involved.