Session 12
Flexible Input Forms

If you need more flexibility than input forms provide you can use the pause window. You already know the simplest form of the pause window (Useful Tools):

pauseScript: "Click Continue when you're done"

This statement draws a window like below and waits for the user to do something and then click Continue. If the user clicks Stop instead, the script is aborted and exits with an error message.

Ok, nice and handy, but not really flexible. Flexibility is introduced with a construct that evolved from the simple pause window to something more powerful. The new construct, which is also called 'pause window' due to its ancestor, differs considerably from the simple pause window, regarding syntax as well as functionality. Let's deal with syntax first. To recreate the simple pause window shown above, we need three lines of code:

beginPause: "stop or continue" comment: "Click Continue when you're done" endPause: "Continue", 1

The definition of a complex pause window starts with the keyword beginPause:, followed by an obligatory string argument (the window title), enclosed in double quotes. The definition ends with endPause:, followed by a button definition. We'll come back to the button definition in a minute.

But first, let's have a glance at the stuff between beginPause and endPause. Do you remember the keyword comment from the previous chapter on input forms? It was a field type, as part of a field definition, and it's exactly the same here: comment: "Click Continue when you're done" is a field definition for a pause window. It's a bit more structured than field definitions in forms, but essentially it's the same. Field types in pause window definitions end with a colon followed by one argument in the case of comment and two arguments in all other cases. Yes, right, you can have all the other field types as well: Integer, real, natural, and positive; word, sentence, and text; boolean, choice, and optionMenu.

The following script illustrates the different field types and the slightly different syntax compared to input forms. If you want to see how the result looks, just copy & paste the code to the script editor and run it—looks familiar, right?

beginPause: "Input different types of data" comment: "Enter some data and see what happens." real: "Real number", -273.15 positive: "Positive number", 373.15 integer: "Whole number", -76543 natural: "Unsigned integer", 42 boolean: "Want icecream", 1 word: "Greeting", "Hello" sentence: "Phrase", "Hello World" choice: "Color", 1 option: "red" option: "green" option: "blue" optionMenu: "Operating system", 2 option: "Linux" option: "Mac OS X" option: "Windows" endPause: "Continue", 1

As you can see, all field type declarations end with a colon, arguments are comma-separated, and string arguments are enclosed in double quotes. It's a bit more typing compared to input forms, but you are rewarded with enriched and consistent syntactic structure (commands with colons, comma-separated argument lists, and quoted strings are the familiar standard of the modern Praat scripting language). But there's more: Compared to input forms, pause windows have important advantages:

  1. Pause windows acknowledge procedural processing; all commands above beginPause are indeed executed before the pause window shows up.
  2. More than one pause window per script is permitted.
  3. Variables in pause window definitions behave like everywhere else.
  4. It's possible to declare more than one continuation button and you can get rid of the stop button.

We'll discuss (1) and (2) bellow, followed by (3) and (4) in separate sections.

Multiple Pause Windows

With input forms there's only one opportunity to ask the user for input, i.e. right at the beginning of the script. With pause windows you can ask whenever you want and as often as you want. More than one pause window per script means that you can have different pause window definitions across your script, but it's also possible to have one pause window appear multiple times if you put the pause window definition in a loop.

Consider a script that loads sound files from a directory, waits for the user to evaluate the sounds, and than writes the evaluated sounds back to the disk. The script provides 3 directories to save the evaluated sounds, good, decent, and poor, and asks the user to choose one before saving. Here's the load file loop, which should look familiar to you:

# create file list list = Create Strings as file list: "SoundFiles", "sounds/*.wav" # determine number of files n = Get number of strings # load files one by one for i to n selectObject: list filename$ = Get string: i fileID = Read from file: "sounds/" + filename$ Play # let the user evaluate the sound removeObject: fileID endfor removeObject: list

Now we insert the command to save the evaluated sound at the end of the loop, before removing the current sound object.

list = Create Strings as file list: "SoundFiles", "sounds/*.wav" n = Get number of strings for i to n selectObject: list filename$ = Get string: i fileID = Read from file: "sounds/" + filename$ Play # let the user evaluate the sound # make sure that the current sound object is selected selectObject: fileID # save sound object to target directory Save as WAV file: target_Directory$ + "/" + filename$ removeObject: fileID endfor removeObject: list

The selectObject command seems redundant, but what if the user does something during evaluation that de-selects the target sound? Remember: Redundant object selection is harmless, a missing selection may have serious consequences.

Setting the target directory is done with a pause window:

beginPause: "Set the target directory" comment: "Choose the appropriate directory for this sound." optionMenu: "Target Directory", 1 option: "good" option: "decent" option: "poor" endPause: "Continue", 1

The comment explains what the user should do, and optionMenu provides a menu to choose one of the three directories. "Target Directory" represents the variable that contains the chosen option. Later in the script, you can use the variable as target_Directory (numeric; index of the chosen option) or target_Directory$ (string; chosen option as it appears in the menu), i.e. initial capitals and spaces must be 'translated' the same way as input form variables. The second argument of optionMenu specifies the default option (1 = first option = good). This definition creates the following window:

That's fine, so we can use the code in the evaluation script. Where would you insert the pause window code? Remember, we want the script user to make a decision for every sound separately, not one decision for all sounds!

To let the user evaluate each sound separately, we need a separate pause window for each sound. Hence, the code must be placed inside the loop. To give the user a chance to listen to the sound before evaluation the code should follow the Play-statement. Because we need the user's input for saving, the code should precede the Save-statement.

list = Create Strings as file list: "SoundFiles", "sounds/*.wav" n = Get number of strings for i to n selectObject: list filename$ = Get string: i fileID = Read from file: "sounds/" + filename$ Play # show pause window for evaluation beginPause: "Set the target directory" comment: "Choose the appropriate directory for this sound." optionMenu: "Target Directory", 1 option: "good" option: "decent" option: "poor" endPause: "Continue", 1 # saving and removing selectObject: fileID Save as WAV file: target_Directory$ + "/" + filename$ removeObject: fileID endfor removeObject: list

With this script we illustrated the first two advantages of pause windows compared to input forms: The dialog window appears multiple times (not only once) and it appears exactly when we need it (not at the very beginning of the script).

Next: Variables in Pause Windows