Max and Javascript
I'm helping out a fellow composer Girilal Baars with a project using Max. Max is a essentially a graphical programming language with lots audio stuff for composition and music making. For a computer scientist using a graphical programming language can be rather painful. For Girilal's project there are quite a lot of data processing tasks, and dynamic creation of tasks on the fly. Luckily, Max has an embedded JavaScript engine that allows you to create Max object that can send and receive messages, schedules tasks, and dynamically create Max patches.
I won't go into details of the project; you'll have to wait until Girilal has finished composing. Instead, I'm collecting together various traps or problems that I fell into while coding.
Toggles and Messages
One of the simplest Max patches is a very simple metronome.
The box with an X is a toggle, and the box with a circle is a button. If you click the X, the metronome starts, every time it clicks it sends a bang message to the button and makes the button flash.
The toggle button is a two state device: each time you click it flips between send a 1 or a 0 on its output port. For a lot of Max objects if you want to make them start, you have to connect a toggle to it and send either a 1 or 0 to start or stop it.
Max has a sfplay~
object that plays sound files. The following
snippet of JavaScript creates sfplay~
objects, tells it to loop,
gives it an audio file to play, connects it to a spat5.pan~
object
(more on this later) and most importantly the last line
sfobj.message(1);
tells the sfplay~
object to start.
var sfobj = this.patcher.newdefault(230,200,"sfplay~");
sfobj.setattr("loop","1");
sfobj.setattr("audiofile","myfile.aif");
this.patcher.connect(sfobj,0,spat_obj,input_port);
sfobj.message(1);
JavaScript is a dynamically typed language, which means that sometimes
you can write almost anything. While it all in Max's excellent
documentation,
it took me a while to work out what was going on. If instead you
replace the last line with sfobj.message("1")
, then your code will
try to send a string containing "1" to the sfplay~
object. Nothing
bad will happen, just nothing that you expect.
Incidentally, for the Max users out there, who are not yet JavaScript programmers, the three lines
var sfobj = this.patcher.newdefault(230,200,"sfplay~");
sfobj.setattr("loop","1");
sfobj.setattr("audiofile","myfile.aif");
are a compact way of creating objects. You don't need to worry about
connecting message boxes that set the attributes of the object. You
can directly set them in JavaScript. In the project with
Girilal we potentially have to create
5000-6000 sfplay~
objects.
Formatting Messages.
Part of the project involves using Ircam's Spat plugin. Spat is an amazing piece of software that allows you to use ambisonics to project sound from various 3D directions. If you have a large speaker array, then you have have sounds moving around. If you using headphone you can use binaural encoding that gives you, quite a realistic, impression of the sound coming from different 3D directions.
My js
Max object is connected on its first outlet to a
spat5.pan~
object. When you are doing Max patches
without JavaScript you can send messages of the form
/source/1/xyz 6.59 0.0 0.0
to tell spat5.pan~
that the sound from source 1 should come from
the point 6.59 0.0 0.0. Don't ask me how the coordinates work.
I don't understand them yet.
Rather naively I though that I could write code as follows:
outlet(0,"/source/1/xyz 6.59 0.0 0.0")
This gives rather strange error messages. The trick is actually to read the documentation. Instead you have to write code that looks something like
var cords = new Array(3);
cords[0] = 6.59;
cords[1] = 0.0;
cords[2] = 0.0;
var to_snd = arrayfromargs("/source/1/xyz",cords);
outlet(0,to_snd);