RTMix
<< | table of contents | >>

4. Scripting Language

RTMix's scripting language is its heart and soul. It is in the scriptfiles where all of the RTMix's power is contained. The scripting language contains a number of various events which can take similar (and often the same) parameters in order to describe their properties (such as timing). If you have ever been exposed to Paul Lansky's RT, then this scripting language will look very familiar. Yet, even if you had no prior exposure to scripts, it should be still a rather smooth experience. We will start with an overview of the language.

 

4.1 Overview

Scriptfiles contain series of commands that are compiled before starting the playback. The events are stored into a virtual cue and are retrieved as needed (usually either based on their timing or using a real-time trigger). Each of the commands are referred to as an EVENT, while each of the options associated with a particular event is referred to as PARAMETER. All events have their MANDATORY and OPTIONAL parameters. Optional parameters usually subtly alter the behavior of the event in question.

 

4.2 Syntax

The scriptfile can only have ONE EVENT PER LINE. Having more than one will result in compilation error. This is to ensure that the scriptfile is as legible as possible. The built-in editor has the word-wrap enabled by default, hence some of the more elaborate events might "spill" into the next line. The editor will treat all this as a SINGLE LINE (kind of like emacs, except that there will be no "backslash" at the end of the line signaling extension of the line). The line counter at the bottom of the "editor" tab reflects this as described.

The scriptfile compiler understands two types of information:

  1. Comments are delineated by C-convention double-slash ("//") at the beginning of the line. Everything following the double slash in a particular line will be considered a comment. Multi-line comments need to have double-slash at the beginning of every line belonging to that comment. A typical example of a comment would be:

    //This is a comment
     

  2. Events which have the following syntax:

    <event-name> ( [>param_1]={"value_1"} [>param_2]={"value_2"} ... [>param_n]={"value_n"} );;

    NOTE: Parameters do not have to be in any particular order.

Spacing is generally not crucial except in a few instances:

  1. All parameter names need to be preceeded with square bracket + greater-than sign ([>) and must end with closing square bracket (]) and must not have any spaces in between (i.e. "[>do]" is ok, while "[> do  ]" is not).

  2. All parameter values need to be delineated by a curly bracket + quotation mark ({") and the opposite for closing brackets ("}). Spaces between those will result in an error.

  3. Termination of an event-line must be done with a double semi-colon (;;). Again, spaces between the two semicolons will result in an error.

There are some additional event-specific exceptions which are listed below, but generally this is the main syntax for the script file.

Finally, the syntax is NOT case-sensitive. However if you do come across an inconsistency, please do let me know because it is most likely a bug.

 

4.3 Available Commands

Each command has an ID value associated to it. This is important since ID values, like many other numeric values can be altered at run-time (something that can be a lot of fun). Each command's ID is equal to the last digit of the sub-chapter number (i.e. event's sub-chapter number is 4.3.1, hence its ID = 1). Events with ID's equal to 0 (something that is achievable only through real-time alterations -- see 4.5.6) are simply ignored.

Available events can be grouped based on their scope and functionality:

Now, we'll look closer at each of these events and their syntax, parameters, as well as their behavior.

 

4.3.1 event

DESCRIPTION:

The event is the "backbone" of external event-invoking mechanism and possibly of the whole scriptfile. It is primarily used for external system calls that will trigger other applications and processes. However, it is also capable of sending an array of MIDI data via MIDI port, a single or an array of OSC events, as well as pose as an MIDI router for other applications requiring MIDI (for more info on MIDI and OSC events, see 4.5.2, 4.5.4, and 4.5.5).

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

event( [>at]={"0.5"} [>say]={"This is an event"} [>do]={"play any_sound.wav"} [>kill]={"play"} );;
event([>say]={"none"} [>at]={"rt[0]"} [>do]={"play any_sound.wav"} [>kill]={"play"} [>light]={"1"} [>lightlength]={"5"} [>accel]={"d"});;

 

4.3.2 countdown

DESCRIPTION:

Countdown event is very similar to the event, except that it also employs a countdown mechanism. At the end of the countdown, it executes the given event, specified with the [>do] parameter. Countdown and Warning events are the only ones allowed to utilize the Main widget's countdown counter. For more info on light events and countdown counters see 4.5.3).

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

countdown( [>at]={"11.23"} [>say]={"This is a countdown"} [>do]={"none"} [>kill]={"none"} [>dur]={"5.77"} );;
countdown( [>say]={"none"} [>at]={"111.1"} [>do]={"CMIX < scorefile.sco"} [>kill]={"play"} [>light]={"4"} [>lightlength]={"5"} [>preplength]={"5"} [>blinkspeed]={"0.5"} [>dur]={"30"} );;

 

4.3.3 text

DESCRIPTION:

Text event is a simple event that outputs text onto the notification interface.

IMPORTANT: any event invoking the [>say] parameter can have v[<num>] variables included, which will be then verbosely displayed on screen with the stored values at the time of execution. For instance, if the first stored variable is equal to 5, then having

[>say]={"Show me the var 0 value: v[0]"}

would result in an output

"Show me the var 0 value: 5"

NOTE: MIDI values cannot be displayed as a part of the text due to fact that they can be already easily logged in the Console window using the "MIDI logging" button (see 3.4.3) and due to their limited scope of behavior cannot serve an important role in the notification interface.

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

text( [>at]={"0"} [>say]={"So it begins..."});;
text([>say]={"Keyboard key 'd' has been released"} [>at]={"rt[0]"} [>light]={"4"} [>lightlength]={"5"} [>accel]={"^d"});;

 

4.3.4 checkpoint

DESCRIPTION:

Checkpoint event is a marker in the timeline that user can quickly fast-forward or rewind to. One can think of checkpoints as being "rehearsal marks" in a score. The beginning of the piece is considered the initial, 0th checkpoint.

IMPORTANT: while this event may have an 'absat' value set, it will never be reachable by any of the "jumping" events, such as "jump" (see 4.3.10), "rew" (see4.3.14), and "ffw" (see 4.3.15), even the transport controls "rew" and "ffw" (see 3.2) due to fact that those events strictly are bound to the non-absat checkpoints. You may still choose to use this one in combination with the "absat" flag as a some kind of a marker (although you could do probably the same thing with a "text" event).

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

checkpoint( [>at]={"1"} [>say]={"This is checkpoint no#1"} );;
checkpoint( [>at]={"15"} [>light]={"4"} [>lightlength]={"5"} [>blinkspeed]={"0.2"} [>say]={"none"} );;

 

4.3.5 pause

DESCRIPTION:

Pause event is equivalent to the "pause" transport control. It can be either bound to a particular time, or a real-time trigger.

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

pause( [>at]={"0.5"} [>say]={"Pausing..."});;
pause([>at]={"rt[0]"} [>accel]={"A"} [>say]={"Here comes pause"});;

 

4.3.6 stop

DESCRIPTION:

Stop event is equivalent to the "stop" button in the transport controls (see 3.2). It can be either bound to a particular time, or a real-time trigger.

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

stop( [>at]={"0.5"} [>say]={"Stopping..."});;
stop([>at]={"rt[0]"} [>accel]={"A"} [>say]={"The performance just came to a screeching halt..."});;

 

4.3.7 clear

DESCRIPTION:

Clear event clears the contents on the Notification widget. It can be either bound to a particular time, or a real-time trigger.

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

clear( [>at]={"2"} );;
clear([>at]={"rt[0]"} [>accel]={"Ctrl+K"});;

 

4.3.8 warning

DESCRIPTION:

Warning event is very similar to the countdown (see 4.3.2), except that it executes the command at the beginning of the countdown, rather than upon reaching the end. Countdown and Warning events are the only ones allowed to utilize the Main widget's countdown counter. For more info on light events and countdown counters see 4.5.3).

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

warning( [>at]={"11.23"} [>say]={"This is a warning"} [>do]={"none"} [>kill]={"none"} [>dur]={"5.77"} );;
warning( [>say]={"none"} [>at]={"111.1"} [>do]={"sox foo.snd"} [>kill]={"play"} [>light]={"4"} [>lightlength]={"5"} [>preplength]={"5"} [>blinkspeed]={"0.5"} [>dur]={"30"} );;

 

4.3.9 metronome

DESCRIPTION:

Metronome is a specific event tied to the Metronome window (see 3.6.4). It utilizes a couple of event-specific parameters and can be triggered both as a timed event or in real-time.

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

metronome( [>at]={"1"} [>say]={"none"} [>num]={"1"} [>bpm]={"93"} [>meter]={"2+3+2+1+0+5"} );;
metronome( [>say]={"Boo!"}  [>light]={"4"} [>at]={"4"} [>num]={"1"} [>bpm]={"144"} [>meter]={"11"}[>lightlength]={"5"} [>preplength]={"5"} [>blinkspeed]={"0.5"} );;

 

4.3.10 jump

DESCRIPTION:

Jump event is used to jump between the established checkpoints (see 4.3.4). Jump can be either forwards or backwards, as well as either absolute or relative. See below for more info.

IMPORTANT: It is quite possible that the awkward placement of "jump" (see 4.3.10), "rew" (see 4.3.14), and "ffw" (see 4.3.15) events can cause an infinite recursion. RTMix is by default able to handle single-level recursions by simply stopping the playback and notifying the user of a recursion. See tutorials for an example.

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

jump( [>at]={"100"} [>say]={"Whee!!!"} [>to]={"-2"} [>abs]={"0"} );;
jump( [>at]={"232.22"} [>to]={"12"} [>abs]={"1"} [>light]={"13"} [>lightlength]={"1"} [>blinkspeed]={"0.1"} );;

 

4.3.11 randomize

DESCRIPTION:

Randomize event is usually used in combination with the "change" event (see 4.3.12), "seed" event (see 4.3.13), and "assign" event (see 4.3.17). All these events are used for manipulation of simple float or integer variables. Up to 256 of the manipulated values can be stored for later retrieval and/or further manipulation. The purpose of such variable manipulation is to provide user with a modular functions that can be used for a variety of purposes:

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

randomize( [>at]={"2"} [>type]={"0"} [>method]={"0"} [>store]={"0"} );;
randomize( [>at]={"1234"} [>say]={"Let's make some random numbers..."} [>type]={"65536"} [>method]={"4"} [>store]={"255"} [>absat]={"1"} );;

 

4.3.12 change

DESCRIPTION:

Change event is usually used in combination with the "randomize" event (see 4.3.11), "seed" event (see 4.3.13), and "assign" event (see 4.3.17). All these events are used for manipulation of simple float or integer variables. Up to 256 of the manipulated values can be stored for later retrieval and/or further manipulation. The purpose of such variable manipulation is to provide user with a modular functions that can be used for a variety of purposes:

Change event has a specific function to alter event values that are result of a MIDI input (only real-time events utilizing MIDI triggers), by retrieving one of the stored variables. or both (see 4.5.6). The resulting value can then be applied to various parameters of the event that follows the "change" event (or a specific event type that might not immediately follow the "change" event in which case RTMix searches for the next event of that type in the cue, ignoring "jumps" and other timeline-altering events) or stored back for later retrieval.

Despite great flexibility, change event is most commonly used to alter probabilities of the oncoming events (see 4.5.9).

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

change( [>at]={"4"} [>func]={"v[0] - 0.7"} [>var]={"happen"} );;
change( [>at]={"4"} [>func]={"v[0] - 0.7"} [>var]={"happen"} [>say]={"With that kind of alteration, the chances for the next (abs!) event to occur are getting slimmer..."} [>absat]={"1"} );;

 

4.3.13 seed

DESCRIPTION:

Seed event is usually used in combination with the "randomize" event (see 4.3.11), "change" event (see 4.3.12), and "assign" event (see4.3.17). All these events are used for manipulation of simple float or integer variables. Up to 256 of the manipulated values can be stored for later retrieval and/or further manipulation. The purpose of such variable manipulation is to provide user with a modular functions that can be used for a variety of purposes:

Seed is directly related to the "randomize" event. It is used to "stimulate" computer to churn out random numbers, something that computer is incapable of doing themselves. Each seed value will give the same resulting number when a "randomize" call is executed. Therefore, the possible array from which one can pick a seed is rather large in order to minimize recurrence of random numbers.

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

seed( [>at]={"55.14"} [>value]={"0"} [>say]={"This one will be based on the unix clock..." );;
seed( [>at]={"0"} [>value]={"13243421"} );;

 

4.3.14 rew

DESCRIPTION:

Rew event (a.k.a. rewind) is equivalent to the "rew" button in the transport controls (see3.2). It can be either bound to a particular time, or a real-time trigger.

IMPORTANT: It is quite possible that the awkward placement of "jump" (see 4.3.10), "rew" (see 4.3.14), and "ffw" (see 4.3.15) events can cause an infinite recursion. RTMix is by default able to handle single-level recursions by simply stopping the playback and notifying the user of a recursion. See tutorials for an example.

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

rew( [>at]={"0"} [>to]={"1"} [>say]={"This one will cause an infinite recursion, but RTMix should be able to handle it..." );;
rew( [>at]={"521.44"} [>to]={"5"} );;

 

4.3.15 ffw

DESCRIPTION:

Ffw event (a.k.a. fast-forward) is equivalent to the "rew" button in the transport controls (see3.2). It can be either bound to a particular time, or a real-time trigger.

IMPORTANT: It is quite possible that the awkward placement of "jump" (see 4.3.10), "rew" (see 4.3.14), and "ffw" (see 4.3.15) events can cause an infinite recursion. RTMix is by default able to handle single-level recursions by simply stopping the playback and notifying the user of a recursion. See tutorials for an example.

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

ffw( [>at]={"0"} [>to]={"1"} [>say]={"Let's skip ahead" );;
ffw( [>at]={"521.44"} [>to]={"5"} [>light]={"12"} [>lightlength]={"4"} );;

 

4.3.16 togglemetro

DESCRIPTION:

Togglemetro event is a specific event tied to the Metronome window (see 3.6.4). It utilizes a couple of event-specific parameters and can be triggered both as a timed event or in real-time. It is also similar in syntax to other toggle events "togglert" (4.3.18), "togglenet" (4.3.20), and "togglemidi" (4.3.21).

This event simply toggles a particular metronome (1-4) on or off. There are 4 types of switches (explained below).

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

togglemetro( [>at]={"1"} [>num]={"1"} [>status]={"0"} [>say]={"Stop & Reset"} );;
togglemetro( [>say]={"Boo!"}  [>light]={"4"} [>at]={"32"} [>num]={"4"} [>status]={"3"} );;

 

4.3.17 assign

Assign event is usually used in combination with the "randomize" event (see 4.3.11), "change" event (see 4.3.12), and "seed" event (see4.3.13). All these events are used for manipulation of simple float or integer variables. Up to 256 of the manipulated values can be stored for later retrieval and/or further manipulation. The purpose of such variable manipulation is to provide user with a modular functions that can be used for a variety of purposes:

Assign is the most rudimentary of this group of events. It simply assigns a particular value to be stored into a particular variable. The value can be either float or integer.

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

assign( [>at]={"1.14"} [>amt]={"0.564"} [>store]={"v[133]"} [>say]={"Text is always being posted the first, hence the following value will not reflect the newly assigned amount: v[133]" );;
assign( [>at]={"rt[0]"} [>accel]={"^t"} [>amt]={"13243421"} [>store]={"v[3]"} );;

 

4.3.18 togglert

DESCRIPTION:

Togglert event is a specific event tied to the monitoring of the real-time events. Its behavior corresponds to the "toggle real-time events" button on the real-time tab (see3.4.3). It also resembles other "toggle" events in its syntax and properties.

Upon enabling the real-time monitoring all inbound real-time events will be interpreted. Furthermore, all resizable windows will cease to be resizable in order to minimize cpu utilization by RTMix's GUI. When the real-time event monitoring is enabled, the MIDI Monitoring button will become available (otherwise it is disabled).

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

togglert( [>at]={"1"} [>num]={"1"} [>status]={"1"} [>say]={"Now you can use the real-time triggers! Yay!"} );;
togglert( [>at]={"32"} [>status]={"0"} );;

 

4.3.19 setnet

DESCRIPTION:

Setnet event is a specific event tied to customizing networking settings. Its behavior corresponds to the various networking buttons found on the "network" tab (see 3.4.4). This event is peculiar because it is the only event that is timeless (does not have [>at] parameter) and is executed at compile-time.

Setnet can either set the localhost's socket to which other clients are going to be able to connect (default 9900), or configure one of the external clients, in which case it supplies client's hostname, port, and the id number to be associated with that connection (0-255 corresponding to the Network table).

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

setnet( [>host]={"localhost"} [>socket]={"9898"} );;
setnet( [>host]={"somewhere.out.there"} [>socket]={"2121"} [>store]={"0"} );;

 

4.3.20 togglenet

DESCRIPTION:

Togglenet event is a specific event tied to enabling/disabling of the networking features. Its behavior corresponds to the various networking buttons found on the "network" tab (see3.4.4). It also resembles other "toggle" events in its syntax and properties.

Togglenet can either enable/disable localhost connectivity, or initiate connection to a remote client listed on the top of the networking tab (numbered 0-255). Such client needs to be initiated first by using the "setnet" event which is timeless and is always interpreted at compile-time (see 4.3.19).

IMPORTANT: while it is possible to create a localhost connection to the same client, this is not advisable, since it may cause an infinite recursion. RTMix has a network recursion filter that should be capable of disconnecting the host as soon as such recursion is found without hindering the continuation of the performance. Such recursions are logged in the console window.

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

togglenet( [>at]={"5"} [>status]={"1"} [>id]={"-2"} [>say]={"Starting localhost..."} );;
togglenet( [>at]={"12"} [>status]={"0"} [>id]={"-1"} );;

 

4.3.21 togglemidi

DESCRIPTION:

Togglemidi event is a specific event tied to the monitoring of the real-time MIDI events. Its behavior corresponds to the "Toggle MIDI Monitoring" button on the real-time tab (see 3.4.3). It also resembles other "toggle" events in its syntax and properties.

This option is only available if the real-time event monitoring is already on. If not, the event will be ignored.

PARAMETERS:

OPTIONAL PARAMETERS:

EXAMPLES:

togglemidi( [>at]={"1"} [>num]={"1"} [>status]={"1"} [>say]={"Now you can use the real-time MIDI triggers! Yay!"} );;
togglemidi( [>at]={"32"} [>status]={"0"} );;

 

4.4 Debugging

RTMix has been designed to offer maximally verbose Console that can provide users with enough information to make bug-tracking easier. Coupled with the "goto error" button, as well as color-coded Console text, it should be more than adequate for most situations.

Console is the focal point when it comes to debugging the scripts. The kinds of errors you might encounter can be split-up into two groups: compile-time, and run-time errors. In addition to errors, Console also notifies user of non-critical "warnings" which affect a particular functionality, but do not hinder the overall performance.

 

4.4.1 Compile Errors

Compile-time errors check for the following errors:

Most, if not all error messages are structured to provide you with an exact line number, as well as the type of error and its possible resolution. Furthermore, if a particular value is outside allowable range, Console should suggest possible values and/or ranges.

Most of the compile-time errors should be easily resolved with some help from this manual and by observing the Console output.

 

4.4.2 Run-Time Errors

Run-time errors and warnings are a bit tougher to track down since they depend on the current state of the script, values stored within the parameters and the storable variable array, as well as real-time interactive events that can dramatically affect the flow of events. Run-time errors can include:

Again, all of these try to be as verbose as possible. Very few run-time errors are show-stoppers (i.e. infinite recursions). Therefore it is always valuable to scroll back through your log to see what really happened. The status LED's at the bottom of the Console should be an additional helper where user can easily monitor event activity, as well as see whether the Console contains any warnings or errors since the last purge (see bottom-right 2 LED's on the Console window).

Beyond that, it is rather hard to give any specific advice. Like any other debugging session, it can be a rather tedious process. But, look at it from a brighter side, when you finally figure it out, you will feel a great sense of accomplishment :-).

 

4.5 Advanced

Topics included below are considered to be advanced primarily due to fact that covering their scope in enough detail would produce too much clutter in the event-listings, and perhaps in some cases are not something that everyone will want to use.

 

4.5.1 Networking

Apart from the straightforward events setnet (4.3.19) and togglenet (4.3.20), networking offers a great deal of flexibility when it comes to routing of the information.

Events that have the [>net] value set to -1 - 255 are sent over the network. "-1" value implies global event that is sent to every existing external connection as well as interpreted locally. All other values (0-255) refer to the specific networked connection.

What is important to understand is that every time transport control is pressed, this event is emanated globally (equiv. to the parameter value of "-1"). Other events, that have the ability to be networked have to be explicitly defined as such. All networked events with the value of "-2" will be interpreted strictly locally.

All events that are emanated globally are received by individual clients with the [>net] value altered to "-2" (even if their originating value was different, such as it is in this example, where original value was "-1"). This way the event will be only interpreted locally. This is to ensure avoidance of infinite recursions. Let's look at the following example in order to explain the issue of recursion:

Let's say we have 2 clients, A and B, which are inter-connected. A is the master of the B, while B is the master to the A. In order to recreate this situation, we can use two examples from the tutorials:

../network-examples/event-master.rmx
../network-examples/event-master-two-way-connection.rmx

We can spawn two instances of RTMix and compile one of the scripts in each instance. Upon compiling, we can connect the two clients by enabling connections on the network tab. By doing this, we have now crated a unique symbiotic relationship between the two instances of RTMix where both clients are both slaves and masters to each other. Needless to say this kind of an arrangement can offer a great setting for an improv session. On the other hand, if an event were to be allowed to propagate itself in such a setting, it would be easy for a global event to continuously jump back and forth between the two clients, thus creating an infinite spawn recursion. While there is a mechanism that filters such recursions in respect to the transport controls, events are simply impossible to track down due to their ability to be spawning at a great density. Furthermore, a recursive behavior of any kind of event is simply not desirable since it can be extremely hard to coordinate from the artistic standpoint.

It is also theoretically possible to connect the client to itself, although such an action yields no benefit over locally spawned events.

 

4.5.2 Accelerators and Custom Parameters

Accelerators are external real-time triggers of events that do not depend on a timeline, but are simply modular. There are two fundamental types of accelerators:

  1. Keyboard keys (including complex combinations) -- this category can be further subdivided into key "presses" and key "releases"

  2. MIDI events that can be limited in range and scope

Keyboard events require the following syntax:

MIDI accelerators are a bit more elaborate. They require 6 parameters. The syntax for the MIDI accelerator is as follows:

"midi: low_status (0-255, MIDI standard utilizes only 128-255), high_status (0-255, MIDI standard utilizes only 128-255), low_data1 (0-255, MIDI standard utilizes only 0-127), high_data1 (0-255, MIDI standard utilizes only 0-127), low_data2 (-1-255, MIDI standard utilizes only 0-127), high_data2 (-1-255, MIDI standard utilizes only 0-127)"

The reason for the the last data2 range allowing for -1 values is because some MIDI messages do not require the second data byte. This way you will ensure that messages that do not require the second data can still trigger the event.

An example of a MIDI accelerator would therefore look like this:

[>accel]={"midi: 128, 255, 0, 127, -1, 127"}

This kind of accelerator would be therefore susceptible to any kind of MIDI data received from the designated MIDI port. This is very useful for MIDI routing (see 4.5.5).

It is also possible to limit the range of acceptable values which can make this kind of accelerator more useful. For instance in order to limit accelerator only to note-on messages on the channel 1, one could say:

[>accel]={"midi: 144, 144, 0, 127, 0, 127"}

By now, it is obvious that RTMix utilizes MIDI on a rather low-level. Therefore one needs to be familiar with the MIDI protocol in order to be able to harness its power. One way to learn more about the MIDI protocol is to use RTMix's MIDI Logging capability (see 3.4.3), or by looking into some additional MIDI documentation (see 7.4).

IMPORTANT: RTMix's built-in protocol ignores any MIDI events that are hardware-specific (namely anything that utilizes status bytes of values greater than 0xEF, or in decimal terms greater than 239). Subsequently, such MIDI events cannot be routed either via OSC protocol (see 4.5.5).

IMPORTANT: both types of accelerators work no matter which of the RTMix's windows is focused. However, if none of the RTMix's widgets are focused, no keyboard events will be registered, while MIDI events will continue to be registered. This is simply due to fact that for any application under X-windows to receive keyboard events, it needs to be focused (i.e. currently selected and/or activated).

 

4.5.3 Custom Routing and Behavior of Visuals

Visuals play an important role in RTMix since they are the main means of conveying information to the performer while providing minimal amounts of distractions. While most events do not have any visual counterparts attached to them by default, almost all events can have custom visual behaviors assigned to them. This is done using optional visuals parameters [>light], [>lightlength], [>dur], [>preplength], and [>blinkspeed].

[>light] parameter specifies which LED, or group of LED's will be targeted, which will further dictate how the visuals will manifest themselves. The following are valid values:

 

4.5.4 MIDI Utilization

MIDI as a real-time trigger has already been covered in the subchapter 4.5.2, so here we'll focus on MIDI utilization as an event. MIDI can be also posted as an parameter in the event call. It can be included in two forms:

  1. MIDI values at the time of triggering can be included into the event by substituting the variables with their respective values (NOTE: you must have a MIDI accelerator associated with this particular event). For instance an event's [>do] parameter:

    cmixplay my_soundmidi[0].wav

    invoked by the MIDI note-on event with values 144, 56, 30 (status byte describing note-on on the 1st channel, 56 standing for pitch, and 30 being its velocity) would result in a following sys-call:

    cmixplay my_sound144.wav

    Any of the three values can be included by simply specifying the correct parameter and they can be included as many times as desired. The three values can be accessed by specifying:

    midi[0] (144), midi[1] (56), or midi[3] (30)

    Therefore a event:

    cmixplay midi[0]midi[1]midi[2].wav

    would result in a system call:

    cmixplay 1445630.wav
     

  2. MIDI can be also used for output to other MIDI devices. In this case, MIDI accelerator can, but does not have to be the trigger (as a matter of fact, the event does not even have to be real-time):

    [>do]={"midisend: 144, 64, 76, 144, 61, 76, 144, 57, 76"}

    This will produce a major triad on a synthesizer connected to the RTMix. There are three note-on's (144) described here with three different pitches (64, 61, and 57) and same velocities (76). Due to fact that the MIDI protocol is linear, these values are fed to the raw-midi port (selectable in the settings menu -- see 3.5.4) one after the other. But this is done so quickly and efficiently that there is no "broken chord" perceived.

    MIDI events of this kind can be used in combination with the first type (in which case they need to be real-time):

    [>do]={"midisend: 144, midi[0], 76, 144... etc. ad infinitum"}

    The number of the events is by no means limited, and one could theoretically send a huge array of events. However, they would be all timed synchronously.

 

4.5.5 OSC Utilization

OSC (Open Sound Control) protocol (see7.4) is utilized by RTMix in order to be able to communicate with the runaway processes spawned via sys-calls. Currently this protocol seems to be (in author's humble opinion) the most promising successor to the aging MIDI protocol. OSC in RTMix can be only utilized as a part of the [>do] parameter. There are three types of OSC events:

  1. OSC router which must be associated with a MIDI accelerator, routing incoming information via local (or remote) socket to another application, hence enabling polling of the MIDI resources between different applications. The only catch is that the receiving application must support the OSC protocol (currently there is already 20+ applications supporting this protocol, and the number is steadily growing see7.4 for more info). MIDI events are sent in the standardized format:

    MIDI EVENT # PARAMS. STATUS RANGE OSC INTERPRETATION
    note-off 3 0x80-0x8F /midi/<channel-number>/noteoff <pitch> <velocity>
    note-on 3 0x90-0x9F /midi/<channel-number>/noteon <pitch> <velocity>
    (NOTE: if velocity=0, then it is interpreted as a noteoff)
    poly aftertouch 3 0xA0-0xAF /midi/<channel-number>/polyaftertouch <data1> <data2>
    control 3 0xB0-0xBF /midi/<channel-number>/control <data1> <data2>
    program 2 0xC0-0xCF /midi/<channel-number>/program <data1>
    aftertouch 2 0xD0-0xDF /midi/<channel-number>/aftertouch <data1>
    pitchbend 3 0xE0-0xEF /midi/<channel-number>/pitchbend <data1> <data2>

    The syntax of an event looks as follows:

    [>do]={"oscroute: <host>, <port>, <typetags>"}

    This syntax needs to be associated with the MIDI accelerator with a specific range. "Typetags" is a boolean variable that determines whether the OSC packets will have typetags included that describe the type of data being sent. For more info on typetags see7.4.
     

  2. OSC event which is a single specified instance of a MIDI message that can have up to 2 data members in addition to the initial hierarchical description of the event (commonly referred to as "address"). This is simply a singular trigger of some sorts. An example syntax would be:

    [>do]={"osc: <host>, <port>, <typetags>, <address>, <data1>, <data2>"}

    For instance:

    [>do]={"osc: localhost, 9999, 1, /midi/foo/bar, 12423, -1"}

    Notice that this introduces some more flexibility than the previous model since now you can have more abstract adresses, and by substituting MIDI data into the call (using midi[0]), you can still use it as a MIDI router of a limited scope. Another flexibility is that now your values (although still having to be numeric), can go beyond the 255 limit, but must still adhere to the -1 rule.
     

  3. OSC CUSTOM event where a series of OSC events can be sent in a bundle and can have any kinds and numbers of parameters:

    [>do]={"osccustom: <host>, <port>, <typetags>, <message1-with-parameters> | <message2-with-parameters> | etc."}

    For instance:

    [>do]={"osccustom: localhost, 9999, 1, /foo/bar 22 a 3.3 | /midi/noteon/ch1 244 111 234 1 -232223.24"}

    As you can see, the last instance is the least limiting one. It provides for simlutaneous sending of various OSC data in a single bundle that is received simultaneously. Furthermore, parameters can now take on integers, float-point numbers, as well as "string" values.

 

4.5.6 Variables, Functions, and Substitutions

Numeric variables in RTMix, both integers and float-point, can be stored and manipulated in order to modify sys-call events, as well as MIDI and OSC events or many other parameters of other events. For this purpose you can use events assign (4.3.17), seed (4.3.13), randomize (4.3.11), and change (4.3.12).

The easiest example of manipulating variables can be found in the explanations of the events listed above. Furthermore, let's observe several examples:

v[<num>] variables always refer to the stored float-point or integer values (0-255). These can be substituted in:

midi[<num>] (0-2) can be used in association with the real-time events utilizing MIDI accelerators (see4.5.2). They behave the same like the v[<num>] substitutions, but can be only used within:

Assign (4.3.17), randomize (4.3.11), and change (4.3.12) events can be used to manipulate stored values (all 256 are 0 by default). See these events' documentation for more info.

 

4.5.7 Color-coding the Text for the Notification Interface

Text destined for the Notification interface can be color-coded using HTML-compatible tags. All text posted on the Notification interface will fade into grey and eventually black as it is pushed away by the new incoming text. This is done in order to preserve legibility by having the new text always show up at the top of the Notification widget. However, the new text will retain its custom color until pushed away. An example of such color-coding would be:

[>say]={"<font color="#FF0000">This is red text...</font>"}

The color is done the same like in HTML where the six-digit number denotes hexadecimal values of the RGB (red, green, blue) elements in the color. Hence FF0000 would be red=255, green=0, blue=0, while 00FF00 would be green, etc.

 

4.5.8 Absolute vs. Relative Events

Absolute events (ones with the optional [>absat] parameter being equal to 1, if applicable) simply occur when the ABSOLUTE TIMER (see 3.6.2) reaches the desired timing specified by the [>at] value (NOTE: real-time values cannot have [>absat] value equal to 1, since they do not depend on either timer). This is because events like pause (4.3.5), stop (4.3.6), checkpoint (4.3.4), jump, (4.3.10), rew (4.3.14), and ffw (4.3.15) can affect the flow of the Main timer therefore hindering its ability to show absolute time since the beginning of the performance. This way, with the existence of the absolute-timed events, one can easily adjust the absolute ending of a particular improvised section (i.e. cadenza) or something similar.

The general notion is that the absolute events only talk nice to other absolute events (i.e. absolute "change" call will not affect the next event in the cue, but rather, next absolute event, if such an event exists, therefore potentially skipping over some other events). However, this is not valid for the following events:

"Jump", "ffw", and "rew" events with an enabled [>absat] parameter cannot jump to absolute checkpoints, but only to relative ones (even though the absolute checkpoints may exist). This is due to fact that the Main timer is unable to backtrack or fast-forward itself accurately, since its leaps and skips might be affected by a wide array of real-time and other non-real-time events. Hence, absolute versions of the aforementioned three events will occur according to the absolute timer, but will still only search for the non-real-time checkpoints.

 

4.5.9 Dealing With Event Probabilities

Event probabilities depend on the built-in, ever-present, yet optionally modifiable two parameters: [>happen] and [>chance]. Both parameters take in float-point values ranging between 0 and 1 (0 and 100% -- hence 0.50 would be 50%).

[>chance] parameter, by default 1 (or 100%) determines what is the chance of a particular event to occur. If at 100%, the only time it will not occur is if the [>happen] value is 0 (or 0%).

[>happen] parameter is the value the should be considered the one to be freely modified during performance, since it is compared every time to the [>chance] command, and if it is less than the 1-[>chance], then the event will not occur.

If the [>chance] parameter is 0 (0%), then no matter what is the [>happen] amount, the event will never happen. To make this a bit clearer, think of it this way:

If a chance of happening is 75% (0.75), then lets subtract this number from 1. We get 0.25. This means as long as the [>happen] value is >=0.25 (up to 1), which is the 75% of the range, the event will occur.

Obviously for such modular probabilities, one must use "change" event (see 4.3.12) in order to alter [>happen] (and/or [>chance]) parameter(s) at run-time. See "chance" tutorials for more info.

 

4.5.10 Issues with Audio Signal Polling

While RTMix solves many of the limitations imposed by using any single audio application, there are still a few issues that are beyond RTMix's control. One, perhaps the most important one for the Linux audio world is the lack of widespread audio-signal-polling (a.k.a. ability to have two applications both output audio together). The issue has become even more convoluted with the recent (and rather welcome) phasing out of the OSS framework and introduction of the ALSA kernel drivers. In the recent years this problem has been addressed in various ways (and with varying amounts of success), but the recent developments have provided the Linux audio community with a couple of promising solutions. They are listed in the order of their quality (in author's humble opinion):

  1. JACK (http://jackit.sf.net/) audio super-lowlatency server that offers inter-app audio routing. It is the most promising project of this kind and is (again, in author's humble opinion) becoming the standard. How-to for this server can be found on its website.

  2. ALSA (http://www.alsa-project.org/) project's dmix and snoop sound polling servers (dmix for output, and snoop for input). Sparse info on these servers can be found on the alsa-devel and alsa-user mailing lists (linked from their main site).

  3. ARTSD (http://www.kde.org/) KDE's sound daemon. Generally has not-so-good latency, but works rather well and is simple to implement. As of right now, this one appears to be the easiest to utilize, at least as far as the audio output is concerned. Artsd can be simply utilized in the sys-calls by preceeding your event with the "artsdsp" command. Therefore a sys-call:

    cmixplay my_sound.aiff


    would become:

    artsdsp cmixplay my_sound.aiff

    This way multiple playback streams become available, whose number is only limited by your cpu's processing capability. This approach should work with both OSS and ALSA apps, although due to various implementations of audio engines, your mileage may vary.

Audio input polling on the other hand is still a bit flaky and I have not come across a full-proof way of polling audio input that will work consistently with older OSS-base applications and the new ALSA-based ones.

That being said, it seems that this problem will very soon become a non-issue since more and more applications are being ported to the JACK architecture, and once ALSA's dmix and snoop sound servers mature (my prognosis would be by the mid-to-late 2003), this chapter will lose its purpose :-).

<< | table of contents | >>