With the Max 
js object, it’s possible to use JavaScript code to perform patcher scripting, where you can create Max objects in a patcher dynamically, setting their properties, sending them messages, and making connections between them. JavaScript allows you to use procedural code to generate patcher elements in ways that may be more difficult to do through messages to the 
thispatcher object (the other way to automatically create Max objects in a patcher). This Tutorial covers how to create and delete objects and connections in a Max patch through custom methods written in JavaScript, as well as to show how to use methods to handle custom messages coming from the patcher.
When you initially open the tutorial patch, you will see a largely empty patcher with a 
js object in the lower part of the patcher window. The 
js object has loaded a JavaScript source file called ‘autosurface.js’, which is located in the same folder as the Tutorial patch.
The 
js object is configured to send numbers to a MIDI output device (using the 
makenote and 
noteout objects). It also has a right outlet sending values to the right inlet of the 
pack object driving messages to a 
multislider object. In addition, our 
js object has a number of objects connected to its inlet. A 
metro object is connected to our 
js object, as are two 
message boxes that will send the messages 
sliders $1 and 
reverse $1, where 
$1 in each case is the value present in the 
number box connected to them.
From the patch layout, we can infer that the JavaScript code in our 
js object should have at least three functions, for 
bang, 
sliders, and 
reverse. It actually has one more, which will become apparent when we use the patch.
Select the 
number box attached to the message box containing the 
sliders $1 message. Type in or scroll to the number 
5, and watch what happens. Change the value in the 
number box. Try setting it to a large number (like 
50).
Set it to 0, and see what happens.
In response to our 
sliders $1 message, our 
js object dynamically 
creates Max objects and connections through 
scripting. It creates pairs of 
ctlin and 
slider objects to match the number of sliders you request through the message to the 
js object. Furthermore, it creates a 
funnel object with the appropriate number of inlets for the 
slider objects and makes the appropriate connections between them. The 
funnel object is then connected to our 
js object, allowing the values generated by the sliders to be used by our JavaScript code as well.
As you create sliders, note that the 
ctlin objects are automatically numbered to listen to incrementing MIDI controller numbers. As a result, a MIDI control surface that sends MIDI continuous control values on multiple controller numbers will send values to independent 
slider objects. Also, note than when you decrement the number of sliders, the excess objects will disappear (actually, everything disappears and is recreated again). If you set the number of sliders to 
0, all the script-created objects (including the 
funnel) will be deleted from the patch.
Set the number of sliders to something modest, such as 
5. Change the values in the 
slider objects, either by clicking on them or by using a MIDI controller input. Turn on the 
metro object by clicking the 
toggle attached to it. The values in the 
slider objects should come out of the 
js object in turn, creating a sequence of MIDI notes.  Double-click the 
noteout object to select a valid MIDI synthesizer, and you should hear them.
The 
multislider object to the right of the patch will give you a running display of the current note out of our sequencer, set at its appropriate position in the sequence.
Click the 
toggle attached to the 
message box containing the message 
reverse $1. Note that the order in which the 
slider values are sequenced is now backwards. Our 
multislider display runs backwards as well.
In brief, our 
js object dynamically creates a scalable MIDI control surface (with 
ctlin and 
slider objects), and uses those objects’ values to create a simple MIDI 
step sequencer. The number of sliders created by our JavaScript code determines the length of the sequence.
Turn off both 
toggle objects, stopping the sequence and putting the sequencer transport back into ‘forward’ mode. Let’s look at the code for our 
js object.
Double-click the 
js object in the Tutorial patch. The code for ‘autosurface.js’ should appear. At the top of the code should be the familiar comment block, explaining what the script does. Below that we should see our global code statements:
// inlets and outlets
inlets = 1;
outlets = 2;
// global variables and arrays
var numsliders = 0;
var seqcounter = 0;
var thereverse = 0;
var thevalues = new Array(128);
// Maxobj variables for scripting
var controlin = new Array(128);
var thesliders = new Array(128);
var thefunnel;
As we saw in the previous tutorial, our 
inlets and 
outlets at the top of the code tell 
js how many inlets and outlets we want in our object. 
The following block of code defines some variables that our JavaScript code will need to use globally. These variables include:
	numsliders: Stores how many ‘sliders’ (ctlin and slider pairs) we have in our patch. This is set by the 
sliders message to our 
js object.
	
seqcounter: Stores the current point in our sequence. This is driven by the 
metro object in our patch, and therefore is changed by a 
bang() method in our code.
	
thereverse: Sets whether or not our sequencer is running backwards. This is set by the 
reverse message to our 
js object.
	
thevalues: An 
array (see below) of values reflecting the state of the 
slider objects in our patch. The 
funnel object in our patch sets these values by sending lists to our object.
The new Array() constructor creates arrays in JavaScript. The array variable thevalues, above, has 128 elements, which are accessed by bracket notation following the array name, e.g.:
	k = thevalues[5];
will set the variable k to the value of the sixth element (starting from 0) of the array thevalues.
	thevalues[n] = 55;
will set the element n of the our array thevalues to 55.
Note that JavaScript treats Arrays as objects, so that:
	k = thevalues.length;
will set the variable k to the number of elements in the array thevalues. For more information on this, consult any good JavaScript reference.
After our variable declarations, we have variables that we will use to reference dynamically created objects in our Max patch. These variable names are used internally in our JavaScript code so that we can create, connect, delete, and modify objects all through properties to these objects. Objects in 
js that refer to Max objects in a patcher are referred to as 
Maxobjs. We have the following Maxobj variables in our script:
	
controlin: An array of Maxobjs that refer to the 
ctlin objects in our patch.
	
thesliders: An array of Maxobjs that refer to the 
slider objects in our patch.
	
thefunnel: A Maxobj which references the 
funnel object in our patch.
Note that there is no difference in JavaScript variable declaration with relation to the type of value that the variable stores; integers, floats, strings, and objects are all considered equivalent when declaring a variable. Similarly, arrays are defined simply to refer to quantity of information, rather than what type of information will be stored in them. Similarly, JavaScript will correctly type variables following a calculation, e.g.:
	x = 4/2;
will set the variable x to 2 (an integer), whereas:
	x = 3/2;
will set the variable x to 1.5 (a floating-point value). Variables can switch types dynamically throughout their existence. This use of untyped variables only exists within the JavaScript environment, however, which is why we still need independent methods (msg_int() and msg_float()) to deal with differently typed numbers coming in from Max.
We will use various properties of the Maxobj object class to perform our scripting, all of which is accomplished by a single function: our sliders() method.
Our 
js object responds to the 
sliders message via a method contained in the 
sliders() function (remember that the function name typically matches the message you want to trigger that function). Examine the code for the 
sliders() function. The comments at the top of each section explain what’s happening at each step in the process:
// sliders -- generates and binds the sliders in the max patch
function sliders(val)
{
	if(arguments.length) // bail if no arguments
	{
		// parse arguments
		a = arguments[0];
		// safety check for number of sliders
		if(a<0) a = 0; // too few sliders, set to 0
		if(a>128) a = 128; // too many sliders, set to 128
		// out with the old...
		if(numsliders) this.patcher.remove(thefunnel); // if we've done this before, get rid of the 
funnel
		for(i=0;i<numsliders;i++) // get rid of the 
ctlin and 
slider objects using the old number of sliders
		{
			this.patcher.remove(controlin[i]);
			this.patcher.remove(thesliders[i]);
		}
		// ...in with the new
		numsliders = a; // update our global number of sliders to the new value
		if(numsliders) thefunnel = this.patcher.newdefault(300, 300, "
funnel", a); // make the 
funnel
		for(k=0;k<a;k++) // create the new 
ctlin and 
slider objects, connect them to one another and to the 
funnel
		{
			controlin[k] = this.patcher.newdefault(300+(k*50), 50, “
ctlin”, k+1);
			thesliders[k] = this.patcher.newdefault(300+(k*50), 100, “
slider”);
			this.patcher.connect(controlin[k], 0, thesliders[k], 0);
			this.patcher.connect(thesliders[k], 0, thefunnel, k);
		}
		// connect new objects to this 
js object's inlet
		ourself = this.box; // assign a Maxobj to our 
js object
		if (numsliders) this.patcher.connect(thefunnel, 0, ourself, 0); // connect the 
funnel to us
	}
	else // complain about arguments
	{
		post(“sliders message needs arguments”);
		post();
	}
}
In pseudo-code, our 
sliders() function performs the following steps:
Check to see if the arguments for the sliders method are valid.
If true…
	Make sure the number of sliders requested are in a reasonable range (
0-
128)
	Delete any objects previously created by our 
js object.
	Make the new objects and connect them to one another.
	Find our 
js object (see below) and connect our new 
funnel to it.
If false…
	Post an error message in the Max window and exit the function.
Our JavaScript code takes advantage of two important features of procedural programming, namely conditional statements (if…else…) and iteration (for() loops). If you’ve used another programming language such as C or Java, you should find these constructions familiar. A JavaScript reference will help you with the specifics.
One of the first things we do in our sliders() function is check to see what the arguments were to the sliders message sent in from the patcher. We do this by checking the arguments property of the function itself, e.g.:
	if(arguments.length) {
		// some code here
	}
will execute the code between the braces only if there are a non-zero number of arguments to the message that called the function. Otherwise, that part of the code will be ignored. Similarly, you can access the arguments by number as an array:
	a = arguments[0];
will assign the variable a to the value stored in the first argument of the message. In our case, this refers to the number of sliders we want to create.
From the perspective of using 
js for object creation in Max, the Maxobj class allows us to use our object variables to create, connect, and destroy objects. This is done by first accessing the 
Patcher object, which is a JavaScript representation of our Max patch. The statement:
	this.patcher.remove(thefunnel)
tells 
js to find a Maxobj called 
thefunnel in the Patcher called 
this (which is always the patcher containing the 
js object) and delete it. The ‘this’ in the statement is actually optional, but it’s worth noting that you can use JavaScript to control objects in patches other than the one in which the 
js object resides.
To create an object, we assign a variable to a new Maxobj created by the Patcher:
	thefunnel = this.patcher.newdefault(300, 300, “
funnel”, a);
In this case, the Maxobj 
thefunnel is created to be a default object at coordinates 
300 by 
300 on the patcher window. The object’s class is set to 
funnel, with the object’s arguments set to whatever is contained in the variable 
a.
Note: the newdefault() method to the Patcher object creates a new object just as if you had created it manually from the palette or patcher contextual menu. This simplifies scripting substantially. If you wish to specify all the object parameters (object width, flags, etc.) you can use the newobject() method instead.
Connections are made by taking two Maxobjs and linking them using the connect() method to a Patcher object, e.g.:
	this.patcher.connect(thesliders[5], 0, thefunnel, 5)
will connect the leftmost (0) outlet of the sixth Maxobj in the array thesliders to the sixth inlet of the Maxobject thefunnel. Remember that numbering starts at 0 for both arrays and inlet/outlet numbers.
We use iteration and arrays to create multiple objects at once, for example:
for(k=0;k<8;k++)
	{
	controlin[k] = this.patcher.newdefault(300+(k*50), 50, “
ctlin”, k+1);
		thesliders[k] = this.patcher.newdefault(300+(k*50), 100, “
slider”);
		this.patcher.connect(controlin[k], 0, thesliders[k], 0);
		this.patcher.connect(thesliders[k], 0, thefunnel, k);
	}
will automatically generate 
8 ctlin and 
slider objects spaced 
50 pixels apart on the patcher window (starting at horizontal coordinate 
300), connect them to one another, and then connect them to the 
funnel object referenced by 
thefunnel. Note that the variable 
k in our JavaScript code is never declared, since we only use it as a local variable (in the 
sliders() function) and re-initialize it every time that function is called. In our actual JavaScript code in the Tutorial patch, the number 
8 is replaced by the local variable 
a, which represents the number of sliders we want to create.
One important thing we accomplish in our 
sliders() method is the connection of the JavaScript-created 
funnel object to our 
js object’s inlet. However, our 
js object was created by hand, not by our JavaScript code (this would be impossible, if you think about it). How do we bind a Maxobj to an object that was created independently of a JavaScript program?
ourself = this.box; // assign a Maxobj to our 
js object
The ‘box’ property of our patcher returns a Maxobj referring to our 
js object itself! We then take the variable ourself and assign it to our 
js object. This allows us to make connections to the object containing our JavaScript code.
We then connect our 
funnel object to our 
js object using our newly assigned Maxobj ourself:
this.patcher.connect(thefunnel, 0, ourself, 0);
The 
js object in this Tutorial doesn’t just create and connect a MIDI control surface; it also reacts to messages from the control surface as well as other messages from the Max patcher.  Open up the source code for the 
js object in the Tutorial patch again, and look for the function called 
list():
// list -- read from the created 
funnel object
function list(val)
{
	if(arguments.length==2)
	{
		thevalues[arguments[0]] = arguments[1];
	}
}
As with our sliders() function, our list() function first checks out how many values we’ve sent in from Max, e.g.:
if(arguments.length==2) {}
The 
funnel object puts out a list corresponding to the number of the inlet receiving the value followed by the value received. For example, the number 
55 arriving at the second inlet (which is really inlet number 1) will trigger the list 
1 55 from the 
funnel object. We check to make sure we have two arguments in our message before we proceed in our 
list() method, as we use both the values in the list in the function. We use the first argument (which slider we moved) to determine which element of the array thevalues we set to the second argument (the value).
Look at the bang() and reverse() functions in the JavaScript code.
// bang -- steps through sequencer
function bang()
{
	if(seqcounter>=numsliders) // reset sequencer
	{
		seqcounter = 0;
	}
	if(thereverse) // read from the array backwards
	{
		outlet(1, numsliders-seqcounter-1); // send out our location in the sequence
		outlet(0, thevalues[numsliders-seqcounter-1]); // send out the current note
	}
	else // read from the array forwards
	{
		outlet(1, seqcounter); // sound out our location in the sequence
		outlet(0, thevalues[seqcounter]); // send out the current note
	}
	seqcounter++; // increment the sequence
}
// reverse -- changes sequence direction
function reverse(val)
{
	if(arguments.length) 
	{
		thereverse = arguments[0]; // flip it
	}
}
Our 
bang() method (which in our patch is triggered by a 
metro object) steps through a sequence of values in a manner analogous to the 
counter object. The maximum count is set by the number of sliders we have in our patch (defined by 
numsliders). The direction of the counting is always upwards, snapping back to 
0 when we exceed the number of sliders. The 
reverse() function sets a variable (
thereverse) based on the arguments for a 
reverse message sent in from Max. This changes the way in which the 
bang() method reads from the array (
thevalues) storing the numbers from our control surface of 
slider objects. Our two 
outlet() functions send our current index value out our 
js object’s right (
1) outlet, followed by the value at that index in the sequence out our 
js object’s left (
0) outlet. Note that we follow the important Max convention of outputting values from outlets in a 
right-to-left order. Otherwise, our 
pack object would be triggered by its left inlet before it receives the value it needs in its right inlet.
The 
outlet() function outputs the value at the current index in the sequence out our 
js object’s left (
0) outlet.
Now that you know how the JavaScript code is working, play with the patch some more. Think about how you would recreate the sequencer using the normal Max table and counter objects.
The 
js object offers you a powerful way to create Max patches dynamically in JavaScript. Object creation is accomplished through the assignment of variables to 
Maxobj objects created by a 
Patcher object, which represents the patch in JavaScript. The 
newdefault() and 
newobject() methods allow you to create objects, which can be destroyed by a 
remove() method. The 
connect() method lets you make patcher connections between Maxobjs in your script. A Maxobj can be assigned to the 
js object itself through the ‘box’ property to the patcher. When designing JavaScript functions to act as methods for Max messages, the arguments passed with the messages are available through the arguments array from within the function.
// autosurface.
js
//
// automatically generate a MIDI control surface with
// visual feedback (sliders), hook it up to a 
funnel
// object, and use it to drive a simple sequencer.
//
// rld, 5.04
//
// inlets and outlets
inlets = 1;
outlets = 2;
// global variables and arrays
var numsliders = 0;
var seqcounter = 0;
var thereverse = 0;
var thevalues = new Array(128);
// Maxobj variables for scripting
var controlin = new Array(128);
var thesliders = new Array(128);
var thefunnel;
// methods start here
// sliders -- generates and binds the sliders in the max patch
function sliders(val)
{
	if(arguments.length) // bail if no arguments
	{
		// parse arguments
		a = arguments[0];
		// safety check for number of sliders
		if(a<0) a = 0; // too few sliders, set to 0
		if(a>128) a = 128; // too many sliders, set to 128
		// out with the old...
		if(numsliders) this.patcher.remove(thefunnel); // if we've done this before, get rid of the 
funnel
		for(i=0;i<numsliders;i++) // get rid of the 
ctlin and 
slider objects using the old number of sliders
		{
			this.patcher.remove(controlin[i]);
			this.patcher.remove(thesliders[i]);
		}
		// ...in with the new
		numsliders = a; // update our global number of sliders to the new value
		if(numsliders) thefunnel = this.patcher.newdefault(300, 300, "
funnel", a); // make the 
funnel
		for(k=0;k<a;k++) // create the new 
ctlin and 
slider objects, connect them to one another and to the 
funnel
		{
			controlin[k] = this.patcher.newdefault(300+(k*50), 50, “
ctlin”, k+1);
			thesliders[k] = this.patcher.newdefault(300+(k*50), 100, “
slider”);
			this.patcher.connect(controlin[k], 0, thesliders[k], 0);
			this.patcher.connect(thesliders[k], 0, thefunnel, k);
		}
 
		// connect new objects to this 
js object's inlet
		ourself = this.box; // assign a Maxobj to our 
js object
		if (numsliders) this.patcher.connect(thefunnel, 0, ourself, 0); // connect the 
funnel to us
	}
	else // complain about arguments
	{
		post(“sliders message needs arguments”);
		post();
	}
}
// list -- read from the created 
funnel object
function list(val)
{
	if(arguments.length==2)
	{
		thevalues[arguments[0]] = arguments[1];
	}
// 
bang -- steps through sequencer
function 
bang()
{
	if(seqcounter>=numsliders) // reset sequencer
	{
		seqcounter = 0;
	}
	if(thereverse) // read from the array backwards
	{
		outlet(1, numsliders-seqcounter-1); // send out our location in the sequence
		outlet(0, thevalues[numsliders-seqcounter-1]); // send out the current note
	}
	else // read from the array forwards
	{
		outlet(1, seqcounter); // sound out our location in the sequence
		outlet(0, thevalues[seqcounter]); // send out the current note
	}
	seqcounter++; // increment the sequence
}
 
// reverse -- changes sequence direction
function reverse(val)
{
	if(arguments.length) 
	{
		thereverse = arguments[0]; // flip it
	}
}
See Also
| Name | Description | 
| js | Execute Javascript |