Scripting Basics

Scripting is one of the most powerful, but least understood aspects of the ecue Programmer software. Although it can’t do everything, it expands the flexibility to a huge degree and adds an amazing array of options in terms of providing conditional logic for timing (very helpful in situations like room partitioning) and allowing for custom written effects.

The scripting language built into the Programmer is based on C. It is very important to note that, though it is based on C, it is not a full implementation of C. Reading some C tutorials online will go a long way toward helping you understand programming in the ecue environment (and it is highly reccommended to do so), just remember that there are some significant differences. Before I get started into how to program, I’ll provide a few bits of important info first. Don’t worry if you don’t understand what it means, you will find explanations below.

 

Major differences from C programming

  • There are only 2 data types: int and string. int can hold only whole integers
  • There is no need for a main function all code is executed from top to bottom
  • There is no such thing as a pointer
  • Variable scope is handled differently from normal C. This will be explained later
  • There are no headers or separate function prototypes. Variables and functions are declared in place.
  • Functions are restricted to returning only the int type.

Resources

There are several places that help you find valuable information on scripting. I use all of them on a regular basis. In fact, I usually have them all at my fingertips any time I am working on any significant programming to do.

  • Pressing CTRL + SPACE at any time in the script editor windows will bring up an auto-complete list of e:script commands. If you haven’t started typing anything yet, it will list all commands. Pressing it after you’ve entered a few letters will start all commands starting with the letters you’ve typed.
  • The e:script help file lists out all of the commands, and while it doesn’t always answer 100% of your questions, it is very valuable.
  • The “System Manual Advanced” help file contains an entire section on e:script that does a great job explaining how to use the language, as well as many code examples that are extremely helpful at showing how all the pieces fit together.
  • The forum on the ecue website is filled with questions and answers. If you have a question that you can’t find the answer to, ask it here and the responses generally come fairly quickly.
  • Probably the most overlooked resources on e:script is the e:script wizards built into the programmer. Go to Wizards/e:script wizards, navigate to a script, right click and choose “edit with external editor” and the script will be opened in notepad. You can copy and paste the text into a new script in the programmer and play with it all you want. These are great for using as a basis for something you want to do, but reading code written by others is also one of the best ways to learn how to program.

Foundations

In order to understand any programming language, it is an absolute must to understand a few specific concepts that I will be introducing. These concepts are applicable to virtually every modern programming language, although the implementation may have been different.

These concepts are:

  • Statements
  • Blocks
  • Variables & Data types
  • Operators
  • Conditional Logic
  • Loops
  • Comments
  • Functions

 

Statements

Programming languages are very similar to human languages in many ways, and for good reason. The purpose of any type of language is to provide a set of rules and structure so that the listener (in our case, the computer) can understand what you are trying to say. In the programming world, a statement is somewhat equivalent to a sentence. A statement generally should have a single major goal.

In e:script, every statement must end in a semicolon, which is like a period in western language. The semicolon lets the interpreter know that the statement is finished.

Here is a few examples of statements:

x = 1;
x = x + 2;
StartCuelist(5);

In e:script, you can put as many statements on a line as you wish, but it gets confusing very quickly if you try to have more than one per line. Unless you have a good reason, it is wise to start a new line after a semicolon.

Blocks

Blocks are a grouping of statements, which are inside a set of {curly brackets} which can basically act as a single large statement. You will see why these are important when we get to conditional logic and loops a little bit further down.

Variables

If you’ve ever taken an algebra class, you’ve worked with variables. A variable is simply a named chunk of space set aside for you to store information in. In order to set the space aside and name it, you must peform a variable declaration, which looks like this:

int x;

This has created an integer variable named x for us to use. Now that it has been created, we can set it to any integer value we’d like:

x = 1000;

You can also declare a variable and assign it a value at the same time:

int x = 50;

You can use multiple variable, and even refer to the variable you are changing:

int x = 5;
int y = 10;
x = x + y;

Can you tell what the value of x is at the end of this code snippet? As you would expect, you would be adding 5 and 10 together, getting 15. If you added another x = x + y, what would you end up with? The answer is 25, because you take the value 15 you got from the addition, and again add the value of y(10) to it.

For those who really want to know, an e:script int is a 32 bit signed integer, which basically means that it can be any whole number between -2,147,483,647 and 2,147,483,647.

Now that you’ve been introduced to the int variable type, I should also explain the string type. A string allows you to store a string of text. Because text can include spaces, we need some way to know where the beginning and end of the string is. To do this we use quotation marks. Here is how you declare and assign a string:

string myString = "This is my new string";

When you add two strings together, the first is simply exteded with the second. Fore example,

string string1 = "This is a ";
string string2 = "complete sentence.";
string cs = string1 + string2;

The outcome of this would be a string variable named cs with the value “This is a complete sentence.”

It should be noted that all code in escript (and most, but not all programming languages) is case sensitive, which means X and x are two different variable names, so it is very important to keep track the case you use to name variables.

One other aspects of strings that is important is called an control characters. Control characters allow to to add a few special character types into your string. There are 4 control characters in e:script

  • \n – New line
  • \\ – Backslash
  • \” – Quote
  • \r Return
The most often used control character is the new line, which is exactly what it sounds like. It is the equivalent of pressing the enter button at the end of a line of text. When you print a line to the log window, anything you print will keep adding on to the end of the line until you use a \n. Here is an example of how that works:
string s = "This prints on line 1 \n And this prints on line two\n";

The backslash control character exists so you can add backslashes without confusing the interpreter, and the Quote control character is used to allow you to add quotation marks, since a quotation mark normally marks the end of the string.

Variable Scope

The scope of a variable basically defines what parts of a program can access a variable and how long it lasts. With most variables, they will only be accessible only within the script you are running, and only exists until that script stops running. Also, variables declared inside a function (you will learn about functions later) only exist with that function, but functions can access variables that were defined elsewhere in the script.

Why would we want to have such limited access to our variables? The first reason is because of namespace. Say you want to use the variables x and y to mark a position. If there is another script that wants to use those, then there is the potential for the two scripts to interact in unknown ways. By compartmentalizing, we are able to re-use variable names where it makes sense. The second reason is limited resources. Most of the time you only need to store information temporarily while you process data, and once the processing is done the data can go away. If we didn’t let the data go away, memory use would constantly increase until the program crashed because it ran out of memory.

There are situations where you want to keep information stored for a long time, or you want different scripts to be able to work with the same variable. For these special cases you want to use what is known as a global variable. A global variable is accessible in any context, and is not destroyed when a script ends. To declare a global variable in e:script, you must simply start the variable name with a n underscore:

int _myglobalvariable = 5;

Once you do run this, the variable is declared and usable until the Programmer is reset.

Once a variable is declared, it should not be declared again until it has been destroyed by the script or function ending, or in the case of global variables, when the Programmer has been reset. If you try to re-declare a variable that is already being used you will get an error. There are ways to see whether or not a variable exists so that you can declare it only if you need to. This will be discussed later.

Operators

An operator performs an action on one or more operands. For example, in math there are the addition (+) and subtraction (-) operators among others. in the following statement:

x = 1 + 2;

We have a two different actions happening: the first operation is that the operands 1 and 2 are added together via the + operator. That value is then assigned to the variable x via the = operator. It also shows the two different types of operators: binary operators and assignment operators. Binary operators create a new value (1 + 2 creates a value of 3), while assignment operators assign that value to something (x = 3 assigns the value of 3 to the variable x).

Here is the list of operators available in e:script (with some of the less common ones removed because they can be confusing, and are not 100% neccesary).

  • < less than
  • > greater than
  • <= less than or equal to
  • >= greater than or equal to
  • == is equal
  • != is not equal
  • % modulo (Very useful in certain situations, it returns the remainder of a division operation)
  • + add
  • – subtract
  • * multiply
  • / divide
  • & AND
  • | OR
  • ! Not
  • = Equals (the only assignment operator we will be discussing)

+, -. /, and * are pretty self explanatory. They simply produce the value of their corresponding operations.

= is an assignment operator, and this is an important concept to understand. = can only be used to assign a value to a variable ( as in x=5;) when you want to ask the question “is x equal to 5?”, you use the double equals sign, which is  a boolean operator. Boolean refers to a binary value, a value that has a state of either true or false.

The boolean operators (>, <, &, ==, !=, <=, and >=) all create binary values (ie True, or False aka 1 or 0).

For example 5>2 would result in a True(1), because 5 is indeed larger than 2, which isn’t all that interesting of information, once you start linking multiple operators together and variables together you can start seeing more power behind these binary operators. For example:

int x = 15;
int y = (x > 1) & (x < 10);

Here is how this breaks down, step by step.

15 is assigned to the variable x

It is true that x(15) is greater than 1, so the first operand of the & operator is True(1)

It is false that x(15) is less than 10, so the second operand of the & operator is False(0)

It is false that The left operand AND the right operand of the & operator are true, so the value is False(0)

We now assign that False value to the variable y.

Don’t worry, you don’t have to worry about all that constantly, it’s just an explanation of how it works internally, and it will help you gain a better understanding of conditional logic in the next section.

Conditional Logic

Conditional logic is what allows us to make decisions based on data. Basically, what it allows us to do is create statements such as “If x is true then do this, otherwise do that”. Conditional logic is really the heart of programming. Rather than trying to get too detailed in theory, let’s just jump in with some code to start us off.

if (x == 5) y=y+1;

This should seem pretty straightforward. The literal meaning is “If it is true that x is equal to 5 then add one to the value of y”. Notice that the “question” part of the statement is inside parentheses. In an “if” statement, this will always be the case, otherwise you will get an error. Also notice that after the question comes another statement which is executed if the “question” is true. This brings us to the blocks that we mentioned earlier. In most cases, after an if statement, you’ll want to perform more than one action. In this case, you’ll want to use a code block to create a group of statements:

if (x == 5) 
{
  y = y + 1;
  StartCuelist(QL(y));
}

This code basically does the same thing as the previous but adds a statement that, after incrementing y, plays cuelist y as well. Within the curly brackets you can place as much code as you want and the entire block with be executed if (and only if) x==5 returns as true. For ease of readability, I generally use a block with all if statements, since it clearly delineates that the code inside is being executed conditionally. Note that the curly bracket does not need a semicolon at the end of it, as the bracket itself marks the end of the series of statements.

The “question” part of the statement can be as complex as you need it to be, and you can take any amount of variables into account as long as the code is valid and provides a true or false in the end. For example:

if ((a==1) & (b>3) & (c<=10))
  {
    printf("Do something cool\n");
  }

By now, I’m sure you can read this as “If a is equal to one and b is greater than 3 and c is less than or equal to 10 then execute the code inside this block”. I don’t think that there’s too much need of an explanation beyond that.

 

The last piece of the puzzle for the if statement is “else”. else allows you to execute a different set of code if the “question” returns a false value. It is used like this:

if (x==5)
 {
   printf("x is equal to 5");
 }
else
 {
   printf("x is something other than 5");
 }

Again, this should be pretty self explanatory and I don’t think it needs much more in the way of explanation.

The “if” statement has the ability to cover all of your conditional logic needs, although there are tools such as the “switch” statement that can streamline your code in certain situations. I’ll leave this up to you to learn about in the e:script help file.

Loops

Loops are yet another vital concept in programming, and paired with conditional logic, what makes computer programming so powerful. A loop is simply a section of code that repeats. There are basically two different kinds of loops: those that repeat indefinitely until a certain condition is true and those that loop a given number of times (although technically, even in this case, the loop repeats until the condition of having reached the maximum number of iterations is true).

We’ll start with the simpler “while” loop:

while (IsCuelistPause(QL(3)))
{
  x = x+1;
}

This code will continually repeat until cuelist 3 is no longer paused, incrementing x by one each time. You could feasibly add a bit of code to delay each loop by one second and then you would be able to use x later to, say, report how many seconds cuelist 5 was paused. In a while loop, you can use any code that you would  in an if statement.

Now, a bit more complex, but probably the more used loop is the “for” loop. This one looks a bit more daunting, but once you understand it, it isn’t too bad. The for loop allows you to loop a given number of times. Say you want to start 10 cuelists in one shot:

int i;
for (i=1; i<=10; i++)
 {
   StartCuelist(QL(i));
 }

Inside the parentheses, we have a series of statements that may look a bit confusing, but it’s actually farly simple. There are 3 statements broken up by semicolons. The first (i=1) simply sets a “counter variable”, in this case i, to start at 1. The second (i<=10) just says that we will keep looping as long as x is less than or equal to 10 and the third statement (i++) says that after each loop we’ll increase the value of i by one. ++ is an “incrementor” which can be used anywhere in your code on an integer variable to add one to a value.

Putting that all together, the who structure says “we’re going to start i at 1 and keep adding one until we get to 10” inside the loop, we use i to decide which cuelist to play. When all the loops are completed, we have started cuelist 1 through 10 in less time than it take you to blink.

Again, each of the statements can be replaced with any valid code. For example, instead of “i++”, you could say “i=i+2” and we would increment i by 2 after every loop, causing every other cuelist between 1 and 10 to start.

You may also note that the loop above could be acheived bye doing this:

int i;
i=1;
while (i <=10)
{
  StartCuelist(QL(i));
  i = i + 1;
}

As you learn to program, you will come to find that there are often many different ways to do anything, and many times the choice is based purely on your preferences. In this case, the for loop makes more sense based on the fact that it makes it uses less code to construct and it makes it clear that you are creating a loop that will repeat a specific number of times, but it makes more sense for you to use the while loop, then feel free. Writing in code is very much like any human language, each person will express the same thing in different ways and there is nothing right or wrong about that.

Comments

As I said in the paragraph above, everyone has their own approach to solving a problem, both in spoken language and in computer code. Something important to remember is that while you’re working on a section of code and you have it in your head, it will generally seem pretty obvious what that code means. When you come back to it a month later to add new code or fix a bug you’ve come across, you’ll find that it may be very difficult to decipher what exactly you were trying to do. Even worse, someone else may become responsible for maintaining your code and they may  have no idea what you were trying to do.

To solve these issues we have comments which allow you to write an explanation in English (or any other language) directly in your code. Typically you’ll have a comment at the beginning of a script explaining the purpose of the script itself plus one before each section of code explaining what that section does. You want to make sure that you comment enough for another person to understand it without going into unnecessary detail. It is a bit of an art to find the right balance.

While C has two different kinds of comments (block comments and single line comments), e:script supports only single line comments which start with a double front slash: // Anything after this will be ignored by the interpreter until you start a new line.

//This script starts cuelist 1
StartCuelist(QL(1));

I’d like to note that if there is a comment on the first line of an e:script, it is displayed in the “comment” column in the script window of the e:cue Programmer.

Also, when you are troubleshooting, “commenting out” a line of code is often helpful to bypass it without deleting it to help you trace down the source of an error.

Thorough commenting is one of the hardest lessons to learn in programming, but trust me, if you don’t do it, it will come back to bite you when you are trying to troubleshoot.

Functions

The last core concept of programming that I have to talk about are functions. I had a hard time coming up with a good description of a function, so I will steal a quote from the wikipedia entry: “[Functons are] a portion of code within a larger program that performs a specific task and is relatively independent of the remaining code.”

Basically a function exists for three reasons:

 

  1. They allow you to be more descriptive in your coding
  2. They allow you to abstract complex code
  3. They prevent you from writing the same code multiple times

Here is an example of a function:

 

function startcuelists(int firstCL, int lastCL)
{
  int i;
  for (i=firstCL; i<=lastCL; i++)
    {
      StartCuelist(QL(i));
    }
  return lastCL-firstCL+1;
}

We’re starting to get a bit more complex here, but it’s still not too bad. Let’s break it into small peices so we can see what’s going on. Declaring a function is fairly similar to declaring a variable, so first you start with the word “function”, which tells the interpreter that we’re creating a new function. This is followed by  in this case by the name startcuelists. The name can be anything you want as long as it’s valid (starts with a letter and includes only numbers and letters and underscore) and it isn’t the same name as a built in function. Then, in parentheses, you define parameters which are variables that are passed to the function when it is called. You can define as many parameters as you need, or if you don’t need any, you can just leave the parentheses. You can also pass strings in addition to integers.

This function does the same thing as we did earlier in the for loop section, except it lets us use it multiple times while only having to write the code once and it’s no longer hard coded to start only cuelists 1 through 10, you can now define the first and last cue when you use it. In order to use it, all we have to do now is call it like this:

startcuelists(1,10);

This will run the code within the function, setting firstCL to 1 and lastCL to 10, starting each of the cuelists. It can be called as many times as you want without having to rewrite all that code.

Finally, there is that return statement at the end, which returns a value back to the calling statement. In this case it calculates the number of cuelists you asked to start. This means that you can use the value of a function anywhere that you would have used a variable before. For example:

int numOfCL = startcuelists(3, 8);

This would start cuelists 3 through 8 and set the value of numOfCL to 5 because we started 5 cuelists.

Unfortunately, in e:script, it is not possible to return a string, although you can have a string defined outside of the function (variables defined within the function are not accessible from the rest of the script) when you set withing the function and then check after calling it.

Writing and Using scripts

The Macro Window

You can open the macro (e:script) window can be accessed by clicking on the scroll icon at the top of the main programmer window, pressing Shift+F2, or View/e:script Macros.

The icons along the top of the window are pretty self explanatory, and will display their function if you hover over them.

The left side of the window will show a list of scripts that are loaded into the show file. Double clicking on the name of a script will cause it to execute. Double clicking the the comment area will open it in the script editor window.

The right side of the window will display scripts that are being run in the background. Background scripts are a subject for an advanced tutorial and will not be discussed here.

The Script Editor Window

The script editor window is very simple and basically just shows line numbers down the left side and a text entry area on the right. To write your code, you simply type it into this window like it was notepad.

You’ll notice that as you enter the code, the text is automatically color coded to help make the code clearer.

Probably the most helpful thing that you will learn from this tutorial is CTRL+SPACE. In the code editor, this key combination will trigger the auto-complete menu. If you press it without starting to type something it will display a list of all built in commands, but if you start to enter something, it will list all commands that start with the text you have entered. This is extremely helpful for reminding yourself the exact name of a command or making sure that you get the capitalization correct.

When you’re writing your code, you cannot execute it until you’ve saved and closed the script. The shortcut for this is CTRL+ENTER.

Using your scripts

Scripts can be started from the macro window, but in most cases you want your script to start as some part of an automated action, either from the trigger engine or as a part of a cue. Anywhere that you can perform an action, you can select the “Call Macro” action and choose your script from the “Name” drop box.

Important e:script commands

There are dozens of built in commands in the e:script language, and they are fairly well documented in the help files included with the Programmer software. I would like, however, to highlight a few that you will likely use on a regular basis. I definitely recommend keeping the help file open for reference at all times while you are writing your code. You’ll find that you’ll memorize a certain number of commands, but you’ll want access to the documentation to make sure you have the parameters correct and such. I always work with a reference handy myself.

printf

The printf command will print text to the main log window of Programmer, which is helpful both in providing information to the user and printing out values to help you debug your code. A printf looks like this:

printf("This is %d %s \n", 1, "complete sentence.");

The parameters of a printf command consist of the string that is to be printed, which can include codes to print strings and integers, followed by the strings and integers to be used. Remember that the “\n” starts a new line.

The command above would print the text “This is 1 complete sentence.” The %d tells the interpreter to insert an integer while %s tells it to insert a string. You can have as many of these as you wish, you just need to make sure that the strings and integers parameters are in the order that they fall in the first string parameter.

QL(x) and Q(x)

Many sets of numbers in programming start at 0 instead of 1 because it is easier for the computer to interpret this way. This is the case with many sets internally in Programmer, and most notably when it comes to cues and cuelists. Cuelist 1 is stored internally as cuelist 0. This means that if you want to start cuelist 5, you actually have to run the command StartCuelist(4); which is just confusing. There are two functions, Q and QL which simply return the value passed minus one so you can run the statement StartCuelist(QL(5)); and while it’s a bit longer, it makes a lot more sense.

StartCuelist

This one really needs not introduction as it is used quite a bit throughout this tutorial. It will start the cuelist number that you pass to it (remember, cuelists numbers are 0 based as mentioned above). Also, it should be noted that this command does not restart the cuelist from the beginning, but rather is the equivalent of pressing the play button, advancing to the next cue or looping around to the beginning if you are at the last cue in the stack.

GotoCue

Gotocue performs a similar function to StartCuelist, but jumps directly to a specific cue within the list. It looks like this:

GotoCue(cuelist, cue, at_once);

All of the parameters are integers, with the first two obviously being the cuelist number and the cue number (both 0 based), followed by the at_once flag. If it is set to 0, the cue will fade in in its programmed time, if set to 1 it will jump instantly to that cue.

StopCuelist

StopCuelist is passed with one integer like so:

StopCuelist(QL(1));

And, exactly like its name suggests, it stops the specified cuelist. The cuelist will follow the rules set in the cuelist settings for release time and action.

ReleaseAll

ReleaseAll will stop all running cuelists (except for protected cuelists) exactly as if you had manually performed a Release All within the interface.

Wrapping Up

There is a lot more to learn about e:script, but hopefully this should give you a good base from which to start. In the future I will be writing more articles about scripting, and their content will depend heavily on the response I get from this one, so please send me your comments and questions at ruby@ruby-lighting.com. I look forward to hearing about how you are using e:script in your projects. In the mean time, dig into the e:script and Programmer advance manuals. There is much more information there, and hopefully I’ve given you enough to allow you to make sense of it all.

3 Comments

Add a Comment

Your email address will not be published. Required fields are marked *