Session 10
Conditionals

Remarks on Conditions

String comparisons

So far, we've only dealt with simple numeric comparisons. But using the already established comparison operators (see while- and repeat-Loops) it's also possible to compare strings. In fact, we've done that already in the session on opening and saving files:

filename$ = chooseReadFile$: "Open a sound file" if filename$ <> "" Read from file: filename$ endif

Using the unequal-operator, this condition is true, if the content of filename$ is different from an empty string, i.e. if there is something stored in filename$ at all.

Application of the equal-operator is also straightforward:

if speaker$ = "male" pitch_floor = 60 endif

This is true if the string male is stored in speaker$; if speaker$ contains Male or MALE or any other string, the condition is false. By the way, this example illustrates the context-sensitive meaning of "=": In the first occurrence (condition context, line 1) it's a comparison operator, in the second occurrence (assignment context, line 2) it's the assignment operator.

Other comparison operators (<, <=, >, and >=) are also applicable with strings, but they are far from being straightforward. Greater/less comparisons of strings in Praat are based on the ASCII sorting order, which could yield unexpected results. ASCII defines 95 standard printable characters in the following order:

!"#$%&'()*+,-./0123456789:;<=>?@ ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` abcdefghijklmnopqrstuvwxyz{|}~

This means that numbers are less than upper case letters, which are less than lower case letters. Some examples:

Condition Truth Value
"z" > "a" true
"Z" > "a" false
"a" < "b" true
"aaa" > "b" false
"aaa" > "a" true
"a" > "1" true
"a" < "999" false

To test this behavior try the following little script with different values assigned to s1$ and s2$:

s1$ = "A" s2$ = "a" clearinfo if s1$ < s2$ appendInfoLine: s1$, " is less than ", s2$ elsif s1$ > s2$ appendInfoLine: s1$, " is greater than ", s2$ else appendInfoLine: s1$, " is equal to ", s2$ endif

However, my advice is to try to avoid greater/less comparisons of strings, especially if the strings contain special characters like punctuation marks.

Combined conditions

It is possible (and often useful) to build complex conditions by combining simple conditions with the logical operators and or or. For instance, if you need to know if x is between 100 and 200 you can either implement two nested if-statements:

if x > 100 if x < 200 writeInfo: x, " is between 100 and 200" endif endif

or you combine the conditions with logical and:

if x > 100 and x < 200 writeInfo: x, " is between 100 and 200" endif

The truth value of a complex and-condition is only true if both sub-conditions are true. Complex or-conditions, on the other hand, are true if at least one sub-condition is true. So, to ignore x-values between 100 and 200 you combine two conditions with or:

if x < 100 or x > 200 writeInfo: x, " is not between 100 and 200" endif

Complex conditions may combine more than two simple conditions and involve more than one logical operator. You are allowed to use parentheses to control the order of evaluation of sub-conditions. To illustrate this, the following script detects x-values between 100 and 200 and between 300 and 400:

if (x > 100 and x < 200) or (x > 300 and x < 400) writeInfo: x, " is between 100 and 200 or between 300 and 400" endif

Any simple condition may be part of a complex condition:

if speaker$ = "male" and mean_pitch < 100 writeInfo: "deep male voice" endif

Functions returning a truth value

Some built-in Praat functions return truth values and may serve as conditions, substituting comparisons. You already know one of these:

if fileReadable (gridname$) exitScript: "The TextGrid was not saved (due to an existing file)!" endif

fileReadable () tests whether the referred file is readable or not. If the file is readable, fileReadable () returns 1, which is equivalent to true, if it is not readable, the function returns 0, which is equivalent to false. It is permitted to combine functions like this with any other conditions using logical and or or.

There's a third logical operator which wasn't mentioned yet: not. It can be used to negate truth values. To ensure that a file is not readable before you do something, you can implement the following evaluation:

if not fileReadable (filename$) # do something endif

You can combine not with comparisons, but usually it's easier to just replace the comparison operator: not x = 10 is the same as x <> 10.

Probably, fileReadable () is the only boolean function that is interesting for you—until you start writing scripts for the demo window: managing user input in the demo window depends heavily on boolean functions.

Undefined

An important job of conditionals is the evaluation of query results, because sometimes queries yield undefined or empty results. For example, if you want to use the minimum pitch of a sound to generate an intensity analysis you can do:

# remember selected sound sound = selected () # pitch analysis pitch = To Pitch: 0, 75, 600 # query minimum minPitch = Get minimum: 0, 0, "Hertz", "Parabolic" # remove pitch Remove # select sound selectObject: sound # intensity analysis To Intensity: minPitch, 0, "yes"

That's fine as long as the selected sound has voiced parts. With an unvoiced sound, however, the query (3. command) is futile, which results in script abortion with an error message in the last line. What happens? Well, with unvoiced sounds there's no pitch and without pitch there's no minimum pitch, i.e. minimum pitch is undefined. In fact, the 'value' undefined is assigned to minPitch in this case. So, after variable substitution, the last line reads:

To Intensity: undefined, 0, "yes"

which, obviously, results in an error message. To avoid this, we should ensure that minPitch is not undefined before using it in a statement:

sound = selected () pitch = To Pitch: 0, 75, 600 minPitch = Get minimum: 0, 0, "Hertz", "Parabolic" Remove selectObject: sound # ensure that minPitch is kosher if minPitch <> undefined To Intensity: minPitch, 0, "yes" else # react to undefined variable, e.g.: writeInfo: "minPitch is undefined" endif

Only numerical variables can get undefined, and only in query contexts (to be accurate: you can assign undefined to a numerical variable yourself; but why would you do that?). And don't confuse undefined with 0! Queries may return 0 as a result (e.g. Count voiced frames) which is a perfectly defined condition. Undefined ist just that: undefined...

String variables, on the other hand, can't be undefined, they can only be empty. If you query labels in a TextGrid for instance, it's possible to come across empty intervalls. Taking this into account is nothing new: Just compare the query result with the empty string. An example from the loop session:

clearinfo numberOfTiers = Get number of tiers for i to numberOfTiers numberOfIntervals = Get number of intervals: i for j to numberOfIntervals label$ = Get label of interval: i, j # react to empty intervalls if label$ = "" appendInfoLine: "no label found" else appendInfoLine: label$ endif endfor endfor

Recap

Conditionals start with the keyword if, followed by a condition in the same line, and end with endif. One optional else section and any number of optional elsif sections are allowed. An associated code block follows the if- and the optional elsif- and else-statements.

Conditionals allow the implementation of processing alternatives (‘branching'). Which alternative is executed depends on the evaluation of conditions. No more than one code block within an if-statement is executed, namely the one following the first true condition or the one following else if an else section is available and all conditions are false. With a simple if-statement (only one condition, no else section) not even one code block may be executed—if the condition is false.

Most conditions are formulated as comparisons. Praat provides 6 comparison operators to compare numeric or string entities (literal values, variables, and formulas). Conditions can be combined using the logical operators and or or.

Next: Workshop: Conditionals