Introduction

The Gig Performer scripting language, which we have rather unimaginatively named GPScript, is a special purpose language designed to add programmable and responsive functionality to Gig Performer, our plugin host for live performing musicians.

For example, you can write scripts with code that can respond to incoming MIDI note events and then transpose them, make chords out of them constrained to a scale, or use them to change widget values or to directly control parameters of a plugin (keyboard tracking, anyone?). Script code can be triggered in response to your moving a knob, slider or button. There are also time generators that can be used as LFOs (with varying shapes) or as ADSRs. Up until Gig Performer 3, you could only create and associate a script with each rackspace in a gig file. As of Gig Performer 4 you can create and associate scripts with individual rackspaces, individual songs, scriptlet plugins and a single “gig file” level script, that last providing some very useful control mechanisms.

Events and Callbacks

Generally, GPScript is event driven. It doesn’t do anything until something “happens” such as you’re playing a key, turning a knob, switching to another rackspace or to a different variation. A certain amount of time passing can also count as something “happening”. All of these examples are known as events and when you write code that can respond to an event, that code is called a callback. GPScript can currently handle the following events:

  • Initialization

  • Rack activation

  • Rack deactivation

  • Variation change

  • MIDI events (notes, CC values, Aftertouch, etc.)

  • Widget changes

  • Plugin parameter changes

  • LFOs (also known as Time Generators)

  • OSC Messages (coming soon)

  • Keystrokes (Gig file script only)

A simple example

var pi : Double

Initialization
   pi = 3.14159
   Print(pi)
End

So, what’s going on here? Well, first we declared a variable called pi and whose value must be a floating-point number (Double). In GPScript all variables must be declared, and they must have a type. The type of a variable defines the kinds of values that the variable can represent and also determines what kinds of operations can be applied to it. So called strongly typed languages make it easier to prevent certain kinds of common bugs.

The keyword Initialization defines the beginning of a callback that will be executed just once when a rackspace is initially loaded. In this example we simply assign a value to the variable and “print” its value. In the context of Gig Performer, printing means to show the item in a special window called the Script Logger. The keyword End completes the definition of this callback.

A more interesting example

// Declare a global variable
var A800 : MidiInBlock  // A800 is a named block in Gig Performer

// Callback when a note event (on or off) is received
On NoteEvent (m : NoteMessage) From A800
   SendNow(A800, m)  // Send the note to the A800 MidiIn block
   SendNow(A800, Transpose(m, 5)) // Also send a transposed note
End

Like before, the first thing we’re doing is declaring a variable. But unlike the example above that just used a floating-point number, the variable A800 is declared with the type MidiInBlock. That type represents a Gig Performer MIDI In plugin block. Consequently, the name of the variable, in this case, A800, is significant. For this script to work there must be a MIDI In block in your rackspace and its scripting name, more properly known as a handle, must be A800. So in this example, we are binding a variable name to an entity in Gig Performer.

screenshot of a *MIDI In* block with the GPScript handle ``A800``

This block has been assigned the handle A800. Note the handle name on the upper left and the {S} on the upper right, the latter indicating that the handle is available for use in GPScript.

Next, we define a callback. A callback is a block of code that will run automatically when the event associated with that callback occurs. The callback above responds to MIDI note events (both NoteOn and NoteOff events) that arrive at the MIDI In block named A800. There are other callbacks that respond to other MIDI events such as Control Change events or Aftertouch. The actual message itself is accessed through the incoming parameter argument m which has the type NoteMessage.

Once you define a callback for a MIDI event you have full responsibility for that event. GPScript will not automatically send the MIDI event back to the MIDI In block which means that the MIDI In block will not forward the event to whatever synth plugins are connected to it. So if you want the incoming note to be played, you have to explicitly send it out, which we do with the statement SendNow(A800, m). Immediately afterwards, we send the note again, after transposing it by 5 semitones. Voilà, instant chords.

Different kinds of scripts

As we briefly alluded above, as of Gig Performer 4, there are several different script targets available:

  • Rackspace scripts: Rackspace scripts have been around from the beginning and other than enhancements due to both language changes and new system functions, they behave as they always did. As of Gig Performer 4, the Global Rackspace has been introduced which also can have its own rackspace script.

  • Song scripts: You can now associate scripts with individual songs. Song scripts have callbacks that can be triggered when you switch from one song part to another so you can do some song specific processing.

  • Gig file scripts: You can define a single “top-level” script that can be used to control Gig Performer itself. The Gig file script has some interesting “superpowers”. For example, you can intercept incoming MIDI from devices, modify them, block them or even redirect them so that those events will appear to other parts of Gig Performer to have been received from different devices. The Gig file script can also respond to key sequences on your computer keyboard and used to trigger actions.

  • Scriptlet script: Gig Performer 4 allows you to create your own plugins to perform specialized MIDI processing. You can define parameters that can be controlled by rackspace widgets, respond to incoming MIDI events, process them and pass them on.