This script reference document contains all scripting functions and parameters for creating advanced sample and synthesis based instruments using Gorilla Instrument Editor.
Instruments can include one or more script modules, allowing you include scripting functions to enhance the functionality of your instrument beyond what's possible with the built-in modules, and expose parameters to the user.
The Gorilla Script language is similar to the NI Kontakt script language. This makes it fairly easy to "convert" sample based Kontakt instruments - many of the Kontakt functions will work without modification.
The example instruments that come with the Gorilla SDK already have script modules in them, but if you have an instrument without one, select the top-level instrument module in the left pane of the editor and insert a script module using the (+) menu.
A script is a plain text file which contains a series of statements. The easiest way of creating a script is writing it in a standard text editor (such as Sublime Text) and then saving it as a ".txt" file.
The resulting file can be dragged onto the script module in the instrument. If there are errors in the script, these are highlighted in the Script display, with a description of the error printed on the status line below. Alternatively, script text can be pasted from the clipboard into the script module.
The script cannot be edited in the Script text box. If you need to edit the script, do that in a text editor, save, and then reload the script in the Instrument Editor.
When you write your script there are some basic rules to consider:
Write each statement on one line each. If a line is too long to read easily, you can type "..." at the end of the first line and then continue on the following line. The lines are now interpreted as a single statement.
Use as many line feeds (empty rows) as you like between the statement lines.
Use as many spaces as you like between the words in the statement. This is very useful for making indents of various parts of the script, to make it easier to read and follow in the text editor.
Make sure you don't accidentally mix upper case and lower case letters in your statements. The names of functions and variables are case sensitive.
Note that in this document 'value' means a numeric value or any expression that evaluates to a numeric value. This could be a variable name, indexed array value, function return value, or a mathematical calculation involving a combination of those things.
All numeric values are 32-bit integers (whole numbers with no decimal places) so calculations involving values above about 2 billion may give wrong results.
Mathematical operators are applied in the same order as other computer languages such as C/C++ and Javascript. e.g. in 1 + 2 * 3 the multiplication is done before the addition so the result is 7. However, parentheses can be used to force the evaluation order (changing the previous example to (1 + 2) * 3 would force the addition to be done first so the result is 9).
Text strings are used as arguments to some functions. The text should be between straight quote marks (e.g. "my string") and quote marks are not allowed within a string. Special characters are allowed in strings (using UTF-8 encoding) but control characters (tab, newline, etc.) are not.
While most module parameters are linear (a series of equally spaced values such as 0 to 100 %) some have non-linear scaling so the control feels right and spreads the useful values over the whole range of movement. Some examples of non-linear parameters and how to identify them are:
Cutoff frequencies or rates in Hz: Exponential. The mid value is much smaller than the maximum value, and the displayed value can be calculated as exp(a + b * slider_position) where a and b are constants and slider_position is from 0.0 to 1.0. See prop_exp.
Envelope times: Exponential, but linear in the bottom 1% of the slider. This allows zero to be reached. See prop_exp.
Volume in dB: Cube-law decibels. The displayed value can be calculated as 20 * log10(slider_position ^ 3) + a. See prop_decibels.
Pre-Delay times, compressor ratios: Square-law. The mid value is one quarter of the maximum, and can be calculated as slider_position ^ 2. See prop_squared.
If you have (for example) a value in seconds or Hertz in the script and want to use it to set a parameter using set_module_param(), then as the parameter is non-linear the script will need to perform a conversion. Sometimes the easiest way to do this is to prepare a lookup table in a spreadsheet and include it as an array in the script. For adjusting volumes set_vol() can be useful as it accepts values in decibels.
Include a Data File module in the instrument to use as a shared array which can be read and written by each script. Declare the array in each script that needs to access it: var Globals["Name Of Data File"].
call trigger_new_event() which triggers on new_event in each script. The event's EVENT_PARAM values can be used to send information with the event, or use it as a notification to update from e.g. a shared array.
For Kontakt users: PGS is available and works the same way as in Kontakt.
Here are some general tips on how to make scripts run as fast as possible:
Use inc(x) and dec(x) rather than x = x + 1.
Try to avoid storing temporary values. e.g. use a = 3 * x + 1 instead of a = 3 * x followed by a = a + 1.
Consider breaking up long if statements. e.g. use if a = b and then if b < 10 rather than if a == b and b > 10 so the second part does not have to be calculated if a does not equal b.
Check the most likely values first in select statements.
if x can be used as a shorthand for if x != 0 and is calculated faster. Another example: while a and not b is shorthand for while a != 0 and b == 0.
Calculations with constant values like 10 * MAX_VEL will be performed in advance, not while executing the script, so there is no advantage to calculating the resulting value yourself.
There is no performance penalty to defining and using functions: function code is always inserted inline wherever the function is called.
Below are a few examples of short scripts, as an introduction to what scripts look like and how they work.
Simple script 1
This script simply displays the text Hello World! on the Status line (below the Script text box in the Instrument Editor.
Any statements between on init and end on are performed immediately when the script is loaded.
on init
print("Hello World!")
end on
Simple script 2
In this script we define a variable x and set it to the value 1. We then append the variable to the text value is and display the combined result as value is 1 on the Status line:
on init
var x = 1
print("value is " & x)
end on
Simple script 3
In this script we define a function that should display the value of the variable x after a mathematical calculation.
Further down in the script we call the print function to display the value of x on the Status line:
function print_x()
print(x)
end function
on init var x
x = 3 * -7 + 100 / 2
print_x() ’should print 29
end on
Note that the text “should print 29” is a comment in the script. Texts after a single quote mark on a line are always comments.
Simple script 4
In this script we define a variable x and set it to the value 1.
We then demonstrate using the conditions if, else and while, and the function inc() to increase the value of x for as long as the while condition is true.
The resulting value x is then displayed on the Status line:
on init
var x = 1
if x > 2
return
else
x = -4 * x + 3
end if
while x < 10
inc(x)
end while
print(x) ’should print 10
end on
Simple script 5
In the previous examples we wanted something to happen when the script started (between on init and end on).
In this example we want something to happen when a MIDI controller value changes, so we put the statements between on controller and end on.
A section of the script starting with on ... and ending with end on is known as a callback. In this script we convert the Mod Wheel data to Sustain Pedal data:
on controller
if EVENT_CC == 1 'convert mod wheel to sustain pedal
set_controller(64, CC[1])
ignore_controller() 'do not change the mod wheel too
end if
end on
Using the Mod Wheel to select which group will play
First in the on note callback, all groups are disabled. Then, only one group is enabled depending on the Mod Wheel position.
Mod Wheel values 0 to 127 are divided by 32 to give values in the range 0 to 3 (you will need an instrument with multiple groups to hear the effect of this script):
on note
group_off(EVENT_ID, ALL_GROUPS)
group_on(EVENT_ID, CC[1] / 32)
print("Playing group " & CC[1] / 32)
end on
In on init we set up an array of values - the number of semitones to transpose each of the 12 notes of the octave:
on init
var interval[12] = (4,4,3,4,3,4,3,4,3,3,4,3)
end on
Then, for each note received in on note we trigger an additional note using the new_note() function. The additional notes are the same as the incoming notes, except transposed according to the array value for that note. (mod 12 is used for converting the MIDI key number to the octave note number 0 to 11):
on note
new_note(EVENT_KEY + interval[EVENT_KEY mod 12], EVENT_VEL, 0, -1)
end on
In on init we declare a variable to store the event ID of the last note that was played, and update that value in on note and on release:
on init
var lastNote = -1 'no event
end on
on note
lastNote = EVENT_ID
end on
on release
lastNote = 0
end on
When the Mod Wheel (CC 1) moves, we adjust the tuning of the last played note. If no note event with that ID is found (i.e. the note was released and has finished playing) then set_tune has no effect:
on controller
if EVENT_CC == 1 and lastNote
set_tune(lastNote, 1575 * CC[1], 0)
end if
end on
Applying random pitch steps to the last played note
While this example could be achieved more simply with an LFO, to produce random pitch steps, it is a good demonstration of how the delay() function can be used.
Each new note first sets the value of lastCallback to the unique ID for that particular callback. Then, until another note arrives and changes the value of lastCallback, the tuning of the note event is adjusted to a random value for every eighth-note (480 ppq).
Why is CALLBACK_ID used instead of EVENT_ID? So this example could be expanded to use the end_delay() function to stop a delay earlier than its scheduled time.
on init
var lastCallback
end on
on note
’changed by each new note
lastCallback = CALLBACK_ID
’random tuning every 8th note
while lastCallback == CALLBACK_ID
delay_ppq(480)
set_tune(EVENT_ID, 100000 * random(-12, 12), 0)
end while
’back to original tuning
set_tune(EVENT_ID, 0, 0)
end on
When a note is played multiple times with the sustain pedal held, voices can stack up so when the pedal is lifted multiple release-triggered samples are played at the same time.
The following script keeps track of the last note played on each key and only enables the release trigger group for that note:
on init
var lastKeyEvent[128]
end on
on note
lastKeyEvent[EVENT_KEY] = EVENT_ID
end on
on release
if lastKeyEvent[EVENT_KEY] != EVENT_ID ’if not last note on key
group_off(EVENT_ID, MyReleaseNoiseGroup) ’switch off group
end if
end on
This example uses the technique of ignoring a note event so it does not trigger any voices, but instead use the on note callback to trigger a sequence of new notes.
An array is used to hold an event ID for each key, which is needed to keep track of the notes that have been triggered and will later need releasing.
on init
'current note event for each key
var id[128]
end on
For as long as the original note event is held, a new note is triggered. Then, after a quarter-note delay (960 ppq) it is released and the while condition repeats to trigger another new note.
This example could be modified to play a specific sequence rather than just repeating the initial note:
on note
'not playing this event, just using it to know how long the key is held
ignore_event(EVENT_ID)
while EVENT_HELD
id[EVENT_KEY] = new_note(EVENT_KEY, EVENT_VEL, 0, 0)
delay_ppq(960)
release_note(id[EVENT_KEY])
end while
end on
This example declares some properties, which appear as user-editable controls in the instrument script module and later as editable parameters of the instrument. prop_linear declares a property that can be adjusted between the specified minimum and maximum values, so for example when the user edits the Key property, the Key variable will be set to a value in the range -12 to 12.
The current property values are applied to each note as it arrives, and for Vol, Pan and Tune, a callback is specified so if the property changes while a note is playing the difference from the old value to the new value is added as a relative offset.
on init
prop_linear Key(-12, 12, 1)
prop_linear Vel(-100, 100, 1)
prop_linear Vol(-20, 20, 1)
prop_linear Pan(-1000, 1000, 1)
prop_linear Tune(-1200, 1200, 1)
var oldVol
var oldPan
var oldTune
end on
on note
set_key(EVENT_ID, EVENT_KEY + Key)
set_vel(EVENT_ID, EVENT_VEL + Vel)
set_vol(EVENT_ID, 1000 * Vol, 0)
set_pan(EVENT_ID, Pan, 0)
set_tune(EVENT_ID, 10 * Tune, 0)
end on
on Vol
set_vol(ALL_EVENTS, 1000 * (Vol - oldVol), 1)
oldVol = Vol
end on
on Pan
set_pan(ALL_EVENTS, Pan - oldPan, 1)
oldPan = Pan
end on
on Tune
set_tune(ALL_EVENTS, 1000 * (Tune - oldTune), 1)
oldTune = Tune
end on
Putting different sets of samples in mappings then selecting which mapping a group should play lets you take full control of articulations and round-robins. This example shows how keyswitches can be scripted to select different mappings. See also EVENT_PARAM_ALT_MAPPING if individual notes need to play different mappings.
'Scripted keyswitches example - switches the mapping played by the first group
on init
const FirstKeyswitch = 48
const LastKeyswitch = 52
set_key_display(FirstKeyswitch, LastKeyswitch, KEY_COLOR_CYAN + KEY_IS_CONTROL)
’also use set_key_name() if targeting NKS or Studio One
var currentKeyswitch = FirstKeyswitch
set_key_selected(currentKeyswitch, 1)
end on
on note
if EVENT_KEY >= FirstKeyswitch and EVENT_KEY <= LastKeyswitch
if currentKeyswitch != EVENT_KEY
’highlight current keyswitch
set_key_selected(currentKeyswitch, 0)
currentKeyswitch = EVENT_KEY
set_key_selected(currentKeyswitch, 1)
When a sample in Recycle, Acid or Apple Loop format is loaded, its original tempo and any transient markers are stored in the Zone the sample is loaded in. An instrument script can access this information to play the individual slices. Ensure the Start Mod Range of the zone is set to the full length of the sample so that playback can start at any startpoint, and use the Group De-Glitch option or scripted fades to avoid clicks.
The following example lists the slice positions and lengths for a zone to the debug window of the editor. See the Sliced Loop scripting examples in the SDK for actual playback.
on init
var zone = -1000000 + 1 'a zone ID (mapping 1, zone 1 in this case) or a prop_waveform
var slice
var slicePos
var sliceLen = 1
while sliceLen ’zero if no more slices
slicePos = zone_slice_start(zone, slice)
sliceLen = zone_slice_length(zone, slice)
print(“Slice “ & slice & “: “ & sliceLen & “us @ “ & slicePos)
inc(slice)
end while
end on
Many effect modules have separate wet and dry levels rather than a wet/dry mix. The following script shows how to create a mix control that applies an equal power crossfade between an effect’s wet and dry outputs:
on init
prop_linear Reverb_Mix(0, 1000, 10)
set_prop_param(Reverb_Mix, PROP_UNITS, "%")
var wet
var dry
end on
on Reverb_Mix ’assumes a Convolution effect in slot 1 of bus 1
wet = Reverb_Mix
WetDryEqualPower()
set_module_param(M_BUS+1, M_EFFECT+1, 0, 7, dry);
set_module_param(M_BUS+1, M_EFFECT+1, 0, 8, wet);
end on
Or for a DJ-style crossfade where both signals are at full volume in the middle:
function DJCrossfade() 'convert wet (0 to 1000) to wet & dry levels
wet = wet - 500
if wet < 0
dry = 1000000
wet = 1000000 - 4 * wet * wet
else
dry = 1000000 - 4 * wet * wet
wet = 1000000
end if
end function
The following script function converts a linearly increasing value to an exponentially increasing value, which may be useful in some calculations:
function pow2()
'converts x to 1000 * 2 ^ (x / 1000)
'so the returned value doubles each time x increases by 1000
temp = x mod 1000
x = (1000 + temp + ((temp - 1000) * temp) / 2980) << (x / 1000)
end function
on init
var x ‘declare the variables used by pow2() function
var temp ’
end on
And a slightly more efficient version using a scaling factor of 1024 instead of 1000:
function pow2()
'converts x to 1024 * 2 ^ (x / 1024)
'so the returned value doubles each time x increases by 1024
temp = x .and. 1023
x = (1024 + temp + ((temp - 1024) * temp) / 3012) << (x >> 10)
end function
Here is an approximation for converting a linearly increasing value to a logarithmically increasing value:
function log2()
'converts x to 1024 * log2(x / 1024)
'so the value increases by 1024 each time x doubles
temp = 0
if x < 1024
if x < 1
return -10240 'too small
end if
while x < 1024
x = x << 1
dec(temp)
end while
else
while x >= 2048
x = x >> 1
inc(temp)
end while
end if
x = (temp << 10) + 3496 - 8642112 / (x + 1448)
end function
Called when the script is loaded, which always happens after the rest of the instrument is loaded. Here you can declare variables and perform any other setup required by the script.
Declare a variable for storing an integer numeric value. All variables used in the script must be declared in on init. Each variable can be a single value or an array containing a series of values, and initial value(s) can be provided.
Alternatively, variables that have a name ending with $, or are initialized with a text string can be used to store text instead of numeric values.
Variable names must start with a letter, and contain only letters, numbers and underscore characters ( _ ). Names of existing script functions, variables or constants cannot be used. It's good practice to start variable names with a lower-case letter.
If initial values are provided for an array but there are not enough values to fill the array, the rest of the array will be set to the last initializer value.
Arrays can only have one dimension so declarations like var xy[10][2] are not allowed. User-defined data structures (and arrays of them) are also not allowed.
An array of numeric values can also be created by specifying the name of a data file module in the instrument instead of a size. The array then directly reads and writes the data in the data file module. If the module is deleted its data is still used by the array until the script is reloaded.
Empty strings have a value of zero in conditional statements. Strings can be compared to other strings using =, !=, etc.
Examples
var x 'create a variable called x, initial value is 0
var y = 1 'create a variable called y, initial value is 1
var z = 0xFF 'create a variable called z, initial value is 255 (FF in hexadecimal)
var a[3] 'create an array that holds 3 values called a[0], a[1], a[2]
var b[4] = (10, 20, 30, 40) 'create an array and set initial values
var c["My Data"] 'create an array that reads and writes to the data in the "My Data" Data File module
var myString$ 'create a variable for storing a text string
var myString = "Hello" 'create a variable for storing text with an intial text string
var myString$[10] 'create an array for storing multiple text strings
var myString[2] = ( "one", "two" ) 'create a variable for storing text with initial text strings
Constant names must start with a letter, and contain only letters, numbers and underscore characters ( _ ). Names of existing script functions, variables or constants cannot be used. It's good practice to make constant names start with an uppercase letter or be all uppercase.
Examples
const MAX_VEL = 127
var velCurve[MAX_VEL + 1]
var i = 0
while i <= MAX_VEL
velCurve[i] = i * i
inc(i)
end while
Print a message to the status line and debug window in Gorilla Editor. On macOS the text is also sent to any attached debugger (including Recon Tools > Inspect device log when running in Recon). On Windows the Microsoft DebugView will receive the text (e.g. via your DAW) if run as administrator.
Limitations The message to be printed must be placed between straight quotes (""). Other types of quotes (""). cannot be used.
The message must be printable as text or a numeric value - so while variables and expressions resulting in a numeric value can be printed, array variables cannot unless an array index is provided to select which value in the array to print.
Examples
print("Hello")
print(3)
print(x) 'prints the current value of the variable x
Print a list of active script events to the debug window in the Instrument Editor. This should only be done while debugging and never in a released product because printing the list may be slow!
&
Joins two text strings or numeric values (or expressions that evaluate to a numeric value) to create a single text string. Useful for the print() function.
Examples
on init
var x = 3
print("Value of x is " & x)
end on
on note
print(“Key “ & EVENT_KEY & “, velocity “ & EVENT_VEL)
end on
Declare a user-defined function. Must be declared outside any callback and before the function is used. Then wherever the function name is placed in the script, the code in the function will be executed. Using functions does not make the script execution slower so feel free to use them instead of repeating the same code in multiple locations in the script.
Limitations
Function names must start with a letter, and contain only letters, numbers and underscore characters ( _ ). By convention function names are followed by parentheses () to make it obvious they are functions but they are not required.
Example
function PrintNoteInfo()
print("Key " & EVENT_KEY & " held = " & EVENT_HELD)
end function
Ends a statement so another statement can start on the same line.
Example
on Button1; buttons[1] = Button1; end if 'only do this if it makes the code easier to read!
on Button2; buttons[2] = Button2; end if
on Button3; buttons[3] = Button3; end if
Equals (assignment, unless used in a conditional statement - see ==).
Limitations
Has no effect if the value (or result of an expression) on the right of the equals sign cannot be assigned to the variable on the left. For example when it's the name of an array without specifying the array index in square brackets.
Example
x = 10 'set x to 10
x = y 'set x to the value of variable y
x = a[0] 'set x to the first value in array a
a[1] = x 'set the second value in array a to the value of variable x
Some calculations are hard to do with only integer values so Gorilla Script has limited support for floating-point numbers. One-line calculations can be made and the resulting value printed or converted back to an integer. It is currently not possible to have floating-point variables or arrays. In addition to standard mathematical operators and functions (+, -, *, /, sin, cos, tan, acos, asin, atan, ceil, round, floor, exp, log, pow, sqrt) the following functions can be used:
If the expression evaluates to a non-zero value, execute the following code, else jump to the next line with “else if”, “else”, or “end if” and continue executing code from there.
Examples
if x 'if x is any value except zero
x = 1 'set x to 1
end if
if x == 1 and abs(y) >= 10
print “success”
else
print “failure”
end if
if x < 3
print “too small”
else if x > 6
print “too big”
else
print “just right”
end if
select <expression> … case <value> [to <value>] … end select
Execute the following code repeatedly, so long as the expression evaluates to a non-zero value. ‘if’ loops found in other programming languages are not supported but it is always possible to implement an equivalent ‘while’ loop.
Example
while(x < 10)
inc(x) 'keep doing this while x is less than 10
end while
These statements can be used to enable or disable parts of a script depending on the Script Defines parameter of the Instrument module, which can contain multiple words separated by spaces or commas. For example the following code only prints something if the Script Defines include the word DEBUG:
USE_CODE_IF(DEBUG)
print("print some debugging text")
END_USE_CODE
Changes to the Script Defines are only applied when the script or the whole instrument is reloaded.
Declare a Boolean property (the value can be either 0 or 1 - usually used as a switch). The default value is 0 but optionally an initial value can be set.
The same rules for variable names apply to property names (as properties are just variables with some extra attributes). In addition, property names should not be longer than 32 characters and must not be the same as any existing name or symbol (including names in the same scope in motherboard_def.lua for Rack Extensions). For display to the user, underscores in property names are automatically replaced with spaces - to avoid this use PROP_NAME to set a specific display name. For access from the plugin UI underscores are kept but all uppercase characters are converted to lowercase. For example a property called LFO_Rate is displayed as "LFO Rate" but accessed from the UI as instrument.lfo_rate.
Declare a property with an exponential display - useful for times, rates and frequencies.
The property value seen in the script varies linearly between 0 and max (the default value is 0 but optionally an initial value can be set).
The value displayed to the user ranges from displayMin/1000 to displayMax/1000 with an exponential scale (the midpoint between 10 and 1000 on an exponential scale is 100).
Arguments
max
The value received by the script when the property is at its maximum value.
displayMin
1000 times the value displayed to the user when the property is at zero. If negative, the value displayed will be 0 when the property is at zero, and -displayMin/1000 when the property is at 1% of its range.
displayMax
1000 times the value displayed to the user when the property is at its maximum value.
prop_exp Cutoff(1000000, 20000, 25000000) = 549000 'cutoff from 20 Hz to 25 kHz, default 1 kHz
prop_exp Rate(1000000, 10, 100000) = 500000 'rate from 0.01 to 100 Hz, defaulting to 1 Hz
prop_exp Decay(1000000, -10, 16000) 'decay time from 0.0 to 16.0 sec, with 10 ms at 1%
Declare a property with linear scaling between a specified minimum and maximum value. This is the most commonly used type of property as it's good for knobs and sliders. The default value is 0 (or the minimum value if the range does not include 0) but optionally an initial value can be set.
The displayed value is the property value divided by scaling. In this way the number of decimal places to be displayed to the user can be controlled, even though the property value itself is always an integer between min and max.
Examples
prop_linear Mix(0, 100, 1) = 50 'display range 0 to 100
prop_linear Mix(0, 1000, 10) = 500 'display range 0.0 to 100.0
prop_linear Tune(-1200, 1200, 100) 'display range -12.00 to 12.00
Declare a property for displaying a value measured in realtime in a module. Values that can displayed are audio level in an Effect Bus, Pan or Send effect; gain reduction in a Compressor, Limiter or Gate effect, and playback position in a Group, Sample Oscillator or Wavetable Oscillator. A prop_meter can be attached to a AudioMeter effect to display accurate peak level, stereo correlation, or a 10-band spectrum.
Gain reduction meters are linear between 0 dB and inf, with 6 dB at the midpoint.
If an array size of N is added after the property name (see example below) the meter will display separate levels for up to N audio channels (if available). If the property is not declared as an array the meter will show a single value measured from all channels.
To meter the level of a bus that should not be heard such as a sidechain, route the bus output to its own input.
If a 2-channel meter is attached to a sample Oscillator, the first channel shows the current playback position and the second channel shows the Sample Pos parameter value including any modulation.
Limitations
It is not possible to attach more than one meter to the same module.
Examples
'level meter at output of first effect bus
prop_meter Level; attach_meter(Level, M_BUS+1, 0)
’stereo level meter at output of third effect bus
prop_meter Level[2]; attach_meter(Level, M_BUS+3, 0)
’level or gain reduction meter (as applicable) for first effect in first effect bus
prop_meter GR; attach_meter(GR, M_BUS+1, M_EFFECT+1)
’playback position meter for first group
prop_meter Pos; attach_meter(Pos, M_GROUP+0, 0)
Declare a property with a square-law display - useful for some delay times and compressor ratios.
The property value seen in the script varies linearly between min and max (the default value is 0 but optionally an initial value can be set).
The value displayed to the user ranges from displayMin to displayMax, proportional to the square of the property value (the midpoint between 0 and 100 on a square-law scale is 25).
prop_squared Delay(0, 1000000, 0, 25) 'delay from 0.0 to 25.0 ms
prop_squared Ratio(0, 1000000, 1, 20) 'ratio from 1.0 to 20.0
prop_squared Bipolar(-1000, 1000, -100, 100) '-100 to 100 with more resolution in the middle
Declare a property with a number of discrete values that are created by calling add_step(). The default value is 0 but optionally an initial value can be set.
Declare a property for displaying or editing a text string. This can be useful for allowing the user to name an item on the GUI and storing the name with the patch.
When waveform overview data is not available (when not enabled in the instrument, or not yet calculated) the sample name is displayed instead of the waveform.
Arguments
group
The index of the group that automatically updates the display whenever the latest sample played in the group changes, or -1 if you only want the waveform to change when set_waveform() is called.
Examples
prop_waveform Wave_Display
set_waveform(Wave_Display, -1, 60, 100) 'show waveform at key 60 vel 100 in the first mapping
Declare a property for controlling an array of values. The default value is 0 (or the minimum value if the range does not include 0) but optionally initial values can be set.
Array properties can not be automated in plug-in hosts - instead you must expose every individual value as a separate property.
Arguments
size
Number of values to store in the array.
min
Minimum value.
max
Maximum value.
scaling
The displayed value is the property value divided by scaling.
Example
prop_array Velocity_Curve[128](1, 127, 1) 'array of 128 values with range 1 to 127
prop_array Pitch_Sequence[16](-1200, 1200, 100) '16 values with range -12.00 and +12.00
For PROP_MIDI_CC the value should be in the range 1 to 119 (or up to 239 for Rack Extensions but not including the following values: 0, 1, 2, 3, 6, 9, 11, 32, 38, 64, 96-101, 120-127).
For PROP_METER_HISTORY the value is the number of history points to display for a meter (Rack Extensions only).
For PROP_SET_BY, the default value is SET_BY_HOST + SET_BY_SONG + SET_BY_PATCH +
SET_BY_REMOTE_AUTO, and the property value is received by the script when it is changed by one of those sources. SET_BY_REMOTE_AUTO means that the property can be remote controlled and automated. This is not allowed for
properties connected to the back panel of a Rack Extension. Other valid combinations are:
SET_BY_HOST + SET_BY_SONG (with or without SET_BY_REMOTE_AUTO): As above but the value is not stored in patches so it does not change when a patch is loaded.
SET_BY_HOST (with or without SET_BY_REMOTE_AUTO): As above but the value is not stored in patches or songs so reverts to the default value when a song is loaded.
SET_BY_SCRIPT: When the script changes the property value, the value can be displayed on the GUI (maps to rt_owner in Rack Extensions).
SET_BY_GUI: The property value can be set by GUI controls but the script does not receive the new value (maps to gui_owner in Rack Extensions).
SET_BY_GUI + SET_BY_SONG: As above, and the value is also saved and recalled with the song.
SET_BY_GUI + SET_BY_SONG + SET_BY_PATCH: As above, and the value is also saved and recalled with patches.
Examples
'assign CC7 to this property
set_prop_param(Volume, PROP_MIDI_CC, 7)
’this is a display, not user editable
set_prop_param(My_Display, PROP_SET_BY, SET_BY_SCRIPT)
’do not change when loading patches
set_prop_param(Latch, PROP_SET_BY, SET_BY_HOST + SET_BY_SONG + SET_BY_REMOTE_AUTO)
’not available for automation
const NOT_AUTOMATED = SET_BY_HOST + SET_BY_SONG + SET_BY_PATCH
set_prop_param(Mode, PROP_SET_BY, NOT_AUTOMATED)
Set the waveform to be displayed in a prop_waveform. The waveform is selected by specifying the group (or mapping), key and velocity. If more than one zone is found at that location the first is used. If no zones are found the waveform display is cleared.
Arguments
property
The prop_waveform to update.
group
The group to search for a waveform. Use negative values to search in a Mapping instead.
key
The MIDI key number to search at in the group or mapping.
vel
The velocity to search at in the group or mapping.
Use with set_prop_param(). Set to 1 for properties that should not be called from the audio thread because they take a long time to complete or set a parameter in a custom module that is not thread-safe or realtime-safe.
Limitations
Do not make a non-realtime property automatable because value changes may then arrive from the realtime thread of the host.
The script code can call set_controller(), set_controller_hd(), set_module_param() and pgs_set_key_val() but must not use other script functions, or modify variables that may be being used simultaneously by other script callbacks.
Use with set_prop_param() to set the units suffix to be displayed after the parameter value.
Set the units to "L|R" to create a pan control that displays either L after the value when it is negative and R when it is positive (does not work for Rack Extensions). Other text can be used e.g. "Front|Rear".
Use with set_prop_param() to replace the normal value and units display of a property with your own custom text. Must be called in 'on init' to override the initial value display otherwise later calls will have no effect. Does not work for Rack Extensions.
The property value can be set from outside the script, and the new value is received by the script. Can be combined with SET_BY_PATCH, SET_BY_SONG and SET_BY_REMOTE_AUTO.
Use with set_prop_param(...PROP_SET_BY...).
The property value can be set by the script and displayed on the GUI. Do not combine with any other SET_BY values except in two special cases: Meta parameters in AU plugins that may change or be changed by other parameters, and Rack Extension displays that should preserve their value when a different instrument blob is loaded.
The property value can be set by controls on the GUI, but the script does not receive the new value. Can be combined with SET_BY_PATCH, SET_BY_SONG and SET_BY_REMOTE_AUTO.
Set a parameter in one of the modules in the instrument.
If you touch a module parameter in the Instrument Editor then copy (Ctrl/Cmd + C) while holding Shift, a set_module_param() command to set the parameter to its current value will be copied to the clipboard. This can save a lot of time working out the correct argument values.
Arguments
module
One of the following...
M_INST (the instrument module).
M_GROUP plus the group (counting from 0).
M_VGROUP plus the voice group (0 for the "Instrument Voices" group).
M_BUS plus the effect bus (counting from 1).
M_MAPPING plus the mapping (counting from 1).
M_MIDI plus the MIDI file number (counting from 1).
M_DATA plus the data file number (counting from 1).
M_SCRIPT plus the script number (counting from 1).
subModule
One of the following...
0 (none)
M_COND plus the trigger condition (counting from 1) in the specified group.
M_MOD_SRC plus the modulation source (counting from 1) in the specified group.
M_FILTER plus the filter/effect slot (counting from 1) in the specified group.
M_ZONE plus the zone (counting from 1) in the specified group.
M_EFFECT plus the effect slot (counting from 1) in the specified bus.
modRouting
One of the following...
0 (none)
M_MOD plus the mod routing (counting from 1) in the specified module or submodule.
1024 * paramIndex + moduleIndex, for accessing child modules in general (not just mod routings) where paramIndex is the index of the parameter in the specified module/submodule that holds a list of modules, and moduleIndex is the module in that list (counting from 1).
param
Parameter index (usually in the order shown in the Instrument Editor module display, starting with 1).
value
For parameters with stepped integer values, specify the exact value.
For continuous parameters displayed as sliders in the editor, specify a value from 0 to 1000000 (see Parameter display scaling).
For draggable floating point values, specify a value 1000 times the actual value (so a value of 1234 sets the parameter to 1.234).
If the parameter is an array of values (e.g. the curve of a Mod Routing module) and the value is also an array, then as many values as are available in either array will be set.
Limitations
If a module or parameter that does not exist is specified, the call has no effect.
If the value is outside the range of allowed values for the specified module parameter, it is clipped to the minimum or maximum of the range as appropriate.
Setting zone zone parameters in the range "Start" to "Loop End" may have no immediate effect as this requires re-buffering of loaded audio.
Setting invalid array data to some destinations (especially Custom Envelope curves) may lead to malfunctions. Make sure you only set values that were previously copied from the same parameter, or that values being set are in a valid range.
Examples
'set parameter 2 in instrument
set_module_param(M_INST, 0, 0, 2, x)
’set parameter 2 of group 0 (groups are counted from 0)
set_module_param(M_GROUP+0, 0, 0, 2, x)
’set parameter 2 of trigger condition 1 of group 0
set_module_param(M_GROUP+0, M_COND+1, 0, 2, x)
’set parameter 2 of mod source 1 of group 0
set_module_param(M_GROUP+0, M_MOD_SRC+1, 0, 2, x)
’set parameter 2 of mod routing 3 in mod source 1 of group 0
set_module_param(M_GROUP+0, M_MOD_SRC+1, M_MOD+3, 2, x)
’set parameter 2 of filter/effect 1 of group 0
set_module_param(M_GROUP+0, M_FILTER+1, 0, 2, x)
’set parameter 2 of mod routing 3 in filter/effect 1 of group 0
set_module_param(M_GROUP+0, M_FILTER+1, M_MOD+3, 2, x)
’set parameter 2 of mod routing 1 in group 0
set_module_param(M_GROUP+0, 0, M_MOD+1, 2, x)
’set parameter 2 of zone 3 in mapping 1
set_module_param(M_MAPPING+1, M_ZONE+3, 0, 2, x)
’set parameter 2 of bus 1
set_module_param(M_BUS+1, 0, 0, 2, x)
’set parameter 2 of effect 3 in bus 1
set_module_param(M_BUS+1, M_EFFECT+3, 0, 2, x)
’set bypass parameter of first script
set_module_param(M_SCRIPT+1, 0, 0, 1, x)
’fill the curve parameter of mod routing 1 in group 0 from myArray[1000] onwards
set_module_param(M_GROUP+0, 0, M_MOD+1, 9, myArray[1000])
Sets all the parameters of a module in the instrument to values from an array.
This function works the same way as set_module_param(), but the last argument is an array containing the parameter values to be set. The first value in the array is the number of values, and usually the array values are obtained by calling get_module_params(), possibly in combination with save_array() to save the values permanently in the instrument.
The function returns the number of values that were actually set, so is zero if the specified module does not exist.
Find the index of a parameter in the specified module by searching for the parameter name.
This function works the same way as set_module_param(), but the last argument is the name of the parameter to find (case sensitive). For efficiency, call one time in 'on init' and store the result rather than calling repeatedly.
The function returns the parameter index, or -1 if the specified module was not found or if no parameter was found with the specified name. Note that parameters of built-in modules will keep the same index in future versions, but that may not be true for third party custom modules.
Read the name of a parameter in one of the modules of the instrument.
This function works similarly to set_module_param(), but instead of returning the parameter index of a given parameter name, it returns the parameter name at a given index.
The function returns the parameter name as a string, or an empty string which evaluates to zero if the specified module or parameter was not found.
Limitations
Reading the names of parameters in the current or following script may not work in on init as those parameters are still being created at that time.
Read the value of a parameter in one of the modules of the instrument.
This function works the same way as set_module_param(), but the last argument is a variable that receives the value that was read. If the variable is a string then the display text for the parameter's value is written instead of the numeric value. If the variable is an array and the parameter is an array (such as the curve of a Mod Routing, Shaper or module) the parameter's values are read into the array starting at the specified index.
The function returns the number of values read (so is zero if reading fails, for example if the specified module or parameter does not exist.
Read all the parameter values from a module in the instrument (not including child modules such as mod routings).
This function works the same way as get_module_param(), but the last argument is an array that is filled with the parameter values that were read. The first value in the array is the number of values so if a later version of the module has more parameters added these will not be set.
The function returns the number of values read (so is zero if reading fails, for example if the specified module does not exist.
Set in which order the effects in a bus are applied. Note the indexes of the effects in the bus do not change, just the order they are rendered.
Arguments
effectBus
Which bus to set the effect order for (counting from 1).
effectIndexes
An array of effect indexes, for example (3,2,1) to reverse the order of the first three effects in the bus. Effects that are included more than one position in the array are only rendered in the first position. Effects in the bus that are not included in the array are rendered after the ones that are included, in their order as shown in the bus.
Example
on init
var orders[18] = ( 1,2,3, 1,3,2, 2,1,3, 2,3,1, 3,1,2, 3,2,1 )
prop_stepped Order
add_step(Order, "123")
add_step(Order, "132")
add_step(Order, "213")
add_step(Order, "231")
add_step(Order, "312")
add_step(Order, "321")
end on
on Order
‘optionally bypass or mute effects here, wait a short time and unmute them afterwards…
’ orderCallback = CALLBACK_ID
’ delay(100000) ‘wait for bypass to fade in
’ if orderCallback != CALLBACK_ID ‘order changed again while we were in the delay?
’ return
’ end if
set_effect_order(1, orders[3 * Order]) ’first bus: choose from array of possible orders
end on
Set the destination of a mod routing in a group module to any mod dest in the group including mod sources and per-voice filters/effects. This enables a “mod matrix” to be scripted without inserting mod routings at every possible destination.
Arguments
group
The group to find the mod routing in (counting from 0).
modRouting
Which mod routing in the group to edit (counting from 1, not including routings in submodules in the group).
subModule
One of the following...
M_GROUP (the destination is in the group module itself).
M_MOD_SRC plus the mod source (counting from 1) in the group.
M_FILTER plus the per-voice filter/effect (counting from 1) in the group.
dest
The destination in the selected group or submodule (couting from 1, in the same order as displayed in the Dest parameter of a mod routing in that module).
ampMod
Set to 0 if the mod source should offset the destination parameter. Set to 1 if the mod source should scale the destination parameter (normally used for volume/level parameters).
Limitations
Using the wrong ampMod setting for a destination may give unexpected/unwanted results. One reason to use the wrong setting is if a LFO should modulate a volume above and below its parameter setting, instead of just attenuating.
Examples
’set first routing in first group to no destination
set_mod_dest(0, 1, M_GROUP, 0, 0)
’set first routing in first group to third mod destination (Tune) of group
set_mod_dest(0, 1, M_GROUP, 3, 0)
’set 1st routing in 1st group to 1st mod destination (Volume) of group, in amp mod mode
set_mod_dest(0, 1, M_GROUP, 1, 1)
’set 1st routing in 1st group to the 1st mod destination (Intensity) of 1st mod source
set_mod_dest(0, 1, M_MOD_SRC+1, 1, 0)
’set 1st routing in 1st group to 2nd mod destination (e.g. Resonance) in 1st filter/effect
set_mod_dest(0, 1, M_FILTER+1, 2, 0)
Reset envelopes or LFOs or copy their current state from one note event to another, to allow analog-style triggering.
Arguments
destID
The event with voices that should get their mod sources reset.
sourceID
The event to copy mod source states from, or 0 to just retrigger from the start.
mask
Bit mask of which mod sources in the group should be affected (1=first, 2=second, 4=third, etc.)
retrig
Set to 0 if the mod sources should continue from their current time position rather than going back to the start.
Limitations
Applies to all voices played by the specified event IDs. Note that voices do not start playing until on note has returned or called a delay function.
Example
on init
var prevEvent
end on
on note
delay(1) ’wait for this event’s voice(s) to start playing
set_mod_sources(EVENT_ID, prevEvent, 9, 1) ’copy mod sources 1 and 4 from previous event
prevEvent = EVENT_ID
while EVENT_HELD
delay_ppq(960) ’then every quarternote
set_mod_sources(EVENT_ID, 0, 255, 1) ’retrigger mod sources 1-8
end while
end on
Allows paths on disk to be resolved when running as a plugin. Paths can be associated with an ID using the Javascript SetContentPackMapping() function.
Returns the path associated with the provided identifier or an empty string if the identifier is not found or when running in Gorilla Editor.
Returns the length of the sample in the specified zone (measured in microseconds) or zero if no sample is found.
Arguments
zone
prop_waveform property that is currently displaying the zone, or 1000000 * groupIndex + zoneIndex (where groupIndex counts from zero or is negative for mapping indexes, and zoneIndex counts from 1).
Returns the Slice Length parameter in the specified sample zone.
Slice Length is a length in beats of the whole sample, which is set when importing an audio file containing Recycle, Acid or Apple Loop information and can also be set manually in each zone.
The function returns the slice length value converted to microseconds at the current tempo, or -1 if the specified group or zone does not exist.
Arguments
group
Which group the sample zone is in (counting from 0). Use negative values to access Mappings instead of Groups.
Which slice to get the position of, counting from 0. When index equals the number of slices a negative value giving the total length of the sample is returned.
Returns the length of the specified slice in microseconds at the current tempo, or 0 if there are not that many slices in the sample or the zone was not found.
When using set_module_param() to modify the Source parameter of a Mod Routing, FIRST_GROUP_MOD_SOURCE is the index of the first mod source specific to that Group (i.e. an envelope or LFO). Use of this constant allows your script to stay future-proof if more non-group mod sources are added in a later version, as they will be added before the Group mod sources.
Use as the module argument to set_module_param() and get_module_param() to access Voice Group parameters. Note that the maximum polyphony of the Instrument Voices module (M_VGROUP + 0) cannot be increased beyond the value that has been set manually.
Ignore the received MIDI controller change - do not update the value for this controller that is seen by modulation routings and trigger conditions in the instrument.
Example
on controller
if EVENT_CC == 1 'modwheel
ignore_controller()
end if
end on
Set a MIDI controller value with high resolution. The resulting value will be seen by modulation routings and trigger conditions in the instrument.
Arguments
channel
MIDI Channel. Normally set to EVENT_CHAN.
cc
Controller number 0 to 127.
value
Value (will be multiplied by 127.0/maxValue to create a high resolution value.
max
The nominal maximum value (would be 127 for normal MIDI CC messages, but can be much higher to increase resolution).
Examples
set_controller(EVENT_CHAN, 99, 1000000, 1000000) 'set CC99 to high resolution value 127.0
set_controller(EVENT_CHAN, 99, 12700, 12700) 'also sets CC99 to high resolution value 127.0
set_controller(EVENT_CHAN, 99, 500000, 1000000) 'set CC99 to high resolution value 63.5
set_controller(EVENT_CHAN, 99, -500000, 1000000) 'set CC99 to high resolution value -63.5
set_controller(EVENT_CHAN, 99, 2000000, 1000000) 'set CC99 to high resolution value 254.0
If on controller is called with an EVENT_CC value greater of equal to CC_FIRST_CV, CC[EVENT_CC] is a new value received from CV socket (EVENT_CC - CC_FIRST_CV).
If set_controller() is called with a cc value greater or equal to CC_FIRST_CV it sends the specified value to CV socket number (EVENT_CC - CC_FIRST_CV). Sending a value greater than zero followed immediately by a value of zero outputs a short trigger pulse from the CV socket.
Called when a note event starts (e.g. when a MIDI key is pressed).
As soon as on note returns (or a delay function is called within on note) any voices due to start because of the note event or calls to new_note() will start playing. This gives the script a chance to modify those notes before they start, for example with group_off() or set_event_param().
Example
on note
print("key " & EVENT_KEY & ", velocity " & EVENT_VEL)
end on
Read-only array of values indicating which notes of the octave are currently held. KEY_DOWN_OCT[0] returns 1 if any C note (that is not set to KEY_IS_CONTROL) is held, or 0 if not held.
Trigger a new note event with a specified key, velocity, sample start position and length/duration.
This function returns the event ID of the new note, which may be needed to adjust and eventually release the note.
Arguments
key
The key (note number) to play, in the range 0 to 127.
vel
The velocity to play, in the range 1 to 127.
start
Sample start position offset in microseconds (limited to within the Start Mod Range of the Zone).
length
The note length in microseconds, or zero to continue until release_note() is called, or -1 to continue until the parent note (that triggered the callback this note was triggered in) is released, or -2 to play one-shot (skipping envelope sustain stages and automatically releasing when the amp envelope or sample being played has ended).
Send a MIDI event to the plugin output (if the plugin has a MIDI out).
Arguments
status
Status byte, optionally including channel.
data1
Data byte 1, for example key or CC number.
data2
Data byte 2, for example velocity or CC value.
Example
on note
send_midi_out(MIDI_COMMAND_NOTE_ON + EVENT_CHAN, EVENT_KEY, EVENT_VEL)
end on
on release
send_midi_out(MIDI_COMMAND_NOTE_OFF + EVENT_CHAN, EVENT_KEY, EVENT_RELEASE_VEL)
end on
on controller
if EVENT_CC < 120 ’only forwarding performance controllers
send_midi_out(MIDI_COMMAND_CC + EVENT_CHAN, EVENT_CC, CC[EVENT_CC])
end if
end on
Create a new event, for example when you want to play a sequence that doesn’t stop when the note that triggered it is released, or to start a timer without delaying the following code in the current call. Returns the ID of the new event which on new_event will be called with after the current call returns or enters a delay.
Example
on note
id = trigger_new_event()
print("triggered new event " & id)
end on
on new_event
print(“handle new event “ & EVENT_ID)
end on
Returns 1 if the specified note event has voices still sounding, or 0 if it is silent.
Arguments
event
The event ID.
Limitations
Returns 0 if the event is not an active note event, or was triggered earlier in the same callback (without a delay inbetween) so has not started playing yet. Must be a specific event, not ALL_EVENTS or tagged_events().
Example
on init
var lastNote
end on
on note
if voices_playing(lastNote)
ignore_event(EVENT_ID) ’don’t play if previous note is still playing
else
lastNote = EVENT_ID
end if
end on
A unique identifier for each event. Set before the associated callback (on note, on controller, etc.) is called, or returned by new_note(), which creates a new note event.
Fade in all the voices triggered by an event. Normally called in on note before the event starts playing, but can also be called later if the event has been faded out.
Arguments
event
The event to fade in.
microsec
The length of the fade in, in 1/1000000ths of a second.
Limitations
Negative microsec values are treated as 0.
Example
on note
fade_in(EVENT_ID, 1000000) 'all notes have a 1 second fade in
end on
The length of the fade out, in 1/1000000ths of a second.
stop
0 = continue playing silently after the fade, 1 = stop all voices at the end of the fade (this saves some CPU load and polyphony if the voices will not need to fade in again later).
Limitations
Negative microsec values are treated as 0.
Example
on note
fade_out(EVENT_ID, 1000000, 1) 'all notes have a 1 second fade out then stop
end on
Fade out and stop the voice (or voices) triggered by an event after the sample position has advanced by the specified time in microseconds. This is useful if you want to play to a specific point in the sample, but the pitch may be modulated so you don’t know how long it will take to get to that point.
Arguments
event
The event to fade out. Must be a single event, not ALL_EVENTS or a TAG value.
delay_usec
What length of the sample to play, in 1/1000000ths of a second, before the fade starts.
fade_usec
The length of the fade out, in 1/1000000ths of a second.
Read-only value of the MIDI channel that triggered the event. For Rack Extensions the channel is 0 for normal notes and 1 for notes triggered by CV/Gate. Only applies to events that are a result of MIDI input.
Read-only value of the status of the MIDI key that triggered the event. 1 = still held, 0 = was released. Updated before on note and on release are called.
Fills the provided array with the event IDs of currently playing note events. Returns the number of events, and writes a zero to the array after the last event ID.
Argument
array
The array to fill with event IDs.
Limitations
Not all event IDs are written if the array is too small.
Returns the tag(s) that an event has been marked with using tag_events(). If more than one tag has been set the resulting value is the sum of all the tags.
Arguments
event
The event to get the parameter value for.
Limitations
Returns 0 if event is not a currently playing event.
Must be a specific event, not ALL_EVENTS or tagged_events().
Example
on release
if get_event_tags(EVENT_ID) == TAG_1
'do something if only tag 1 is set
else if get_event_tags(EVENT_ID) .and. TAG_3
'do something if tag 3 (and maybe other tags) are set
end if
end on
Use with set_event_param() for storing a custom value with a note event, which can be read by the script at a later point with get_event_param(), or can be used as a mod source in mod routings within the instrument. It can also be written to by an Envelope Follower module within a Group so the current audio level of a voice can be read by the script. If more than one envelope follower writes to the same event parameter, only the last value written is kept.
Use with set_event_param() to specify which Mapping module each Group triggered by the event should play.
The value is added to the Group’s Alternate Mapping value.
Limitations
Has no effect if modified after voices triggered by the event have started playing (Events start playing as soon as the script code returns or enters a delay).
Example
on init
prop_stepped Mapping
add_step(Mapping, "1")
add_step(Mapping, "2")
add_step(Mapping, "3")
add_step(Mapping, "4")
end on
on note
’add an offset to the Group Alternate Mapping parameter
set_event_param(EVENT_ID, EVENT_PARAM_ALT_MAPPING, Mapping)
end on
Use with set_event_param() to set a delay in microseconds before voices start to play after they have been triggered. This can be useful for randomizing or “strumming” the timing of notes without having to add small delays in the instrument script. During the delay the voice is using polyphony but modulation and audio rendering is paused.
Use with get_event_param() to read the current sample playback position in microseconds. If an event is playing more than one sample, the position in the first sample is returned. Returns -1 if no samples are playing, or the note has just been triggered and no samples started playing yet.
Use with get_event_param() to reverse sample playback by setting the value to 1. If an event triggers more than one sample, all samples will be reversed. Samples that are already reversed in their Zone settings will play forwards.
Limitations
Has no effect if modified after voices triggered by the event have started playing (Events start playing as soon as the script code returns or enters a delay). Playback is only possible from regions of the sample that are preloaded in memory. Set the Start Mod Range in each Zone to the full sample length to allow playback from any point in a sample.
Use with get_event_param(). Returns -1 if the event was triggered by external input, 0 if it was created by the first instrument script, 1 for the second instrument script, and so on. Can be useful if you want to handle the release of incoming MIDI notes differently to the release of notes triggered by new_note().
Use with set_event_param() to specify a sample start position offset in microseconds for all voices triggered by
the event (up to a maximum set by the Start Mod Range parameter in each zone).
Limitations
Has no effect if modified after voices triggered by the event have started playing (Events start playing as soon as the script code returns or enters a delay).
Use with the following functions in place of a specific event ID to apply the function to all currently playing events: release_note(), set_key(), set_vel(), set_tune(), set_pan(), set_vol(), fade_in(), fade_out(), set_event_param(), group_on(), group_off().
Mark an event so that groups of events with the same tag can be modified together.
Arguments
event
The event to tag.
tags
The tag(s) to apply. Must be a combination of TAG_1, TAG_2, TAG_3 ... TAG_16 (TAG values can be combined by addition, or with the .or. operator, e.g. TAG_1 + TAG_2 is equivalent to TAG_1 .or. TAG_2).
Limitations
Must be a specific event, not ALL_EVENTS or tagged_events().
Example
on note
if EVENT_KEY < 60
tag_event(EVENT_ID, TAG_1) 'tag any notes below middle C
end if
end on
The tag(s) to remove. Must be a combination of TAG_1, TAG_2, TAG_3 ... TAG_16 (TAG values can be combined by addition, or with the .or. operator, e.g. TAG_1 + TAG_2 is equivalent to TAG_1 .or. TAG_2).
Limitations
Must be a specific event, not ALL_EVENTS or tagged_events().
Example
untag_event(event, TAG_1 + TAG_2 + TAG_2 + TAG_4) 'remove the first 4 tags if set
Use with the following functions in place of a specific event ID, to apply the function to all active events with the specified tag(s):
release_note(), set_key(), set_vel(), set_tune(), set_pan(), set_vol(), fade_in(), fade_out(), set_event_param(), group_on(), group_off().
If more than one tag is specified, events with any of those tags are affected.
Arguments
tags
The tag(s) to find matching events for.
Example
on controller
if EVENT_CC == 1
set_pan(tagged_events(TAG_1), 8 * CC[1]) 'modwheel pans events tagged with TAG_1
end if
end on
Disable a group from being triggered by the current event.
Note events created with new_note() inherit the group on/off settings of the note event that triggered the current callback.
Arguments
event
The triggering event.
group
The group to disable (group number, counting from 0), or ALL_GROUPS.
Limitations
Has no effect if event is not a currently playing event, or the specified group does not exist. Has no effect if called after an event has started playing (Events start playing as soon as the script code returns or enters a delay).
Example
on note
group_off(EVENT_ID, ALL_GROUPS)
group_on(EVENT_ID, CC[1]/32) 'play only group 0,1,2 or 3 depending on modwheel position
end on
Enable a group to be triggered by the current event (initially all groups can be triggered, so group_on() only has an effect after a call to group_off().
Arguments
event
The triggering event.
group
The group to enable (group number, counting from 0), or ALL_GROUPS.
Returns the index of the Group module with the specified name, or -1 if no Group with that name was found. For best performance call this function in on init and store the result in a variable for later use.
Returns the index of the Mapping module with the specified name, or zero if no Mapping with that name was found. For best performance call this function in on init and store the result in a variable for later use.
Returns a zone identifier that can be used as an argument to functions such as num_slices_zone(). The name must exactly match the sample path and filename shown in the zone. Call this function in on init and store the result in a variable for later use.
0 if the samples should be unloaded, 1 if they should be loaded.
Using ALL_GROUPS does not affect the purge settings of individual groups but instead unloads all samples in the instrument. Samples that are then triggered will load and play, unless they are in an individually purged group or inactive mapping. Use purge_group(ALL_GROUPS, -1) to reset the list of samples that have been played and unload them all again. Using purge_group(ALL_GROUPS, 1) resets the list and loads all samples that are not in purged groups or inactive mappings.
Limitations
For Rack Extensions, all samples in the same .blob file are loaded together in memory so this function will not reduce memory usage. It is however possible to split each mapping into a separate .blob file to be loaded and unloaded independently.
Report audio latency to the host application. Some GE effects (currently only Pitch Shift) must delay the audio signal to apply their processing, but because audio routing is flexible and some delays can be ignored (for example before a 100% wet reverb) the total delay of a network of effect cannot be calculated automatically. Instead your script should calculate the value and report it using this function. For more information see examples/Script Examples/Latency.inst.
Limitations
Has no effect in Rack Extensions. Instead set the dsp_latency value of each audio output in realtime_controller (e.g. in response to property value changes that can affect the latency).
Arguments
sampleFrames
sum of values collected fron the hidden Latency parameter of relevant effects.
Delay execution of the current callback by an approximate time in milliseconds. This is more CPU efficient than delay() and delat_ppq() because the delay won’t end in the middle of an audio buffer, so use when the delay time only has to be accurate to the nearest one or two milliseconds.
Arguments
msec
Time in 1/1000ths of a second.
Limitations
usec values less than 0 will be treated as 0.
Stops the current delay in the specified callback. Script execution continues in that callback from the next statement after the delay.
Arguments
callbackID
The callback (a value taken from CALLBACK_ID).
andFutureDelays
If non-zero, any delay or delay_ppq calls in the callback in the future will also be skipped (will have zero delay).
Limitations
Has no effect if the specified callback no longer exists or is not delayed.
Example
on init
var currentCallback
end on
on note ’for each new note
end_delay(currentCallback, 0) ’if previous octave note did not play yet, play it now
currentCallback = CALLBACK_ID ’remember this is now the callback with a delay
delay(1000000) ’wait 1 second
new_note(EVENT_KEY + 12, EVENT_VEL, 0, -1) ’play a note an octave higher
end on
Set a custom position (usually SONG_POS_PPQ for the current position) for beat-synced effects to align to. This is particularly useful for aligning e.g. tremolo to a note played when the host transport is stopped. Use a negative ppq value to remove the custom position and allow effects to synchronize to the host-provided bar and beat positions.
Returns the number of samples at the current sample rate equal to the specified time interval in microseconds.
Arguments
usec
Time in 1/1000000ths of a second.
When the audio output starts or restarts, on controller will be called withe a MIDI all-notes-off message (CC 123). This is a good place to check if the host application's sample rate has also changed.
Elapsed time in milliseconds since audio started running (always increasing - doesn’t depend on song position). The time is stored as a 32-bit number so the value will jump (wrap around) once every few weeks if you keep the instrument loaded that long.
Read-only value: Current transport position, measured in ppq (960 per quarternote). If the transport is stopped the value keeps increasing from the stop position at the current tempo, so it can still be used as a timing reference. Use SONG_PLAYING to detect if the transport is stopped or playing.
Limitations
Do not use in on init as the song position may not yet be known.
Check if two arrays have the same length and contain the same values in the same order. Returns 1 if the arrays have the same length and contents, else 0.
Arguments
array1
The first array.
array2
The second array.
Example
var a[3] = (1, 2, 3)
var b[3] = (1, 2, 4)
var x = array_equal(a, b) 'x is 0 as arrays have different contents
Copy count values from the source array (starting at index start1) into the destination array (starting at index start2). If the count is bigger than the source or destination as much data as possible is copied. If source is a numeric value instead of an array, that value gets copied to the specified range of dest. The same array can be specified for source and dest and the copied ranges can overlap, allowing the array data to be shifted left or right.
Arguments
source
The source array and the start index to read from, or a numeric value to fill the destination array with.
dest
The destination array and the start index to write data to.
count
The number of values to copy.
Examples
array_fill(0, myArray[10], 20) 'fill myArray indexes 10 to 30 with value 0
array_fill(myArray[10], myArray[0], 100) 'shift myArray contents 10 positions to the left
array_fill(array1[100], myArray[0], 10) 'copy 10 values starting at array1[100] into myArray
Find the maximum value in the array, searching the specified number of values starting at the specified index (or zero if just the array name is given). Returns the maximum value found.
Arguments
array
The array to search, with optional start index.
value
The number of values in the array to search.
Example
var myArray[3] = (7, 8, 9)
var x = array_find)_max(myArray, 2) 'x is 8 (the highest of the first 2 values)
Find the minimum value in the array, searching the specified number of values starting at the specified index (or zero if just the array name is given). Returns the minimum value found.
Arguments
array
The array to search, with optional start index.
count
The number of values in the array to search.
Example
var myArray[3] = (7, 8, 9)
var x = array_find_min(myArray[1], 2) 'x is 8 (the lowest of the two values starting at index 1)
Find the first occurrence of value in the array, searching the specified number of values starting at the specified index (or zero if just the array name is given). Returns the array index where the value was found, or -1 if the value was not found.
Arguments
array
The array to search, with optional start index.
value
The value to find.
count
The number of values in the array to search.
Example
var myArray[5] = (1, 2, 3, 4, 5)
var x = array_find_range(myArray[1], 5, 3) 'x is -1 as the value 5 was not found in the 3 values starting at index 1
Find the first difference between two arrays (or two regions of the same array) starting at the specified indexes (or zero if just the array names are given). Returns the index in array1 where the difference was found, or -1 if no differences were found before the end of either array was reached.
Arguments
array1
The array to search, with optional start index.
array2
The array to compare it to, with optional start index.
Example
var array[8] = (1, 2, 3, 4, 1, 2, 0, 4)
var notes[32] = ( 60, 64, 67, 0 )
var x = array_find_difference(array, array[4]) 'x is 2 as the value at array[2] is different to the value at array[4 + 2]
x = array_find_difference(array, notes) 'x is 0 as the value at array[0] is different to the value at notes[0]
x = array_find_difference(notes[10], notes[20]) 'x is -1 as no differences were found comparing notes[10] onwards with notes[20] onwards because all the values are zero
0 = sort from lowest to highest, 1 = sort from highest to lowest. A negative value -N means sort the first N values in the array from lowest to highest.
Example
var myArray[3] = (3, 1, 2)
array_sort(myArray, 0) 'myArray now contains (1, 2, 3)
Calculates the nearest matching chord based on an array of held notes:
Chord
Return value
None
-1
5
0
M
1
6
2
7
3
M7
4
b5
5
aug
6
m
7
m6
8
m7
9
mM7
10
m7b5
11
dim
12
sus2
13
sus4
14
Arguments
root
Variable that is set to the chord root note by identify_chord, or to -1 if no chord.
heldKeys
Array of 12 values representing one octave of pitches (C to B). Value 0 means the key is not held. If the chord is ambiguous, notes with higher values are preferred as root.
Example
var heldKeys[12] = { 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0) 'C major chord
var root
var chord = identify_chord(root, heldKeys) 'now chord is 1 and root is 0
Similar to identify_chord, but also writes the bass note of the held chord to the provided variable.
If a note more than a fifth below the other chord notes is played it is used as the bass note, otherwise the bass note is assumed to be the same as the root note.
The heldKeys array is assumed to have a bit set for each octave that key is held in, with higher bits representing lower octaves.
Copy values from a Data File module to a script array.
Arguments
array
An array variable in the script.
nameOrIndex
The index of the Data File module in the instrument (counting from zero) or its name.
Limitations
If the array or the data to be copied are different sizes, the number of values copied is determined by whichever is smaller.
A Data File can contain either numeric or text values. If it contains numeric values it can only be loaded into a numeric array. If it contains text values it can only be loaded into a text array.
Select which MIDI File module in the instrument to use as the source of MIDI data in the instrument script.
Note only one MIDI File can be selected at a time, even if there are multiple Script modules in the instrument. The current position in each MIDI File is remembered when switching between files.
Returns the index of the MIDI file, or -1 if the specified file was not found.
Arguments
nameOrIndex
The name of the MIDI File module, or its number in the instrument (counting from 0).
Called when the user wants to drag MIDI data from the instrument to the host application. In response you should fill the provided MIDI_DRAG_DATA array with a series of tick positions followed by MIDI byte values as shown in the example below.
Events written to the array do not have to be strictly sorted by tick position, but avoid overlapping notes on the same key and channel. To end a note, use a note-on message with velocity zero rather than a note-off message unless you want to set a specific note-off velocity.
Limitations
May be called at the same time as other script functions, so be careful not to change the value of any variables those functions could be using.
Not supported in Rack Extensions.
Example
on midi_drag
MIDI_DRAG_DATA[0] = 0 'at start tick
MIDI_DRAG_DATA[1] = (MIDI_COMMAND_NOTE_ON << 16) + (60 << 8) + 100 'note on, key 60, vel 100
MIDI_DRAG_DATA[2] = 960 'at one quarternote
MIDI_DRAG_DATA[3] = (MIDI_COMMAND_NOTE_ON << 16) + (60 << 8) 'note off
end on
Called when an audio output is connected or disconnected. Allows an instrument to change its internal audio routing depending on which outputs are being used.
Limitations
Currently only supported in Rack Extensions.
Example
on io_changed
print("Output " & BUS_INDEX & " connected = " & BUS_CONNECTED)
end on
Set how a range of keys are displayed on the plug-in GUI or on hardware with key lights.
Arguments
lowKey
Lowest key in range.
highKey
Highest key in range (can be the same as lowKey).
color
The following colours are available: KEY_COLOR_RED KEY_COLOR_ORANGE KEY_COLOR_LIGHT_ORANGE KEY_COLOR_WARM_YELLOW KEY_COLOR_YELLOW KEY_COLOR_LIME KEY_COLOR_GREEN KEY_COLOR_MINT KEY_COLOR_TURQUOISE KEY_COLOR_CYAN KEY_COLOR_BLUE KEY_COLOR_PLUM KEY_COLOR_VIOLET KEY_COLOR_PURPLE KEY_COLOR_MAGENTA KEY_COLOR_FUCHSIA KEY_COLOR_DEFAULT (playable keys) KEY_COLOR_INACTIVE (disabled keys) Add KEY_IS_CONTROL to the color value if the key(s) are keyswitches.
Limitations
Requires support in the instrument/UI framework being targeted.