Usine Scripting Tutorial
Usine Scripting Tutorial
BY BENJAMIN MOUSSAY
VERSION 1.00
Table of content
1.Introduction:
...................................................................5
Acknowledgement:
.................................................................................5
Limitations: ..............................................................................................5
Variables: ................................................................................................10
Constants: ..............................................................................................10
Types: .....................................................................................................10
II.Loops: ...............................................................................................................14
2
Table of Contents
2.Case: .......................................................................................................15
Functions: ..............................................................................................16
Procedures: ............................................................................................17
Scale, color, min and max and default values, displayed symbol, format: ...22
ListBoxes: ............................................................................................................24
5.Arrays:
..........................................................................28
Array declaration:
..................................................................................28
3
Table of Contents
6.Strings:
.........................................................................34
7.Midi Codes:
...................................................................36
Definition of a midi code:
.....................................................................36
10.Conclusion: ................................................................53
4
1. Introduction
1.Introduction:
Acknowledgement:
Thanks a lot to Bjoern Sorknes and Olivier Sens for proofreading this document and for their
great advices and suggestions.
For example:
• Dealing with arrays (especially when their size is variable)
• Dealing with midi data
• Doing data loops with repetitive iterations and logical conditions
• Doing complex maths
• Etc…
Limitations:
Scripts can process audio, but the CPU usage is very high. However for most data, midi and
text use they will be perfect.
Just be aware that, usually, scripts are more CPU hungry than patches, but in some cases
scripts are really the best solution.
If you want to manipulate audio, you should consider using the C++ SDK to build your own
modules.
5
2. Getting Started
2. Getting started:
A. Open a scripting window:
A script is a text document you can edit in any basic text editor (wordpad, etc…).
Unlike word processor programs, a text editor saves text without any formatting or other
data in the file, just like in the “plain text” format word processors can save to.
In Usine in “patch design mode”, drag and drop an “empty script” module (located in the
“scripts” folder).
6
2. Getting Started
There you have a file menu to save or load your scripts, an edit menu for copying, pasting
and so on, and a script menu to compile your script when it’s ready for testing or using.
Below you have two tabs:
• Script to process: there you write your script or copy and paste from a text
document.
• Help: a list of the most important types, functions and procedures you can use.
When you have finished writing your script just choose script->compile (shortcut: [ctrl + F9])
to compile it and create your module.
7
2. Getting Started
B. Basic concepts:
Basically by when you write and compile a script, you build a module of your own, with its
own inlets and outlets, and its own way to process data.
So before creating a script you just have to plan which inlets you need, which outlets, and
how the data is processed inside.
It’s also important to figure what kind of inlet-outlet you need (will it be a fader, a switch, a
midi input, or anything), and its properties: scale, minimum-maximum value, number of
decimals (precision), default value, etc…
Some precision about the “type” of an inlet-outlet: actually if you choose your input to be a
fader, you can still plug a switch or anything to it, but choosing the type of an inlet-outlet
defines two things:
• What the input will expect: if your inlet is a button for instance, it will expect
values either 0 or 1, if it’s a midi inlet, it’ll expect midi (but you can still plug
something else if you want to obtain weird results), etc…
• The kind of “interface design” module Usine will create when you drag a wire from
this inlet-outlet. If your inlet is a midi note fader for instance, when you drag a wire
from it Usine will create a midi note fader.
For example, I could create a simple A+B script to add only integers between 1 and 10, (it’s
totally useless, since the A+B module already exists in Usine): for this I would need to
create an inlet labeled “A”, with a precision of 0 decimals (integer), a min value of 0, a max
of 10, a linear range, and this inlet would be a fader. Same for the “B” inlet.
I would need also an outlet let’s call it “sum”, precision 0 decimals.
Then inside the script, I would need to access the values of my inlets, store them into
variables, compute the sum, and send the sum to the outlet.
8
3. Pascal Basics
3. Pascal basics:
The script language is based on the Pascal programming language, but it’s quite simple to
understand.
In this language, as in many others, there are basic “building blocks” you can combine to
achieve what you want to do. Here weʼll review some basic notions. You can find on the
internet many tutorials about Pascal and Delphi, that could help you learn more
advanced concepts.
Notation conventions:
• Like other computer languages, the scripting language is made with a combination
of keywords (words specific to the language like : “for”, “to”, “begin”, “end”, “case”,
etc…), operators (either mathematical: +, -, /, *, etc… or logical: >, <, =, <>, OR,
AND, not), and variables (you choose their names).
• By convention in this manual, the code (scripting language) will be written with the
Courier font (this is an example of Courier font), and the Pascal
keywords will be written in bold (if x=1 then x:=x+1) to make it more clear.
• The scripting language is NOT case sensitive, so “Var” and “var”, “GetValue”
and “getvalue”, “For” and “for”, or “NbOfMidi” and “nbOfmidi” mean exactly
the same things.
• A script is made of a series of instructions. Each instruction is separated by a
semicolon “;”. Don’t forget these, it’s a common source of errors. You can write
several instructions on the same line like:
Var x : integer ; x:=2 ; x:=x*2 ;
But usually it’s more clear to put each instruction on a separate line:
Var x : integer ;
x:=2 ;
x:=x*2 ;
• Everything that is situated after two slashes (//) is considered as a comment (it’s
not processed by the script compiler, and is just here to give comments or
explanations about the code).
For example:
//initialisation procedure to create parameters.
• You can also use multi-line comments (especially when debugging it's convenient
to comment several lines in one go). You insert these comments between (* and *)
or between {$ and $}.
For example:
(* this is
A multi-line comment *)
9
3. Pascal Basics
A.Variables:
You give them a name (a, x, tick, midi_input, out2, or anything you like).
Their name must not be a Pascal keyword, and must start with a letter (a...z) or an
underscore (_).
You use them to store data and make calculations, you can send them to functions and
procedures to be processed.
B.Constants:
These are variables that keep the same value throughout the script without being changed.
Can be useful if the same value is used many times in your script, or, for instance if you deal
with arrays of a fixed size and want to be able to easily change this size, etc…
C.Types:
Every variable in Pascal must have a “type”. (this tells basically to the computer how much
memory space must be allocated for it). These are the common types used:
integer Whole numbers from -32768 to 32767
byte The integers from 0 to 255
real Floating point numbers from 1E-38 to 1E+38
boolean Can only have the value TRUE or FALSE
char Any character in the ASCII character set
shortint The integers from -128 to 127
word The integers from 0 to 65535
longint The integers from -2147483648 to 2147483647
single Real type with 7 significant digits
double Real type with 15 significant digits
extended Real type with 19 significant digits
comp The integers from about -10E18 to 10E18
In Usine, we’ll use mostly: integer, single, byte, boolean, char
You can also use other types of data : array and string, we’ll explain them further.
10
3. Pascal Basics
• Along with the common Types of data described before, you can build your own
types.
To do this, just write the keyword: type followed by your custom type name, then
the keyword = and the type definition.
You can also use to declare a type a data structure called “record”. For details about
records read further.
Examples:
Type MyInteger = integer;
Type Apple = record
Color : byte;
Weight : single;
Origin : string;
End;
• Usine’s script language has some useful types implemented you can use. They are:
ptAudio,ptDataField,ptDataFader,ptButton,ptListBox,
ptSwitch, ptArray, ptIpAddress, ptSmpte);
// these are the diffent available kind of parameters.
You’ll soon learn all what you need to fully understand parameters, and midi.
11
3. Pascal Basics
Variable declaration:
Before using any variable in a script, you have to declare it. You have to do it with
the keyword var:
Var Variable_Name : Type
Examples:
Var x : integer; //this declares variable x to store integer
values
Var tab1 : array of double; //this declares a table of
floating point values called tab1
Var Input1 : tParameter; //this declares an inlet-outlet
called input1
Var MidiIn : tMidi; //this declares a variable called MidiIn
that will store Midi Code.
If you need to declare several variables of the same type you can do like this:
Var x, y, r : single;
Constants declarations:
Const constant_name = Value;
12
3. Pascal Basics
I. Basic keywords:
var : used to declare a variable
:= : used to assign a value to a variable (ex: x := 2; , stores the number 2 into
variable x)
; : beware not to forget it at the end of each individual instruction
begin end; : used to group instructions in “blocks” of instructions.
Example of a block:
Begin
X:=1;
Y:=2;
End; // this block is considered as one single
instruction
Often you’ll use blocks inside blocks inside blocks, etc…, a bit like “Russian Dolls”.
It’s a good habit to indent each new begin and to align it with its related end;
This helps for clarity, and to avoid mistakes.
Example:
Begin
// instructions
Begin
// instructions
Begin
// Instructions
End;
// instructions
Begin
// instructions
End;
End;
// instructions
End;
13
3. Pascal Basics
II.Loops:
To execute a block of instructions several times (let’s say n times) you have two
basic options:
1. The for loop:
Var i, n : integer;
For i:=1 to n do
Begin
// instructions
End; // the block will be executed n times,
and at each iteration i will be incremented
14
3. Pascal Basics
2.Case:
Let’s say we have a integer variable called n. (n can store for instance the
value of a combobox inlet). If you want to execute different instructions
according to the value of n, you can do like this:
case n of // let’s say n can be 1, 2 or 3
1:
begin
// instructions processed if n = 1
End;
2:
begin
// instructions processed if n = 2
End;
3:
begin
// instructions processed if n = 3
End;
End; //end of case
This is especially useful when you use listboxes.
15
3. Pascal Basics
E.Functions:
• They have a name optionally followed by argument(s) between parentheses. They
return a result, according to the argument(s). Each argument has a specific type.
Example:
round(x); returns the rounded value of x.
• You can build you own functions and use them in you script, or use Pascal’s or
Usine’s built-in functions.
The basic syntax of a function is:
function_name(param1, param2, …, paramN);
• You can assign the result of a function to a variable:
Var x, y, r : single;
r := function_name(x, y); // the result of the function
with arguments x and y is stored to r
• You can also use the function directly in an expression:
Var x, y, z, r : single;
r := x*function_name(y, z);
• As said before, the type of the result, and the types of the parameters must
match with the function definition, else the script will not compile. Example from the
script documentation:
function CreateParam(S1: string; s2: Longint) : TParameter;
// This function “CreateParam”, expects as arguments a
String (the display name of the parameter), and a
LongInteger. And it returns a Parameter (type
tParameter).
The script documentation is very useful, since it contains all built-in functions
definitions, and tells you exactly the number and types of parameters expected by
each function, and the type of its result.
16
3. Pascal Basics
F. Procedures:
• Procedures also have a name optionally followed by argument(s) between
parentheses, but don't return any result like functions do. If however an argument is
declared with var before the variable name, you can pass a variable as an argument
and the procedure can change the value.
Example:
SetArrayLength(table1, 16); // sets the length of the array
named “table1” to 16.
• Beware that the types of the parameters must match with the procedure
definition, else the script will not compile. Example from the script documentation:
procedure SetIsInput(Param: integer; val: boolean);
// This procedure “SetIsInput”, expects as arguments a
Parameter (type tParameter), and a boolean value.
The script documentation is very useful, since it contains all built-in procedure
definitions, and tells you exactly the number and types of parameters expected by
each of them.
17
3. Pascal Basics
• You can also use built-in functions to perform more advanced maths:
Function Timems :extended;
Function Sin(e: Extended) : Extended;
Function Cos(e: Extended) : Extended;
Function ArcCos(e: Extended) : Extended;
Function ArcSin(e: Extended) : Extended;
Function Arctan(e: Extended) : Extended;
Function Sqrt (e: Extended) : Extended; // Square root
Function Round(e: Extended) : Longint; // rounds to the
nearest integer
Function Trunc(e: Extended) : Longint; // removes decimal
Function Int(e: Extended) : Longint;
Function Pi: Extended;
Function Abs(e: Extended) : Extended;
Function Ln(e: Extended) : Extended;
Function Log(e: Extended) : Extended;
Function Exp(e: Extended) : Extended;
Function power(base,e: Extended) : Extended; // example 2
power 4 will be written power(4,2);
Function Random : single;
18
4. Structure of a script
4. Structure of a script:
Now letʼs get deeper into the script syntax and organization.
For Usine to deal with the inlets-outlets we need, we have to declare some variables that
will represent these inlets-outlets.
Usine has a built-in Type to store inlets-outlet, called tParameter.
The name of the tParameter variables has nothing to do with the actual way they show
up outside the module, it’s only a reference name to access the inlets-outlets inside the
script.
Let’s imagine we want to create a simple addition script that will add two numbers A and B.
We need 2 inlets: A, B, and 1 outlet (sum).
We’ll call these for instance: InA, InB and Output.
This is how to declare them:
Var InA : tParameter;
Var InB : tParameter;
Var Output : tParameter;
19
4. Structure of a script
Now that we have declared the parameters, it’s time to give them a real existence, and to
define their individual properties.
We’ll do it within a procedure called “init”.
Note that this procedure in executed only once: when the script is compiled (in other
words when you choose “compile” in the script menu of the script editor, or when a patch
containing your script is loaded, or when you drop your script module in the patch design
area).
The basic syntax is:
Procedure init;
Begin
// Instructions, functions procedures to create and initialize
parameters.
End;
And between begin and end are a series of instructions to initialize our inlets-outlets:
• Define their display name
• Define their type (fader, midi, array, switch, button, etc…)
• Define if they are inputs or outputs or both
• Optionally define their range, scale, number of decimals, etc…
20
4. Structure of a script
1.CreateParam:
// Create a new parameter, returns the parameter's number
function CreateParam(S1: string; s2: tParamType):TParameter;
• S2 : tParamType is the type of your parameter. It’s value can be one of the
following:
The function will return the parameter’s number, that you’ll store into the tParameter
variable you’ve declared before.
Example:
Let’s get back to our A+B example. We have declared a tParameter variable
called inA.
Now in the init procedure, we’ll create the parameter inA, we want it to have as
display name “A”, and we want it to be a fader. This is how we’ll do it:
Procedure init;
Begin
inA := CreateParam(‘A’, ptDataFader); // a datafader called
‘A’ is created and stored to inA
End; // end of the init procedure
More examples:
• inA is a button labeled “mybutton”:
inA := CreateParam(‘mybutton’, ptButton);
• inA is a midi input called “midi in”:
inA := CreateParam(‘midi in’, ptMidi);
• inA is a list box called “list”:
inA := CreateParam(‘list’, ptListBox);
-Etc…
21
4. Structure of a script
2.SetIsInput, SetIsOutput:
When you create a parameter with the CreateParam function, you have to specify
if the parameter has an inlet, an outlet, or both.
For this you have two procedures: SetIsInput and SetIsOutput.
They accept 2 arguments:
• Param: integer is the name of the parameter
• Val: boolean is either true or false
By default these procedures are true. So if you don’t use them, your parameter will
have an inlet and an outlet.
So you have to write:
SetIsOutput(Parameter_Name, False);
if you want only an inlet and vice versa.
Examples:
• inA has only an inlet:
SetIsOutput(inA, false);
• inA has only an outlet:
SetIsInput(inA, false);
These procedures allow you to define your parameters more precisely, if you need
to.
22
4. Structure of a script
If you don’t use it, the fader’s scale will be linear. Here are the possible values of
tScale:
type TScale = (lsLinear,lsLog,lsExp);
Example: inA is a fader and you want a min value of 10 and a max value of 2000:
Setmin(inA, 10);
SetMax(inA, 2000);
This sets the default value of the parameter. (the value the parameter will reset
to when you [ctrl-click] on it).
23
4. Structure of a script
4.ListBoxes:
// set listbox items ie.'"item1","item2"'
procedure SetListBoxString(Param: integer; val: string);
Example: inA is a list box and you want the following options for the list:
“up”, “down”, “random”
SetListBoxString(inA, ‘“up”, “down”, “random”’);
Don’t forget the single quotes around the list.
5.Other procedures:
You won’t use them often, but they can be useful in certain situations:
The “callback” is, so to speak, the speed at which Usine scans the parameters of
the script for their values. Normally scripts are processed in the “windows
message processing”, wich is quite slow (but fast enough for most scripting
applications). If you want some parameter to be more “responsive”, you can use
this procedure, but your script will be more CPU hungry.
24
4. Structure of a script
If you need custom functions and/or procedures, just declare them before your main
procedure.
If your script is quite complex, it can be more clear to read and to further modify if you
split your code into custom functions and procedures and use these in the main
procedure.
These are also handy when you need the same functionality several places within a
script, for instance a procedure that builds several midi messages and puts them into the
outlet array while also keeping count of the number of messages created.
This way the main procedure always stays simple and clear.
H.Main procedure:
This is the core of your script, and is located at the end.
It is processed at every computing cycle of Usine (unlike the init procedure which is
processed only when the script is compiled).
25
4. Structure of a script
// title
// parameters declaration
Var Parameter_Name : tParameter;
// other parameters declarations
// init procedure
// it can also contain variable declarations
// you can use all variables and constants declared before
Procedure init;
Begin
// use CreateParam, SetIsInput, SetMin etc…
// you can use all variables and constants declared before
// This block is processed only once at compilation
End;
26
4. Structure of a script
// main procedure
// it can also contain variable declarations
// You can use all variables and constants declared before, and all your
custom functions and procedures
// the main procedure is processed every cycle, it’s the core of your
script
Begin // beginning of the main procedure
// Here’s the code of the main procedure
End. // end of the main procedure and end of the script
N.B: it can happen that you need to use some custom functions or procedures inside the
init procedure. In this case, just declare them before the init procedure.
27
5.Arrays
5.Arrays:
An array is a variable that can store a series of numbers. You can imagine it like a table
containing a row of values. Arrays have certain characteristics:
• The length of an array is the integer number of elements stored in the table.
• The elements of the table are numbered from 0 to len-1 (where len is the length
of the array).
• The integer number corresponding to the position of one element in the table is
called the index.
Array declaration:
Var array_name : array of Type_of_values_stored_in _the_array;
Examples:
Var tab1 : array of integer;
// this creates a table that stores integer values.
Example:
Var tab1 : array of integer;
SetArrayLength(tab1, 10); // declares an table containing 10
integers.
28
5.Arrays
Example:
Var tab1 : array of integer;
Var x : integer;
SetArrayLength(tab1, 10);
X := GetArrayLength(tab1); // the value 10 is assigned to x.
The first elementʼs index is 0, the 4th oneʼs index is 3 the last oneʼs index is len-1 (len
is the length of the array).
You can access an array value by typing the array name and the index between
brackets.
Example:
Tab1[0] // this is the first value stored in the table
Tab1[5] // this is the 6th value stored in the table
29
5.Arrays
Example:
Letʼs say we want to build a table of 50 integers containing numbers from 1 to 50.
Doing this index by index would be time consuming.
Another example:
Letʼs say you have a midi input in your script, waiting for midi notes.
You donʼt know in advance how many notes youʼll receive at a time (a single note,
or a 4 notes chord).
The good strategy in this case would be to create an array storing the incoming
midi codes (letʼs call this array MidiInArray).
Then you measure the length (weʼll see how to do this later) of this array (the
number of notes), letʼs call the length NbOfMidi.
Then you have to process each midi note in the following loop:
Multidimensional arrays:
Until now, weʼve only used arrays containing one row of numbers.
They are said to have one dimension.
30
5.Arrays
In some situations, youʼll need to create a table with rows and columns.
You can create arrays of any dimension (array of array of array, etc…) if you like, but
youʼll mostly use 1 or 2 dimensions arrays.
To create a bi-dimensional array, you first have to create a custom type for your
“columns”, then create an array of “columns”.
Example:
Imagine you want to store all the modes of the major scale into an array called
MajScaleModes. A mode will be stored in an array of integers. Weʼll create a new
Type for these arrays called tMode. These integers will represent the intervals in
semitones from the tonic.
Each mode has 7 notes, there are 7 modes so the table must be 7x7.
SetArrayLength(MajScaleModes, 7);
SetArrayLength(ionian, 7);
SetArrayLength(dorian, 7);
SetArrayLength(phrygian, 7);
SetArrayLength(lydian, 7);
SetArrayLength(myxolydian, 7);
SetArrayLength(aeolian, 7);
SetArrayLength(locrian, 7);
MajScaleModes := [ionian, dorian, prhygian, lydian,
myxolydian, aeolian, locrian];
Ionian := [0, 2, 4, 5, 7, 9, 11];
Dorian := … etc...
If we want to assign a major third (4 semitones) to the 3rd value of ionian we can
do:
Ionian[2] := 4;
Or directly:
MajScaleModes[0][2] := 4;
// You can read this assign the value 4 to the 3rd element of
the 1st element (ionian) of MajScaleModes.
This is the value of the fifth (index =4) of the myxolydian mode (index = 5):
MajScaleModes[5][4]
31
5.Arrays
This happens when you try to store a value of a certain type into a variable of
another type.
For example:
The code :
Var x : integer;
x := GetValue(inA);
• In general a larger type is compatible with a smaller one, but the opposite
doesnʼt work:
Example:
Var x : single;
Var y : double;
Y := x; // this should work
X := y; // this will return a “type mismatch” error
• Fortunately there are built-in functions to avoid these problems: the type
conversion functions.
32
5.Arrays
N.B. We could also have written our function with a more compact
code:
33
6.Strings
6.Strings:
The string type is used for processing text.
Remember that char is the type used to store characters (any of the 256 character of the
ASCII table).
34
6.Strings
//Removes leading and trailing spaces and control characters (ie ASCII
0-32) from s
N.B: Always use single quotes when directly manipulating string or char types.
Example:
StrSet(‘H’, 0, Mystring1);
// MyString1 is again ‘Hello’ (uppercase H)
35
7.Midi Codes
7.Midi Codes:
Definition of a midi code:
A midi code typically consists of 4 different values each having a length of 1 byte
(0-255):
Or you can see it as several variables all grouped under a common name.
36
7.Midi Codes
Example 2 - transpose:
Letʼs transpose Midi1 an octave higher:
Midi1.data1 := Midi1.data1 + 12;
Etc…
37
8. Accessing Parameters Data
Before studying some script examples and see how to process data, we need a last step:
How to access to inletsʼ data, and how to sent data to outlets.
Remember that inlets and outlets are named “parameters” in Usine Script.
The script language has built-in functions and procedures to read data from and write
data to those parameters. Here they are:
Remember the types of parameters you can create with Usine Script:
• ptTextField
• ptChooseColor
• ptMidi
• ptGainFader
• ptAudio
• ptDataField
• ptDataFader
• ptButton
• ptListBox
• ptSwitch
• ptArray
• ptIpAddress
• ptSmpte
38
8. Accessing Parameters Data
As you can see, the result returned by this function is of type single.
single is the most common floating point number used in Usine Script.
Example:
Letʼs create a fader inlet named inA (display name “A”):
Var x : single;
x := GetValue(inA);
II.Array parameters:
ptArray, ptIpAddress, ptSmpte
It accepts 2 arguments:
•Param is the parameterʼs name
•i is the index
Example:
Letʼs say we have an array input called ArrayIn.
If we want to read the 4th element value weʼll do:
GetDataArrayValue(ArrayIn, 3);
39
8. Accessing Parameters Data
III.Midi parameters:
ptMidi
For example if those midi messages are NOTE ON message, if the midi inlet receives 1
note, the array length will be 1, if the midi inlet receives a 4 notes chord, the array length
will be 4.
Example:
Letʼs say we have created a midi input to our script, called MidiInput.
Letʼs assume this input receives a 4 note chord.
Letʼs declare a variable of type TMidi called Midi1.
Var Midi1 : TMidi;
To store the 3rd note of the chord into Midi1 weʼll do like this:
GetMidiArrayValue(MidiInput, 2, Midi1);
IV.String parameters:
ptTextField
Example:
If we have a text field inlet called TextIn.
Letʼs create a string variable to store the text:`
Var Text : string;
Then simply do:
Text := GetStringValue(TextIn);
40
8. Accessing Parameters Data
It returns an integer.
If the inlet receives something then the message length is greater than 0.
So, for instance, if we have an fader inlet called inA, and we want our script to be
processed only if inA receives something, weʼll do:
If GetLength(InA)>0 then
Begin
// here are the instructions for processing
End;
This is very useful to save CPU resources, since Usine will just execute the
GetLength function at each cycle, and execute the block of instructions only if
something is present at the input.
It can be connected for instance to the array output of a Step module, or whatever.
41
8. Accessing Parameters Data
In this case, to process the array itʼs crucial to know itʼs length, especially to do
loops.
Example:
Letʼs say we want to store the content of ArrayIn to an array variable
called tab1.
Youʼll do this:
Var tab1 : array of single; // we declare an array of
single
Var len, i : integer; // we’ll use i for the loop and len
to store the array length
Itʼs unlikely we can guess in advance how many midi codes will be present at a
midi input.
Example:
Letʼs say we have a midi inlet, called MidiIn.
Letʼs create a array of midi codes called TabMidi, and store all the codes entering
MidiIn to it:
42
8. Accessing Parameters Data
You can use them either to send data to an outlet after processing, or during the init
procedure to set initial values to your inlets.
Example:
Letʼs say you have a data outlet called Out1.
Letʼs send send the number 10 to out1:
SetValue(Out1, 10);
Var x : single;
SetValue(Out1, x);
SetValue(Out1, x+2);
43
8. Accessing Parameters Data
When the length of the message sent to a parameter is 0 then this parameter sends
nothing.
Setting the length to 0 can be a security to avoid sending or “dummy” messages to the
outlets.
You have to use SetLength when you deal with arrays or midi codes, all youʼll see later.
Example:
Letʼs say we have an array inlet called ArrayIn, and an array outlet called
ArrayOut, and we simply want to pass through an array from ArrayIn to
ArrayOut.
Weʼll do this:
Len := GetLength(ArrayIn);
// we measure the length of ArrayIn, store it to len
SetLength(ArrayOut, len);
// we make sure ArrayOut will be the same length as ArrayIn (if you
don’t do this it can lead to weird behaviors or errors)
SetDataArrayValue(ArrayOut, I, Arraytemp[i]);
// send the same element to ArrayOut
End;
44
8. Accessing Parameters Data
IV.Midi parameters:
Example:
Letʼs say we have a midi output called MidiOut.
Letʼs send a NOTE ON, C3, vel 95, channel1 to it:
SetMidiArrayValue(MidiOut, 0, MidiNote);
// We send the note as the first element of an array (thus the index 0)
to MidiOut.
SetLength(MidiOut, 1);
// if you forget this nothing will be present in MidiOut. We send 1
note, so we have to specify that the length of the Midi array we send is
1.
45
8. Accessing Parameters Data
With the example above, in between each computation of the main process,
the MidiOut outlet would still contain the value MidiNote.
This can lead to errors, since itʼs like if MidiNote was sent at each cycle.
We have to use a security, and “clear” the midi output after weʼve sent our
note once, this means to set the length of the output to 0.
This is why we'll add following line when no midi message is to be sent:
SetLength(Midiout, 0);
Usually, when you have to process and send out midi data, youʼll use the if
then else statement:
If (condition to process and send midi is true)
Then (process and send midi)
Else (Make sure you send nothing)
If (condition_to_process_and_send_midi_is_true) then
begin
// Here are instructions to process midi
Else
begin
SetLength(Midiout, 0); // “close” the output, so that the note
is not isn't sent once for each cycle
End;
46
8. Accessing Parameters Data
V.Text parameters:
No surprise here, the simple procedure to send a string is:
Example:
We have a text field output in our script, called TextOut.
Letʼs send the word “hello” to it:
SetStringValue(Textout, ‘Hello’);
The procedure:
writeln(string);
If you want to print out numerical values, use the following functions:
IntToStr(integer); // this converts an integer to a string
FloatToStr(Extended); // the same for floating points values.
Examples :
Var x : integer;
x :=10;
Writeln(intToStr(x));
47
8. Accessing Parameters Data
Var i : integer;
Var f : single;
i :=1;
f := 2,34;
Writeln('i= ' + IntToStr(i) + ' f=' + FloatTostr(f));
// this will display “i= 1 f= 2,34” in Usines’s console
48
9.Global Scripting Strategies
Remember that the main procedure is processed at every cycle, in any case.
So, if your script is very light, (some simple math calculation for example), just create you
inlets-oultets, your variables, and write the processing part in the main procedure.
But in many cases, your script will become heavier (processing arrays, text or midi data).
Then itʼs better to have the script processed only when you need to (for instance if some
input parameter has changed, or when some midi data is received, or when the script
receives some rythmic pulse, etc…).
Procedure init;
Begin
Tick := CreateParameter(‘tick’, ptButton);
SetIsOutput(tick, false);
//creation of the “tick” inlet, it’s button, it’s an input
Var ??? : ??? ; // here you declare all your global variables
/////////////////
// main procedure
/////////////////
Begin // beginning of the main procedure
If GetValue(tick) = 1 then //test to check if tick has received an
impulse
Begin
49
9.Global Scripting Strategies
SetValue(tick, 0);
// for security, we immediately reset tick to 0, so that the block isn’t
processed several times
// here you write your processing instructions
End;
// end of the if block, if tick hasn’t received any impulse, the block will not
be processed
End. // end of the main procedure and end of the script
One midi message, then another one, etc… (unlike audio which is continous).
In Usine, remember that the midi flow is considered as an array of midi messages.
When one message is present, the array length is 1, when 4 messages are present the
array length is 4, when no message is present, the array length is 0.
So, basically the best way to deal with midi messages in scripts is to do the main
processing part only if the length of the midi input parameter is greater than 0.
Then, if you want to actually send some messages to the midi output, donʼt forget to set
the length of the midi output parameter to the number of messages you want to
send.
And if there is no message received, donʼt forget to set the length of the midi output
parameter to 0, or youʼll be sending midi messages continuously.
Procedure init;
Begin
MidiIn := CreateParam(‘Midi In’, ptMidi);
50
9.Global Scripting Strategies
SetIsOutput(MidiIn, false);
// We have Created our midi input and output, you can now create your
other parameters
Var NbOfMidi : integer; // we’ll use it to store the number of incoming midi codes
Var i : integer; // we’ll use it for loops
// here you can declare other global variables
/////////////////
// main procedure
/////////////////
Begin // the beginning of the main procedure
NbOfMidi :=GetLength(MidiIn);
// we get the length of the midi in array (i.e. the number of incoming midi messages)
51
9.Global Scripting Strategies
Important tip:
When you deal with array outputs or with midi outputs, never forget to use
the SetLength function in you script.
This make sure you set the right length for the outgoing array, or to set the
correct number of midi messages that should go to the midi output.
Example 1:
Letʼs say you have an array of single, letʼs call it Tab1, of length len,
and you want to send it to the parameter youʼve created called
ArrayOut.
Var i : integer;
Var x : single;
For i:=0 to len-1 do
Begin
X:=tab1[i]; // we store the ith value of tab1 to x
SetDataArrayValue(ArrayOut, i, x);
// we set the ith value of ArrayOut to the value of x
End;
// after the loop has been processed from 0 to len-1, ArrayOut will
contain all the values of Tab1
SetLength(ArrayOut, len);
// here we make sure ArrayOut has the same length as tab1
Example 2:
Letʼs say you want to send a three notes chord to your parameter
MidiOut, if some condition is true (letʼs call this condition
MidiHastoBeSent)
The chord is stored in an array of tMidi of length 3, called
MidiChord.
52
10. Conclusion
10.Conclusion:
Weʼve got through the basics of scripting.
You should now have some understanding about how to create inlet-outlets, how to
access their data, and how to write simple scripts.
The next step would be to analyze the scripts ready-made in Usine or in the Add-Ons
library, to learn more.
If I have some time, Iʼll try to add some script analysis to this tutorial in the future.
May be itʼll be a little hard at the beginning, but with practice itʼll get simpler and simpler.
I hope this tutorial can help you and wish youʼll make some great scripts.
Benjamin Moussay
July 2009
53