Sep 13, 2012 at 12:43am
I’m trying to connect various mxj instances together, with some awareness of the patcher hierarchy.
In Java, something to this effect:
From the docs:
My current kludgy attempt at rectifying this is to iterate over all of the mxj instances, as returned by MaxContext.getAllObjects(). Then I grab each MaxObject’s MaxPatcher, and recurse downward through any subpatchers it might contain. Each child-parent patcher relationship I discover gets stored in a static HashMap, which in turn lets me simulate the effect of traversing upwards through patcher relationships towards the highest patcher (or patchers) I’ve found.
This doesn’t really sit well with me – I’d rather not maintain a parallel model of the Max environment if I can help it.
Is there an easier way?
Sep 13, 2012 at 1:22am
I’ve never looked at Java for Max so I don’t know what functions are available. However, I’m not convinced that capturing the child-parent references constitutes modelling the Max environment. If I needed the functionality you describe, I’d just define a tree structure that has parent links in it, then traverse the patcher hierarchy once (or whenever you add/remove patchers) and build the tree on the fly, complete with child-parent links. I’d use the hashmap simply as a quick way to find the appropriate link in the tree and then just go up that tree.
On a separate note, I’d encourage you to wrap that recurse function with
Sep 13, 2012 at 2:07am
Then again, “every line of code not written is 100% bug free.”
PS: Thanks on the bugfix for the Java example. Any idea under what circumstances p would be null?
Sep 13, 2012 at 2:17am
This wasn’t a bug fix, but rather a defensive move.
I don’t know if ‘this.getParentPatcher’ could fail — what happens if you invoke your script on a top level patcher?
Personally, I just like to have functions protect themselves rather than assuming that they will never be called with invalid parameters.
If you’re certain it can never happen, then throw in
assert(p != null)
at the top and prepare for crashes if (when) it does happen :-)
The assertion is also a good way to notify users of your code (which includes yourself months later when you’ve forgotten the code) what args are legitimate. For example, if you were building a square root function, you should always put (assert(parameter) >= 0) so that you can easily detect attempts to get the square root of a negative number.
Sep 13, 2012 at 3:23pm
This won’t help you now, but I am currently working on developing a JNI library to extend
In the meantime, maybe you should drop an email to email@example.com to point out this thread as a feature request as the current patch scripting stuff in Java is kind of crippled without this—as you’ve disovered.
Sep 14, 2012 at 5:28pm
OK, totally agree about the defensive patching – thought maybe you knew something about how these mxj methods return that I might be able to work with.
MaxObject.getParentPatcher() returns a reference to the patcher containing the [mxj] box that the MaxObject Java peer lives in. I’m actually trying like hell to get it to return me a null, since that might let me notify my datastructures that the patching environment has changed, and then let me update them in a more atomic way (rather than doing a complete traversal and rebuild of my model of a potentially large patch).
No luck so far.
That sounds pretty definitive then. I’ll just keep building boilerplate. Good luck with the JNI library!
Sep 15, 2012 at 2:54am
What is your definition of a large patch? Patchers are relatively static, I suspect it’s rare that large numbers of patchers will be getting created dynamically, so you’re not going to have to perform the traversal very often. Also, tree traversal is not very expensive so it will happen pretty quickly unless you have thousands of patchers.
I think you’re getting concerned by what those of us in the software development world call “premature optimization”. In other words, until your system is negativelyimpacted by the traversal, don’t worry about it.
Sep 15, 2012 at 11:00am
It will never return
So the bottom line is that you will not be able to use
But I agree, you might wait to optimize like that until you need to. When I have done traversals of very large patches, I only needed to do so after I was done working on changes so a short wait for a rescan was no problem. If you are looking for some sort of live updating you are probably right that you don’t want to do a whole traversal more than once but only update as needed.
I’ll be back in Boston if a few weeks if you wanted to chat about some of this stuff and maybe help test that JNI stuff if it would be useful to you.
P.S.: Thanks for haniging out in Java land, I think Nick, Charles, and I were getting a little lonely ;)
Sep 15, 2012 at 11:03am
Not much better, but maybe a slightly nicer workaround would be to put your patch parser mxj all of your top level patches so you can dive into all your subpatches from there (as you said, relying on the hope that there is at least one mxj in each top level patch doesn’t seem like a robust solution).
Sep 18, 2012 at 4:51pm
I see now about the MaxObject.getParentPatcher() never returning a null reference. Looks like the only reliable way to test if a patcher has been deleted is not inside the MaxObject’s notifyDeleted() call, but rather the next time a new MaxObject is added to the patch (by triggering a rescan).
I’m not into dropping a sentinel object into the top level patcher, although I acknowledge that that makes this problem so much simpler. Still, I’m getting pretty close to a flexible register/unregister system that avoids full traversals on every addition or deletion of [mxj] instances. I’ll write back with the code once I get a little time to finish it up.
PS: I’d love to meet up to talk shop about this JNI business. Message me the dates!
You must be logged in to reply to this topic.