Some questions about node.script and Max 8

to_the_sun's icon

I currently (Max 7) use mxj net.udp to communicate with an external Python script. In Max 8 would the new node.script have the same plussides/downsides as this method? e.g. the script runs in true parallel as a separate process; but using UDP incurs some amount of latency.

Can node.script refer directly to things like colls and dicts? The NPM libraries wouldn't happen to also be available in the regular js object, would they?

Sam Tarakajian's icon

Hey there, lots to cover here but I'll try to sum up as best I can.

Yes, node for max runs a node script in a separate process. Communication with the process happens over a socket, so there is some non zero latency. Whether that latency matters depends on your application. Each node.script object owns its own node process, so you'll have as many processes as you have node.script objects.

There are some advantages to node for max. First, the node processes are true child processes of the main Max process, so you don't have to close those processes manually if you want them to go away when Max quits. Second, there's some attempt to convert types between JavaScript and Max types. If you send a dictionary to Node from Max, it will be converted into a JavaScript object (and visa versa).

There is support for reading/writing to named Max dictionaries from Node, but not coll objects.

Finally, you can use require and include in the plain JS object. However, these word differently from the Node equivalent. Check the reference docs for more info.

to_the_sun's icon

Thanks, very informative! Has that always been the case with the plain JS? I really need to look deeper into that object.

I've heard that node.script can easily create files and folders. Can it delete files and folders just the same?

Sam Tarakajian's icon

As far as I know (admittedly I haven't been too close to it) this has been the case with JS for a while, though maybe not forever.

As far as what Node can do, here's the api docs for the version of node that ships with Node for Max.

Node can absolutely create and delete files. It can navigate up and down the operating system folder hierarchy, enumerate files, spawn processes--basically anything an application can do. If you look in Extras -> n4m-launcher, there's a button to launch an example that shows how to interact with the file system.

good luck and have fun!

Florian Demmer's icon

just quickly mentioning that js require is/has been available since Max 7. you can find more info here:

Iain Duncan's icon

Sam, that was really helpful. I'm not sure if Sam works for Cycling or not, but if any Cycling folks are listening, it would be really nice to have some version of this explanation in a page of the node-for-max help!

Florian Demmer's icon

Hey Ian.

The Node For Max package does contain a Guide that touches the differences about js and node.script. You can also find it here: https://docs.cycling74.com/max8/vignettes/04_n4m_jsdifferences

Iain Duncan's icon

Ah, nice, I had not stumbled across that page yet.

Iain Duncan's icon

Though it doesn't have quite the level of detail I'd like. Something similar that dug in into the differences with regard to scheduling and serialization in more detail would be nice, in a perfect world. :-)

sefable2 sefable2's icon

First, the node processes are true child processes of the main Max process, so you don't have to close those processes manually if you want them to go away when Max quits.

Would you confirm that contrary to the js object, the node process run as high-priority instead of low-priority?

I'm referring to this doc https://docs.cycling74.com/max7/vignettes/jstaskobject

the function runs in a low-priority thread. Therefore you should avoid using a Task function in a time-critical operation.

Sam Tarakajian's icon

Heya, just wanted to comment quickly on scheduling. Keep in mind that node.script runs in an entirely separate process. As I've written above, that means that when Max sends a message to node.script, it has to be sent over a socket connection to the Node process, and then read back from that socket when Node responds. So the notion of high priority versus low priority doesn't really apply. The high priority queue is something that the Max process owns, and the Node process doesn't run in the Max process at all!

Maybe this description of the Task object implies that you can't use Task if you care about time at all, which is not the case. This doesn't mean that Task (or node.script for that matter) is slow. For example, here's a project that uses Node for Max to coordinate musicians in real time https://www.youtube.com/watch?v=BXlaSBo0KXs

In general, unless you need really tight timing, node.script is probably fine. But if you're relying on sample accuracy for a particular application, then nether [js] nor [node.script] will work.

Iain Duncan's icon

Hi Sam, thanks for that detail. Are you able to say which thread the node.script object itself runs in for the serialization to and from the external process?

Sam Tarakajian's icon

Serialization into node.script depends on the source of the message. Messages coming out of node.script will use the low-priority queue.

Iain Duncan's icon

So if node.script writes to a dict, I assume under the hood that serialization will also be low-priority queue then?

Iain Duncan's icon

And, please correct me if I'm wrong, I assume the fact that serialization happens in the low-priority thread prevents one's node script from borking audio rendering when a dict is updated or read?

Sam Tarakajian's icon

I believe that's correct on both counts. The audio thread and the low priority thread shouldn't interfere with each other.

Iain Duncan's icon

Cool, thanks for the help.