Storing/Recalling patch data in M4L device? (how-to and best practice)

Rodrigo's icon

So I'm finally getting around to building some of my patches as M4L devices, and I'm not sure how to go about some things.

Going by this (old) document:
https://downloads.ableton.com/misc/maxforlive_production_guidelines.pdf
(are there any more detailed and/or current guides for this kind of thing?)

I see that it's good practice to have parameters be stored/recalled by Live, which obviously makes sense.

I'm just not sure how to do that for certain objects.

polybuffer~:
(I would presume this one is straight forward as long as the files that were loaded remain in their current paths?) Is there anything special you need to do with buffers/polybuffers for their contents to be stored/recalled with Live?

colls:
So many colls... I have many colls throughout the patch, some of which are static 'save data with patcher' ones, some are nameless and dynamically loaded (though the state of these would need to be stored with the patch), and the third type are named, filled dynamically, and referred to in multiple places in the patch.

entrymatcher~: (an external by Alex Harker for complex queries on arbitrary data sets)
This object doesn't have a native store/recall mechanism, so I use some of the colls to dynamically populate this external with lots of data. I would imagine it's not as easy as just exposing the object to some kind of preset system, but would I then need to manage a separate data storage structure and re-brute-force the data back in each time the Live set is loaded?

So any input is welcome here, as this kind of loading/recalling is new to me, in the world of M4L.

brianbuchanan57's icon

When starting to work on Max for Live devices, I was a little wary about objects that would need other files – usually txt files – to work, such as [coll] and [pattr] (at least, as I understand them). I'm sure there's a way to handle all of that just fine, but my thinking was/is if I ever had a complicated device like that, I'd just want to be able to send it to people without having to worry about search paths and all that.

So I'm not sure if this is what you're looking for – and again, I'm sure there's a better way to do this – but for [coll], I normally do something like I've done in the patch I've attached. I figured, if I was going to need a txt file anyway, I might as well just find a way to get it in a [comment] and save that (now that I know about it, though, perhaps 'save data with patcher' would work just as well. So far, I haven't had the need to change the guts of a [coll], but I'd assume I'd just do something like this to cover any/all bases and switch between them as needed.

(Rodrigo, I remember a while back you had a thread about trying to emulate the digital pitch shifting-ness of Whammy pedals, right? I figured out a lot of this [coll] stuff for a patch to exploit the MIDI input of Whammy pedals – if you have one, take it for a spin! http://www.maxforlive.com/library/device/3994/whammy-iv-midi-controller)

So again, maybe this isn't what you're looking for/want but I hope it helps – I'd also be interested in a better solution if anyone has one!

Sample-M4L-coll.maxpat
Max Patch
broc's icon

You may replace [coll] with [dict]. It has a 'parameter_enable' mode to store changes with the Live set. Conversion between them can be done with messages 'pull_from_coll' and 'push_to_coll'.

Rodrigo's icon

@Brian
For the coll stuff I've gotten quite handy at loading/storing/recalling to colls, just have to see how that translates to the world of M4L.
You really nailed the UI on the whammy thing! Will have a play with it.

@Broc
I've give dict a spin. I've been meaning to wrap my head around it, as it seems the way forward for data management. I just find the documentation a bit confusing.

broc's icon

For understanding [dict] this article may be helpful.

Rodrigo's icon

That is a fantastic blog post!

Stephane Morisse's icon

Thanks Broc for the link. Does anyone know a ressource about the Dict family that doesn't imply JS ?
Like Rodrigo I really want to dig the Dict family but couldn't get it using the documentation and topics I read. Seems like the help for it would need a rewrite, or at least clarification.

broc's icon

Notice that the article uses JSON only to explain 'object notation' for representing the content of [dict]. The main part is dedicated to examples in Max.

After understanding the basics, I've found the best way to learn more about [dict] is to play around with the related objects/messages and use 'print' to see what actually happens.

Rodrigo's icon

Ok, been wrapping my head around dict a bit, and have switched a few bits of my patch to dicts.

There's a couple of things I can't quite figure out yet.

First is, is there a way to know you've finished dumping data out of a dict like coll's last outlet? Like if I'm dumping a really long object (a 150,00+ entry analysis database file), how do I know it has finished dumping? (short of putting in a footer entry or something, which I would want to avoid doing)

Second, in terms of packing that long list of entries into a dict, I'm using "append analysis::" to set up an object called "analysis", which itself contains all the analysis data formatted as follows:

"analysis" :     {
        "0" : [ -30.743082, 0.0, 110.99221, -14.119069 ],
        "10" : [ -29.847477, 0.0, 102.78936, -18.857525 ],
        "20" : [ -30.850266, 0.0, 106.913391, -14.339486 ],
        "30" : [ -34.505981, 0.0, 100.441933, -19.840559 ],
        "40" : [ -37.735123, 0.0, 96.140182, -22.903746 ],
        "50" : [ -45.966511, 0.0, 90.787933, -27.842623 ],
        "60" : [ -38.871426, 124.842621, 103.400925, -15.41413 ],
        "70" : [ -35.512058, 0.0, 105.463936, -14.856118 ],
        "80" : [ 31.557777, 0.0, 114.881561, -7.335074 ],
        "90" : [ 24.237932, 0.0, 106.483566, -12.101012 ],
        "100" : [ 24.299706, 0.0, 101.199158, -17.09067 ],
        "110" : [ 29.310883, 0.0, 95.058838, -24.040127 ]
    }

So the 'key' is the time (in ms), and the array is the analysis data at each time stamp.

So that would mean creating messages that say "append analysis::10 -30.743082 0.0 110.99221 -14.119069", etc..., but that doesn't work in this context because of the lack of separation between the "::" and the time(key). I can run the whole mess through some regexp voodoo, but I don't really trust regexp in cpu intensive applications.

broc's icon

Ad 2: Why not using simple 'set' messages?

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

Rodrigo's icon

That works for top level stuff, but I want to nest all of this inside the "analysis" object.

This is getting quite niche (as relative to the original post, so I will break this out into a new thread).

EDIT: new thread discussing this here: