You are on page 1of 53

USINE SCRIPTING TUTORIAL

BY BENJAMIN MOUSSAY
VERSION 1.00

Scripting language tutorial - version 1.00 - July 2009 1


Table of Contents

Table of content
1.Introduction: ...................................................................5
Acknowledgement: .................................................................................5

Why use scripts: ......................................................................................5

Limitations: ..............................................................................................5

2. Getting started: .............................................................6


A. Open a scripting window: ..................................................................6

B. Basic concepts: ..................................................................................8

3. Pascal basics: ...............................................................9


Notation conventions: ............................................................................9

Scripting language building blocks: ...................................................10

Variables: ................................................................................................10

Constants: ..............................................................................................10

Types: .....................................................................................................10

Precisions about types: ........................................................................11

Variable declaration: .............................................................................12

Constants declarations: .......................................................................12

Pascal specific keywords: ....................................................................13


I. Basic keywords: ...............................................................................................13

II.Loops: ...............................................................................................................14

1. The for loop: .........................................................................................14

2.The while loop: ......................................................................................14

III. Conditional statements: ................................................................................15

1. If then else: ............................................................................................15

2
Table of Contents

2.Case: .......................................................................................................15

Functions: ..............................................................................................16

Procedures: ............................................................................................17

Mathematical and logical operators: ...................................................18

4. Structure of a script: ...................................................19


Declaration of the inlets-outlets: ..........................................................19

Initialization procedure to build, define and initialize the inlets-


outlets: ....................................................................................................20
CreateParam: .......................................................................................................21

SetIsInput, SetIsOutput: .....................................................................................22

Scale, color, min and max and default values, displayed symbol, format: ...22

ListBoxes: ............................................................................................................24

Other procedures: ...............................................................................................24

Declaration of the global variables ......................................................24

Declaration of custom functions and procedures (optional): ...........25

Main procedure: .....................................................................................25

Summary of the script structure: .........................................................26

5.Arrays: ..........................................................................28
Array declaration: ..................................................................................28

Setting the length of an array: .............................................................28

Getting the length of an array: .............................................................28

Store a value into an array: ..................................................................29

Read a value from an array: .................................................................29

Loops and arrays: .................................................................................30

Multidimensional arrays: ......................................................................30

3
Table of Contents

6.Strings: .........................................................................34
7.Midi Codes: ...................................................................36
Definition of a midi code: .....................................................................36

The type TMidi: ......................................................................................36

Handling Midi data: ...............................................................................37

8.Accessing Parameters Data: ......................................38


Getting parameters data (reading inlets values): ...............................38
Parameters storing single values: .....................................................................38

Array parameters: ...............................................................................................39

Midi parameters: ..................................................................................................40

String parameters: ..............................................................................................40

Important function: GetLength() ........................................................................41

Setting parameters data (setting inlet or outlet values): ...................43


Single Values parameters: ..................................................................................43

SetLength procedure: .........................................................................................43

Array parameters: ...............................................................................................44

Midi parameters: ..................................................................................................45

Text parameters: ..................................................................................................47

Printing to the Usine message console: writeln ...............................................47

9.Global Scripting Strategies: ........................................49


The “tick” trick: ......................................................................................49

Midi tips and tricks: ...............................................................................50

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.

Why use scripts:


In Usine, you can resolve almost any problem using modules. But sometimes it can lead to
complicated or very repetitive patches, which can be very time consuming to change or
update.

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…

This is where the scripting language comes in useful.

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

Double click on the module, the scripting window opens:

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.

You also have a basic skeleton of the script structure:


• title
• Parameters declaration
• Initialisation procedure (surrounded by the keywords “begin” and “end”;)
• Global variables
• Main script procedure (surrounded by the keywords “begin” and “end.”).

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 *)

{$ this is also a multi-line comment $}

9
3. Pascal Basics

Scripting language building blocks:

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

Precisions about types:

• 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:

type TParameter // this is a “Parameter”, which means an inlet or


an outlet for your module.

type TScale = (lsLinear,lsLog,lsExp); // these are the diffent


possible scale values for parameters.

type TParamType = (ptTextField, ptChooseColor,ptMidi,ptGainFader,

ptAudio,ptDataField,ptDataFader,ptButton,ptListBox,
ptSwitch, ptArray, ptIpAddress, ptSmpte);
// these are the diffent available kind of parameters.

type TMidi = Record


Msg : Byte;
Data1 : Byte;
Data2 : Byte;
Channel : byte;
end; // this is a midi code.

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

D.Pascal specific keywords:

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

Important things about begin and end; :

• begin must always be “closed” by an end;


• One instance of begin always relate to the closest following end;
• One instance of end; always relate to the closest previous begin
• You always have a semicolon (;) after end excepted in the following
cases:
➡The last end of the script is followed by a dot.
➡In the if then else statement (see later in this chapter),
a instance of end preceding else is not followed by a
semicolon.

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

2.The while loop:


While condition do // condition is a Boolean
expression (like x<10, A AND b, y <> x, etc…)
Begin
// instructions
End;
Important: don’t forget to have somewhere in the while block some code that will
make the condition change after some time, else your loop will go forever, and you’ll
probably crash Usine!

14
3. Pascal Basics

III. Conditional statements:


Often, you’ll want a block of instructions to be processed only if a condition is true,
or if a variable has only certain values. These are two ways to achieve it:
1. If then else:
If condition then // condition is a Boolean expression
(like: x<10, A AND b, y <> x, etc…)
Begin
// instructions processed if the boolean is true
End // notice the absence of “;” after end!
Else
Begin
//instructions processed if the boolean is false
End;
When there is only one instruction to process, you can simply write for
example:
Var x, y : single;
If x<>0 then y:=1/x;

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.

• You can build your own functions, this way:


function function_name ( param1 : type ; param2: type ; … ;
paramN : type): type_of_result;
Var variable_name : variable_type; // here you declare
the local variables used in your function
Begin
// Here’s the code of your function, assign the result of
it to the variable Result
Result := ….;
End;

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.

• You can build your own procedure, this way:


procedure procedure_name ( param1 : type ; param2: type ; … ;
paramN : type);
Var variable_name : variable_type; // here you declare
the local variables used in your procedure
Begin
//Here’s the code of your procedure, nothing to assign to
result since a procedure doesn’t return any value
End;

17
3. Pascal Basics

G.Mathematical and logical operators:


• The scripting language contains all mathematical operators: +, -, *, /

• You can also use the usual logical operators:


<, >, =, <=, >=, <> (not equal), and, or, not
All these logical operators return a boolean value (true or false).

• 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.

All scripts have the same structure:

1. Declaration of the inlets-outlets (called “parameters” in


Usine)

2. Declaration of global variables and constants used

3. Creation and initialization of the Inlets-outlets

4. Main procedure (the main process of the script)

A.Declaration of the inlets-outlets:

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

B.Initialization procedure to build, define


and initialize the inlets-outlets:

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…

To do all this we use the following built-in functions and procedures:

20
4. Structure of a script

1.CreateParam:
// Create a new parameter, returns the parameter's number
function CreateParam(S1: string; s2: tParamType):TParameter;

This is the function you’ll use to actually create a parameter.


It accepts 2 arguments:
• S1 : string is the display name of your parameter, you have to put it
between single quotes (examples: ‘input 1’, ‘midi in’, ‘A’, etc…). Note that this is
the only place in the script where the display name of the inlet-outlet appears.

• S2 : tParamType is the type of your parameter. It’s value can be one of the
following:

type TParamType = (ptTextField,


ptChooseColor,ptMidi,ptGainFader,
ptAudio,ptDataField,ptDataFader,ptButton,ptListBox,
ptSwitch, ptArray, ptIpAddress, ptSmpte);

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:

Var InA : tParameter; // declaration of the parameter inA

Procedure init;
Begin
inA := CreateParam(‘A’, ptDataFader); // a datafader called
‘A’ is created and stored to inA
End; // end of the init procedure

You just have to remember that creating a parameter needs 2 steps:


• Declare the tParameter variable.
• Use the CreateParam function during the init procedure to actually create it.

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:

// set to true if the parameter has input port


procedure SetIsInput(Param: integer; val: boolean);

// set to true if the parameter has output port


procedure SetIsOutput(Param: integer; val: boolean);

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);

3.Scale, color, min and max and default values,


displayed symbol, format:

All the following procedures accept two arguments:


• Param : integer is the parameter name
• Val: depends on the specific procedure

These procedures allow you to define your parameters more precisely, if you need
to.

22
4. Structure of a script

// set the scale, if the param is a fader


procedure SetScale(Param: integer; val: TScale);

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 logarithmic scale:


SetScale(inA, lsLog);

// set the front color of the fader or on Color of the switch


procedure SetColor(Param: integer; val: integer);

By default, faders are blue, and on switches are yellow.

// set the off color only if the parameter is a switch


procedure SetOffColor(Param: integer; val: integer);

By default, off switches are grey.

// set min parameter value


procedure SetMin(Param: integer; val: single);
// set max parameter value
procedure SetMax(Param: integer; val: single);

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);

// set default param value, when created


procedure SetDefaultValue(Param: integer; val: single);

This sets the default value of the parameter. (the value the parameter will reset
to when you [ctrl-click] on it).

// set displayed symbol ie. 'ms','%'


procedure SetSymbol(Param: integer; val: string);

Example: inA is a fader and you want it to display milliseconds (ms)


SetSymbol(inA, ‘ ms’);

// set format string of the displayed value ie. '%g','%.0f','%.1f'


procedure SetFormat(Param: integer; val: string);

This sets the number of decimals displayed.


Example: inA is a fader and you want it to display zero decimals:
SetFormat(inA, ‘%.0f’);

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:

// set to true if the user can't modify value


procedure SetReadOnly(Param: integer; val: boolean);

// set to true to use a fast callback instead of the Windows


message processing
procedure SetFastCallBack(Param: integer; val: boolean);

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.

// specifies if the parameter need to be save in the patch or not


procedure SetDontSave(Param: integer; val: boolean);

F. Declaration of the global variables


Global variables are used all along the script.
You have to remember one thing:
A variable must have been declared before you can use it.
In practice, it is common to declare the variables you plan to use between the init
procedure and the main procedure.
But if you plan to use some variables inside the init procedure, you’ll have to declare them
before the init procedure.
If you need a variable only locally (for instance I for a loop, or inside a custom function or
procedure), then you can declare it just before the loop, function, or procedure code.

24
4. Structure of a script

G.Declaration of custom functions and


procedures (optional):
The syntax for declaring custom functions and procedures has been explained before.

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).

Itʼs syntax is:

Begin // beginning of the main procedure


// Here’s the code of the main procedure
End. // end of the main procedure and of the script (notice the
dot after this final end)

25
4. Structure of a script

I. Summary of the script structure:


To recap, this is the basic structure of a script:

// title

// parameters declaration
Var Parameter_Name : tParameter;
// other parameters declarations

// declarations of constants and global variables


Var Variable_Name : Variable_Type;
// other variables declarations
Const Constant_Name = Constant_Value;
// other constants 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;

// optional: declaration of more variables


Var Variable_Name : Variable_Type;
// other variables declarations

// declaration of custom functions and procedures


// they can also contain variable declarations
// you can use all variables and constants declared before
// you can have local variables with the same name as global variables
function function_name ( param1 : type ; param2: type ; … ;
paramN : type): type_of_result;
Var variable_name : variable_type;// local variables
// other variables declarations
Begin
// Here’s the code of your function
Result := ….;
End;
// other functions declarations

26
4. Structure of a script

procedure procedure_name ( param1 : type ; param2: type ;


… ; paramN : type);
Var variable_name : variable_type;//local variables
// other variables declarations
Begin
//Here’s the code of your procedure
End;
// other procedures declarations

// optional: declaration of more variables


Var Variable_Name : Variable_Type;
// other variables declarations

// 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.

Scripts are very useful to manipulate arrays.

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.

Var MidiValues : array of TMidi;


// this creates a table that stores midi codes.

Setting the length of an array:


Use the built-in procedure:

SetArrayLength(Array_name, length); // where length is an integer.

Example:
Var tab1 : array of integer;
SetArrayLength(tab1, 10); // declares an table containing 10
integers.

Getting the length of an array:


Use the built-in function:

GetArrayLength(array_name); // the result is an integer.

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.

Store a value into an array:


Remember that the values in an array are indexed from 0 to the length of the array minus
1.

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

To store values into an array just do:


Var tab1 : array of integer;
SetArrayLength(tab1, 4);
Tab1[0] :=1;
Tab1[1] :=4;
Tab1[2] :=3;
Tab1[3] :=12;
// this stores the values (1,4,3,12) into the table.

You can also store values this way:


Var tab2 := array of single;
Tab2 := [1.2 , 2.23 , 4 , 5.1];
// this stores the values 1.2 , 2.23 , 4 , 5.1 into the array.
// Notice the commas to separate values

Read a value from an array:


To read a value from an array just do:
Var x : integer;
X :=tab1[2];
// this stores to x the value of the third element of the array.

Of course, the index between brackets can be a variable, for instance:


Tab1[i];

29
5.Arrays

Loops and arrays:


Sometimes itʼs convenient to go through the whole array to read or store values.
To do this, you can use the for loop.

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.

You can simply do it this way:

Var tab1 : array of integers;


Var i : integer;
For i :=0 to 49 do
Begin
Tab1[i] := i+1; // stores the value i+1 to the ith element
End;

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:

For i:=0 to NbOfMidi-1 do


Begin
// here you do the processing on MidiInArray[i] (the ith
note)
End;

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.

This is actually an array (row) of arrays (columns). It has two dimensions.

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.

Letʼs create a two dimensions array of integer:

Type tMode : array of integer;


Var MajScaleModes : array of tMode;
Var ionian, dorian, prhygian, lydian, myxolydian, aeolian,
locrian : tMode;

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

Important note about TYPES:


• A common error when scripting is the type mismatch.

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);

would return an error, since GetValue(inA) is by definition a single,


and x is declared as an integer (which is not stored in memory with
the same structure).
There is so to speak not enough room in x to store the single value.

• You have to be careful about the size of the types of variables:


For numerical values, these are the types you can use from the largest to the
smallest:
extended, double, single, longint, int, byte

• 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.

Round(val) ; // this converts extended, double or single to


integer.

IntToString(i: longint): string; // this converts a number


into a string of characters (that means that InToString(1423)
is no more the number 1423, but a string containing the
characters ‘1’, ‘4’, ’2’, ‘3’)

StrtoInt(s: string): longint ; // does the opposite

FloatToStr(e: extended): string; and StrToFloat(s: string):


extended; // those are the same as before, but for floating
point numbers.

32
5.Arrays

• You can also built your own type conversion function.


Example:
Letʼs build a function to convert an integer to a boolean.
If the integer is equal or larger than 1, the boolean is TRUE, if the
integer is 0 or less the boolean is FALSE:

Function IntToBool(i: integer): boolean;


Begin
If i>=1 then result := True
else result := False;
End;

Now we can call our function:


Var x : integer;
Var y : boolean;
x := 9;
y := IntToBool(x); // this will set y to TRUE

N.B. We could also have written our function with a more compact
code:

Function IntToBool(i: integer): boolean;


Begin
result := (i>=1);
End;

• About switches and buttons:


Switches, and buttons can by definition only have values of 0 or 1, these
0 and 1 are considered as single when you access the switch or button
with GetValue.

33
6.Strings

6.Strings:
The string type is used for processing text.

It is simply a particular kind of array: an array of char.

Remember that char is the type used to store characters (any of the 256 character of the
ASCII table).

You can use the following built-in functions to manipulate strings:

function inttostr(i: Longint): string;


// converts an integer to a string

function strtoint(s: string): Longint;


// the opposite

function strtointdef(s: string; def: Longint): Longint;


// Converts s to a number. If s doesn't represent a valid number, def
is returned instead.

function copy (s: string; ifrom, icount: Longint): string;


// returns a part of the string s, ifrom is the position from where the
copy starts, icount is the number of char to be copied.

function pos(substr, s: string): Longint;


// returns the position of a substring into a string (kind of search
function)

procedure delete(var s: string; ifrom, icount: Longint);


// same as copy, but deletes a part of the string s

procedure insert(s: string; var s2: string; ipos: Longint): string;


// inserts the string s2 into the string s at position ipos

Function StrGet(var S : String; i : Integer) : Char;


// returns the char of index i

procedure StrSet(c: Char; I : Integer; var s : String);


// sets in the string s the character of index i to the value c

Function Uppercase(s: string) : string;


Function Lowercase(s: string) : string;
// no comment

Function Trim (s: string) : string;

34
6.Strings

//Removes leading and trailing spaces and control characters (ie ASCII
0-32) from s

Function Length(s: String) : Longint;


// Returns the length of the string (equivalent of GetArrayLength for
arrays)

procedure SetLength(var S: String; L: Longint);


// Sets the length of the string (equivalent of SetArrayLength for
arrays)

Function FloatToStr(e: Extended) : String;


// Turns a extended number to a string

function StrToFloat(s: string): Extended;


// Opposite

Function Padl (s: string;I : longInt) : string;


// Puts i spaces before s

Function Padr (s: string;I : longInt) : string;


// Adds as many spaces needed to make a string of length i

Function Padz (s: string;I : longInt) : string;


// Is similar to Padl, but adds zeroes instead of spaces

Function Replicate(c: char;I : longInt) : string;


// Builds a string containing i times the character c

Function StringOfChar(c: char;I : longInt) : string;


// Creates a string where the character c is repeated i times

N.B: Always use single quotes when directly manipulating string or char types.
Example:

Var MyString1, MyString2, MyString3 : string;


Var char1 : char;
MyString1 := ‘Hello’;
MyString2 :=‘how are’;
MyString3 := MyString1 + ‘ ’ + MyString2 + ‘ ’ + ‘you?’;
// MyString3 now equals ‘Hello how are you?’
Char1 := ‘h’;
StrSet(Char1, 0, MyString1);
// MyString1 now equals ‘hello’ (lowercase h)

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):

• The Message value (msg):


It can be NOTE ON (144), NOTE OFF (128), CONTROL CHANGE, PITCH
BEND, PROGRAM CHANGE, SYSEX, etc.
Itʼs basically the nature of the midi message.

• The Data1 value :


It depends of the message value (for instance for a NOTE ON message,
data1 contains the pitch value (0-127, note C3=60).

• The Data2 value:


It also depends on the msg value (for instance for a NOTE ON message,
data1 contains the velocity value (0-127, 0=silence, 127= loudest).

• The Channel value:


It says on which midi channel the message is sent.

The type TMidi:


To deal with the multiple-value Midi message, Usine Script has a built-in type defined as
follows:

type TMidi = Record


Msg : Byte;
Data1 : Byte;
Data2 : Byte;
Channel : byte;
end;

Tmidi is a data structure used in Pascal called record.

A record is a variable containing several “sub-variables”.

Or you can see it as several variables all grouped under a common name.

36
7.Midi Codes

Handling Midi data:


Letʼs declare a midi variable:

Var Midi1 : TMidi;


// Midi1 will store a Midi message

To access the different values of the Midi1 message do like this:

Var m, d1, d2, c : byte;


m := Midi1.msg;
d1 := Midi1.data1;
d2 := Midi1.data2;
c := Midi1.channel;
// the different values of Midi1 are stored to m, d1, d2, c.
// notice the dot between Midi1 and it’s values, this is how you
access a record’s subvariables.

Example 1 - create a Note On message:


Letʼs store in Midi1 the message ( NOTE ON, note=C3, vel=90, channel=1):
Var Midi1 : TMidi;
Midi1.msg := 144; // Note ON
Midi1.data1 :=60; // C3
Midi1.data2 := 90; // vel 90
Midi1.channel :=1; // Channel 1

Example 2 - transpose:
Letʼs transpose Midi1 an octave higher:
Midi1.data1 := Midi1.data1 + 12;

Example 3 - arrays of midi codes:

If we have an array of Midi codes, itʼs the same:

Var TabMidi : array of TMidi;


TabMidi[3].msg := 148;
TabMidi[3].data1 := 60;

Etc…

37
8. Accessing Parameters Data

8.Accessing Parameters Data:


Until now weʼve seen the basics of Pascal, how to create inlets-outlets for our script
module, how to deal with arrays and midi.

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:

A.Getting parameters data (reading inlets


values):

Remember the types of parameters you can create with Usine Script:

• ptTextField
• ptChooseColor
• ptMidi
• ptGainFader
• ptAudio
• ptDataField
• ptDataFader
• ptButton
• ptListBox
• ptSwitch
• ptArray
• ptIpAddress
• ptSmpte

Letʼs look closer at these different types:

I.Parameters storing single values:

Those parameter store single numerical values:


ptChooseColor,ptGainFader,ptAudio,ptDataField,ptDataFader,pt
Button,ptListBox, ptSwitch

38
8. Accessing Parameters Data

To read the values of these parameters, youʼll use the function:

function GetValue(Param: integer): single;

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 inA : tParameter;


// we declare the variable inA as a parameter
inA := createParam(‘A’, ptDataFader);
// we create the inlet, display name “A”, type datafader
SetIsOutput(inA, false);
// inA has an inlet (no outlet)

Letʼs declare a variable x

Var x : single;

To store the value of the fader “A” to x, we simply do:

x := GetValue(inA);

II.Array parameters:
ptArray, ptIpAddress, ptSmpte

For these parameters you need another access function:

function GetDataArrayValue(Param, i: integer):single;

It accepts 2 arguments:
•Param is the parameterʼs name
•i is the index

It returns a single value.

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

Midi flow is considered as an array of midi messages.

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.

To access midi codes youʼll use the procedure:

procedure GetMidiArrayValue(Param,I: integer; var val:TMidi);

It accepts three arguments:


• param is the name of the parameter we want to access
• I: integer is the index (donʼt forget the minus 1 since arrayʼs indexing starts
from 0)
• var val:TMidi is the tMidi variable to which the result will be stored

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

To read a string, just use:

function GetStringValue(Param: integer;) : string;

It has only one argument:


•param : integer is the name of the parameter. The result is a string.

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

You can check Chapter 6.Strings to learn how to manipulate strings.

V.Important function: GetLength()

Hereʼs a crucial function to deal with parameters:

function GetLength(Param: integer):integer;

It has one argument:


•param : integer is the name of the parameter.

It returns an integer.

This function has several purposes:

1.Checking if the inlet receives any data:


If nothing is connected to an inlet, or if it doesnʼt receive any data, then Usine
considers the length of the message to be 0.

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.

2.Getting the length of arrays for array inlets, the


number of midi codes for midi inlets, the length of a
string for a text inlet:
Letʼs say we have a array inlet called ArrayIn.

It can receive an array of any length up to 512.

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

Len := GetLength(ArrayIn); // we store the length of


ArrayIn to the variable len
For I := 0 to len-1 do //loop for each element of ArrayIn
Begin
Tab1[i] := GetDataArrayValue(ArrayIn, i); // use
the GetDataArrayValue function to store each of the
elements of ArrayIn to Tab1
End;

For midi codes, itʼs the same.

Itʼs unlikely we can guess in advance how many midi codes will be present at a
midi input.

But the function GetLength will tell us.

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:

Var TabMidi : array of TMidi; // we declare an array of Midi


codes
Var len, i: integer;
Len := GetLength(MidiIn);
For I := 0 to Len-1 do
Begin
GetMidiArrayValue(MidiIn, I, TabMidi[i]); // note the
the difference of syntax with the array example since
GetMidiArrayValue is a procedure and not a function.
End;

42
8. Accessing Parameters Data

B.Setting parameters data (setting inlet or


outlet values):
Here weʼll use procedures (not functions since the fact to set a parameterʼs value can not
return any result)

These procedures are quite similar to the functions used before.

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.

Let’s detail these procedures for all kinds of parameters:

I.Single Values parameters:


ptChooseColor,ptGainFader,ptAudio,ptDataField,ptDataFader,pt
Button,ptListBox, ptSwitch

The procedure is:

procedure SetValue(Param: integer; val: single);

It has two arguments:


•Param is the name of the parameter
•Val is the value (single).

Example:
Letʼs say you have a data outlet called Out1.
Letʼs send send the number 10 to out1:

SetValue(Out1, 10);

You can also send a variable (it must be a single) or an expression:

Var x : single;
SetValue(Out1, x);
SetValue(Out1, x+2);

II. SetLength procedure:


This procedure is the opposite of the GetLength function:
procedure SetLength(Param: integer; val: integer);

It has two arguments:


•Param is the name of the parameter
•Val is the length (integer).

43
8. Accessing Parameters Data

When the length of the message sent to a parameter is 0 then this parameter sends
nothing.

If the parameter contains a value, the length is positive.

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.

III. Array parameters:


Here the procedure is:
procedure SetDataArrayValue(Param, I: integer; val: single);

It has three arguments:


•Param is the name of the parameter
•i is the index (integer).
•Val is the value (single)

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:

Var ArrayTemp : array of single; /array to store the data from


ArrayIn
Var I, len: integer;

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)

For i:= 0 to len-1 do // loop for all indexes


Begin
ArrayTemp[i] := GetDataArrayValue(ArrayIn, i);
// store the ith element of ArrayIn to the ith element of
ArrayTemp

SetDataArrayValue(ArrayOut, I, Arraytemp[i]);
// send the same element to ArrayOut
End;

44
8. Accessing Parameters Data

IV.Midi parameters:

The procedure is:

procedure SetMidiArrayValue(Param,I: integer; val: TMidi);

It has three arguments:


•Param is the name of the parameter
•i is the index (integer).
•Val is the value (TMidi)

Itʼs the exact opposite of GetMidiArrayValue.

Example:
Letʼs say we have a midi output called MidiOut.
Letʼs send a NOTE ON, C3, vel 95, channel1 to it:

Var MidiNote : TMidi; // declare the note variable


MidiNote.msg := 144; // Note ON
MidiNote.data1 : =60; // C3
MidiNote.data2 := 95; //Vel 95
MidiNote.channel := 1; // Channel 1

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

Warning about midi codes.


In general when you send a midi code, you want it to be sent as an impulse
(not continuously).

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.

Thus you would be sending the note continuously.

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)

Example of sending a single midi note:

If (condition_to_process_and_send_midi_is_true) then
begin
// Here are instructions to process midi

SetMidiArrayValue(MidiOut, 0, MidiNote); // Store the note


to midi out
SetLength(MidiOut, 1); // actually send the note
End

Else
begin
SetLength(Midiout, 0); // “close” the output, so that the note
is not isn't sent once for each cycle
End;

Youʼll have more examples about Midi in chapter 9.

46
8. Accessing Parameters Data

V.Text parameters:
No surprise here, the simple procedure to send a string is:

procedure SetStringValue(Param: integer; val: string);

It has two arguments:


•Param is the name of the parameter
•Val is the string to send (String)

Example:
We have a text field output in our script, called TextOut.
Letʼs send the word “hello” to it:
SetStringValue(Textout, ‘Hello’);

VI.Printing to the Usine message console: writeln


Sometimes youʼll need to have a visual feedback of whatʼs happening inside your script,
either for debugging, to follow the status of a variable during the script, or for any other
reason.

The procedure:

writeln(string);

will print the string to Usineʼs console.

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

//this will display the number 10 in Usine’s console

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

9.Global Scripting Strategies:


One of the key concepts when scripting is to control how often the script will be
processed.

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…).

The “tick” trick:


A good general strategy is to create a button inlet (call it “tick”, or “process”, or “has
changed”, or whatever), and to have the main part of the script processed only when this
inlet receives an impulse.

This is how to do it:

// example of a tick inlet


Var tick : tParameter; //here we declare the “tick” inlet
parameter
// here you declare the other parameters you need

Procedure init;
Begin
Tick := CreateParameter(‘tick’, ptButton);
SetIsOutput(tick, false);
//creation of the “tick” inlet, it’s button, it’s an input

// here you create the other parameters


End; // end of the init procedure

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

This is a basic strategy I use in many scripts.

Midi tips and tricks:


For midi scripts, here are a few things you have to know:

A midi flow is by definition not continuous, but made of discrete impulses.

One midi message, then another one, etc… (unlike audio which is continous).

Of course several messages can be present simultaneously (a chord, several CCs


moved at the same time).

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.

This is how to do it:

// midi script example

Var MidiIn : tParameter;


Var Midiout : tParameter; // we declare our midi in an midi out
// here you can declare other parameters

Procedure init;
Begin
MidiIn := CreateParam(‘Midi In’, ptMidi);

50
9.Global Scripting Strategies

SetIsOutput(MidiIn, false);

MidiOut :=CreateParam(‘Midi Out’, ptMidi);


SetIsInput(MidiOut, false);

// We have Created our midi input and output, you can now create your
other parameters

End; // end of the init procedure

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)

If NbOfMidi >0 then // check if any message is present


Begin
For i:=0 to NbOfMidi-1 do // loop to process each incoming message
Begin
// here you do your midi processing
End; // end of the for loop to process each incoming midi message
Setlength (MidiOut, NbOfMidi); // we actually send the codes to MidiOut
End // end of the if (if there are no incoming message the script jumps here)
Else
// the next block will be processed only if there are no incoming midi messages
Begin
SetLength(MidiOut, 0);
// we make sure we do not send anything to midi out
End;
End. // end of the main procedure and end of the script

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.

Var MidiNote : tMidi;


Var i : integer;
If (MidiHasToBeSent) then
begin
For i:=0 to 2 do
Begin
MidiNote := MidiChord[i];
// we store the current note into MidiNote
SetMidiArrayValue(MidiOut, I, MidiNote);
// we send the current note to MidiOut
End; // after the loop, MidiOut contains the chord
SetLength(MidiOut, 3); // we actually send the chord
End
Else // in the case MidiHasToBeSent is false
Begin
SetLength(MidiOut, 0); // we make sure nothing is sent
End;

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.

Then the best thing to do is to start writing scripts.

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

You might also like