Ability to cleanly destroy LiveAPI’s callbacks ?
Tweeter
I initiated a post on the Cycling 74 forum.
It was about the fact that if you instantiate LiveAPI objects, setting up callbacks, through javascript, I had doubts about how those callbacks could be cleanly, I mean: with a REAL memory liberation, destroyed and garbage collected.
Indeed, javascript’s Max implementations provide all stuff from classic javascript.
It means the garbage collector is also totally working.
So, if I want to make a LiveAPI call (instantiation) from javascript, I can do that:
trackObject= new LiveAPI(this.patcher, “live_set tracks 5″);
This row call the object in the LOM and “put it” in trackObject variable, basically for further access.
I can also do that:
trackObject= new LiveAPI(this.patcher,track_callback,”live_set tracks 5″);
trackObject.name = trackObject.get(“name”) ;
trackObject.property = “name”;
function track_callback()
{
post(“The track 5 is named:” + this.name;
}
This piece of code instantiate an object and observe if something changes and react by doing something.
Here, if the name of the track 5 changes, the callback is executed and pops out the new name.
If trackObject is out of scope (I mean, NOONE calls/runs the part of the code where it has been declared), the javascript’s (precious) garbage collector destroy and free the part of the memory where there was this variable.
It works.
BUT the problem is on the LiveAPI (and Live) side.
How could I be sure the callback is totally collected ?
Especially, I have been surprised by using the same piece of code by creating a HUGE table of LiveAPI objects, using callbacks and other stuff.
The Memory was a bit … busy and even the CPU (callbacks were working)
So I decided to … basically as I used to do in javascript: to try:
- myArray.length = 0; (this totally weird tip works fine usually)
- myArray = null; (no comment)
Nothing worked fine BECAUSE there were those callbacks still working or even sleepy zombified or ?!
So the question became: How to really free memory from this callbacks ?
Tom answered and give an important information in the thread I began there.
cb_private seems to be a property for all LiveAPI objects (I guess it is trivial for those which don’t have a callback)
So, inside the callback, Tom suggests to add
delete liveAPIObject.cb_private
Where liveAPIObject is the related object for which you need to free the memory addressed for the callback.
Let’s test that in case we need it.
I suppose C74′s dudes will answer soon, but it is a nice news/clue/tip to test.
Targeting a parameter on a smart way
Tweeter
Using Ableton Live & Max for Live, you probably want to adress a specific parameter of your live set in order to change it remotely.
If you studied max for live and LiveAPI a bit, you probably already know that you need to use the famous live path to “progressively” enter in the Live engine by walking on the path, beginning by the live_set root, the track, the device and finally the targeted parameter.
A nice way, used by a lot of people, is to use 3 umenus objects in max for live.
Those 3 menus are populated progressively by clicking on the first one to choose the track, the second one to choose the device in that track, and the 3rd one to choose the final target: your parameter.
I made ONE of the possible implementation and gave it as an example.
It involves javascript and several max objects.
The whole architecture is:

Here is the stuff:
———-begin_max5_patcher———-
1357.3oc2YsraiaCEccFf4efPqSEDeHRwhhBLcV2MEY2fAAJVz1LQRzPh1Mo
C5+dIodaaYKmnNdxrHQVWRQcOm64d4C8sO9ga7dP8rnzC7qfu.t4luYrbiyl
0xMMFtwKK94EowktN5kIJKiWI7tstwMw5Eqk4qtuPrPWMT3vHeBKJ.wtEfoQ
9A2BBCr+GR8C.es4Iy2lo1pSEZ2.CaLWYS+xFQ0n4408HKU4573LWKdepPFm
15GxDmQ0CO9KPu98uT9Ot9CstP2qVl27lQNi+6G+f8p4xsSlKxE+s48091zh
mcLfWpJNwxSfEoh3hSQUj.lkXPDGKACpnonYml.+gJM4XbEO5xHK3rSVOVBt
as3ypDg+ikmhqfXjeHiiITKEE3yY7PN2PdrP+HDEQwml5HiSc216uWEMhoWF
MRlcZbSgXiHOAHSNYpYDuM0DgHWIQGDRt1ptkEprxWxdPkNY5J.5jeFUFk88
mwvWaFqQfsItv3yZQwTyUwlhazPJlgtNhsfn2Ihs.rOCGfPgWYwFk8ihVKQr
StPLUgFhG4a9IhQtJBMD98gNCAY9gQbjUbccKpQn+nHzzEwKdZx5LB2GyMYp
vqSAML88gPa.mcUEZ3uaolayD4am7LiHV+UfwFmQvsiXgnTjqi0RU9.pRpEY
UtvuIx1ne428FkDk45WwpcsCP8dE6dnAKQoSV12K6W4IzGAobnQDX1hHkERP
10ra.NOLhQh1mC5Gq3W2PEh8SUnJ7BBUD36rPEN3mmPEmcAQJyF5nTBM75En
Rk6D9toIZF337bUGw584T4hm.qEEBfVARjkKT6DEf3zz5E6UBTKAun1V.riU
oPChsa5PsYaZr17PqEf6rSVC9y9RhcwEsrbgXogoV2i2TZkkma6gtPtZknvO
QrLdap9zBKrSEE5Nfl5otBGWRgNqjpc+S2abnGREmYBugxoLUhqkf9SIWSs2
YPUGsuUqx5n8OUjc7Ufc3b6GReGU1A4NFoJWiYUR.RPedoyC54eq5sswgRtF
qkw6DI2GqMwnG1pEc+prV20H7rA8zsB0xF6sMzmianxl3xfFk4RsIirWfH3X
cqbspnKI9up3GfwmrL+wd.STxjU3fkaF9izkTU9p1grMq4KvuN5.JcrXvHCm
L+I6vUNJHrCwdhm83hkJmybTGXqgoJGuYUQhIvN1PaRyNQqkaDhjTYlitNN5
J0hMkmvy2IKkmJ.ZpTjUmO4RD5zhsx0g8+4Mpbil+DtTWYs62WYLNApeoNc+
3QnFMi+HM2p.past.c2O5pXWgKivJ+fy22Ujy1vd0wKM0bWzT1o8T5.8xnSD
kZYdaQkuzdZ6.XWmVKSRD4CpQkIS1nLSO1NO23SuLYmytGH.9r9l8Xy5Cgy6
cXScMdPHMfafE2UWyYp9T.cllODfNGBrmEyEB.H1GwoQDRG.rlpOYoYF.vyF
Brax+xP.xTzjFEEvCaQf0TP8YVLeHvczfmWguuV67H.RP9AMaxqdQCP2kg2A
IgsBrFMGIblPGBOYvgd0fy9I85.2f6Z.We83rAN2gfLQzAesnCU8wKqwyv6p
Q2.s5rgtoAN2wZbYoV8QWcp0Allm3CYxgmKF.VplEdfuylMsEbRYNGL+3Dmb
o8yuEr+jKNSyD8OMEj8f.t7hyMUhQHZ0WuFWkJL3NFY+Hjyzr.ONaZ4Gz2R9
AhvN.AD1rU+ZRZLN6MgfJI1Allorjvof.zapFEhePdtyzrf.5zTQP5qZIX0q
2BCOnJqyzLEClVZ99qy4BmjuJi9.SySpbz+O4ADyZQBamztonzv6pJXML8fd
DbYMXt7e.8otWMB
———–end_max5_patcher———–
The JS code is :
/*
//////////////////////////////////////////////////////////////////////////////
this funky code has been written by me, julien bayle, a particular sunday morning,
but you can edit it, as a lot of my others work, in order to inspire you, etc.
this code is licensed under the Creative Commons Attribution 3.0 License.
//////////////////////////////////////////////////////////////////////////////
*/inlets = 4;
outlets = 4;function get_those_funky_tracks()
{
for (t = 0 ; t < num_tracks; t++)
{
track_table[t] = new LiveAPI(this.patcher, “live_set tracks ” + t);
outlet(0, “append ” + track_table[t].get(“name”));
}
}function get_those_cooly_devices(track_n)
{num_devices = track_table[track_n].getcount(“devices”);
for (d = 0 ; d < num_devices; d++)
{
device_table[d] = new LiveAPI(this.patcher, “live_set tracks ” + track_n + ” devices ” + d);
outlet(1, “append ” + device_table[d].get(“name”));
}
}function get_those_gorgeous_parameters(device_m)
{
num_parameters = device_table[current_device].getcount(“parameters”);
for (p = 0 ; p < num_parameters; p++)
{
parameter_table[p] = new LiveAPI(this.patcher, “live_set tracks ” + current_track + ” devices ” + device_m + ” parameters ” + p);
outlet(2, “append ” + parameter_table[p].get(“name”));
}
}function export_the_so_so_looked_for_ID(parameter_o)
{
outlet(3, parameter_table[parameter_o].id) ;
}function clear_all()
{
outlet(0, “clear”);
outlet(1, “clear”);
outlet(2, “clear”);
}function track(n)
{
outlet(1, “clear”);
outlet(2, “clear”);
current_track = n;get_those_cooly_devices(n);
}function device(m)
{
outlet(2, “clear”);
current_device = m;
get_those_gorgeous_parameters(m);
}function parameter(o)
{
current_parameter = o;
export_the_so_so_looked_for_ID(o);
}function bang()
{
clear_all();liveset_observer = new LiveAPI(this.patcher, “live_set”);
num_tracks = liveset_observer.getcount(“tracks”);current_track = 0;
current_device = 0;
current_parameter = 0;
track_table = new Array();
device_table = new Array();
parameter_table = new Array();
get_those_funky_tracks();
}


