Do closures work at all in Javascript on Max?

    Jan 04 2010 | 7:46 am
    I have just started to use Max (5.1.1, for Live) and I notice some irregularities when trying to establish callback functions written in Javascript. It seems that when passing functions to external objects (like LiveAPI), the function is passed by name (or, if I use a literal function, as a string) to the underlying object, invalidating all references to closed-over variables. Now, I can imagine how to work around this restriction by passing the callback arguments through 'this', but that is much less modular and much more error prone than just using closures. Is there any fix for this in the works?
    Consider function record_clip(track) { var clip_nr = find_free_clip(track);
    function set_clip_length() { var live = new LiveAPI(this.patcher); live.path = ['live_set', 'tracks', track, 'clip_slots', clip_nr, 'clip']; live.set('loop_end', 4.0); post('clip length set'); post(); }
    var live = new LiveAPI(this.patcher, set_clip_length);
    live.path = ['live_set', 'tracks', track]; live.set('arm', 1);
    live.path = ['live_set', 'tracks', track, 'clip_slots', clip_nr]; = 'has_clip';'fire'); }
    which generates these errors:
    js: livetest.js: Javascript ReferenceError: set_clip_length is not defined, line 148 js: livetest.js: Javascript ReferenceError: track is not defined, line 140
    Thanks, Hans

    • Jan 06 2010 | 11:50 am
      I fixed some closure issues in jsliveapi post-5.1.1. Send me a PM with your email address and OS if you want to do some testing.
    • Jan 06 2010 | 12:00 pm
      Sorry, just realized that this forum software doesn't support PMs. Send me an email at with that info, if you're interested.
    • Jan 15 2010 | 2:06 am
      As I previously documented on this forum, closures don't work in callbacks only.
      There's a simple workaround though!
      // Tasker is a  class with a single method, Run, that applies the given function
      // with the given "this" and args.
      // Tasker works around the issue documented in
      function Tasker(object, method, args) {
        this.object = object;
        this.method = method;
        this.args = args;
        this.running = false;  // Perfect for adding a listener to!                                                  
        this.Run = function() {
          this.running || this.Execute();
        this.Stop = function() {
          if (this.running) {
            this.task = this.task && this.task.cancel() && false;
            this.running = false;
        this.Execute = function() {
          this.method.apply(this.object, this.args);
        // Schedule this.Loop to run after a delay.
        this.Schedule = function(delay) {
          this.task = this.NewTask();
          this.running = true;
          return this.task;
        // This method is overriden in tests.
        this.NewTask = function() {
          return new Task(this.Execute, this);
    • Jan 15 2010 | 11:31 pm
      The canonical URL for this code is
    • Jan 16 2010 | 11:13 am
      Hi Maybe check out the "net.loadbang" stuff - I think there is a Groovy instantiation that may help you out.... Cheers