jMax is based on the same programming paradigm as the other members of the Max family, but it go a little bit further, and introduce a first set of language extensions to augment its expressive power, and to finally simplify the life of patch programmers, by giving better ways to customize and parametrize patches and patch libraries, and to refer data from objects.
This first release of jMax introduce the set of basic mechanisms; these mechanisms will be used as the fundation for a new object library, and will be extended in future releases.
A jMax programm consists of objects, which appear in the context of a patcher and can be connected via connections between their inlets and outlets in order to pass messages between each others.
In general a jMax object represent a statement in the jMax language; as in other programming language, a statement may realise an operation, or declare some data structure (variables), or make reference to system resources (like i/o channels).
The patcher context helps to make modular jMax programms. A patcher can have in- and outlets and can appear in form of a subpatcher or a template just like an object inside another patcher. It is the jMax equivalence to subroutines, functions or classes.
A variable is a symbolic name associated to a jMax object, that reference a data structure represented by it.
Variables are a generic mecanisms defined to be able to globally share a data structure between objects (a table, a sample, a MIDI sequence, a delay line, a input/output bus, etc).
In older version of the MAX language the sharing of data structure was done with object specific mechanisms, like delay lines. jMax provide a generic mechanism that can be used by all objects representing or using a shared resources.
Any objects can export data by using a very simple API (to be
documented) an example is the object const, an object without
inlets and outlets, export a value, that correspond to its first
argument.
A variable is declared by prepending the variable name followed
by a semicolon to the object description, like in sr : const 44100.
A variable value can be used in the instantiation of an object. An
argument in the form $variable-name is substituted with the
reference to the correspoding data structure before the object is
instantiated.
Since the variable substitution is handled by the system, the object code don't need to know about variables, and all the object can be used with variables as arguments.
jMax use local scoping for variables; this means that a variable defined in a patcher will be visible in all its subpatchers, but it will not be visible outside the patcher of definition; a patcher see all the variables defined in its parent and ancestor patchers.
The flexibility given by this scoping rule avoid conflicts and errors in reusing variables names and simplify writing reusable patches.
Variables will be the preferred way to handle reference to any kind of
data in the future (like table and table~ objects), so that locality
of scoping will be available to all the form of data referencing. In
a future version, local variables will be accessible from the outside
of a patch by using a composite variable name (like
$spat.input.level).
The system keep track of all the dependencies between variables, and
automatically update all the depending objects when a variable change
value as an effect of an editing operations; since variables can
depend on variables, the dependency handling is recursive; all the
unresolved dependencies handled as instantiation errors (red
objects); the resolving of pending dependencies cause automatic
object reinstantiation.
A variable can also contains an array of values; an array can for example
be defined by the object rates: const {32000 44100 48000},
and accessed with the standard syntax <tt>$rates[1]</tt>.
As we saw in the previous paragraph, we can use a variable in instantiating
an object, by putting a $ followed by the variable name in the object arguments.
The dollar sign is an evaluation operator, that applied to a name return the value
of the corresponding variable; the sequence $name is a very simple expression.
jMax actually support more complex expression; an object argument can be
defined as the result of an arbitrary complex expression; the expression syntax
is derived from the C programming language expressions, and include parentesys,
all the arithmetic, logic, bit-by-bit operators, the conditional operators, array access
and function calls, and the variable evalution operator $.
Also the object class can be defined by an expression.
Functions calls are calls to a set of predefined functions; this release define a single
function, unique() that return a unique number each time is evaluated;
future releases will include a complete function library, and the possibility to define
functions thru a C API.
The arguments of an object must be simple expressions. A simple expression is either a variable access operation, an array access operation, or a expression between parentesys. In other words, an expression used as object argument should be enclosed in parenthesis.
In the following example patch, we define three variables to parametrize a table object size with respect to the sampling frequency; note that the variable sr will be a system defined variable in a real patch programming case.
Another way to define a variable in jMax is provided by the patcher object.
A patcher object implicitly defines a variable args in it's context containing the arguments of the patcher (including its name).
The arguments passed thru the args variable are positional parameters,
i.e. they are assigned to positions in the args corresponding to
their position in the patcher object.
A patcher can also have named parameters, i.e. define new variables explicitly,
adding at the end of the arguments a list of assignement in the form
variable = value.
A template is the implementation of a new object in the jMax language itself; a template definition is the content that will be used to produce new objects; in jMax, any patcher can be used as template definition, because, as we saw in the previous paragraph, the language itself provide a generic mechanisms to pass arguments to patchers, there is not need to make a distinction between a standard patcher file and a template definition file.
Since Templates use the same argument passing paradigm than all the subpatchers, positional and named arguments can be used.
There are several way to define templates, depending on your configuration, and on the project you are working on. Please refer to the wiki page [[ProjectEnvironment | project environment settings]. In general, you define a number directories where template can be stored.
Any file foo.jmax saved to these directories will automatically define a template called foo. You can simply edit a patch and save it to this directory to define your first template.
This method has a problem (common to the ISPW Max environment): Since you are editing a template body, the variables (arguments or variables inherited from the outside scope) used by the template are not defined, so you can neither complete the editing, nor test the template body.
A better way is to create the template you want to define within the context where you want to use it (or in a similar, ad hoc test oriented context). For example, in an empty patcher, create a subpatcher object with some example arguments that you would give to the template, create the template body, test it, and when it work reasonably well, and save the subpatcher it to your template directory using the menu item “Save To” in the patcher editor Once saved, you can instantiate it as many time you want.
What we said about a new subpatcher apply as well to any template instance; you can modify a template instance and save it as the new definition for a template. This is possible because the object text in the template instance is not changed, but stay exactly the same as in the template definition (i.e. the definition of a template is one example instance).
Please note that saving a new template definition will automatically redefine all the existing instances to conform to the new definition.
Note: The template concept is very close to the abstractions of ISPW Max. We use a different name to avoid confusion, since jMax is able to load and use also the older ISPW Max abstractions.
Some simple lexical conventions are applied to whatever one types to a jMax object. On this level intergers, floats, symbols are recognized as follows:
In addition to the blank charakter the following characters are acting as separators in any textual description of a jMax object:
$ , ( ) [ ] { } : . ; '
This makes for example that the text 1,2 actually represents
three symbols “1”, “,” and “2”, while 1+2
represent a single symbol “1+2”
(since the binary operators are not considered as separator tokens an expression
with a binary operator like 1 + 2 must be written using blanks between
the operands and the operator).
(Note that the lexical conventions of jMax differ slightly from that ones of ISPW Max! Objects loaded from original ISPW patches are converted on the fly.)