Language Constructs =================== Comments -------- You can have both line comments and multiline comments. Single line comments start with a double slash and end at the line end: .. code-block:: // This is a line comment Block comments start with ``/*`` and end with ``*/`` and they can be nested. .. code-block:: /* This is a multiline comment and /* you can nest multiline comments */ as well */ Constants --------- GP Script 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 ``60``, ``D#4`` (or ``Eb4``) is the same as ``75``. Declarations ------------ You can declare global variables and local variables. The general syntax for a declaration is: .. code-block:: var identifier : type If you want to declare multiple variables of the same type, just separate them with a comma: .. code-block:: var i, j, k : integer If you are declaring multiple variables one after the other, you do not need to repeat the ``var`` keyword (although you can) .. code-block:: var i : integer s : string n : NoteMessage 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`, `Ramp`, etc.,) can only be declared at global scope. .. todo:: which ones exactly? The type system --------------- All variables must be declared with a type. Primitive types ^^^^^^^^^^^^^^^ Primitive types include `Integer`, `Double` and `Boolean`. 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 `Integer` and `Double`. Opaque types ^^^^^^^^^^^^ 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 `ChordRecognizer` types. Over time, as new functionality is added to Gig Performer, more opaque data types are likely to be added. Hybrid types ^^^^^^^^^^^^ There are a couple of types that are treated specially, with some built-in operations even though they are otherwise opaque. Strings ^^^^^^^ 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. GP Script adopts the latter approach. While there are as yet no string processing system functions (and it´s unclear what functions might actually be needed within the context of Gig Performer automation), 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 of the ``+`` operator can be of type `Integer` or `Double` and the value will be automatically converted to a string type. This makes it easy to write such things as .. code-block:: 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., .. code-block:: SetWidgetCaption(w, "Value: " + v) Arrays ^^^^^^ It is possible to have arrays of types (although currently you cannot have an array of arrays). Arrays currently have a maximum length of 128 (no prizes for guessing why that value). Array indexing is zero-based. .. code-block:: var mySmallArray : Integer[32] 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. .. code-block:: 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 Dynamic arrays ^^^^^^^^^^^^^^ 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: .. code-block:: Var Fader1, Fader2, Fader3, Fader4 : Widget Faders : Widget array Initialization Faders = [Fader1, Fader2, Fader3, Fader4] // Array initialization End Then you can use array indices to reference individual widgets. The `Size` function works as expected and will return the current size of the array which of course is 4 in the above example. Operators ^^^^^^^^^ Boolean operators """"""""""""""""" GP Script includes the usual Boolean operators but has some interesting additions to make scripting a little easier for users. .. todo:: which? in """ The ``in`` operator allows the left hand side, normally an integer (`Integer`) or a floating point number (`Double`) to be tested against an integer or floating point respectively range. So you can write: .. code-block:: If n in [C3..C4] Then The variable ``n`` would normally be an integer type. However, this will also work if ``n`` is a `NoteMessage` or a `ControlChangeMessage` and in these cases the note number or controller number will be used.