How to save Javascript object to Max for Live preset using pattr?

Zach Hall's icon

Hi all,

I've developed a simple Max for Live MIDI effect that relies on a javascript object for storing information. An example of this object is as follows:

var chordMap = {
12: [15,16,17],
13: [30,31,32],
14: [50,60,64]
};

I can keep track of this variable until I close Live, but it doesn't save as a preset. I think the easiest way to save it would be to stringify it as a JSON string and write it through pattrstorage, but I can't figure out how to do it.

I tried making a simple patch where I store and recall the value of the JS object itself using getvalueof() and setvalueof() and a string to hold the data but Max crashes when I hook this JS object to a pattr object and attempt to open the parameters window.

Can anyone point me in the direction of a way of serializing and deserializing a JSON object using Max for Live parameters and pattr? It would seem possible since pattr supports a "blob" type which says it can be used for strings, lists, etc. When I attach my JS object to a pattr object though it comes up as an "atom" type, and the crash occurs when I enable parameter mode and set the type to "blob" for the parameter storage.

I'm assuming that pattr is the right object to use since I've seen that autopattr doesn't work with M4L parameter mode in a help article. My end goal is to be able to load and save this dictionary as part of an Ableton .adv preset file.

I've attached my patch to this post. The variable in the JavaScript file called "chordMap" is the one that I need to save and restore. I'm familiar with JavaScript but I'm completely new to M4L and any help or pointers in the right direction would be greatly appreciated!

Thanks!

MemoChord.amxd
amxd
Zach Hall's icon

After a few hours of working on it, I feel a lot more confident that this problem can be solved. Sans-javascript, I'm able to load and save the states of dictionaries through the dict object and arbitrary strings through the textedit object. I'm not sure which would be more efficient: using a dict object in JavaScript or simply serializing a JS object and storing it in a textedit (or if there's a way to bypass both of these and do it directly in JS).

I pasted the toy patch I'm working with below. If you load it into M4L and click the add / append buttons it'll append the time, and if you save using Live's system you can make an .adv with those attributes saved.

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

At this point, I know it's possible to store so it's a more a question of how that works in JavaScript. For instance, I've read about declaring an attribute in a JS object in one implementation, and someone else talked about making the JS object itself act like it has a value using get / setvalueof. That may be a better way of doing it than manipulating a textedit?

Thanks for taking a look!

rjungemann's icon

Cool! I like the use of [dict] and [textedit]!

I'm working on a little JS-powered sequencer and I needed the ability to store notes that the user input. So I had to find a way to store a JS array. It took some time to wrap my head around it, but I ended up using [pattr] to do it. Attached is a simplified example of the approach I took.

JS-Storage.zip
zip
Lee's icon

Use getvalueof/setvalueof and connect the js object to the bind output of a pattr

Zach Hall's icon

Thanks so much for the responses! The .zip file is helping incredibly :) I didn't know that a JS object can accept function names as messages and call those so that's very cool!

I did a bit of cursory testing this morning and was able to reproduce the JS example with pattr using in/out patches instead of bindto. Will continue working on it and update. It sounds like from what y'all are saying I can use patcher.getnamed() to get a pattr and set it without using the patch cables. I'll give it a try.

Zach Hall's icon

I've successfully saved my presets to a .adv preset! Thanks again for the help. For anyone else who comes across this same issue, I took an approach that's similar to the one in @rjungemann's .zip file. I've attached a screenshot of the section of the patch that deals with I/O. I found hard-wiring the pattr is easier to follow in the long run than using .getvalueof() but it could be done either way.

The JavaScript for the section of the code is as follows:

function load(fromPattr) {
    post('Load', fromPattr + '\n');
    chordMap = JSON.parse(fromPattr);
    outlet(2, chordMap);
}

function recall() {
    outlet(2, chordMap);
}

function save() {
    var out = JSON.stringify(chordMap);
    outlet(1, out);
}

function reset() {
    chordMap = {};
    save();
}

patch.png
png