Table of Contents

Geosonix User’s Manual

Version and Licensing

Contact Information

If you have questions or comments contact: A Geosonix forum will soon be available.

Quick Introduction to Geosonix

Rosette Henon Map Moving Object on Jazz Image Non-Rhythmic

GeoSonix is a graphical open-source music generator, non-traditional sequencer, and live performance environment.

At right are few of the many sample scores included with Geosonix.

Fast Tour of Geosonix:


GX2 is compatible with Mac OS X 10.6+ or higher (and in the future, Windows 7 though 10).

To install on a Mac:

Geosonix Concepts

The Geosonix User Interface is much like other desktop applications:

The Workspace is a 2D or 3D arrangment of the objects such as curves, cursors and triggers in the graphical view of the score application. The score file contains a snapshot of the objects and their properties that were in the graphical view when the score file was last saved.

The Script is Javascript code in the script tab of the property inspector. A script can consist few or many lines of code which may include few or many function definitions - almost any type of Javascript code. The Script tab is not only a place to see scripts - it’s a syntax highlighting code editor. In the Script editor you can execute all or any part of the script. When you execute script code you will immediately see the results, possibly in the graphics view, or as response text below the editor.

Geosonix Score Files:

Messages: Messages are generated by interactions among graphical objects. For example a cursor colliding with triggers can generate messages based on features like the location of the collision, which objects participated in the collision, the time of the collision, and the colors of the image pixel behind the collision point. Typical MIDI messages would be note-ons and note-offs, bend and continuous controllers. A typical OSC message may include score parameters such as the score time and the x, y, and z coordinates of a moving cursor.

Generating Sound: Geosonix does not generate sound. Its messages are designed to trigger sound or effects in other audio applications or synthesizers. Message values such as MIDI note numbers, velocities and durations may be generated as a function of the parameters of the “score context” at the exact moment the message is generated. This provides an extremely rich source of sound patterns that you are unlikely to hear from any conventional sequencer. You define the messages and what aspects the score context they depend on, mapped using Javascript functions and code, and route them to an external music environment or synthesizer to generate sound.

The GeoSonix Scripting Language: The scripting language is standard Javascript and includes large number of predefined functions and objects with which you can define the messages sent by objects, customize object behavior, and modify or build scores. The advantage of using a script to build a score is that you can automate steps that would be tedious by hand, difficult to coordinate the relationships between the parts, or build different versions based on changes in a few parameters. You can parameterize scripts so that you can easily explore variations on an idea without having to make careful manual modifications to copies of scores.

Messages Are Javascript Functions: You can build almost all of a score without scripting, but a script functions must be used to define object messages. Messages are the way that objects make anything happen, musically such as playing notes, or graphically such as changing or moving other objects. One of the properties of an object is the name of a Javascript function that it calls when it’s triggered to send a message. Message functions are defined just like other Javascript functions in the script buffer with normal syntax (unlike GX1 which had a custom language for defining messages).

A advantage of messages as functions is that they can related to one or more objects by being named in each object as its message function. Multiple objects can share the same function making it much easier than in GX1 (and Iannix) to maintain consistent object behavior, and much easier to edit message functions while the score is playing, for example as way of experimenting with ideas and as a performance technique.

Another advantage of messages being real Javascript is that they can do far more, far more easily - almost anything you can do in Javascript. Yet another advantage of the new design is that all messages share the same execution environment, and the same environment as the script that may have built the score, opening up the potential for interaction among them that was exxtrememly difficult or impossible in GX1. For example the message of one object can access or alter properties of other objects, or alter shared properties that alter the behavior of an entire group of objects.

The Script Editor: The editor is a syntax highlighting Javascript editor that is tightly integrated into the rest of Geosonix. It’s also what programmers would call a REPL: A read-evaluate-print-loop. This is a place where a you can type Geosonix commands, evaluate them, and immediately see any text output printed in a scrollable area below the editor.

You don’t have to execute all the script code every time. It can be executed a line at a time, a range of selected code, any single function, or the entire script. here are buttons just below the editor to execute these types of code blocks and keyboard shortcuts to quickly execute code as you write it. Button names include reminders of the keyboard shortcuts. The script is also auto executed when a score file is loaded.

The editor a great way to learn scripting or explore new Geosonix commands because evaluating a command will also immediately affect the score itself. You can enter commands and execute them one at a time, and immediately see the results. For example if you type a command to add or delete an object and execute that line, the object will instantly appear in the Score.

If you execute a command to print some object property the result will appear as as text in the output buffer below the script editor. Also, if you add a line to a message function, when the score plays the function will print the value of the property in the output area each time the object is Triggered. This is very useful for testing.

Another advantage of the REPL is that one or a more lines of script can be written and executed repeatedly to do complex things that would be a lot of work to do manually. If you have created useful fragments of script, they get saved with the score file and are available next time you open the score. The REPL is also great for debugging. Having live script editing with all of Javascript and all Geosonix objects and scripting commands at your fingertips allows you to enter diagnostics such as print statements to write intermediate results to the output buffer to see what’s happening, and immediately change it as needed. In the future a complete Javascript debugger may be available.

Finally, the REPL can allow Geosonix to be used as a live performance or “Live Coding” performance environment. For more on Live Coding look it up in Wikipedia or see the Toplap web site.

Geosonix Scores as Performance Instruments: A Geosonix score is not just something where you press the play button and passively listen. You can alter scores as they play through the Geosonix user interface or though through external MIDI or OSC controllers such as Leap Motion, Microsoft Kinect, Monome, Ableton Push and many others. The output of a score may sound rich and complex, but it’s completely deterministic to its layout and inputs, and varying the inputs in real time can instantly vary the outputs in very interesting ways, not unlike playing a convertional musical instrument. You can in effect treat any given score as an instrument and with a little practise “play” or improvise on it for fun or in a performance.

User Interface


Features of the Geosonix window, starting at the upper left and moving clockwise:

The Menu Bar on a Macintosh is:


In addition to the Geosonix app menu there is a File menu and Edit menu which are similar to those of many other applications you will have used and will be mostly self explanatory. The File menu also includes commands for loading an image file as a background image for the score, clearing the background image, and opening the default folder where score files are stored on your system. The File menu also includes a command to open the Patchbay, which is discussed below.

The Edit menu includes a command that copies the Javascript code to clipboard that would be required to reconstruct the object or objects selected in the score. If you paste this in the script editor it will be useful in understanding the necessary commands to create an object and set its non default properties. However this feature is a work in progress so you may find not all necessary commands are created, or the commands that are created are redundant. This will be improved in the future.

The Display and Playback menus mostly duplicate toolbar buttons or transport buttons so you will rarely use them. The equivalent commands will be discussed in the toolbar and transport documentation. You may find it useful to look in these menus for reminder of the keyboard shortcuts of some useful commands. They are:

All these commands require the input focus to be on the score view, not the property inspector or script editor, otherwise they would be taken as text input. If necessary click on the score background or some object in the score to set the input focus to the score.


The Patchbay can be opened from the File Edit-Patchbay menu. It allows you to map the virtual port names, such as vMidi1 used in messages to actual ports on your system. This allows you to change the MIDI or OSC address where a score’s messages are sent without without having to edit all messages in the score. It also lets you write scores that can be reused with different synths or on different system without having to change to the script. There is more about the Patchbay in section on scripting.

Score Objects

Scores are made up of three types of objects that can be added to the main workspace with toolbar buttons or with scripting commands. Every score object is assigned a unique id when it is created, integers ranging from 1 to 32767. IDs are not usually needed when creating scores with toolbar tools as IDs are assigned antomatically. However IDs are the way you uniquely refer to objects in scripts.

Three Object Types

Examples of Four Curves, Four Cursors and Three Triggers:

Note that in Geosonix we use the term “trigger” in two ways. First, a Trigger is a type of score object. Second, we say that some object has been triggered when some event has caused its message function to be called. In this sense any object can be triggered. For example when when a cursor collides with a curve beat point, or when any type of object calls its AutoMessage function, we also say it has been triggered.

The Inspector

The Inspector has three tabbed panels:

Inspector Object Properties Tab

All property fields for all types of objects are always visible in the Properties Tab and always stay in the same place. Fields not applicable to any objects selected in the score are inactive and greyed. Once you learn what a field does and where it is you can count on it being where you remember, and if it’s not greyed you know it’s applicable to some selected object.

Having all the fields always visible is also very convenient when you are experimenting, improvising or performing with playing scores. Everything you need (except for the script editor which is in the next tab) is at your fingertips in the properties tab.

I’ve tried hard to give the fields titles that are self explanatory, and all fields have ToolTips with more information. You should be able to quickly get to the stage where you almost never need to refer to the documentation.

The fields are organized into related groups separated by horizontal dividers.

The top of the Object Properties Tab shows the type of object or objects selected in the score and the id of what we call the Focus Object. If you’ve only selected one object then this is the Focus Object. If you’ve selected multiple objects then the Focus Object is the first one you selected.

The Object Properties dialog shows just the properties of the Focus Object even if multiple objects are selected. However any property fields relevant to any type of selected object are active (ungreyed). If you change some property it’s applied to all selected objects that support that property. When editing properties be careful to only have selected objects that you really want to change, although you can back out of undesired changes with undo. To use undo on score objects, the focus cannot be on the property inspector. Click on the score background before trying to undoing (or redoing) property edits.

In most cases when changing properties it’s a good idea to have either a single object selected, or only one type of object selected at a time (e.g. just triggers or just curves). However there are legitimate reasons to select a mixture of object types to set some property such as when you want to assign them all to the same group, or give them all the same color.

At the top of the property inspector are counts of the number of currently selected objects or each type. This can be useful in confirming what’s in the selection.

Trigger Properties in the Inspector


When a Trigger is selected in the score you can edit trigger properties in top part of the Property Inspector tab. These include:

Properties of All Objects

Trigger Position and Appearance Properties

Trigger Message Functions

Trigger Automessage Interval

Trigger Sync to Beat

Curve Properties in the Inspector


Properties of All Objects

Curve Position and Appearance Properties

Curve Message Functions

Curve Automessage Interval

Curve Beat Point Properties

Cursor Motion Properties

These cursor properties are enabled when a cursor’s curve is selected because it’s often easier to select a curve than a moving cursor.

For all these see Time, Durations and Speeds.

Cursor Properties in the Inspector


Properties of All Objects

Cursor Position and Appearance Properties

Cursor Message Functions

Cursor Automessage Interval

Cursor Motion Properties

For all these see Time, Durations and Speeds.

Note and Harmony Properties


The bottom of the Object Properties tab shows Note and Harmony properties for the entire score and is visible even if no objects are selected. When an object is selected in the graphics view, the note harmony properties for that object are revealed above the score properties.

The names of the properties for the score and all objects are the same. They are the Tonic and Scale Name of the current scale, and the Root and Chord Name of the current chord. Below these is the range of notes to generate in terms of the Lowest Note and size of the Range in Semitones. There is also the “Map Notes To” property (called mapNotesTo in scripting) which determines whether note mapping should be into notes from the current scale or the current chord. All notes that are in the chord/scale, and that fall anywhere in the Range in Semitones, are available for mapping. i.e. If the range is more than an octave the chord or scale will be repeated as needed up to the top of the range.

By default objects inherit the equivalent score properties. This can be overridden for any object and any property. i.e. If an object’s message function uses an Object Harmony property that reads “Score” in the Property Inspector (or -1 in the case of Range), then the value of that property for Score Harmony is returned. All object harmony properties default to “Score”, so by default objects generate notes and harmony compatible with the score and with each other. In effect, this means that objects inherit the harmony properties of the score.

You can override the score properties for one or more objects by entering one or more specfic harmony properties. A use might be to force some objects to play different ranges of notes from others. Or you may set some objects to play chords and others to play notes from a scale compatible with the chords as is done in jazz improvisation.

See The Harmony Processor for information on using all these fields to control harmony.

At the bottom of the Properties Tab are some fields with some useful general information:

This information can be helpful in writing message functions and understanding how message functions respond to the score.

Inspector Scripts Tab

Script Tab

The script editor is in the Script tab of the property inspector. The main parts of the editor are:

Inspector Message Monitor Tab


This tab is where you can see MIDI or OSC messages that have been sent and received by Geosonix.

Note that by default message monitoring is turned off as it adds an significant load to your system. Therefore turn on monitoring with the Enable Logging checkbox when you need to see the flow of messages and be sure to turn it off again when you no longer need it.

Both lists scroll and have a capacity of the most recent 10000 messages. You can clear either list by clicking in the list and selecting all the text with Command + A and pressing the delete key on your keyboard. (When I have time I’ll add a button to clear each list.)

Also, although it’s not related to message monitoring there is a field at the bottom of this tab to set the Open Sound Control input port. This is the port you use to send messages to Geosonix on localhost or to your computer’s IP address over your LAN. If you use OSC you probably already know how to use this, but there will eventually be a tutorial on using OSC with more detail.

The Transport


The Transport controls starting and stopping the score playing, rewinding, showing the current playing time, setting the playing speed, and synchronizing Geosonix with an external clock using either MIDI Clock or MIDI Time Code. You should find this self explanatory if you’ve any used any other music sequencer or workstation.

Time is measured in beats, and playing speed is measured in beats per minute. Objects have internal rates that are synchronized to the master score rate. There are two ways to synch an cursor’s clock to to the master clock:

Another type of sync to the transport is AutoMessages which all types of objects can be set to generate. When enabled they are spontaneously generated at a regular interval whenever the score is playing. Similar to curve beat points, the interval for an object’s AutoMessage is set as a note duration such as a quarter note or a sixteenth note triplet.

This design allows objects to generate messages, all synchronized to the master clock even as the master rate changes, and the timing of the beats is synchronized across all objects.

It’s also possible to set any object’s internal timing to lead or lag the master clock by any multiple of a given note type. A simple example would be if you set two objects to generate messages (that play notes) at quarter note intervals, but then set one of them to lag by two quarter note triplets. This in effect gives a swing rhythm.

Many unusual effects are possible by mixing and matching these settings across a number of objects. It’s also possible to change any of these settings on the fly either manually or based on varying score properties as the score plays, and the results can be very interesting!

Using The Toolbar

Adding Objects to the Score

Adding objects to the score

From left to right the buttons to add objects are:

Filtering the Selection of Objects

Filtering the Selection of Objects

These are the Filter Selection buttons. There is one for triggers, one for curves and one for cursors. But first an introduction to selecting objects:

When we talk of selecting an object in the score we mean clicking on it or dragging to encompass one or more objects with the selection rectangle. Selected objects are marked with a yellow rectangle that we call the marquee. Of course the reason we want to select an object is that this causes its properties to be visible in the property inspector. You can also mouse-down and drag on one of any number of selected objects, which moves them in the score. There is also a toolbar button that causes only selected object to send messages. More on this below.

You can add to the selection by Command-Clicking on each successive object, or by Command-Dragging to encompass more objects. Shift-Clicking on an object removes it from the selection. You can select all objects in the score by pressing Command+a on the keyboard.

By default all types of objects can be selected. It’s sometimes useful especially when selecting with the marquee to prevent some types of objects from being selected, for example if you just want to move a some triggers, or to rename their message function. Another use is dragging a marquee that selects cursors but not their curves. Selecting specific types of objects is the purpose of the selection filtering toolbar buttons.

By default no selection filtering buttons are pressed and in this mode you can select any type of object (triggers, curves and cursors).

When one or more of the selection filtering buttons are clicked to toggle them down (they become darker), only those types of objects can be selected and others are ignored. For example if you click the button with a picture of a trigger on it, only triggers can be selected. You can even use the Command+a shortcut to select all object in the score and in this case just triggers will be selected.

To return to being able to select all types of object, click on any “pressed” (darkened) buttons to toggle them off.

Playing Selected Objects

Playing Selected Objects

The Play Selected button is normally not pressed. When you click it to toggle it down, only selected objects are able to send messages of any kind. If a score is playing and you click this button with no objects selected the score will stop sending notes or any other type of MIDI or OSC messages. If you select some object it will be able send messages and you will hear it, assuming that its messages are sending MIDI notes. Any number of objects can be selected in this mode and all selected objects will be able to send messages and the others will be muted.

You will find the Play Selected button very useful for understanding what scores are doing. It can also be used in performance or improvisation. For example you may create a score where multiple objects would be sending messages, but then only play one or a few of them at a time in various groups to achieve variations in the performance.

Grid Control Toolbar Buttons

Grid Tools

The Grid Tool contains the image of a grid. Click on it to hide the grid. Click it again to reveal it.

You can also change the grid spacing with the Grid setup command in the Display menu. For historical reasons the units of grid spacing are time with the default spacing being “1 second”. Time time does not have a lot of meaning in the current version of Geosonix, but you can still use the commands to adjust the relative spacing. For example choose “500” milliseconds to have a spacing twice as close as the default.

The Snap to Grid Tool enables snap to grid mode where the mouse operations on objects are constrained to conform to be aligned to the grid. Click on the grid tool to exit snap to grid mode. You can tell you are in snap to grid mode when the button appears pressed (darker).

Pan and Rotate Toolbar Buttons

View Adjust Tools

The Pan Tool looks like a hand. Clicking the Hand Tool allows you to pan the score left/right and up/down in the view by dragging with the mouse anywhere in the score. Click the Hand Tool again to return to normal mouse operations on the score.

Using the Hand Tool is equivalent to holding down the Shift key and dragging with the mouse.

The 3D Rotate Tool which contains “3D”, allows you to rotate the score about the x axis and y axis to see the score tilted into the z dimension. Drag up/down to rotate about the x axis and dragging left/right to rotate about the y axis. While in this mode you can return the view to flat by double clicking on the score background.

Using the 3D Rotate Tool is equivalent to holding down the Command+Shift keys and dragging with the mouse. As with the tool you can restore the view to flat Command+Shift double click on the score background.

Note that while the is not flat you cannot select or drag object in the score. This means that having the view rotated is mainly for viewing and not for interacting with. Possilbly 3D interaction will be added in a future version of Geoxsonix.

Label and ID Toolbar Buttons


The icon of the Object ID Tool is “ID”. Clicking on it shows tags above each object with the ID of the object. The IDs are displayed in the color of the object. Click the button again to hide the IDs.

The icon of the Text Labels Tool icon is “Abc”. Click on it to reveal the text label (if any) above each object in the score. Labels are displayed in the color of the object. Click again to hide the labels. By default no objects have labels so you will only see labels if you have added them with the Object Label field in the property inspector, or with a script.

It can be very useful to assign labels in the script especially for information that changes in message functions or script callbacks from Geosonix. For example the following is a trigger message function that sends a note when a cursor collides with the trigger. The line “this.label = note” inserts the note number in the label:

function triggerMessage() { note =mapHarmony(this.x,-16,16); //note number from x position vel = map(this.y,-12,12,20,127); //velocity from y position dur = map(this.cursor.angle,0,360,50,2500); //duration from this.label = note; //put note number in label midi.note(this.port,,note,vel,dur) }

Clicking the Text Labels button would now show above each trigger the trigger’s most recently sent MIDI note number.

Note Numbers in Labels The number is automatically converted to text. The labels will automatically show the number of the most recent note sent by each object. Here is how this would look in the score:

Inspector or Transport Hiding Toolbar Buttons


The Hide Inspector Tool contains “i”. Click on it to hide and show the Property Inspector.
The Hide Transport Tool contains “>”. Click on it to hide and show the Transport.

Full Screen Mode


The Full Screen Tool expands the graphical view of the score to fill the entire window. Leave this mode by pressing the Escape key. The ability to interact with the score in this mode is very limited so it’s currently only for viewing playing scores. Some ability to interact with the score in full screen mode may be added in the future.

Help Tool

Help Button

Press the Help Tool to open Geosonix online help in your default web browser. Help is currently only available online because it’s being frequently updated and improved. It’s possible that in the future offline help will also be included with Geosonix.

Mouse and Keyboard Shortcuts In the Graphics View

In-Depth Topics

Time, Durations and Speeds

Set the Global Speed of the Score


Sets the global speed of the score in beats per minute. It some time has elapsed on the transport, it’s possible to enter aa negative score speed which will cause time (and all score activity) to run in reverse. When running in reverse the transport will stop when the time reaches zero. It’s not possible for time to become negative.

The score speed is combined with the speed factor or duration parameter of each cursor to determine the speed, or more intuitively the transit time of the cursor on its curve. If the cursor speed was specified in terms of a note duration per beat (if on a beat curve) then those beats are synched to the master transport. If the cursor is on a curve without beat points then its speed is specified as a multiplier times the master rate, or as a duration to travel around the curve.



Set the Local Speed of a Cursor in Proportion to the Master Speed of the Score

setSpeedMultiplier(objectID, localSpeed);

This is how cursor speed is specified if it’s not on a curve with beat points.

Cursors have a speed independent of each other, but that is related to the global speed. The cursor can move in the negative direction if the its speed factor is negative (and the global speed is positive).

Cursor speed is best understood by thinking in terms of the time duration required for a given cursor to traverse its path one time. If the master speed of the transport is set to 1.0 (with the “setScoreSpeed” command or the transport slider), and a cursor’s time is set to say 10.0 seconds, the cursor will take 10 seconds to traverse the curve once. Doubling the master speed to 2 would cut the transit time of this cursor to 5.0 seconds.Thus each cursor can have it’s own transit time (or inversely, speed), proportional to the master speed of the score.

This example sets the speed of cursor 9 to be five times the global speed.


Set the Duration of a Cursor Traversing its Curve

setDuration(objectID, durationInSeconds);

SetDuration automatically sets the speed of a cursor so that it will traverse its curve once in the specified amount of time. This command also automatically causes the LockDuration option to be set, which maintains the given duration even if the curve is resized by dragging its points with the mouse or with the resize command. This makes it easier for you to create scores that maintain the timing relationship between cursors on different curves even when you adjust the shape of the curves. Note that if you need to clear the LockDuration at any time, this can be done with the checkbox in the inspector, and is also automatically cleared if a different speed is directly entered into the Inspector.

This example sets the cursor 99 to traverse its curve in 23 seconds:

setDuration(99, 23);

Define a Pattern of Speeds for Successive Cycles of a Cursor

setPattern(objectID, patternString);

This parameter is text string that is a list of numbers where each successive number provides a speed multiplier each successive cycle. (First number = first cycle, second number = second cycle, etc.)

As the number cycles exceeds the length of the list, the list is cycled to continue to supply numbers. For example the list “1 -1” would provide a factors of 1, -1, 1 -1 in successsion.

The following example sets cursor 99 with a pattern that causes the cursor to run one cycle at the normal speed, one at 0.7 times the speed, one loop at 0.5 times the speed, one loop at 0.3 times the speed, then cycling back to 1 … if needed:

setPattern(99, "1 0.7 0.5 0.3");

Define the Number Times a Cursor Should Cycle

The Cycles field to the right of the Cycle Speeds field in the Inspector allows you to set how many times a cursor should loop before stopping. A value of -1 causes the cursor to run without stopping. Any other number in the range 1 .. 9999 set a limit. For example a value of 1 will cause the cursor to cycle once and stop. If there were more than one speed defined in the Cycles Speeds field, only the first would be used.

Sync Time To MIDI Master

Geosonix can be synced to a master using MIDI Clock. Click on the “Slave” menu button next to the beats per minute display. There are options to Sync to MIDI Clock and to disable sync. Geosonix automatically adjusts its internal clock even as the tempo changes. Song position pointer is also accepted so for hosts the support it Geosonix rewinds and repositions the transport based on changes in the host.

When Geosonix is synced its transport controls are locked. Tempo must be set on the host and the host transport must be used for start, stop and rewind.

Sending MIDI Messages

Use methods on the predefined midi Javascript object to send midi messages. Here is a simple script that might be used in a message function to send a midi note:

note = 60;
velocity = 100;
duration = 1000;
midi.note(this.port,,note,velocity,duration);  //Sends the message`

This can be shortened as:


The arguments this.port and refer to the port and channel properties (in the property inspector) set for “this” object. By default this.port has the value “vMidi1” and has the value 1. You could also have entered the port and channel as their literal values as in the examples below.

The port property defaults to “vMidi1” which is the name of the first of the four virtual midi ports than can be defined in the patchbay. To see the Patchbay use the File-Edit Patchbay menu. In the patchbay you can define which midi ports on your system is sent to by each of the four available virtual midi ports vMidi1….vMidi4.

Here is an example of a midi message that sends pitch bend. It would bend all notes played on channel 1 of the port “vMidi1” slightly upward (sharp):

midi.bend01("vMidi1", 1, 1.1); //The 1.1 is the bend.  A bend of 1.0 would be no bend.

Here is another example that sends a pitch bend message, bending notes played on channel 1 as far as possible downward:

midi.bend01("vMidi1", 1, -1.0);

Most often midi messages are used in message functions as the way the function sends a MIDI message. However they can be used outside of functions. For example you might define this message somewhere in a script:"vMidi1", 1, 1, 127);

Whenever executed as a single line with Command+. this will send a midi cc 1 (mod wheel) with value 127 to channel 1 on port “vMidi1. This can be useful as a way to send a specific controller to a synth to accomplish a”MIDI learn“. In this case if the synth were put into learn mode on some parameter, say a VCO level, then when this message is sent the mod wheel controller would be assigned to that parameter.

Another useful one might be:"vMidi1", 1, 123, 0);

… which sends an All Notes Off message when this line is executed.

There are predefined functions for sending every type of MIDI message. See any of midi.note, midi.noteOn,, midi.cc01, midi.bend, midi.bend01, midi.programchange, midi.channelpressure, midi.channelpressure01, midi.aftertouch, midi.aftertouch01 and midi.system in the function reference.

See the scripts of of the sample scores for more examples of sending MIDI messages.

The Rhythm Processor

Message Functions

Message Functions

Message functions are how the rhythm processor makes anything happen such as sending MIDI notes, sending MIDI controllers or anything else. In fact message functions can do a lot which is not really related to rhythm but we document them here because this is their most important use.

There are several ways objects can create “beats”, but when any beat happens, one of the object’s message functions is called in the script, if that function exists (otherwise nothing happens). What the function does can be anything you can do with Javascript and Geosonix commands. Often it sends a MIDI (or OSC) message with values mapped from on the state of the object and/or score at the moment the beat was triggered.

A new score’s script contains no message functions. An object might create beats in this state but nothing will happen until a message function has been defined in the script with a name that matches the message name in the object generating the messages.

The property inspector has places for the names of two types of message functions, one for beat or trigger messages and another for “automessages”. There are places for both so that both types of messages can be being used at the same time with functions that do different things.

These are the main things that make objects call message functions:

There are two fields (see above image) to define message function names:

The above image happens to show the message function names for a trigger, but each type of object prefixes its message functions with its type.

There are also two buttons next to the function names that show that function in the script, and offer to create a function if non exists yet:

The auto-created funtions are quite versatile. They normally generate MIDI note messages based on the position of the object, but if an image has been added to the score background they use the colors in the image to generate the notes. Also, if you change the Object MIDI Port or Channel the message function uses the new settings, and if you enter a non zero note into the note field the message sends only that note, which is useful for drum programming.

A very important feature of message functions is that objects can share them. In fact by default all triggers call a function named triggerMessage when a cursor collides with them and a function called triggerAutoMessage for automessages. All curves call curveMessage when their cursor collides with a beat point, and so on. This is convenient because you often want all objects of a given type to do the same thing, and if you want to change what all objects of that type do, you only need to change one function.

However you are free to give some object or objects any message functions name you want and as long as you define a function with that name in the script those object will call it. This allows some objects to one thing and others to do something different.

Predefined Message Functions

Functions created with the Create button are versatile enough that you could create scores entirely without scripting. They send MIDI messages that vary based on the position of the object in the score, but if there is a background image they automatically switch to creating MIDI messages based on the colors in the image. Also they normally generate note pitches matching the current score harmony, based either on object position or background color. However if you set a non zero note number in the MIDI Object Note field the object automatically switches to sending that that note. This could be used, for example, to have each object send a different note number to a drum synthesizer, triggering different percussion instruments.

You can also use auto-created functions as a starting point for your own functions. You should be quickly able to learn to tweak the mappings in small but significant ways. As you learn more you will be able to be more adventurous in your changes, working up to creating your own functions.

See The Structure of Message Functions for a better understanding of how message functions work.

Automessage Interval

AutoMessage Intervals

Each type of object has an Automessage Interval field to define how frequently it sends automessages. They can also be turned off which is the default.

The Automessage Interval is the interval between calls to an object’s auto message function. Calls to the function also only occur when the transport is running. Choose the interval from the popup menu, for the appropriate type of object, which are only enabled if that type of object is selected in the score. Values can range from a 384th note up to four whole notes.

Defining the interval in terms of a note length allows the message rate to vary with the speed the transport is running. Remember that these messages are sent by calling a function in your script with the same name as defined in the Automessages property field for this object. No messages will be sent if this function does not exist or has a different name.

Intervals as short as a 384th note may seem excessively short but they are useful if the beats are trigging the sending of a MIDI continuous controller or an OSC message in which case you may want very frequent messages to simulate smoothly changing values.

Note that although basic automessages are sent at regular intervals it can be very interesting to script automessage intervals to change as the score plays. For an example open and play the score “Varying Intervals for AutoMessage Improvisation.score”. Unique rhythm textures can be automatically generated.

Beat Points on Curves

Curve No Beat Points Curve Beat Points - Normal Curve Beat Points - Euclidean Cursor Speeds

Beat Points which look like small tick marks can be added to a curve with the “Curve Beat Points” drop down menu button in the property inspector. See right.

The menu contains three options:

If Normal or Euclidean are chosen then the cursor speed is synced to the transport speed so that the beats are synced to the master BPM. Use the Beats/Cycle field to enter the number of beat points to place on the curve. Use the Beat Interval control to choose the length of a beat from a dropdown menu with note types ranging from a 384th note to four whole notes.

There are two other cursor settings that are available no matter which beat point option is chosen:

Beat points can be used for a number of things:

The Active Beats Field

The Active Beats Field is used to specify which beat marks on the curve actually trigger messages. Typical usage is to specify a usually number of beat points (say 32) and then mark some of them as active in a pattern to create a rhythm. Details:

The Beat Strength Field

The Beat Strength Field is used to modify the velocity of midi notes produced by active beats according to some repeating pattern.

Object Time Lag

Fundamental Properties

You can set the time in an object to be delayed with respect to the score time on the transport. This affects the start time of the object’s automessages and beat point messages, lagging their onset with respect to other objects in the score.

The object’s events will occur later than would normally have been set by the master transport.

The fields for time lag are:

Among the uses for time lag are:

Attaching A Trigger to a Beat Point

Sometimes it is useful to attach triggers to the beat points on a curve. In the score this is possible dragging and dropping them on a beat point. It is also possible to attach trigger to beat points with a script.

Scripting command:

setBeatTrigger(triggerId, curveId, beatPoint);

Sets the trigger with ID triggerID to the curve with ID curveID. The argument beatPoint give the number of the point to which it should be attached. The first point on the curve is numbered 0. Example:

setBeatTrigger(12, 99, 5);

Attaches trigger number 12 to point number 5 of curve number 99.

For a fun example of triggers snapped to a moving curve see the sample score “Pulsating Ellipse with Triggers.score”.

Object MIDI Port, Channel, Note and Controller

Object Port Channel Note and Controller.png The this.port and in the messages of most sample scores refer to the “port” and “channel” fields in the property inspector (above). They enable you to write more versatile message functions by allowing different objects to use the same message function but, for example, send on different channels.

Similarly if you use this.port in a message function you can change the midi port it’s sending on without having to edit the message function. You could redirect that object’s messages to a synth on a different port simply by changing what’s in the Port in the property sheet, say from “vMidi1” to “vMidi3”. Other objects using that function would still be using it to send to “vMidi1”.

You could also use “this.note” in place of “note” in a message function and it would switch to sending just the particular note number set in the Note field of the property sheet. This can be very useful in drum machine programming where a particular note number is a particular percucussion sound. So you could write one message function that sends percussion beats and then customize what sound it makes when called, say by different triggers, by setting a different note number in the note field of each trigger.

Cursor Speeds

Cursor Speeds - No Beats See Define a Pattern of Speeds for Successive Cycles of a Cursor.

The Structure of Message Functions

This is a simple message function:

function triggerMessage() {
    note = mapHarmony(this.cursor.x,-4,4);
    velocity = map(this.cursor.x,-4,4,50,127);
    duration = map(this.cursor.y,-4,4,100,400);

This is a function that is called whenever a cursor collides with any trigger that has “triggerMessage” defined as the name of its message function. Each time it’s called it uses this.cursor.x to fetch the x position of the cursor when it collided with the trigger and uses it in the mapHarmony function to convert the position (assumed to be in the range -4 .. 4) in the mapHarmony function to get a note compatible with the currently defined score harmony. For more on how harmony works see The Harmony Processor.

In Javascript we use the “.” (dot) operator to refer a property (or method) of a object. The “this” keyword in a message function always refers to the Geosonix score object that called the function, in this case a trigger. Then using the dot operator “this.cursor” refers to the cursor that collided with the trigger this time, and the “this.cursor.x” gets the x position of the cursor. This position is then used as the first argument in mapHarmony and determines the position of the generated note within the current note range for the score, or for this object if it has a custom range defined.

Then the note velocity is determined, also based on the cursor x position using the “map” function to scale it from the range of -4 .. 4 to a range of 50 .. 127. If the x position were exactly -4 the velocity would be mapped to 50 (fairly quiet) and if the x position were 4 it would be mapped to 127 (fully loud). Intermediate values are proportionally mapped in between.

Then the note duration is determined by mapping the cursor y position (this.cursor.y) to a range of 100 to 400 milliseconds.

Finally a midi note is sent using the midi.note function.

The Javascript experts among you may be thinking that it wasn’t necessary to assign each part of the message to variables and then use the variables in the midi.note function. It would have been possible to omit the variables and write this as one big complicated statement. However, the clarity gained from this is worth the small processing cost.

For the even more expert among you, you may be thinking that we should declare the variables as local by putting “var” in front of each. (Because otherwise they become global, and bad things will happen!) However, it’s reasonably safe to do this here as long as we are consistent in always giving these helper variables the same name, and know never to use them for anything else. They get redefined every time a message function uses them so there isn’t much likelihood of cross contamination. I omitted the “var” here because I’ve tried to make the standard functions as uncluttered as possible.

Detecting The First Message or a Repeat Message

Sometimes you need to do something in a message function the first time an object sends a message and never again. Or, sometimes you need to do something each time a cursor starts on a new cycle around its curve. You can use the following special object properties in message functions to detect these states:

For an example of using these flags with every possible type of message see sample score “Example of firstMessage and repeatMessage.score”.

Here is an example of one of the message functions from this example script:

function cursorAutoMessage() {
    if (this.firstMessage)
        print("cursorAutoMessage firstMessage",;
    else if (this.repeatMessage)
        print("cursorAutoMessage repeatMessage",;
    note = 40;
    velocity = 100;
    duration = 100;
    print("cursor autoMessage note-on",;    

Above you can see that this.firstMessage and this.repeatMessage are being used in “if” statements to carry out actions that will only happen under those conditions. The code in the if statements will be ignored otherwise leaving the message function able to perform its normal actions.

The Harmony Processor

Harmony Properties

At the heart of the harmony processor is a user interface to set a range of harmony-related properties globally for a score, and for objects to inherit them, but with the ability to override some or all score properties selectively in any object. The property system is then integrated into the Javascript environment allowing all sorts in interesting harmony generation and manipulation, developed purely in Javascript, also having access to properties from rhythm processor, and having final control of MIDI note and controller generation.

Score Harmony Score Harmony

Object Harmony Object Harmony

The score and every object have an identical set of harmony properties:

By default all objects inherit each of these properties from the score. You can selectively give any objects their own values that will be used in place of the score settings. The above images show the default values for all the properties. Notice that the default values for all Object Harmony properties are “Score”, or -1 for the Range property. These values cause inheritance from the score.

If you change any object property to something other than the default, the new value is used for that property for that object when it generates notes. Most importantly this happens in the mapHarmony script function which is used to generate notes matching a harmony from the instantaneous score state.

If you stay with using the property inspector user interface and auto-created object message functions which use mapHarmony, then the above is allmost all you need to know to do a lot of interesting work with the harmony system. As you become more proficient at tweaking the auto-generated message function and eventually creating your own you will want to know more about how the harmony system is used in scripting. For this, see The mapHarmony Function and other sections following.

Values of Harmony Properties

The above images show the harmony properties user interface. The fields are mostly popup lists from which you can choose values for each property. Open Geosonix and click on each of the fields in the Score Harmony section. You will the following options are available:

Create a blank score and add any object (e.g. a trigger) to the score and select it. This will reveal the Object Harmony properties for that object. Browse these fields.

You will see that the available values are the same as for the score, but if you look carefully you will see the word “Score” at the top of each list, and the value for “Range” is -1. These mean that the object inherits that value from the score. If you choose any other value for any of the properties, note mapping for this object will use those properaties instead of those score properties.

For example you could define an object to have a lower “Lowest Note” and smaller range than most objects in the score, causing it to create a sort of bass part for the composition.

Another example might be to choose the “chFifth” chord which just generates the tonic and 5th of the scale. Other objects may be generating more complex chords by it may be useful to have some objects, maybe sending on a different channel, use a simpler harmony. Again this may be useful in creating a bass accompaniment.

To learn more about harmony open any of the sample scores, play them and try modifying them. Almost all of them use harmony in some way.

The mapHarmony Function

The mapHarmony function makes it easy to automatically generate notes matching the current harmony.

mapHarmony(value, lowValue, highValue, rangeLow, range, tonic, root, notes) 

This proportionally map the position of an input value assumed to be in a range of lowValue…highValue, into a note constrained to be in a the current harmony. The size of the range mapped into is given in semitones, with lowest note number equal to rangeLow. If mapHarmony is used in an object’s message function it will automatically use the settings for that object but inherit the score setting of any property set to “Score”. Typically most or all objects not have specific harmony properties so you can control the overall harmony of the componsition just by changing the score properties.

The mapHarmony function is almost always used in the form:

mapHarmony(value, lowValue, highValue);

i.e. The arguments of mapHarmony may be omitted starting at the right, and any omitted are replaced with values from the currently prevailing harmony, and we almost always want to use properties set for the score or object. The extra arguments are only needed only for specialized scripting.

The most common use of mapHarmony in a message function omits is something like:


This will generate a note using all harmony properties in effect in the score taking into account any overridden in the object, at the moment the function was called. The above mapHarmony in a message function this will map the red component of the pixel behind the object into a note using the object’s current note range, tonic, root and either chord or scale. Note that colors are expressed as a number from 0.0 … 1.0.

Whether notes are chosen from the current chord or scale is determined by the mapNotesTo property of the score, which may be overridden by the mapNotesTo property of an object. The score’s mapNotesTo property can be set to either “Chord” or “Scale”. The mapNotesTo for objects may also be set to “Score” meaning to use the score’s mapNotesTo property.

Note that chord and scale are defined as an array of integers so you can also directly define your own chord or scale in a call to a harmony function. e.g. [0, 4, 9, 11] would be a definiton of a custom scale (or chord). For example:

Using Harmony Properties in Scripts

The _score object, and trigger, curve and cursor objects all have the same harmony properties:

  • scale: The name of the scale as a text string. For objects it could also be set to “Score” meaning it inherits the score scale.
  • chord: The name of the chord as a text string. For objects it could also be set to “Score” meaning it inherits the score chord.
  • root: The note number of the root as an integer.
  • rangeLow: The note number of the low note as set in the property inspector in Lowest Note.
  • range: The size of the range in semitones as set in the property inspector in Range in Semitones.
  • mapNotesTo: whether to map notes to the current Chord or Scale. May have the value “Chord” or “Scale”.

For the score these properties can be read and written. For objects they are read-only. There are three other properties that are read only for the score and objects:

  • notes: The notes of the current chord/scale in the form of a Javascript array. Whether chord or scale is determined by the current mapNotesTo property.
  • chordNotes: The notes of the current chord in the form of a Javascript array. e.g. A major chord would be [0,4,7].
  • scaleNotes: The notes of the current scale in the form of a Javascript array. e.g. A major scale would be [0,2,4,5,7,9,11].

Each object by default inherits the score’s properties because all object harmony properties are set to “Score” (or -1 for the Range field). This makes it easy to change the harmony of the score in a coherent way for all objects in a score. because all object inherit this these settings.

You can define some parameters for an object while inheriting others from the score. For example it’s possible to set the object chord while using the score’s tonic and scale. An object might have a different chords but continue to be transposed by changing the score tonic.

Because object harmony properties may actually refer to a score property (if inheritance is happening) we need a different set of property names to guarantee we read or write to the real object properties. These special object properties are:

  • objectTonic: The scale tonic for the object. May have the value of -1 meaning inherit from score.
  • objectScale: The scale name for the object. May have the value of “Score” meaning inherit from score.
  • objectRoot: The scale tonic for the object. May have the value of -1 meaning inherit from score.
  • objectChord: The chord name for the object. May have the value of “Score” meaning inherit from score.
  • objectRangeLow: The scale tonic for the object. May have the value of -1 meaning inherit from score.
  • objectRange: The scale tonic for the object. May have the value of -1 meaning inherit from score.
  • objectMapNotesTo: Whether to map notes to the current Chord or Scale. For objects may have the value “Chord”, “Scale”, or “Score”.

Harmony properties are accessible with the “dot” operator in Javascript. Examples:

  • _score.chord is the name of the current chord for the score
  • _score.rangeLow is the value of “Lowest Note” for the score
  • this.rangeLow when used in a message function returns the value of “Lowest Note” for the object calling a message function. This may actually be inherited from the score value if the value of this property for the object is “Score”.
  • _score.chordNotes returns a list (Javascript array) of the note offsets for the score chord. For a major triad this would return [0,4,7].
  • this.scaleNotes when used a message function returns a list (Javascript array) of the note offsets for the object chord. For a major scale this would return [0,2,4,5,7,9,11]. If the object scale is set to “Score” this would actually return the scale as set for the score.

Setting the Score and Object Harmony Properties

You can use one of these script functions

Or you can directly assign to one of the properties:

_score.tonic = 0;  //Sets the tonic to C
_score.tonic = 1;  //Sets the tonic to C#
_score.tonic = 11;  //Sets the tonic to B (the highest it can be set)
_obj(3).objectChord = scminor; Give object 3 a custom scale property, overriding the score.
_obj(99).objectScale = "Score"; Restore object 99 to inheriting the score scale property.

The script editor autocompleter knows the names of all available scales, chords and scale degrees. To see a list of available scales start typing “sc” and a list of scales will appear. To see chords start typing “ch”. To see scale degrees start typing “deg”.

Moving Through Chord Progressions

Some of the sample scripts implement a simple means of stepping a score through chord changes that constrain the ongoing mappings of notes to some desired harmony.

The first step is to add to the script an array containing the steps the harmony should go through:

var changes = [


This is in fact an array of two-element arrays, where each of the component arrays holds a scale degree and a chord.

Then we create a curve in the score and add beat points at regular intervals, with at least as many beat points as steps in the harmonic sequence, in our example 16 chord steps and 16 beat points.

Set the “beatInterval” property for the curve to be a reasonably long note so the harmony doesn’t change too quickly, say a quarter note or half note. We then change the name of default message function of the array from “curveMessage” to something else, say “chordMsg”.

Then create a message function in the script with the above name, and at least containing the following code:

function chordMsg() {
    _score.chord = mapList(this.beatNumber,0,this.nBeats-1,changes)[1];
    _score.root = mapList(this.beatNumber,0,this.nBeats-1,changes)[0];

The way this works is that each time the cursor on the curve hits a beat point, the chordMsg function is called. The property this.beatNumber is set on each call to the number of the beat point which will step from 0 through 15 for a curve with 16 beat points. This is then used with the maplist library function to map the beat position into the array of harmony steps. The [1] and [0] on the end of each line picks out the chord and root respectively, and these are assigned to the _score.chord and _score.root poperties respectively.

We also need to put some code in the onPlay callback:

function onPlay() {
    if (_s.scoreTime==0) {
        _score.chord = mapList(0,0,_o(13).nBeats-1,changes)[1];
        _score.root = mapList(0,0,_o(13).nBeats-1,changes)[0];

This ensures that the harmony is properly reset for the first beat if the score is rewound to start at time 0. Note that “_o(13)" refers to object number 13 which is the curve that the cord changing beats are on.

For a complete example see sample score “Dramatic Melody.score”. (Not all harmony changing examples implement this feature in onPlay.)

Much more can be done with the harmony system but these are the only examples I’ve had time to implement so far.

Scripting Arpeggiators

Another type of harmony-related scripting writing arpeggiators that notes matching the current harmony based on some pattern. For an example see sample score “Computed Arpeggiator Crazy Beats.score”. The triggers in the score use automessages to drive an arpeggiator. This one is pretty simple but much more is possible.

More examples will be included in the next update or in the Geosonix forum. It will be interesting to use the new mappingNotes function to supply notes matching the current harmony and to step through them with various algorithms. There is also the possibly for an arpeggiator to use information from both the rhythm processor and the harmony processor to produce notes and determine their timing. This will be an area for future experimentation.

As new capabilities such as this are developed they will be included in the Javascript function library of future releases.

Curve Drawing

Draw a Path of Line Segments

    setPointAt( objectID, <index>, x, y, z);

A curve must be defined a sequence of points. The points index starts at point number 0. Note that point coordinates are defined to be relative to the position of the curve object. For more detail, see the section on drawing curves in the scripting section.

If instead of a number the index is entered as “next”, the next number is supplied automatically, making it easier to work with sequences of points. This feature also works with setSmoothPointAt and setBezierPoint At.

The following sequence of commands creates object with ID 99 and sets it at a position of (-1, -1, 0). Then it draws a line from that position to a point 3 up and 3 across from the object location, and then a line to the point 1 up and 5 across.


The following does the same as the example above but the numbers are generated automatically.

setPosition( 99, -1, -1, 0 );
setPointAt( 99, "next", 0, 0, 0 );
setPointAt( 99, "next", 3, 3, 0 );
setPointAt( 99, "next", 1, 5, 0 );

Draw a Path of Lines With Curved Corners


This command is similar to setPointAt(), but the sharp corners created by setPointAt() are instead curved.

The following sequence of commands creates object with ID 99 and sets it at a position of (-1,-1,0). Then it draws a line from that position to a point 3 up and 3 across from the object location, and then a line to the point 1 up and 5 across. However the corner between the two straight line segments is curved.


Draw a Path of Bezier Curves

setPointBezierAt(objectID, index, x, y, z,  dxStart, dyStart, dzStart, 
                                            dxEnd,   dyEnd,   dzEnd);

Bézier curves are formed from curved line segments defined giving the endpoint of each subsequent segment. They can give you graceful curves, with more control of shape and curvature than the setSmoothPointAt() command. The start point of the segment is the end of the previous segmen. The end point of this segment is given by the point (x, y, z). The curvature is defined by providing two additonal “control points” to the setPointAt function. The point (dxStart, dyStart, ) is a point defined as an offset from the starting point of this segment that controls the curve’s tangent at its start. The point (dxEnd, dyEnd, dzEnd) is a point defined as an offset from the end point of this segment that controls the tangent to this segment at its end. If the curve is being drawn in just the x-y plane (two dimensional) then all the z coordinates of the points can be omitted. If any are specified then they must all be specified. For a more detailed explanation of drawing bezier curve see the section on drawing curves.

The following sequence of commands draws a curve with some sharp corners and other segments formed of bezier curves.

setPointAt( "next",-2,3,0);
setPointBezierAt( "next", 2,3,0, 2,2,0, 0,3,0);
setPointAt( "next", 0,2,1 );
setPointBezierAt( "next", -2,-1,0, 0,-1,2, 4, 0, 0);

Draw a Path From Text

setPointsTxt( objectID, scaleFactor, font, textString )

Creates a curve in the shape of the characters of a text string. The resulting curve can be rescaled with the scale factor, the font can be defined by specifying the name of any font available on the system surrounded by quotes. The text string to be drawn can be any sequence of characters in the font. A single call to the setPointsTxt command defines a single curve spanning all of the characters. To create a separate curve for each letter used the setPointsTxt command repeatedly.

The following sequence of commands creates a curve shaped like the letter “Hello”:

setPointsTxt( 0.1, "Arial", "Hello")

Resize a Curve

setCurveSize(objectID, width, height);

The size a curve can be changed by specifying a new height and width.

The following sequence of commands creates an circle (a 1x1 ellipse) at position 0,0,0 and stretches it to 2x5:

addEllipse(99, 1,1, 0,0,0);
setCurveSize(99, 2,5);

See the parameter list for the score-state variables available for use in curve messages.

Format a Curve as a Broken Line with Dashes and Spaces

setLine( objectID, dashStyle, dashPattern);

Sets a style dotted with dash pattern which must be a sequence of 0 and 1, dash style defines the space between each dot.

This example adds a 1x2 ellipse with ID 100 and gives it a pattern of dashes and spaces:

ellipse(100, 1,2, 0,0,0);

setLine(2000, 1);

Set the Thickness of a Curve or Cursor

setLineThickness( objectID, thickness);

Set line thickness. The maximum is 10 units.

This example adds a circle (i.e. a 1x1 ellipse) with ID 100 and gives it a thickness of 5 units:

ellipse(100, 1,1, 0,0,0);

setLineThickness(100, 5);


You can animate objects by placing code that gradually changes their position inside either the [onPaint] or [onTick] callback functions. If it’s inside onPaint, if you want object motion to stop when the score stops playing you need to protect it with the _score.playing property. It is easier to use onTick to update motion although it’s less efficient because onTick is called more often.

Here is an example from sample score “Pulsating Ellipse With Triggers”:

function onPaint() { _obj(1).x = 3*cos(_doc.scoreTime/3); _obj(1).y = 1*sin(_doc.scoreTime/3); _obj(1).width = 8+7*sin(_doc.scoreTime); _obj(1).height = 5+4*cos(_doc.scoreTime); }

This changes both the position and dimensions of an ellipse as a function of score time. To see it running open and play the sample score.

A more advanced example that creates very interesting motion is to have objects be nudged on each position update in directions and amounts based on the colors of the pixel currently behind the object. This causes semi random looking wandering that is fully repeatable but different with each starting position and with each new image.

This is implemented in a function supplied in the Javascript library. Here is how to use it:

Include the following sort of code in the [onRewind] function:

function onRewind() {
    _mv = [];
    Math.seed = 8;
    new mover(1, [1,2,0], 0.01, 0.005);
    new mover(2, [1,3,0], 0.01, 0.005);
    new mover(3, [1,4,0], 0.01, 0.005);
    new mover(4, [0,3,0], 0.02, 0.002);
    new mover(6, [0,2,0], 0.02, 0.002);    

Insert the id of each object you want to animate into a mover function:

mover(objId, startPos, colorImpulse, maxVel);
  • objId is the Id of a object to be animated. The object must have already been created
  • startPos is a Javascript array with the x, y, z starting position for the object. e.g. [1,3,0]
  • colorImpulse defines the amount of “force” applied by the colors in the background image on each animation update. The direction of the impulses from a color (r, g, or b) are determined randomly at the start, inside the mover function. The impulse number scales the amount of force. Small values work best (0.005…0.05).
  • maxVel sets the highest velocity objects are allowed to achieve. Very small numbers work best.

After calling mover() for all desired objects, call initMotion() to complete preparation for animation.

Before calling mover() you also must hve defined an array called _mv to hold the movers. Optionally provide a random number seed. Each value of the seed will initialize the objects to respond to the colors in the image differently.

Also include in your script the following in the [onPaint] callback function:

function onPaint(time) {
    if (_score.playing) 
        updateMotion() ;

This repeatedly calls the updateMotion() library function, but only if the score is playing.

Or this in [onTick]:

function onTick(time) {

onTick is only called when the score is playing. It’s called about eight times as often as onPaint and so results in smoother motion but it more processor intensive for updating.

You al need to supply a backround image to provide the colors that will drive the motion. The easiest way to do this is to drag one from somewhere in you files system and drop it on the score background.

For examples of animation see “Two Wandering Triggers.score”, “Wandering Objects.score”, or “Wandering Object and Chord Changer.score”.

There’s much more that could be done with animation but these are the only examples I’ve implemented so far.

Object Colors

Colors in the Property Inspector

Position, Size and Color In the Property Inspector colors are set in the two Colors fields (see at right) , one for the color used when the object is active and the other for when the object is inactive. By default all objects are active so this is the color you will mostly see.

Colors are set in a dropdown list containing the standard colors used for each type of object. At the bottom there is an option to define a custom color just for this object. You can also use scripting commands registerColor or registerColorHue to register a name for a particular custom color you can then reuse for multiple objects.

Setting Colors With Scripting

In color theory a color can be specified either in terms of Hue, Saturation, Brightess and Alpha (HSBA), or in terms of Red, Green, Blue and Alpha (RGBA), where Alpha is the opacity.

Geosonix has a family of functions for setting colors in terms of RGBA and and another for setting color in terms of HSBA (hue). Which each is should be clear from the function names.

The normal setColor functions take RGB values are numbers ranging from 0 to 255, and HSB values ranging from 0 to 360. Alpha for both RGBA and HSBA is specified as a number ranging from 0 (fully transparent) to 255 (fully opaque).

Remember if you set alpha to zero the object will become invisible!

There is also a family of message functions with identical names but ending in “01” where all arguments can be specified as a number ranging from 0.0 to 1.0, which is often more convenient in scripting.

There are six functions for setting RGBA:

setColorActive( objectID, red, green, blue, alpha );
setColorInactive( objectID, red, green, blue, alpha );
setColor( objectID, red, green, blue, alpha );
setColorActive01( objectID, red, green, blue, alpha );
setColorInactive01( objectID, red, green, blue, alpha );
setColor01( objectID, red, green, blue, alpha );

Similarly there are six functions for setting HSBA:

setColorActiveHue( objectID, hue, saturation, brightness, alpha );
setColorInactiveHue( objectID, hue, saturation, brightness, alpha );
setColorHue( objectID, hue, saturation, brightness, alpha );
setColorActiveHue01( objectID, hue, saturation, brightness, alpha );
setColorInactiveHue01( objectID, hue, saturation, brightness, alpha );
setColorHue01( objectID, hue, saturation, brightness, alpha );

For all these commands the objectID specifies the object. If alpha is omitted a maximum value is assumed, so the color is not transparent.

This example the color of the most recently referred to object is given hue=212, saturation=90, brightness=271 and alpha=255:

setColorHue( 212, 90, 271, 255);

Registering New Named Colors

In addition is it possible to defined named colors for convenience in applying the same color to multiple objects. There is one version of defining the name in terms of RGBA and another for HSBA:

registerColor( "colorName", red, green, blue, alpha );
registerColorHue( "colorName", hue, saturation, brightness, alpha );
registerColor01( "colorName", red, green, blue, alpha );
registerColorHue01( "colorName", hue, saturation, brightness, alpha );

This example defines the color called “myColor” with red=40, green=123, blue=231 and alpha=125, and applies it to objects with ID 98 and 99:

registerColor( "myColor", 40, 123, 231, 125 );
setColor( 98, "myColor" );
setColor( 99, "myColor" );   

Assigning Images to Objects

An image from a file used to change the appearange of triggers all triggers globally, individually or for group of triggers. If future it will be possible to similarly assign images to cursors.

As for colors, a separate image can be assigned for each of the following types of triggers:

  • Triggers that are active and have at least one message defined
  • Triggers that are active and have no messages defined
  • Triggers that are inactive and have at least one message defined
  • Triggers that are inactive and have no messages defined

Registering and Naming an Image

registerImage(assignTo, xTopLeft, yTopLeft, xBottomRight, yBottomRight, filePath)

AssignTo gives a Geosonix-internal name to assign to the image, xTopLeft through yBottomRight allow resizing the image to meet your requirements, and filePath gives the name and if necessary the path to the image file. If the file is in the current project’s “Geosonix Project Info” folder or the “Geosonix Project Info” in the Geosonix application folder then only the file name is needed. On Macintosh the file may be a jpg or png image. On Windows it must be a png image.

The assignTo parameter may take for following special values to assign the image to specific features of the score:

  • “trigger_active”: Assigns the image to all active triggers in the score without messages.
  • “trigger_inactive”: Assigns the image to all inactive triggers in the score without messages.
  • “trigger_active_message”: Assigns the image to all active triggers in the score with messages.
  • “trigger_inactive_message”: Assigns the image to all inactive triggers in the score with messages.

In addition any name other than the above five can be assigned to an image. This allows an image to be referred to by its internal name rather than the name of its file. Names images of this type are also used in the setImage commands described below that allow allow images to be assigned to individual triggers overriding the default or custom global image.

The following example sets the score background to the image in the file “music-image.png” The image is sized to fit a region with upper left corner (-8, 6.5) and lower right corner (13, -8.5):

registerImage("background", -8, 6.5, 13, -8.5, "music-image.png")

The score background can be cleared by assigning an image to it but setting the region to have zero size. Any image can be used, but the image “background.png” is provided with Geosonix so it is convenient to use. For example the following command clears the score background of any previous image:

registerImage("background", 0, 0, 0, 0, "background.png")

Auto-loading the background image: If the name of the background file ends in an exclamation mark, the score background will be refreshed each time the background file is rewritten. For example assume you have loaded the file “shapes!.jpg” as the Geosonix score background. Then if you open the file in an image editor, change it and save over the original file, the background in Geosonix will automatically change. This can be used, for example, to automatically reload the background with images captured at regular intervals with a webcam. It’s also useful for “improvising” using an image editor by changing and repeadedly resaving the background of a score. This assumes the messages use parameters such as cursorRed, triggerHue, etcetera, to affect the musical results. It’s best to keep image files reasonably small so as not to cause the playing score to hesitate when the images are reloaded.

The following command defines an custom named image called “myCustomImage” containing the image in the file “trigger_speaker.png”. The stored image is sized to fill a rectangle with an upper left corner of (-2,2) and a lower right corner of (-2,2):

 registerImage( "myCustomImage", -2, 2, 2, -2, "trigger_speaker.png")

Assigning a Named Image to a Trigger

In addition to setting a global image for triggers it is also possible to override the global image and assign images to triggers individually. This is a two step process. First it is necessary to define a named image using the registerImage command, as described above. Then the image can be assigned by name to triggers as required using a setImage command.

As for setting colors, there are five forms of the setImage command as follows:

setImage( assignTo, xTopLeft, yTopLeft, xBottomRight, yBottomRight, filePath )
setImageActive( assignTo, xTopLeft, yTopLeft, xBottomRight, yBottomRight, filePath )
setImageInactive( assignTo, xTopLeft, yTopLeft, xBottomRight, yBottomRight, filePath )

The following sequence of commands assigns the image “trigger_speaker.png” to be the default image for active triggers that have messages. It also defines an custom named image called “myCustomImage” containing the image in the file “trigger_speaker.png”, but this time sized to fill the rectangle with upper left corner (-2,2) and lower right corner (2,-2). This larger image is assigned just to the trigger with id 2.

registerImage( "trigger_active", -1, 1, 1, -1, "trigger_speaker_1.png"); 
registerImage( "myCustomImage", -2, 2, 2, -2, "trigger_speaker_2.png");
setimage(1, "myCustomImage");

Geosonics Scripting

Introduction to Scripting

The scripting language of Geosonix is Javascript. There are also numerous predefined commands, objects and properties for interacting with Geosonix. I’m not going to try teach you Javascript, but if you’ve ever done even basic programming or scripting. If you are resourceful can probably pick up what you need as you go along because there will be lots of examples.

However unless you’re a Javascript expert you’ll find it useful to have a language reference available, on which there are many online. Here’s one example. In fact Javascript is so widely used that you can probably find any answer you need with an Internet search.

Watch out however that a lot of information on the Internet assumes your Javascript is running in a browser which provides an HTML document object and lot’s of related propertes. There is no HTML document Geosonix, and things like JQuery are also not available (and not needed).

Therefore you should use a pure Javascript reference to learn the Javascript you need, but use this Geosonix documention to learn about the runtime environment and available objects and properties.

The Script Editor

Script Tab

Note: There is a tutorial on using the script editor in one of the example scores you downloaded with Geosonix. It will be in the “Geosonix Scores” folder that was created in in your Documents folder the first time you gan Geosonix. Open the score called “Script Editor Tutorial”, click on the Script tab in the Property Inspector, then read the description of the editor below while noticing the parts of the editor as they are mentioned. Then follow the instructions in the sample script for a hands on tutorial of basic use of the editor.

The main parts of the Script Editor are:

  • You edit the script in large area with white-background that occupies most of the space. We also call the contents of the editor the Script Buffer because it contains the entire script for this score. In this example the script is just one trigger message function called triggerMessage. The editor highlights Javascript syntax making it easier understand the parts of the script.
  • Below the editor near the bottom is the Output Area which in this case contains “ok” which is the result of successfully evaluating the script that produced no other text output.
  • Below the output area are some buttons:
    • The Selection button evaluates exactly what is selected in the editor (i.e. what is highlighted) even just part of a line.
    • The Line button evaluates the entire line containing the text cursor
    • The Function button evaluates the entire function containing the text cursor. Note that this does not call the function. What it does is take the text definition in the edit and update the function definition in the live Javascript buffer.
    • The All button evaluate the entire
    • The Clear Output button clears the output area.
    • The Stop Script button forces a script to stop. You should almost never need to use the stop script button unless you create and evaluate something like an infinite loop.

The Script Runtime Environment

Each score provides its own invisible runtime environment where scripts are executed. The environment contains Javascript itself and a large number of predefined commands, properties and objects for interacting with Geosonix. When you evaluate some or part of a script that is in the editor, the score’s script environment is updated to include any variables, objects and functions defined by your script. A score interacts with these when it’s running.

It’s important to understand that the script you see in the Script Editor does not become part of the runtime environment until it is evaluted. Geosonix helps by auto evaluating the script when a score is loaded. It also automatically evaluates message functions defined using the property inspector. However if you edit the script you need to evaluate it again, or at least the part that you changed.

Another important detail is that your script may have a syntax error preventing some part from being evaluated, the items containing the error may not be updated in the runtime environment. A confusing situation can occur where you delete a function from the editor or a syntax error prevents a function from being evaluated. In this case the previous of the function version continues to exist in the runtime environment. Geosonix avoids this situation by deleting the previous version of a function that’s about to be evaluated, and then doing the evaluation, resulting in it being redefined. Thus if you evaluate all or part a script and find some function is no longer defined, this is a clue that your function contained an error. Most of the time errors in evaluation will also be reported in the output buffer, including the line number and possibly other helpful information.

More on The Script Editor

The editor is much like other programming editors you may have used. It has:

  • Context sensitive help. Put the cursor in almost any keyword, press the F1 key, and Geosonix will show the documentation on it in your default web browser. (The user’s manual is online so it can be continually be improved and updated)
  • Line numbering
  • Syntax highlighting
  • Automatic indentation
  • Highlighting of matching parentheses and other brackets
  • Cut, Copy and Paste with the usual Command+x, Command+c and Command+v keyboard shortcuts.
  • Unlimited undo and redo using the keyboard shortcuts Command+z to undo and Command+Shift+z to redo. The focus must be on the editor for undo to work on the script. (Otherwise undo and redo applies to the graphics view)
  • Keyword completion, both for Javascript keywords and even for Geosonix commands. Matching keywords appear after you’ve typed at least the first two letters of any new word in the editor.
  • Code-tips that indicate the parameters for functions. These appear after you type a keyword and type a “(” to begin entering any parameters. Note that as in most languages functions in Javascript with no parameters still need to include empty parentheses because this is what indicates that a keyword is a function. Find Replace
  • The editor includes commands to find find and find/replace text. Press Command + F to open it with the keyboard. There are fields to enter the text to find and, if any, text to replace it with. The controls are: <: find backward (which currently does not work!); > find forward ; x: close; Rep: replace; Rep>: replace and find; All: replace all instances.
  • The editor can automatically convert one or more lines of text into Javascript comments by prefixing the lines with “//” causing them not to be evaluated. For example in the image at the right lines 19 to 22 are commented causing the function onRewind() never to be evaluated. To comment a block of lines, select them and press Command+Option+/ . To uncomment a block of lines, select them and press Command+Option+/ again. For the commenting to be reversed all selected lines must have “//” at the far left. If you comment or uncomment lines remember to re-evaluate the script to cause the change to take effect. Any functions commented out in this way will be deleted from the Javascript global context when the script is re-evaluated. You can also undo and redo commenting added this way.

The Geosonix editor also has some special features to interact with the score:

  • Any function in the editor that is the message function of at least one object has a small blue triangle added in the left margin. See the above “Script Editor” image for an example.
  • This triangle turns red for any objects that are selected in the graphical view of the score. (All selected objects are surrounded with a yellow rectangle)
  • If you place the text cursor in the first line of function that is a message function, all objects that use that message function are highlighted in the graphical view of the score.
  • The buttons below the output buffer provide smart code evaluation. See above for list of the buttons. There are also useful keyboard shortcuts for the buttons. I stongly advise you to learn these as they they are a nice way of interacting with the editor.
  • When you evaluate code in the editor that produces text output, it’s printed below the editor. For a simple example type 2 + 3; on a line in the editor and press the “Line” button. The sum of 5 should appear in the buffer. Note that in Javascript the output of an object is itself. i.e. Type just 3 on a line, evalute the line, and the output will be 3. (No need for a print command) However the result of evaluating of multiple lines of code is only the value of the last line. For example, if you type 2 on one line and 3 on the next, select them and press the evaluate Selection button, only 3 will be printed.
  • It’s not necessary to execute code in the editor in order from top to bottom. For example if you want to peridically check some property of a object, say the local time, you could add a this line anywhere in the editor, place the cursor in the line and execute it as needed with the execute line button or the Command + . keyboard shortcut:

    print(_obj(99).localTime); //Print the local time for object with id 99

    On each evaluation of the line the local time in the object would be printed in the output buffer, even while the score is playing.

More tips and tricks on using the editor will be included in the tutorials.

Using Object IDs in Scripting

Every score object is assigned a unique id when it is created, integers ranging from 1 to 32767. Ids are used to refer to objects in the script. For example:

  • addTrigger(99,1,-1,0); //Adds a trigger with id 99 at position x=1, y=-1, z=0
  • addTrigger(100,3,3,0); //Adds another trigger with id 100 at position x=3, y=3, z=0
  • remove(99); //Removes object with id 99 from the score
  • _obj(100); //Converts object 100 into a Javascript object so you can use Javascript to refer to its properties
  • print(_obj(100).x, _obj(100).y); //As above but prints x and y coordinates of the object
  • _obj(100).x = 2.0; //As above but sets the x position of the object to 2.0, causing to to be reloated in the score

Try copying these lines and pasting them into the script editor and evaluating them one at a time from top to bottom using the execute Line button (or try evaluating each with the keyboard “Evaluate Line” shortcut which is Command+. on a Mac).

When you paste these lines into the editor they will wrap to the next line although they are still treated as one “line” of code. If you put the cursor anywhere in a wrapped line and evaluate the “line” the entire line is evaluated. You can drag the edge of the property inspector to the right to to enlarge it if you want to see the lines in unwrapped form.

Ids are normally assigned to objects automatically in increasing order starting at 1 although you can create an object with any id through scripting, and you can change the id of an object in the property inspector. However you are prevented from giving two objects the same id. If an object with a given id exists and another is created with that id it will delete the previous object before creating the new object.

All commands that create objects (that start with “add”) return the id of the added object as the value of the function. This is very useful in creating understandable scripts, and in making reusable code fragments. Example:

//Add an ellipse with id 100.  Assign id to variable myId.
var myId = addEllipse(100, 2,3, 4,4,0);
setLineThickness(myId, 5); //Use the variable myId to set the line thickness.
setColor(myId, 0,0,255);  //Use the variable myId to set the color.

We use the Javascript keyword var to define a variable called myId and assign the added object’s id to it. Then use the variable as the myId in following functions.

Of course we could have directly used 100 as the id in each command but writing the script as above allows you to change the id in the first line and all other lines work automatically. You could for example copy and paste these lines twice and enter a different id into the second addEllipse, giving it a different size, position and color. Code like this could also be put in a loop to create multiple objects, or in a subroutine that you pass the id so the code gets reused.

Special ID Codes

There are predefined keywords you can use as the id in scripting commands to refer to various groups of objects:

  • “all”: Applies the command to all objects in the score with types compatible with this command.
  • “current”: Applies the command to the same object that was referred to in the previously executed scripting command.
  • “lastcurve”: Applies the command to the most recently added curve.
  • “selection”: Applies the command to all objects selected in the score with types compatible with this command.
  • The name of a group: Any object can be assigned to some group in the property inspector or with the setGroup scripting command. The group name can be any text string other than an integer or one of the above keywords. These group names can be used in place of ids in any scripting command.


Copy these lines and paste them into the editor in Script tab. Then execute one line at a time using the Line button at the bottom of the editor, or preferably the Command+. keyboard shortcut.

addTrigger(99,1,-1,0);  //Add a trigger
setGroup(99, "mygroup");  //Assign to group "mygroup"
addTrigger(100,1,0,0);  //Add a trigger
setGroup(100, "mygroup");  //Assign to group "mygroup"
addTrigger(101,1,1,0);  //Add a trigger (not assigned to the group)

setColor(99, 0,0,255);  //Set the color of object 99 to blue
setTriggerSize("current",3);  //Set the size of the previously referred to object
setColor("all", 255,0,0);  //Set the color of all objects to red
setColor("mygroup", 0,255,0);  //Set the color of "mygroup" to green
setColor("selection", 255,255,0);  //Set any selected objects to yellow

Score Objects as Javascript Objects

In addition to using scripting commands such as setColor() to access object properties, you can also access score objects as real Javascript objects using the _obj command. Then you can use Javascript syntax to get and set their properties. You can also access an object for the current score using the predefied Javascript object _score. Direct use of object properties allows you to do some things that aren’t possible with Geosonix functional commands. There are also many methods (specialized functions) that can be called on these objects.

As above, you can copy all these examples into the editor and execute them one line at a time using the Command+. keyboard shortcut.

addTrigger(150,2,-1,0);  //Add a trigger
print(_obj(150).x);   //Print x coordinate to the text output area
_obj(150).x = 3;  //Changes the x coordinate.  The object will be moved.

//Use the short form of _obj to assign the object to a new variable
var savedObject = _o(150);  //avedObject is the object 150 in JS
savedObject.y = 4;  //Change y position using the new variable.

//Use the predefined object _score to print the current global scale.
_score.scaleName = "Minor";  //Change the scale for the score.

Another important way to directly access score objects in Javascript is with the keyword this in message functions. When a message function is triggered by a particular object, the Javascript keyword this in the function context is set to to that object. Here’s a brief example that sends a midi note using the port, channel and note properties of the object that triggered the message function, with a velocity of 127 and a duration of 1000 milliseconds:

function triggerMessage() {
    midi.note(this.port,, this.note, 127, 1000)

Note that the keyword this only refers to score objects inside message functions and only when they have been called by an object being triggered.

Another useful trick is to use the _obj function to convert newly creatly objects to Javascript objects. You could rewrite the above example as follows:

//Use _obj to convert the ellipse id into variable myObj
var myObj = _obj(addEllipse(100, 2,3, 4,4,0));
myObj.lineThickness = 5; //Assign a value to the lineThickness property of myObj
myObj.label = "Hello World";   //Assign to the label property of myObj

Using Object IDs in Scripting

All this will be more fully covered in the section on messages and message functions.

Score Callbacks

Callbacks are functions you can define in the script to be called by Geosonix when certain events happen. Use them to carry out custom actions.

  • onRewind() - Called when the rewind button is pressed. Use onRewind to reset settings in your script that are not automatially reset by Geosonix. For an example see “Chord Changer.score” where onRewind is used to reset the position of the moving objects.
  • onPlay() - Called when the play button is pressed. Use onPlay to start actions in your script that are not automatically started by Geosonix.
  • onStop() - Called when the stop button is pressed. You might use this to send an “all notes off” midi message to silence external synthesizers.
  • onPaint() - Called at start of display refresh, approximately once per 40 milliseconds. Use this to update object properties related to the display such as position or color. For example it could be used for object animation. For an example see sample score “Pulsating Ellipse with Triggers.score”. This is also used in score with drifting objects such as “Chord Changer.score”.
  • onTick(time) - Called each tick of master clock, a rate ranging from 5 to 20 milliseconds. Use this to update that affect event generation.
  • onDrop(droppedObjects) - Called when object drag/drop or image is dragged in from file. For an example of use see sample score “Drag Drop Changes Rhythm.score”.

The following functions are called when Geosonix receives a MIDI or OSC message. More documentation and examples will be added on this topic in the near future.

  • onMessage(protocol, sourceURL, sourcePort, address, value); For OSC protocol = “osc”
  • onMessage(protocol, notUsed, channel, msgType, param) For MIDI protocol = “midi”

Scripting Commands


Returns the object with given id. Examples: _obj(5).x, or _obj(99).cursorWidth=4. _o(id) is an abbreviation for _obj(id). For more detail see Score Objects as Javascript Objects.


This or its shortcut _s are actually functions, but a global object that’s always defined in the scripting envronment that represents the score itself. From this object you can access score properties and methods using the “.” operator.

For example

_score.backgroundFile; //The complete path to the file of the background image
_score.scoreTime; //The current elpased playing time of the score
_s.chordNotes; //A Javascript array of the notes in the current score chord
_s.playing; // Equal to true if the score is currently playing

You can also set properties by assigning to them:

_s.scale = scMinor;  //Set the score scale to minor

Some score properties can only be accessed, not changed. For example:

_score.backgroundSize; can only be accessed in property

Although you can resize the background image with setBackground.

For a list of score properties see Properties of the Score.


The keyword this is a normal part of Javascript. Here it one good source of complete details of how it’s used. You don’t need to know any of this to make good use of Geosonix although you may want to get to understand it for more advanced scripting.

However, in Geosonix message functions this is special in that it holds a reference to the Geosonix object calling the function. Its a very convenient way of accessing and even changing the properties of the calling object. We almost always want to access some properties of the calling object in a message function because this is how the message is able to do something interesting using the exact current state of the object. For example:

this.x;  //In a message function fetches the x position of the object
this.angle;  //In a cursor message function fetches the current angle of the cursor 

There are many examples of this in the sample scores and through this documentation. For example see the message function in Label and ID Toolbar Buttons. Other examples are in Object MIDI Port, Channel, Note and Controller. For another example of a message function see The Structure of Message Functions.

More than one object can sometimes particpate in a message function being called. For example a trigger might call its message function because a cursor collided with it. The this object in the trigger message function will refer to the trigger, but you can still get at the cursor because the colliding cursor has become a property of the trigger. Example:

this.x;  // In a trigger's message function would get the x position of the trigger
this.cursor.x; //  In a trigger's message function is the x position of the colliding cursor

Similarly in a curve message function, which would be called when a cursor hits a beat point on the curve:

this.x;  //Gets the position of the beat point
this.cursor.xVelocity; //Gets the x velocity of the cursor when it hit the beat point

You will see this two-step way of referring to objects in some of the sample scores.

setActive(id, active);

To enable or disable an object set active to true or false. Disabling an object prevents it from sending messages. Example;

setActive(99, false);  //Disables the trigger.
setActiveBeats(curveId, activeBeats)

Define which of the beat points on a curve are active. Only active beats call the curve message function when the cursor collides with them. The activeBeats pattern is a text string of just “x” and “.” characters indicating active and inactive beat positions. The pattern is applied sequentially to all beat points starting with the first on the curve. If the activeBeats string is shorter than the number of beat points, it is recycled as many times as necessary. Example:

setActiveBeats(99, "x.x.xx..x.x.xx..");

See The Rhythm Processor section for more detail.

addCursor(curveId <, cursorId>);

Cursors are not automatically added to curves created by scripting. Added a cursor of needed with the addCursor function. If both curveId and curveId are included then a cursor with cursorId is created and added to a curve with curveId. The curve must already exist.
If cursorId is omitted then the new cursor’s id is automatically assigned and it is added to the curve with id curveId.

This example adds a 2 unit wide by 3 unit tall ellipse at position (1,2,0) with an id of 100. Then it adds a cursor with an id of 101:

ellipseId = addEllipse(100,2,3,1,2,0);   

Add a zero length curve with given id. It will be invisible until the script assigns segments or points to it. Use an id of -1 to choose the next available id.

This example adds a curve with id 1000 at position (0,0,0). Then it adds point number 0 which sets the starting position with respect to the curve position. Then adds another points, and then adds a Bezier curve. Entering “current” as the id in a function assumes the same id as in the previous function. Example:

addCurve(1000);  //Adds a curve with id 1000 at position (0,0,0).
setPointAt("current", 0,  -2, 1,0);  //Add point number 0. 
setPointAt("current", 1,  -2, 3,0);  //Add another point.
setPointBezierAt("current", 2,  2, 3,0,   +2, +2,0,   +0,+3,0 ); //Add Bezier segment
addCursor(1000,101); //Add cursor with id 101 to the curve (which was given id 1000)

See setPointAt for explanation of adding points to a curve.
See addCursor for more on adding cursors to curves. See Curve Drawing for a detailed discussion of curve drawing.

Forms of addCurve:

addCurve();  //Add a curve at 0,0,0 with next available id.
addCurve(200);  //Add a curve at x=0, y=0, z=0 with id 200.
addCurve(200,2,3);  //Add a curve at x=2, y=3, z=0 with id 200.
addCurve(200,2,3,-3);  //Add a curve at x=2, y=3, z=-3 with id 200.
addCurve(-1,2,3,-3);  //Add a curve at x=2, y=3, z=-3 with next available id.

All “add” functions return the id of the object created. Example:

crvId = addCurve(200,2,3,-3); //As above and crvId is set to 200.
crvId = addCurve(-1,2,3,-3); //As above and crvId is set to the auto-assigned id.
addEllipse(curveId, width, height, x, y, z);

Add a circle or ellipse with given id at position x, y, z. Use an id of -1 to auto-choose the next available id. If x, y, z are omitted the object is created at (0,0,0);

Forms of addEllipse:

addEllipse(200,1,7); //Add ellipse of height 1, width 7 at 0,0,0, id 200.
addEllipse(200,1,7,2,3); //Add ellipse of height 1, width 7 at 2,3,0, id 200.
addEllipse(200,1,7,2,3,5); //Add ellipse of height 1, width 7 at 2,3,5, id 200.
addEllipse(-1,1,7,2,3,5); //Add ellipse of height 1, width 7 at 2,3,5, auto id.

All “add” functions return the id of the object created. Example:

ellId = addEllipse(200,1,7,2,3); //As above and ellId is set to 200.
ellId = addEllipse(-1,1,7,2,3,5); //As above and ellId is set to the auto-assigned id.

For how to add a cursor to the curve see addCursor.


Add a trigger with given id at position x, y, z. Use an id of -1 to auto-choose the next available id. If x, y, z are omitted the trigger is created at (0,0,0); All add functions return the id of the object created.

Forms of addTrigger:

addTrigger();  //Add a trigger at 0,0,0 with next available id.
addTrigger(200);  //Add a trigger at x=0, y=0, z=0 with id 200.
addTrigger(200,2,3);  //Add a trigger at x=2, y=3, z=0 with id 200.
addTrigger(200,2,3,-3);  //Add a trigger at x=2, y=3, z=-3 with id 200.
addTrigger(-1,2,3,-3);  //Add a trigger at x=2, y=3, z=-3 with next available id.

All “add” functions return the id of the object created. Example:

trgId = addTrigger(200,2,3,-3); //As above and trgId is set to 200.
trgId = addTrigger(-1,2,3,-3); //As above and trgId is set to what was the next id.
setAutoBeatInterval(id, ticks)

Set the time interval in ticks between auto-messages. (A quarter note is 96 ticks).

Autocomplete in the editor includes definitons for many note intervals. e.g. noteQtr. Start typing “note” and a list of notes will pop up.

Example to set the autoBeat interval of trigger 212 to an eigth note trill, use:



setPopupLabel(id, a, b, c, d, e, f, g, h);

Assign up to eight items to appear when the pointer hovers over the object or the object is selected. Example:

addTrigger(150,2,-1,0);  //Create a trigger
//Add two labels: "Hello World" and the object's x position:
setPopupLabel(150, "Hello World",_obj(150).x);  

If you hover the mouse pointer over the trigger or click on it you will see the two part popup label of “Hello World” and the x position of the object. If the data to be displayed is continually changing such as the object position you may want to have the label continually updated which you can do by putting the command in the onPaint() callback. However don’t put any more code than necessary in the callback or it could slow the updating of the score.



Enable or disable adjusting trigger size for better visiblility as the score is zoomed. Set to true or false.

setBackground(filePath, topLeftX, topLeftY, bottomRightX, bottomRightY);

Set background image from image file. Use file=“” to resize current image. Example:

setBackground("/Users/chrisgr/Pictures/MyPicture.jpg", -5, 5, 5, -5);

This loads a picture called “MyPicture.jpg” that is in the Pictures folder on my system and sets it as a background image of size with upper left at (-1,5) and lower right at (5,-5). Of course you need to use the path to the picture on your system.

Note that it is easy to change images by dragging and dropping them onto the score background. You can find the file path of the current background image from the backgroundFile property of the _score object. For example the following print statement into the editor and execute the line with Command+. .


It will print the complete path in the output area. Copy and paste this path as the filePath of the setBackground command and the script will load that same image. Remember to enclose the file path in quotes.

setBeatEmphasis(curveId, beatEmphasis)

Define beat emphasis pattern for beats on a curve. e.g. beatEmphasis = “8575”. See The Rhythm Processor section for more detail.

setBeatInterval(id, ticks)

Set the time interval in ticks between the beats on a curve. (A quarter note is 96 ticks). See The Rhythm Processor section for more detail.

Autocomplete in the editor includes definitons for many note intervals. e.g. noteQtr. Start typing “note” and a list of notes will pop up.

Example to set the interval of the beat points on curve 99 to eigth notes, use:


setBeatPoints(curveId, pattern)

Define pattern of beat points for a curve e.g. Use beatPoints = “b 32 4”, or “e 16 9 0 2”. See The Rhythm Processor section for more detail.

setBeatTrigger(triggerId, curveId, pointNumber) 

Attach a trigger to a curve on a given beat point number. See The Rhythm Processor section for more detail.



Set the master playing speed of the score in beats per minute. Example:

setBPM(120);  See the speed in the transport to 120 bpm. 
center(x, y);

Set the chord for either the score or an object with given id. (e.g. chMinor, chMaj7) Omit the id to refer to the score.

Specify the coordinate to be located in the center of the viewport. Enter center() for x=0, y=0.


Remove all objects in the workspace.


Remove the selection marquee.

setColor(id, red, green, blue, alpha);

Set the color of an object for all its states. Values of red, green, blue, alpha in range of 0 .. 255. Alpha is optional.

setColor(id, colorName);

Set the color of an object for all its states using the color name. The color name must have been previously defined. Example:

id = addTrigger(1,0,0,0); //Add trigger at 0,0,0
registerColor("myOrange",250,130,50,200); //Create a color
setColor(id,"myOrange");  //Assign it to the trigger

This allows you to change the colors of all objects with the color “myOrange” by using registerColor to define different values for myOrange.

For more detail see Object Colors.

setColor01(id, red, green, blue, alpha);

Set the color of an object for all its states. Values of red, green, blue, alpha in range of 0 .. 1. Alpha is optional.

For more detail see Object Colors.

setColorActive(id, red, green, blue, alpha); 

Set the color of an object for when it is active. Values of red, green, blue, alpha in range of 0 .. 255. Alpha is optional.

For more detail see Object Colors.

setColorActiveCurve(id, red, green, blue, alpha)

Set color of trigger for when it is attached to a beat-point. Values of red, green, blue, alpha in range of 0 .. 255. Alpha is optional.

For more detail see Object Colors.

setColorActiveHue(id, hue, saturation, value, alpha);

Set the color of an object for when it is active. Values of hue, saturation, value, alpha in range of 0 .. 255. Alpha is optional.

For more detail see Object Colors.

setColorHue(id, hue, saturation, value, alpha);

Set the color of an object for all its states. Values of hue, saturation, value, alpha in range of 0 .. 255. Alpha is optional.

For more detail see Object Colors.

constrain(value, min, max);

Constrain a value to a range by clipping at max and min.

setCursorHeight(cursorId, height);

Set the size of the cursor in the z dimension. This is most useful if the cursor is on a curve that is above the xy plane and you want to enable it to collide with triggers above or below xy plane. i.e. If either the curve or some triggers have values where their z coordinate is not zero.

setCursorWidth(cursorId, widthL, widthR);

Set the size of the left and right side of the cursor.

setCurve(cursorId, curveId);

Assign an unattached cursor to a curve.

setCurveSize(curveID, width, height);

Change the size of an existing curve.

setCycles(cursorID, cycles);

Define the number of cycles a cursor should operate before stopping. Use -1 for unlimited cycles. After this number of cycles the cursor stops moving and stops triggering messages due to collisions. Its autoMessages also stop. Examples:

setCycles(33,6); //Set cursor 33 to run for six cycles and then stop.
setCycles(33,-1); //Set cursor 33 to run as long as the transport is running.    
dist(x1, y1, z1, x2, y2, z2);

Distance between two points. Examples:

dist(0,0,0, 3, 4, 0);  //Distance from origin to point (3,4,0).  Returns 5
dist(0,0,0, 2, 2, 2);  //From origin to point (2,2,2).  Returns 3.4641016151377544

setDuration(cursorId, duration);

Set the time it takes for a cursor to go around its curve.

setGroup(id, groupName);

Assign an object to a group. The name of the group is entered as a text string. Example:

triggerId = addTrigger(); //New trigger.  Next available id.  Assign id to triggerId.
setGroup(triggerId, "MyGroup2"); //Assign it to a group called MyGroup2.
setHidden(id, hide);

Set an object to be hidden or visible. Set hide to be true or false. Examples:

triggerId = addTrigger(); //New trigger.  Next available id.  Assign id to triggerId.
setHidden(triggerId, true);    //Hide it
setHidden(triggerId, false);    //Reveal it
setHideInactive(id, hideInactive);

Set an object to be hidden if inactive. Use hideInactive = true or false.

setImage(id, imageName);

Assign an image to a trigger. Image must be first registered with registerImage().

See [Assigning Images to an Objects] for more detail.

setImageActive(id, imageName);

Assign an image to a trigger that is only used when the trigger is active.

See [Assigning Images to an Objects] for more detail.

setImageActiveCurve(id, imageName);

Assign an image to a trigger that is only used if on the beat-point of a curve.

See [Assigning Images to an Objects] for more detail.


Musically invert a chord or scale.


Return the text character with ascii character code i.

setLabel(id, label);

Set a text label for an object. (Click the “Abc” toolbar button to see labels.)

setLine(id, dashStyle, dashPattern );

Define curve’s line in terms of dash-style and dash-pattern.

setLineThickness(objectId, thickness);

Set the thickness of a curve or cursor.


Rescale val in range lowVal1..highVal1 to range lowVal2..highVal2.

mapList(value, lowValue, highValue, list)

Chooses an item out of a list by proportionally mapping a value’s position in a range into an item in the list. Example:

mapList(0.0, 0, 1, [3,4,5]);  //Would choose 3 from the list
mapList(0.5, 0, 1, [3,4,5]);  //Would choose 4 from the list
mapList(1.0, 0, 1, [3,4,5]);  //Would choose 5 from the list        
mapChord(value, low, high, rangeLow, range, tonic, root, chordNotes);

Deprecated. Use mapHarmony.

mapHarmony(value, lowValue, highValue, rangeLow, range, tonic, root, notes) 

Proportionally maps a numeric value to a note chosen to match the current harmony settings: the chord or scale and note range. Whether the chord or scale is mapped-to is determined by the setting of the “mapNotesTo” property. By default this would be this would be the setting for “mapNotesTo” for the score, however for any object you can override this by changing the object’s “mapNotesTo” from “Score” to either “Chord” or “Scale”.

Most often mapHarmony used in the form:

mapHarmony(value, lowValue, highValue);

This results in the note range and harmony information being taken from the current settings for the score, which may also have been overridden by values for the object triggering the message where mapHarmony is used.

The input value to map must be between lowValue and highValue. The mapHarmony function returns a midi note number which is guaranteed to be in the note range set by the score/object properties, and in the current chord or scale depending on the setting of mapNotesTo.

Additional arguments may be supplied to override the score/object settings. Arguments may be omitted starting at the right. Any that remain omitted are replaced with values from the currently prevailing harmony. All arguments to the left of one that is supplied must also be supplied.



In a message function this will map the red component of the pixel behind the object into a note using the object’s current note range, tonic, root and chord (assuming mapNotesTo was set to “Chord”. (colors are expressed as a numbers between 0.0 … 1.0).

The following example is the same but overrides the currently prevailing note mapping range and replaces it with a custom range from note number 30 up to 30+24=54. One use of this would be to define a lower range of notes to be generated by some object that is to provide bass notes to a composition


For more information see The Harmony Processor.


Choose whether to map notes to the “Scale” or the “Chord”. For objects you can also set the mapping to “Score” which means to use the same choice as was made for the entire score. Omit the id to set the property for the score. Enter the id if it is for an object. Set mapOption to be one of the text values “Scale” or “Chord”, or for objects only to “Score”.

mapScale(value, low, high, rangeLow, range, tonic, root, scaleNotes);

Deprecated. Use mapHarmony.

mappingNotes(value, lowValue, highValue, rangeLow, range, tonic, root, notes);

Returns a Javascript array of the note numbers that match the current harmony settings. This is the set of notes that mapHarmony chooses a value from. The arguments for mappingNotes are the same as for mapHarmony. See mapHarmony for details.

The difference between mapHarmony and mappingNotes is that mapHarmony returns a specific note that has been chosen based on the value it has been passed, whereas mappingNotes returns the entire list of notes.

For simple harmony mapping all you need to know is mapHarmony. However you might use mappingNotes for some special purpose such as scripting a custom arpeggiator. See Scripting Arpeggiators.

For more information see The Harmony Processor.


Send a midi note with a duration. A note off is automatically sent after the duration has elapsed unless that score has sent another note note-on with the same note number before the previous note has ended. The arguments are:

  • port: a string containing one of the four virtual port names, “vMidi1” through “vMidi4”. In message functions this.port is often used to refer to that object’s defined port which may be changed in the Property Inspector. The entered property would still be one of “vMidi1” through “vMidi4” but it’s convenient to be able to change the port as if it were an object property.
  • channel: A number from 1 .. 16. In message functions is often used to refer to that object’s defined channel which may be changed in the Property Inspector. The entered property would still be in integer from 1 .. 16 but it’s convenient to be able to change the channel as if it were an object property.
  • noteNumber: An integer in the range 0 .. 127
  • velocity: An integer in the range 1 .. 127 (0 means note-off)
  • duration: Duration until a note-off is sent, in milliseconds. The note may last a shorter time than requested if the score sends another note with the same number before the previous note would have ended.
  • minDuration: Optional. Sets the minimum time this note should last even if the score tries to send another note with this number. If a note with this number is sent within the minDuration the note is ignored.
  • monoOption: Optional but if entered, minDuration must also have been entered. The monoOption is a string that may be one of: “curveMono”, “groupMono”, or “channelMono”. If this option is specified then only one note (no matter what the note number) may be sounding for this category. For example if a “groupMono” was specified when an object in this group started a note then as soon as another object in this group tries to start a note, the previous note is forced off as long as minDuration has passed. Note offs and note ons are overlapped so that the transitions are legato.

The minDuration option is a way to thin the number of notes that are sounding at the same time. For example a cursor may sweep across a large number of triggers result in an a large number of notes as short as a few milliseconds, which may or may not be what you want. In this case you could set minDuration to say 100 or 200 milliseconds and note-ons that would have produced note-offs shorter than this would be ignored, which can often sound more musical, or lighten the load on your midi transmission or your synth.

The monoOption feature is another way of dealing with too many notes, in this case by reducing the number of notes that are sounding at the same time. For example you may sending notes with long durations, say for some ambient composition, but under some conditions too many notes may be starting so too many are overlapping, and the sound gets too thick. You can overcome this by for example having cursor message send notes with a curveMono option which results in only one note at a time being allowed for this entire curve.

Another use for mono options is playing a monosynth patch where only one note is intended to be sounding at a time. You might put this patch on a given midi channel and send its notes with “channelMono” and Geosonix will send a note-off of the current note before the next noteo-on.

These things will be covered more completely in a future tutorial.


midi.noteOn(port, channel, noteNumber, velocity);

Send note with no scheduled note off. Velocity in range 0..127. This message is useful to start a sustained midi note and then alter the sound with midi controllers. The note will continue to be on until you send a noteOn with a velocity of zero.

For details of the arguments see midi.note.

Here is how to start a note, pan it with a midi controller and eventually stop it:

midi.noteOn("vMidi1", 1, 60, 127);  //Send note number 60, channel 1, velocity 127.
//Repeatedly Send cc 10 (pan) on channel 1 based on the red pixel behind the object
midi.cc01("vMidi1", 1, 10, this.r);  //This line must be in a message function
//....Eventually, send note number 60 at velocity 0 to turn note off
midi.noteOn("vMidi1", 1, 60, 0);,channel,ccNumber,value);

Send a midi continuous controller. Value in range 0 .. 127. The arguments are:

  • port, channel: See midi.note.
  • ccNumber: The MIDI controller number ranging from 0 to 127.
  • value: The value to send to this controller, ranging from 0 to 127.

See sample score “3d henon map with midi cc.score” for an example of sending a controller.


Send a midi continuous controller. Value in range 0.0 .. 1.0

  • port, channel: See midi.note.
  • ccNumber: The MIDI controller number ranging from 0 to 127.
  • value: The value to send to this controller, ranging from 0.0 to 1.0.
midi.bend(port, channel, value);

Send midi bend. Value in range 0 .. 16383. Use 8,192 for no bend.

  • port, channel: See midi.note.
  • bend: The bend amount ranging from 0 to 16383 with zero bend being 8192.
midi.bend01(port, channel, value);

Value in range -1.0 .. 1.0. Use 0.0 for no bend.

  • port, channel: See midi.note.
  • bend: The bend amount ranging from -1.0 to 1.0 with zero bend being 0.0. This is more convenient to work with when converting from score parameters to bend amounts.
midi.programchange(port, channel, instrumentNumber);

Send a midi program change.

This is the MIDI message used to specify the “instrument” that should play on a synth. For the meaning of program change for your synthesizers, consult their documentation. If you’re using a General MIDI synth then program numbers refer to specific instruments. For example 57 would select a trumpet on a GM synth.

  • port, channel: See midi.note.
  • instrumentNumber: A number ranging from 0 to 127.

midi.channelpressure(port, channel, value);

Sends MIDI channel pressure.

  • port, channel: See midi.note.
  • value: A number ranging from 0 to 127.

midi.channelpressure01(port, channel, value);

Sends MIDI channel pressure.

  • port, channel: See midi.note.
  • value: A number ranging from 0.0 to 1.0.

Sends MIDI aftertouch.

midi.aftertouch(port, channel, note, value);

  • port, channel: See midi.note.
  • note: The number of the on-note to control with aftertouch.
  • value: A number ranging from 0 to 127.

Sends MIDI aftertouch.

midi.aftertouch01(port, channel, note, value);
  • port, channel: See midi.note.
  • note: The number of the on-note to control with aftertouch.
  • value: A number ranging from 0.0 to 1.0.

midi.system(port, value1, value2, value3);

All MIDI messages are sent as three numbers ranging from 0 .. 127. By specifying these three numbers midi.system message allows you to send any MIDI message. This is an advanced topic. Consult a detailed MIDI specification.

setMidiPort(id, port);

Set the midi port of of an object. The default port for objects is “vMidi1” so it’s only necessary to specify this if it’s a different port. The port is entered as a quoted string. Example:

setMidiPort(100, "vMidi2"); //Object 100 will use vMidi2
setMidiNote(id, note);

Set the midi note number property of an object. This would only have an effect if you are using the note property in the message function. The note number must be in the range 0 .. 127 although notes lower than about 30 or above about 110 may be too low or high to hear.

setMidiController(id, controller);

Set the midi controller number property of an object. This will only have an effect if you are using the controller property in the message function.

setMidiChannel(id, channel);

Set the midi channel number of an object. This would override the score midi channel. The channel must be in the range 0 .. 16.

osc.newMsg(QString port, QString address);

Create a new OSC message. e.g. osc.newMsg(“vOsc1”,“/reset”);


osc.addString(QString str);

Append a string to OSC message. e.g. osc.addFloat(“Hello”);

osc.addFloat(qreal value);

Append a number of the OSC message. e.g. osc.addFloat(1);


Send a previously prepared OSC message. e.g. osc.msgSend();

monitor(val1,val2, ...);

Print values to the message monition.

nearestInList(val, array);

Returns item in array closest to given value.

nearestInScale(note, scaleList, stepsPerOctave);

Round note to nearest note in scale.


Create a new score with given name. Enter newScore() to use default name.


Rescale val ranging from lowVal to highVal into range of 0.0 .. 1.0.

setOrigin(x, y, z);

Define an offset to be added to positions defined by setPosition.

setPattern(cursorId, pattern);

Set direction and speed of cursor on each cycles e.g. “1 2 4”.


Start score at given speed in beats per minute. Enter play() to start with current speed.

plot(nPts, fX, fY, fZ, iStart, x0, y0, z0);

Plot a parametric 3D curve.

plotPolar(nPts, fTheta, fR, fPhi, iStart, theta0, r0 ,phi0);

Plot a 3D curve using polar coordinates.


Add straight segment to curve. Coordinates are relative to the zero point of this curve (not global score coordinates). Copy this to the script editor and execut it one line at a time:

addCurve(1000);  //Adds a curve with id 1000 at position (0,0,0).
setPointAt("current", 0,  2, 1,0);  //Add point number 0. 
setPointAt("current", 1,  0, 3,0);  //Add another point.

Point number 0 will not be at score coordinates (2,1,0), but at (5,4,0) which is computed as (3+2, 3+1, 0+0). The global position of point number 1 is (3,6,0) which is (3+0, 3+3, 0+0). If you pasted the and executed the above code in the editor try changing the numbers and re-executing to get a feel for how this works.

See Curve Drawing for a detailed discussion of curve drawing.

setPointBezierAt(curveId, pointNumber,  xCoord, yCoord, zCoord, 
                                        dxStart, dyStart, dzStart, 
                                        dxEnd, dyEnd, dzEnd);

Add a segment to a Bezier curve. For more information see Draw a Path of Bezier Curves.

See Curve Drawing for a detailed discussion of curve drawing.

setPointsEllipse(curveId, width, height);

Convert an existing curve into a circle or ellipse.

See Curve Drawing for a detailed discussion of curve drawing.

setPointsTxt(curveId, scaleFactor, font, textString);

Convert an existing curve into a path based on a string of text characters.
See Draw a Path From Text for more information. See Curve Drawing for a detailed discussion of curve drawing.

setPosition(id, x, y, z);

Sets the position of the an object on the score. Example:

addTrigger(99); //Add a trigger with id 99 at the default location of (0,0,0)
setPosition(99,4,6,1);   //Move it to (4,6,1)
setPosition(99,-4,-1,0);   //Move it again to (-4,-1,0)
print(val1,val2, ...);

Print values to console. Any number of items from 1 to 10 can be printed. Examples:

print("Geosonix is cool!"); // Print the phrase to the console
print(random(2,13));  //Generate a random number from 2..13 and print it.
myTrig = addTrigger(-1,2,5.43); Add trigger, auto id at x=2,y=5.43. Put id in myTrig
myTrgObj = _obj(myTrig);  //Use id in myTrig to make a JS version of the object
print(, myTrgObj.x, myTrgObj.y); Print id and position of the trigger

You can also use the print function in message functions. For example this use of print will cause it to output all the midi data for each note that this message function is triggered to send. This is very useful in understanding what message functions are doing:

function cursorAutoMessage() {
  note = mapHarmony(this.r,0,1); //Create a note based on the red pixel behind cursor
  vel = map(this.g,0,1,20,127); //Create velocity mapped from green pixel
  dur = map(this.b,0,1,50,2500); //Create a duration mapped from the blue pixel
  //Print the port, channel, note number, velocity and duration:
  midi.note(this.port,,note,vel,dur) //Send this midi note

However don’t leave frequently called print statements active in your script as outputting text takes considerable CPU resources. You can make print statements inactive by inserting “//” at the start of the line. i.e. Commenting them out as is usual in Javascript. For example change the print statement in the above example to:


Then re-evaluate the function to cause the change to take effect. A quick way to do re-evaluate a singe function is to put the text cursor anywhere in the function and press the “Function” button below script editor or use the Command+’ keyboard shortcut.

A useful shortcut for commenting one or more lines of code is to select them and press Command+Option+/ . To remove the comment marks repeat this. You still need to re-evaluate the code containing the commented lines for the change to take effect.

To restore the ability of a commented-out line to operate remove the “//” and re-evaluate again as above.

random(low, high);

Return a random number in the range low to high. Example:

print(random(2,13));  //Generate a random number from 2..13 and print it

Copy the above line to the script editor, put the text cursor in that line and use Command+. to repeatedly evaluate it. Each time it will print a random number chosen from 2..13 in the output console.

_rnd(max, min)

Generates a repeatable sequence of pseudo random numbers, each number in the range min..max. Precede first call with Math.seed=someValue. A given seed produces the same number sequence on repeated calls for _rnd. Example:

Math.seed = 42;
print(_rnd(0,10));  //Prints 3.82121913580247
print(_rnd(0,10));  //Prints 4.257291666666667
print(_rnd(0,10));  //Prints 1.1679012345678998

If the seed is reset to 42 the same sequence will repeat. Starting with a different number will produce a different sequence.

This is useful if you want a parameter that varies in an apparently random way but is repeatable. For example if you add this to a score it will cause the seed to be reset each time the score is rewound with the transport.

function onRewind() {  //This defines the onRewind callback function
    Math.seed = 42;

Now you can use _rnd to produce numbers, say in a message function and every time the score is rewound and played it will sound the same. To seed a different repeatable sequence use any different number.

randomChoose(probList, valueList);

Randomly choose a value from valueList based on probabilities in probList. The first list is a Javascript array of probabilities, each in the range 0.0…1.0 and must add up to 1.0 for correct results. The second list is an array with a number of Javascript objects equal to the number of probabilities. Any type of Javascript objects can be in the second list. Example:

randomChoose([.1,.4,.5],["rock","paper","scissors"]); //Chooses from a list of three words

Paste this line into the script editor and execute it repeatedly. This will print one of the words each time. “rock” will be printed approximately 10% of the time, “paper” 40% of the time, and “scissors” 50% of the time.

range(value, lowValue, highValue);

Scale a value of 0..1 into the range lowValue .. highValue. Examples:

range(0.3, 23, 87); //Returns 42.2 which is the number 0.3 of the distance from 23 to 87.

When used in a message function the following example will return a number for output to a midi controller (range 0..127) scaled from the strength of the red component of the pixel behind the object. The “r” refers to object property that is the red component of the pixel of the background image behind the object at the moment this message function was triggered. These color properties are always in the range 0.0 for no color to 1.0 for maximum strength color.

rangeMid(value, low, mid, high);

Rescale a value into a range with peak at mid.


Define a named color using the RGBA color system for future reuse. See setColor for an example of use.


Define a named color using the HSVA color system for future use.


Load an image from a file and give it a name or use in assigning it to objects.

See Registering and Naming an Image.


Delete an object from the score.


Reverse order of notes in list. (Lists can store chords or scales.) Example:

myChord = [0,4,7]; //A major triad
print(reverse(myChord));  //Prints [7,4,0]


Reset the playback time to 000:00.000.


Change viewing angle of the score. Use rotate() for zero rotation.


Set the master playing speed of the score where 1.0 is 60 bpm, 2.0 is 120 bpm, etc. See setBPM for the command to set the speed directly in beats per minute.


Set the size of the note range for either the score or an object with given id. Omit the id to refer to the score.


Set the lowest note number of the range for either the score or an object with given id. Omit the id to refer to the score.


Set the scale degree of the chord root (degI…degVII)for either the score or an object with given id. Omit the id to refer to the score.

Editor autocomplete includes defintions for the degrees of a major scale: degI=0; degII=2; degIII=4; degIV=5; degV=7; degVI=9; and degVII=11. Start typing “deg” in the editor and a list of the degrees will pop up. If you need a sharp or flat degree you can add or subtract one semitone from one of these degrees. Examples: e.g. A minor third would be (degIII-1);

setRoot(degIII);  //Set the root for the score chord to be on the major third of the scale
setRoot(99, degVI-1); //Set the root of chord of object 99 to be on the a minor sixth of the scale

Set the scale for either the score or an object with given id. (e.g. scMinor, scBlues). Omit the id to refer to the score.


Add curved segment to curve, tangent to previous segment. See Draw a Path of Lines With Curved Corners for more information.

setSpeedMultiplier(cursorId, localSpeed);

Set the speed of a cursor as multiplier times the master transport speed.


Stop the score playing

setTimeLagMultiplier(id, multiplier);

Set time lag multiplier. Total lag is timeLagMultiplier x timeLagNoteTicks.

See Object Time Lag for a more information on time lagging.

setTimeLagNoteTicks(id, ticks);

Set the length of the note in ticks in which time lag is stated. Note that unlike in the property inspector the scripting command requires the time lag to be set in ticks where a quarter note is 96 ticks. You can easily compute the number of ticks for standard note lengths. The advantage of being able to use ticks here is that you can use any number, not just standard note lengths. For example although a quarter note is 96 ticks you could specify 97 ticks for the interval, or anything else, allowing unusual non rhythmic shifting of note times, and message times in general.

See Object Time Lag for a more information on time lagging.

Autocomplete in the editor includes definitons for many note intervals. e.g. noteQtr. Start typing “note” and a list of notes will pop up.

Example to set the timeLagNoteTicks of object 45 to an quarter note trill, use:



Set the tonic note number (0…11) for either the score or an object with given id. Omit the id to refer to the score.

setTriggerSize(triggerId, size);

Set the size of a existing trigger.

setTriggerSync(id, duration)

Set the trigger sync note duration in ticks (A quarter note is 96 ticks). If triggerSync is off, a triggers creates a message instantly when a cursor collides with it. If triggerSync is set to a note type, the triggering of the trigger is delayed until the next even multiple of that interval.

This example sets trigger 33 to delay triggering to align with quarter note oundaries with respect to the master beat:

setTriggerSync(33, 96); 

This example sets trigger 37 to delay triggering to align with sixteenth note boundaries with respect to the master beat:

setTriggerSync(37, 24);  //i.e. 4*24=96 and there are 4 sixtenth notes in a qurter note

See “Trigger Sync Example 2.score” and “Varying Intervals for AutoMessage Improvisation.score” for examples of using trigger sync.

Autocomplete in the editor includes definitons for many note intervals. e.g. noteQtr. Start typing “note” and a list of notes will pop up.

Example to set the triggerSync of trigger 45 to an quarter note trill, use:


Set the magnification factor for the view. Zoom should be in the range 1.0 to 2000.0. 100 is normal size. Use zoom() without any parameter.

Math Functions

abs(x);  //Absolute value of x.
acos(x);  //Arccos of x
asin(x);  //Arcsin of x
atan(x);  //Arctan of x
atan2(x,y);  //Arctan function with two arguments
ceil(x);  //Smallest integer greater than or equal x
cos(x);  //Cosine of x
exp(x);  //E to the power x
floor(x);  //Largest integer less than or equal to x
log(x);  //Natural logarithm of x
min(x,y);  //Minimum of x or y
max(x,y);  //Maximum of x or y
pow(x,y);  //x to the power y
radians(degrees);  //Convert an angle in degrees to radians
round(x);  //x rounded to the nearest integer
sin(x);  //Sine of x
sqrt(x);  //Square root of x
sq(x);  //x squared
tan(x);  //Tangent of x
degrees(radians)  //Convert an angle in radians to degrees

Object Properties and Methods

These are the properties and methods that can be accessed in scripts using the “.” operator. Many of these can also be set using one of the set… commands documented above, but accessing them as properties is sometimes more convenient. It also allows the current value of properties to be read, which is not possible with the setter functions. There are also many properties that are read-only that are very useful for mapping to musical actions (note numbers, cc values, etc.) in message functions.

Each property includes, first the type of data that it refers to in the c++ code, then the property name, and then whether it can be just READ or can be READ and WRITTEN.

More documentation on these will be added in the future. For now, you can see examples of how to use some of them in the sample scores.

The methods are functions callable on an instance of an object to get it to carry out some action. For example this causes object number 99 to send its message an though it had been triggered. This can be done even outside of a message function. It could even be executed as a single line of code in the editor with the Command+. keyboard shortcut.


Similarly this line could cause an object to send its automessage function:


These can be useful for testing and other special purposes.

Properties Shared by Triggers, Curves and Cursors

  • bool selected (READ,WRITE)
  • quint16 id (READ,WRITE)
  • QString groupId (READ,WRITE)
  • QString documentId (READ,WRITE)
  • QString label (READ,WRITE)
  • QStringList autoLabel (READ,WRITE)
  • QString posStr (READ,WRITE)
  • qreal x (READ,WRITE) //Object x position
  • qreal y (READ,WRITE) //Object y position
  • qreal z (READ,WRITE) //Object z position
  • qreal x01 (READ) //Object x position scaled in proportion to the background width
  • qreal y01 (READ) //Object y position scaled in proportion to the background width
  • QColor pix (READ) //Color of backround pixel
  • qreal r (READ)
  • qreal g (READ)
  • qreal b (READ)
  • qreal a (READ)
  • qreal h (READ)
  • qreal s (READ)
  • qreal v (READ)
  • quint16 lineFactor (READ,WRITE)
  • quint16 lineStipple (READ,WRITE)
  • bool active (READ,WRITE)
  • bool hidden (READ,WRITE)
  • QString colorActive (READ,WRITE)
  • QString colorInactive (READ,WRITE)
  • QString colorActiveHue (READ,WRITE)
  • QString colorInactiveHue (READ,WRITE)
  • qreal messageIntervalMs (READ,WRITE)
  • qreal messageIntervalTicks (READ,WRITE)
  • QString beatEmphasisStr (READ,WRITE)
  • bool firstMessage (READ,WRITE)
  • bool repeatMessage (READ)
  • qreal beat (READ)
  • QString type (READ)
  • QString autoMsgFunction (READ,WRITE)
  • QString msgFunction (READ,WRITE)
  • qreal timeLagMultiplier (READ,WRITE)
  • qreal timeLagUnit (READ,WRITE)
  • QString port (READ,WRITE)
  • int channel (READ,WRITE)
  • int controller (READ,WRITE)
  • int note (READ,WRITE)

These object properties implement inheritance from the score. This means that if an object property is set to “Score”, the following properties will not return “Score”, but instead will return the value of that property for the score.

  • int tonic (READ) Returns the object tonic
  • QString scale (READ) Returns the object scale
  • int root (READ) Returns the object root
  • QString chord (READ) Returns the object chord
  • int rangeLow (READ) Returns the object’s lowest notes for mapping
  • int range (READ) Returns the size of the range for mapping, in semitones
  • QString mapNotesTo (READ) Indicates whether note mapping for this object is to the “Chord”, the “Scale”.
  • QList chordNotes (READ) List of notes in this object’s chord
  • QList scaleNotes (READ) List of notes in this object’s scale
  • QList notes (READ) List of notes generated by this object. The notes could be based on the chord or the scale setting, depending on the “mapNotesTo” property.

These properties set and get the actual object property values. This means they can set the a property to “Score” which would restore inheritence from the score.

  • int objectTonic (READ,WRITE) Sets the object tonic (set to -1 to use the score tonic)
  • QString objectScale (READ,WRITE) Sets the object scale (set to “Score” to use the score scale)
  • int objectRoot (READ,WRITE) Sets the object root (set to -1 to use the score root)
  • QString objectChord (READ,WRITE) Sets the object chord (set to “Score” to use the score chord)
  • int objectRangeLow (READ,WRITE) Sets the object’s lowest notes for mapping (set to -1 to use the score value)
  • int objectRange (READ,WRITE) Sets the size of the range for mapping, in semitones (set to -1 to use the score valse)
  • QString objectMapNotesTo (READ) Sets object note mapping to be to the “Chord”, the “Scale” or to use the same setting as the “Score”.

Methods Shared by Triggers, Curves and Cursors

  • void sendMessage() //Trigger the message function of this object
  • void sendAutoMessage() //Trigger the automessage function of this object

Properties of Trigger Objects

  • qreal triggerSize (READ,WRITE)
  • QString textureActive (READ,WRITE)
  • QString textureInactive (READ,WRITE)
  • QString textureActiveCurve (READ,WRITE)
  • QString textureInactiveCurve (READ,WRITE)
  • qreal triggerDistance (READ)
  • qreal beat (READ)
  • QScriptValue cursor (READ)
  • QScriptValue snapCurve (READ)
  • qint32 snapPoint (READ)
  • qreal triggerSync (READ, WRITE) Sets the triggerSync note size in ticks (96 ticks = quarter note). Off = -1.

Properties Curve Objects

  • qreal pathLength (READ)
  • CurveType curveType (READ)
  • int nPoints (READ)
  • QString resizeStr (READ,WRITE)
  • qreal resizeF (READ,WRITE)
  • qreal beat (READ)
  • QString beatPattern (READ,WRITE)
  • qreal beatInterval (READ,WRITE)
  • QString activeBeats (READ,WRITE)
  • QScriptValue cursor (READ,WRITE)
  • qreal height (READ,WRITE)
  • qreal width (READ,WRITE)
  • qreal beatNumber (READ,WRITE) Returns the value of variable ‘beat’
  • QString beatPatternType (READ,WRITE)
  • int nBeats (READ,WRITE)
  • int nActiveBeats (READ,WRITE)
  • int beatShift (READ,WRITE)
  • int nRepeats (READ,WRITE)

Methods of Curve Objects

  • int addPoint(int index, qreal x, qreal y, qreal z, bool smooth=false);
  • int addPoint(qreal x, qreal y, qreal z, bool smooth=false);
  • inline QScriptValue getCursor(int index)

Properties of Cursor Objects

  • QString repeatPattern R(READ,WRITE)
  • qreal duration (READ,WRITE)
  • qreal speedMultiplier (READ,WRITE)
  • qreal speedMultiplierRT (READ,WRITE)
  • qreal cursorWidth1 (READ,WRITE)
  • qreal cursorWidth2 (READ,WRITE)
  • qreal cursorHeight (READ,WRITE)
  • quint16 nbLoop (READ)
  • qreal cycles (READ,WRITE)
  • qreal timeLocal (READ,WRITE)
  • qreal x (READ,WRITE)
  • qreal y (READ,WRITE)
  • qreal z (READ,WRITE)
  • qreal r (READ)
  • qreal g (READ)
  • qreal b (READ)
  • qreal a (READ)
  • qreal h (READ)
  • qreal s (READ)
  • qreal v (READ)
  • qreal xOffset (READ)
  • qreal yOffset (READ)
  • qreal zOffset (READ)
  • qreal xVelocity (READ)
  • qreal yVelocity (READ)
  • qreal zVelocity (READ)
  • qreal localTime (READ)
  • qreal localTime01 (READ)
  • qreal angle (READ)
  • qreal beat (READ)
  • QScriptValue curve (READ)
  • QScriptValue trigger (READ)

Properties of the Score

These are accessed from the _score object that is automatically defined in each Javascript global context. A shortcut name called _s is also defined for the same object. For example you might print the score scale name like this:

  • int currentId (READ) The id number of the most recently accessed object.
  • int currentCurveId (READ) The id number of the most recently accessed curve.
  • QList backgroundSize (READ) Backround image position and size as a four element array. [upperLeftX,upperLeftY,lowerRightX, lowerRightY] e.g. [-14,10,14,-10]
  • QString backgroundFile (READ) Background file complete path as a string.
  • qreal bpm (READ,WRITE) Score beats per minute.
  • bool playing (READ,WRITE) True if the transport is running.
  • QString timeSig (READ,WRITE) The time signature as a string. e.g. “4/4”
  • bool hasBackgroundImage (READ) True if the score has a non blank background image.
  • QString scoreName (READ) The name of the score file.
  • qreal scoreTime (READ) The elapsed time for the score in seconds.
  • int tonic (READ,WRITE) Score tonic as a note number from 0 … 11
  • QString scale (READ,WRITE) Score scale name as a string.
  • QString chord (READ,WRITE) Score chord name as a string.
  • QList chordNotes (READ) Score scale notes as a Javascript array
  • QList scaleNotes (READ) Score chord notes as a Javascript array
  • int root (READ,WRITE) Score chord root in scale scale step number
  • int rangeLow (READ,WRITE) Lowest note of mapping range as a note number.
  • int range (READ,WRITE) Size of mapping range in semitones.

Harmony Properites of the Score:

  • int tonic (READ,WRITE)
  • QString scale (READ,WRITE)
  • int root (READ,WRITE)
  • QString chord (READ,WRITE)
  • int rangeLow (READ,WRITE)
  • int range (READ,WRITE)
  • QString mapNotesTo (READ,WRITE) Set mapNotesTo to “Chord” or “Scale” to select mapping of notes into the current chord or scale.
  • QList chordNotes (READ) Returns a list of notes in the score chord
  • QList scaleNotes (READ) Returns a list of notes in the score scale
  • QList notes (READ) List of notes generated by this object. The notes may be based on the chord or the scale. setting, depending on the “mapNotesTo” property.

Methods of the Score

Most of these have function style commands that do the same thing. It is not recommended that you use them, at least for now.

  • QScriptValue obj(int id); Returns the object with given id. Used in implementing _obj.
  • QList objectList(QString val); Returns a list of ids for object matching certain criteria.
  • int nextAvailableId(quint16 minimum); Returns the next unused id higher than a given minimum.
  • int addTrigger(int id); Adds a trigger.
  • int addTrigger(int id, qreal x, qreal y, qreal z); Adds a trigger at a position.
  • int addCurve(int id); Adds a curve.
  • int addCursor(int id); Adds a cursor.
  • int addCursor(int id, int curveId); Adds a cursor and attaches it to a curve.
  • int ellipse(int id, qreal w, qreal h, qreal x, qreal y, qreal z=0, bool addCursor = true); Adds an ellipse.
  • int del(int id); Deletes an object.
  • void delList(QList); Deletes a list of objects.
  • QString background(QString filePath, int xTopLeft, int yTopLeft, int xBottomRight, int yBottomRight); Loads an image file as a background image.
  • QString registerImage(QString filePath, QString name);
  • qreal zoom(qreal amount = 100);
  • qreal rotate();
  • qreal rotate(qreal zAngle);
  • qreal rotate(qreal zAngle, qreal xAngle, qreal yAngle);
  • void origin(qreal x, qreal y, qreal z=0);
  • void center(qreal x, qreal y);
  • void center();
  • qreal play(qreal speed);
  • qreal play();
  • qreal stop();
  • qreal rewind();
  • QList select(QString filter);
  • QVariant print(QVariant arg1, QVariant arg2=“”, QVariant arg3=“”, QVariant arg4=“”, QVariant arg5=“”, QVariant arg6=“”, QVariant arg7=“”, QVariant arg8=“”);
  • QVariant p(QVariant arg1, QVariant arg2=“”, QVariant arg3=“”, QVariant arg4=“”, QVariant arg5=“”, QVariant arg6=“”, QVariant arg7=“”, QVariant arg8=“”);
  • void clearScore();
  • QString pop(QString name); Pust
  • void pop();
  • QString push(QString name);
  • void push();
  • qreal speed(qreal speed);
  • qreal speed();

Licenses and Copyrights

Geosonix License

Copyright (C) 2015,2016 Christopher Graham (

This file is part of Geosonix.

Geosonix is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 3
as published by the Free Software Foundation, or (at your option)
any later version.

You should have received a copy of the GNU General Public License
along with Geosonix.  If not, see



Geosonix is a fork from the open source project, IanniX:
The IanniX web site states "IanniX is licensed under GPL 3, free and

QScintilla License

The Geosonix script editor is based on the QScintilla library

License for Scintilla and SciTE

Copyright 1998-2003 by Neil Hodgson <>

All Rights Reserved 

Permission to use, copy, modify, and distribute this software and its 
documentation for any purpose and without fee is hereby granted, 
provided that the above copyright notice appear in all copies and that 
both that copyright notice and this permission notice appear in 
supporting documentation. 


RtMidi License

Geosonix MIDI Communication is based on the RtMidi library.

RtMidi: realtime MIDI i/o C++ classes<BR>
Copyright (c) 2003-2016 Gary P. Scavone

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

Any person wishing to distribute modifications to the Software is
asked to send the modifications to the original developer so that
they can be incorporated into the canonical version.  This is,
however, not a binding provision of this license.