Looping through directories and files
Since you already know how to read files, and you know how to loop, this should be cake. If you want to run your script on every item contained in a folder, you need to loop over its contents.
To get a list of files in a directory, use "Create Strings as file list", which is a command in the "New" dropdown menu. ("Create Strings as directory list" will give you a list of folders). Try it out with the mouse to see what arguments the command needs, and what it returns to you.
The first argument is the name of the Strings object you will create, and the second is the path to a folder. Take a look at the strings object it created for you. Click on View & Edit, see what's in there. Look at the available commands in the buttons on the right in the object window.
Using this information, figure out how to write a script that gets a list of files in your Downloads folder, and prints their names to the info window. Try it out and come back to see my version below.
clearinfo wd$ = homeDirectory$ + "/Downloads/" downloadsList = Create Strings as file list: "downloadsList", wd$ # not necessary here, just OCD selectObject: downloadsList numFiles = Get number of strings for fileNum from 1 to numFiles fileName$ = Get string: fileNum appendInfoLine: fileName$ endfor
One potential issue with this is that we got all of the files in that folder. It's typically much easier and safer to open, for example, all of the .wav files only. We can do this with a "wildcard", which is a character that will match anything, and in this case is the asterisk "*". Let's get a list of all of the .wav files in praatTutorial/sampleData/fileLooping . Note the variables I set up for the path here:
clearinfo wd$ = homeDirectory$ + "/Documents/praatTutorial/sampleData/" inDir$ = wd$ inDirWavs$ = inDir$ + "*.wav" appendInfoLine: inDirWavs$ wavList = Create Strings as file list: "wavList", inDirWavs$ selectObject: wavList numFiles = Get number of strings for fileNum from 1 to numFiles fileName$ = Get string: fileNum appendInfoLine: fileName$ endfor
Heads up with chooseDirectory
Remember the chooseDirectory command from the last lesson, that lets the user choose a folder for us? Enter this and run it:
inDir$ = chooseDirectory$: "Choose the folder containing your wav files" appendInfoLine: inDir$
The path that it returns doesn't have a slash at the end, so we'll have problems if we do this:
inDir$ = chooseDirectory$: "Choose the folder containing your wav files" appendInfoLine: inDir$ # watch out here! outPath$ = inDir$ + "jazz.wav" appendInfoLine: outPath$
If you look closely at the result, it's not what we want, since we're missing a slash. If I chose the desktop, I would get this:
That means we'll get a file called "Desktopjazz.wav" in my home folder! Here's my preferred way, since I don't have the habit of prepending slashes to names of files:
inDir$ = chooseDirectory$: "Choose the folder containing your wav files" #this makes things easier for me inDir$ = inDir$ + "/" appendInfoLine: inDir$ # Now we should be good outPath$ = inDir$ + "jazz.wav" appendInfoLine: outPath$
Lastly, you'll have to add your wildcard if you only want files of a certain extension:
inDir$ = chooseDirectory$: "Choose the folder containing your wav files" inDir$ = inDir$ + "/" inDirWild$ = inDir$ + "*.wav" wavList = Create Strings as file list: "wavList", inDirWild$
Practice: Make a TextGrid for each .wav file in a folder
Let's use this newfound knowledge to open every .wav file in a folder, and create a TextGrid with an interval tier named "segments" and a point tier named "points", and save them to the same directory. This script will be very useful, so let's try to make it flexible, and easily shareable with non-scripty friends (we'll have them choose the directory). Again, try it out yourself first for maximum fun and learning. Watch out! The list of strings gives you the file names, it doesn't give you a complete path to the files! Also, watch out for which objects are selected when you loop.
clearinfo # Let's set the names of the tiers at the # beginning, so that this script will be easier # to use in the future # Actually, we should let the user # enter this information with a popup. # I'll include this at the end of the # chapter. We'll talk more about that # later tierNames$ = "segments points" pointTiers$ = "points" inDir$ = chooseDirectory$: "Select folder with your .wav files" # make sure they made a choice if inDir$ == "" exitScript: "No folder given. Exiting" endif inDir$ = inDir$ + "/" inDirWild$ = inDir$ + "*.wav" # Get list of files wavList = Create Strings as file list: "wavList", inDirWild$ # See how many there are for the loop numFiles = Get number of strings #if there are no files, we have a problem if numFiles == 0 exitScript: "I didn't find any .wav files in that folder. Exiting" endif # Note that the script exits without error # if the value is zero # If the loop began with: # for i from 1 to 0 # It wouldn't throw an error, it would just # never run for fileNum from 1 to numFiles # I always select objects explicitly # at the beginning of a loop, since # they may not be selected by the end selectObject: wavList wavFile$ = Get string: fileNum wav = Read from file: inDir$ + wavFile$ textGrid = To TextGrid: tierNames$, pointTiers$ # Get the name of the object, use it # to create a file name for the TextGrid objName$ = selected$: "TextGrid" outPath$ = inDir$ + objName$ + ".TextGrid" # Since this will be for the "public", # be strict about overwriting files if fileReadable: outPath$ pauseScript: objName$ + ".TextGrid" + " exists! Overwrite?" endif Save as text file: outPath$ # Remove newly opened objects for cleanup selectObject: wav plusObject: textGrid Remove endfor # Remove the wav list selectObject: wavList Remove # Tell the user the script ended without error pauseScript: "Done! The script ran with no errors."
And here's the topmost part of the same script, altered to use a form, to have the user enter the names of the tiers for the TextGrid. We should now have a simple script that anyone could use. Feel free to check out forms in the Praat manual, we'll talk about them more in depth later (in the chapter named Pop-up windows) since they have their quirks.
clearinfo form Tier information comment Tier names, separated by spaces sentence Tier_names comment Which of these are point tiers? sentence Point_tiers endform # The tier names can't be empty if tier_names$ == "" exitScript: "We need at least one Tier name" endif # Just to keep my naming scheme # consistent and not change my working script, # I'm going to rename the variables tierNames$ = tier_names$ pointTiers$ = point_tiers$
Next page: Challenge: Formant script
This work is licensed under a Creative Commons Attribution 4.0 International License.