Tutorials

My Favorite Object: jstrigger

I’m a huge fan of using Javascript in Max via the js and jsui objects. It provides a fairly comprehensive tool set for patcher scripting and more programmatic approaches to certain Max tasks, all in the familiar wrapper of Javascript. Along with Javascript comes an API that provides number of very useful features, such as text manipulation, array usage, dates, and regular expressions. These days, a lot of these are bundled elsewhere in Max objects, but there are still instances when using Javascript is a much cleaner approach.

But, when you want to utilize a very specific Javascript feature in a streamlined way, making a new js object, opening its text editor, saving a text file, and then hooking the object up feels like a few too many steps. This is where the jstrigger object comes in handy.

Granted, the object isn’t going to solve all of your problems, but I’ve found it incredibly useful for doing things that would otherwise be cumbersome with other objects or to avoid the somewhat drawn out process that is required for setting up a new js object and script.

The basic concept of the object is that it can be used like a trigger object, but with the twist of being able to perform different Javascript instructions on the incoming data for each outlet:

Each parentheses pair describes an outlet, and whatever is within that parentheses specifies how the data is evaluated and processed. In this example, we have three different instructions, output each to different outlets - this is an exceptionally simple example, and only hints at the true potential of the object.

Digging a little deeper, and starting to lean on the Javascript API a bit more, let’s look at some of the possibilities with the Javascript Math Object. I’m always wanting to generate random float numbers. There are numerous ways to do this in regular Max (random->multiply by a float, float32 jit.noise->jit.spill, etc) but it’s always just a few too many steps for me, so I use jstrigger:

It’s one stop shopping! The whole statement is in parentheses, to let the object know where to begin parsing, and we are utilizing the random function of Javascript’s Math object. Of course, we might not always want our random float value to be between 0. and 1., so we can easily add a range, using an array-style reference to what is coming into the object:

The ‘a’ refers to the incoming list, and the [0] and [1] refer to the position of a value in the list. The first value is a min and the second value is a max

You can make this as complicated as you want, adding various other Math functions or logic to fine-tune to your specific needs. It all happens in one box, so it is very portable and fairly easy to read. Here is an example of prepending a string to the output:

I’m simply making an array out of the entire statement, with the first entry being my ‘freq’ string, and the second entry being the random value.

Most any of the global Math functions will work in this manner. For a list, check out MDN.

Max already has the rexexp object, which is reasonably easy to use. But if you are more comfortable with Javascript, and you have a simple one-liner, why not use jstrigger?

Here is a simple example that removes spaces from incoming data:

Again, we treat the incoming text like the first element of the array, a[0], and then use the replace() function to look for the spaces (s), and then replace them with nothing (‘’).

Another feature that I love is the ability to use conditional operators as shorthand for if statements:

Conditional (or ternary) operators evaluate a condition that return ‘true’ or ‘false’ (does the input match ‘bob’?), and then returns an expression based on what is returned. In this case, if it (a[0] == ‘bob’) is true, “bob has entered” is returned, and if it is not, “someone else has entered” is returned.

I’m just scratching the surface here, as you could do a whole lot more, but hopefully this at least shines a light on a dimly lit corner of Max that you might find useful in your patching. Enjoy!

Learn More: See all the articles in this series

by Ben Bracken on January 10, 2017

Floating Point's icon

Hey Ben, thanks for the topic. Is it possible to have for (or while etc) loops inside a js trigger? If so how?
(I suspect not)

Ben Bracken's icon

@FLOATING POINT, good question! Currently you can't really use loops in jstrigger.

-Ben

nick rothwell | project cassiel's icon

You should have access to things like map, reduce and filter which let you do iteration over arrays in a functional manner.

For example, this works (for summing arrays):

jstrigger "(a.reduce(function (a, b) { return a + b; }))"

Ben Bracken's icon

Indeed, most of the Array methods are available. One that is *not* is Array.forEach(), which would be handy.

-Ben

Floating Point's icon

Thanks Nick & Ben, that's handy to know.

Mattebass's icon

Hi, I've tried to use jstrigger with array property length and Max crashes every time

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

Ben Bracken's icon

@MATTEBASS it looks like jstrigger doesn't like lists > 10 in length, interesting. Thanks for the heads up, we will take a look.

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

Here is a goofy workaround in the meantime:

-Ben

Holland Hopson's icon

Thanks for this series. It's great for learning about objects I've missed. I'm loving the elegance of Math.random() already.

Ahmed Hentati's icon

Hi there,
Thanks for this this article, the examples are great. I've been using the jstrigger a lot lately, and managed to execute a for loop inside it.

jstrigger (yo(a.join(' ')).split(' '); function yo(list){var ret='' ; for(i=0; i<5; i++){ ret += ' '+list } ; return ret } )


I'm using it to concatenate biquad coefficients and send them to a cascade~ , and now I'm realizing that using a prepend append and a trigger is way simpler...

I found that it behaves quite weirdly sometimes, I had an error due to a space before a semicolon, slice() and concat() wont work everywhere etc...

Anyway, now we can all do loops inside jstriggers haha. Happy patching...