Language Constructs in Detail¶
In this chapter, you will learn more about types, declarations and other topics.
GPScript supports integer, floating point, boolean and string constants (more on strings below).
For convenience, MIDI note names can be used in place of integers. E.g,
C3 is the same as
Eb4) is the same as
SysEx Message constants can be defined as well (more on SysEx messages below).
You can declare global variables and local variables. The general syntax for a declaration is:
var identifier : type [optional initialization]
If you want to declare multiple variables of the same type, just separate them with a comma:
var i, j, k : Integer [optional initialization]
If you are declaring multiple variables one after the other, you do not need to repeat the
var keyword (although you can)
var i : Integer [optional initialization] s : String [optional initialization] n : NoteMessage [optional initialization]
Global variable are defined outside of any callbacks or user-defined functions and are visible only from the point at which you declare them.
Certain types such as Plugins, Widgets and function generators (
ADSR etc.,) can only be declared at global scope.
The type system¶
All variables must be declared with a type. All the available types are listed in the list of types, in the reference part of this manual.
Primitive types include
With a couple of exceptions, operators for primitive types are part of the language syntax itself.
For example, arithmetic operators (
%) and comparators (
>=) can be used on both
Opaque types are types whose behavior is controlled completely by system functions and you have no direct access to them.
Variables that refer to “physical” widgets and plugin blocks instances of opaque types.
Some opaque data types do not have any “physical” existence.
These include function generators, the
NoteTracker and the
Over time, as new functionality is added to Gig Performer, more opaque data types are likely to be added.
There are a couple of types that are treated specially, with some built-in operations even though they are otherwise opaque.
Language designers struggle with the best way to handle strings.
Some leave all string processing up to their libraries (but still have language support to define string constants), others make strings be a special type with language support.
GPScript adopts a hybrid approach.
There are numerous library functions for manipulating strings but the
+ operator is overloaded so that strings can be concatenated together.
More importantly, if you start an expression with a
String type, then the RHS 1 of the
+ operator can be of type
Double and the value will be automatically converted to a
This makes it easy to write such things as
Print("The value is " + i) // Display the value of i in the script log window
and is mainly intended for debugging purposes although it can be convenient to use this mechanism to set the caption of a label or widget, e.g.,
SetWidgetCaption(w, "Value: " + v)
Like many languages, a string constant is simply a sequence of characters bracketed with the double-quote character
If you need to include a double-quote inside your string, you can use the backslash character to escape the quote.
"This is a string containing an embedded \" double-quote"
You can bracket text with
>>> so as to allow a string to be spread out over multiple lines.
Var multilineText: String = <<< First line of text Second line of text >>>
System Exclusive (SysEx) messages¶
You can define a constant that represents a SysEx message. The format is as follows:
# F0 12 34 56 .. F7
Spaces are optional and intended for readability when defining longer messages that may be difficult to read.
You must include
F0 at the beginning and you must have
F7 at the end – you can use lowercase though – and the hex bytes in between must be between
Variables of type
SysexMessage can be used to store a SysEx message:
Var mySysex : SysexMessage = # F0 12 34 56 F7 // works
Var mySysex : SysexMessage = # F1 12 34 56 F7 // will not compile as the message does not begin with F0
There are system functions available for sending SysEx messages to MIDI In blocks and MIDI Out blocks as well as for getting and changing values in a SysEx message. That last is useful for parameterized real-time SysEx messages.
Parameters are available in Scriptlets only.
A Scriptlet plugin can define variables representing three different kinds of parameters:
Continuous parameters can have floating point values between 0.0 and 1.0.
Var Foo : Continuous Parameter = 0 // Declare a continuous parameter called Foo Var a,b,c : Parameter = 0.5 // Declare three parameters initialized to 0.5
A subrange parameter is a sequence of integer values. Note that MIDI Note Names can be used in place of integer values.
Var Subrange Channel : Parameter 1..16 // Declare a subrange parameter called Channel Var ScaleRoot : Parameter C3 .. B3 = D3; // Define a range of scale roots and initialize to D
A discrete parameter can hold any one of a predefined number of strings.
Var Leslie : Discrete Parameter "Slow", "Off", "Fast"
Discrete are optional in parameter declarations as they can be inferred from the clause on the right hand side of the parameter keyword.
However, should you need to use an array of parameters, you will need to refer to these types explicitly.
It is not possible to have an array containing different parameter types.
AsNoteNames operator can be used to create a discrete parameter that is intended to allow a sequence of note names to be conveniently defined.
This is particularly useful if you need parameters to span a significant number of MIDI notes.
Var notes : Parameter AsNoteNames C3 .. E3
is equivalent to writing:
Var notes : Parameter "C3", "C#3", "D3", "D#3", "E3"
Changing a parameter value from your script is as simple as assigning a new value to the parameter variable. Examples:
Channel = 2 Leslie = "Off"
As with most other variables, you can (and should) follow a declaration with an initialization. The compiler will produce a warning message if you do not include an initialization.
Var Leslie : Parameter "Slow", "Off", "Fast" = "Off"
Assignments to parameter variables are checked at runtime so if, for example, you tried to assign 17 to that Channel parameter above, it will quietly fail. In any such failure situation, the parameter will be set to the minimum possible value.
When you declare a parameter variable for a Scriptlet plugin, the name of that variable is used automatically as the parameter name that you see in the plugin editor or in the widget mapping parameter list. This can cause conflicts if the parameter name you want to use is the same as some other variable or is the same as an existing system function. For example, you cannot declare a parameter variable called “Transpose” since there is already a GPScript system function with that name. However, since it might typically be desirable to use such a word for display purposes, you can optionally include an explicit parameter name in the declaration:
Var MyTranspose("transpose") : Parameter -12 .. 12
The declaration above will declare a new variable called
MyTranspose which you will use to reference the parameter in your script.
However, the word transpose will be used for the parameter name for that plugin as far as widgets are concerned.
Under the covers, parameters are integer numbers.
Parameter numbers start at zero and increment by one for each new parameter that you declare.
You can access the parameter number directly by appending a hashsign (
#) to the parameter identifier:
Var a,b,c : Parameter = 0.5 // Declare three parameters initialized to 0.5 Print(b) // Prints the value 0.5, the value of that parameter Print(b#) // Prints 1, the second parameter number
It is possible to have arrays of types (although currently you cannot have an array of arrays). Arrays currently have a maximum length of 256. Array indexing is zero-based.
var mySmallArray : Integer
This creates an array that can contain 32 values. Attempts to reference the array outside the defined range will be trapped by the runtime system and the script terminated. While this adds a little cost, we feel that array range errors are sufficiently common that it’s worth the cost. In the future, we may add an option to disable range checking.
You can pass arrays as dynamic parameters to functions and the system function
Size will return the current size of the array parameter.
Function IntSum(someArray : Integer Array) returns Integer var s : Integer // Track the sum index : Integer For i = 0; i < Size(someArray); i = i + 1 do s = s + someArray[i] End result = s // Return the result End
Rather than defining a constant size, you can add the keyword
Array after any primitive type to create a dynamic array.
For example, the following declaration is allowed:
Var Fader1, Fader2, Fader3, Fader4 : Widget Faders : Widget Array Initialization Faders = [Fader1, Fader2, Fader3, Fader4] // Array initialization End
or more conveniently:
Var Fader1, Fader2, Fader3, Fader4 : Widget Faders : Widget Array = [Fader1, Fader2, Fader3, Fader4]
Then you can use array indices to reference individual widgets.
Size function works as expected and will return the current size of the array which of course is 4 in the above example.
The empty array
 can be used to clear the contents of a dynamic array.
Var x : Integer Array = [1, 2, 3, 4] Initialization x =  End
RHS is short for right hand side.