Javascript dictionary and Live API issues

John Comer's icon

Hi, I am fairly new to using Javascript in Max but have been wanting to get more proficient with it, particularly with the use of dictionaries and the "get_notes_extended" and "add_new_notes" functions in the Clip class for passing note data back and forth between Max and Ableton Live. To begin with this, I've been trying to figure out how to get a dictionary from the "get_notes_extended" function, construct a new dictionary, send note data to the "add_new_notes" function for it to appear in the currently accessed Clip in Ableton Live, and then send the name of the created dictionary out the js outlet. Example code is below. I've written questions as comments in the code below:

var clipApi = null

function id(id) {
    clipApi = new LiveAPI("id " + id)
    if (clipApi.path === "") clipApi = null
}

function myDictTest(from_time, time_span)
{
    if (clipApi == null) throw("No clip")

// Get notes from Clip corresponding to id defined in function above.
    var notesJson = clipApi.call("get_notes_extended", 0, 128, from_time, time_span);
// I have found that the "get_notes_extended" function does not return a dictionary but appears to return a String representation of a dictionary

// If I use:
    // var notesObject = JSON.parse(notesJson);
// an object is returned that allows accessing data more easily, but it is not a dictionary
// How can a dictionary be made?

// I then try to create a new dictionary
var newDict = new Dict();

// I would like to create a dictionary of an appropriate form for use with the "add_notes_function" which is generically represented by :
// { "notes" : { [] }
// where each entry in the list is a dictionary with the expected key/value pairs for a note event

// I can explicitly define a single note as:
newDict.setparse("notes", '{"pitch" : 72, "start_time" : 0.0, "duration" : 0.125, "velocity" : 100.0, "mute" : 0, "probability" : 1.0, "velocity_deviation" : 0.0, "release_velocity" : 64.0}');

// however, I do not know how to append additional data to the "notes" value; i.e. how to make a list of dictionaries. My attempts at using the dictionary "append" function have resulted in Max crashing or other unexpected behavior.

// To test the "add_new_notes" function, I tried
clipApi.call("add_new_notes", newDict);

// however, the single note event that I defined above does not appear in the expected clip in Arrangement view in Ableton Live

// I can send the created dictionary name out the js outlet for use in the graphical Max environment:
outlet(0, "dictionary", newDict.name);
}

I would really appreciate any help with the questions that I wrote above in the comments. I'd really like to take advantage of the "get_notes_extended" and "add_new_notes" Javascript functions as I believe they would allow for some really interesting algorithmic composition. Thanks so much for any help.

Bradley Korth's icon

If you want to put dictionaries as items in another dictionary using JavaScript, it'd be like this:

Dict("biggerDictionary").replace(lineItem, Dict("smallerDictionary"));

If then you want to add to that smaller dictionary that you added as an item...
Dict("biggerDictionary").replace(lineItem + "::" + subLineItem, anything));

Matan Zohar's icon

The above doesn't answer the question. I would also like to know how to format a dictionary of "notes" to be called by "add_new_notes" in javascript. Can anyone give a direct answer?

The problem is with putting the note dictionary inside an array inside another dictionary with the "notes" key.

Everything I've tried has resulted in a formatting error. Please help!

tyler mazaika's icon

Maybe try this? Needing to use this "wrapper" step is annoying, but I think its the easiest way to get Max JS to parse the array/list into a Dict key called "notes".

var notesdata = {"notes" : [
        {"pitch":60, "start_time":0., "duration": 2},
        {"pitch":65, "start_time":1., "duration": 2},
        {"pitch":80, "start_time":2., "duration": 2}
    ]}
var d = new Dict()
d.setparse("wrapper", JSON.stringify(notesdata))
post( d.stringify(), "\n" )
var notesdict = d.get("wrapper")
post( notesdict.stringify(),"\n")
post( notesdict.get("notes[1]").stringify(), "\n")

api.call("add_new_notes", notesdict)

Matan Zohar's icon

Thank you Tyler, this works!