name: title class: left, middle .fancy[Introduction to Praat and Praat Scripting] .big[Lab Skills Workshop, Phonetics Laboratory, University of Oxford] <br /> ###Chenzi Xu .big[DPhil Candidate | 2021/12/30 (updated: 2022-02-03)] --- class: right, middle ![:scale 20%](me.png) ## Find me at... [<svg viewBox="0 0 512 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path></svg> @ChenziAmy](http://twitter.com/ChenziAmy) [<svg viewBox="0 0 496 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"></path></svg> @chenchenzi](https://github.com/chenchenzi) [<svg viewBox="0 0 512 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"></path></svg> chenzixu.rbind.io](https://chenzixu.rbind.io) --- # Our Goal .left-column[ ### First ### Second ### Third ] .right-co[ .big[To know a full range of functions Praat can perform To master how to navigate and use Praat's GUI To learn scripting basics, parse praat script, and .fancysmall[start] praat scripting] ] ??? Q: 1. how many have used Praat? 2. how many have used praat scripts? 3. how many have learnt other scripting/programming languages? --- ## Outline .right-column[ 1. ### [Why Praat?](#why) 1. ### [What is Praat capable of?](#functions) 1. ### [Praat scripting](#script) 1. ### [Demo and Practice](#demo) ] --- class: inverse center middle # Why Praat? ![Praat Icon](icon.png) --- name: why ## Why Praat? - Open source, **free** of charge - Available for major computer platforms (MacOS, Windows, Linux) and systems - Graphical User Interface - A macro recording mechanism (Command History) - You can create your own Praat scripts to .fancysmall[automate] things! - Recurring tasks become less tedious and more efficient. - **Consistent** and **Replicable** measurement - Minimising human error - You can create your own application with an autonomous GUI. - Python-praat package: [Parselmouth](https://parselmouth.readthedocs.io/en/stable/) - R-praat package: [rPraat](https://fu.ff.cuni.cz/praat/rDemo.html) ??? commercial software countless hours of soul-crushing repetitions --- name: functions class: inverse center middle # What is Praat capable of? -- .medium[ **Creating and manipulating sounds** **Visualizing and annotating sounds** **Phonetic measurement and analysis** **Creating publication-quality plots** **Conducting phonetic experiment** ] --- name: chart background-image: url('praat.png') background-size: cover background-position: middle right --- ## Are you familiar with these tasks? .medium[ - Loading files - Managing objects (create, copy, rename, save, remove) - View objects and analyses - Setting analysis parameters - Querying objects (using buttons or menu commands) - TextGrid annotation ] ??? Demonstrate load file,view, textgrid, draw a pic. --- background-image: url('spectrogram.png') background-position: 90% 70% ## Are you familiar with these tasks? .left-co[ **` Spectrum > Show spectrogram`** **` Pulses > Show pulses`** **` Pitch > Show pitch`** **` Intensity > Show intensity`** **`Formant > Show formants`** ] --- ## What does Praat contain? .pull-l[ ###Praat Objects - Sound - TextGrid - Spectrogram - Pitch, PitchTier - Intensity, IntensityTier - ExperimentMFC - ... ] .pull-m[ ###Praat Editors - SoundEditor - TextGridEditor - PitchEditor - PointEditor - SpectrumEditor - ... ] .pull-r[ ###Praat Commands - To Intensity... - To TextGrid... - Zoom in - Get Minimum - Convert to mono - ... ] .footnote[You must select the **correct** object/environment to **issue** the right commands!] --- name: script class: inverse center middle # Praat Script -- **String and numeric variables** **For loops, if else statements, while loops** **Regular expression matching** **Comments** **Syntax** -- ### OR ... Fast track? ??? teach fishing Sequentially ordered set of instructions that are given to a program that can interpret & execute them editor type in instructions/commands In programming, a variable is a place in the computer’s memory where something is stored, containers.name = value --- background-image: url('pitch1.png') background-size: 32% 56% background-position: 10% 90% ## Scripting Hacks I ### Check GUI for Syntax .pull-right[ ![Arguments for "To Pitch"](pitch2.png) ```r * To Pitch: 0.0, 75.0, 600.0 ``` ] ??? We're all linguist. Transitive Verbs take direct object otherwise ungrammatical. command: arguments/components too! otherwise not running --- ## Scripting Hacks II ### Macro Recording Workflow (Command History) - Obtain a sequence of instructions ``` 1. New Praat Script 2. Edit > Clear history (script editor) 3. GUI actions 4. Edit > Paste history (script editor) ``` --- background-image: url('save.png') background-size: 40% 70% background-position: 90% 80% ## Scripting Hacks III ### Parse others' script and adapt .pull-left[ - Parse the script in chunks and see if they suit your needs. Sometimes no need to reinvent the wheels. - Learn from others' script. > Be cautious when using others'script. The syntax of Praat was updated since 2014. > **Test** it out first and remember to **cite** it! > > **Save frequently!** ] --- ## Scripting Hacks IV .left-co[ ### Boilerplate code Place all paths, input/output files, and global variables at the top Paths must end with a backslash / Paths can be **relative** or **absolute** Windows: `"C:\Users\Chenzi\mydir\data\"` Avoid "special" characters in file/path names. ] .right-co[ ```r *dir$ = "/Users/Chenzi/mydir/data/" Create Strings as file list: "file_list", dir$ + "*.wav" nFiles = Get number of strings for i from 1 to nFiles selectObject: "Strings file_list" filename$ = Get string: i basename$ = filename$ - ".wav" Read from file: dir$ + filename$ ######################## #### MORE CODE HERE #### ######################## endfor ``` ] ??? formulaic, wrapper code Underscore/lowercase is a good combo. --- ## Scripting Hacks IV .left-co[ ### Boilerplate code Create list of all .wav files in the directory and save the number to a variable String variable ends in **`$`**; strings wrapped in **`""`** Assignment operator **`=`** Variable names in Praat must begin with a lowercase ASCII letter ] .right-co[ ```r dir$ = "/Users/Chenzi/mydir/data/" *Create Strings as file list: "file_list", dir$ + "*.wav" *nFiles = Get number of strings for i from 1 to nFiles selectObject: "Strings file_list" filename$ = Get string: i basename$ = filename$ - ".wav" Read from file: dir$ + filename$ ######################## #### MORE CODE HERE #### ######################## endfor ``` ] ??? In Praat, Names must start with lowercase letters, and have only letters, digits, and underscores. Informative names help your future self to understand your script! --- ## Scripting Hacks IV .left-co[ ### Boilerplate code Set up a for loop to iterate over all files on the list `1` is the starting point. It `+1` each time through the loop Comments (Praat will ignore) must start with "`#`" or "`;`" Comments are good for reproducibility (and your future self)! ] .right-co[ ```r dir$ = "/Users/Chenzi/mydir/data/" Create Strings as file list: "file_list", dir$ + "*.wav" nFiles = Get number of strings *# for-loop to iterate over all files on the list *for i from 1 to nFiles selectObject: "Strings file_list" filename$ = Get string: i basename$ = filename$ - ".wav" Read from file: dir$ + filename$ ######################## #### MORE CODE HERE #### ######################## *endfor ``` ] --- ## Scripting Hacks IV .left-co[ ### Boilerplate code Read in each .wav file. `Get string` : get the nth row of the list of filenames There are different ways to get the basename. ``` Read from file: dir$ + filename$ basename$ = selected$ ("Sound") ``` ] .right-co[ ```r dir$ = "/Users/Chenzi/mydir/data/" Create Strings as file list: "file_list", dir$ + "*.wav" nFiles = Get number of strings for i from 1 to nFiles * selectObject: "Strings file_list" * filename$ = Get string: i * basename$ = filename$ - ".wav" * Read from file: dir$ + filename$ ######################## #### MORE CODE HERE #### ######################## endfor ``` ] --- ## Scripting Hacks V .left-col[ ![:scale 85%](error.png) ] .right-co[### Errors are stepping stones #### How to debug? - In script editor: `Search > Go to line` - Use `printline` statements regularly when testing #### Types of errors - Syntactic errors: typos, use of quotes, etc. - Runtime errors: file doesn't exist, command doesn't exist etc. - Semantic errors: output doesn't match your goal... ] --- name: demo class: inverse center middle # Demo and Practice Task 1: Get total duration of all .wav files Task 2*: Measure f0 in specified interval --- # Task 1 .pull-left[ ###Basics 1.1 Get the number of .wav files in a directory 1.2 Get duration of each .wav file 1.3 Get total duration of all .wav files 1.4 Print results in Praat Info window ] .pull-right[ ###Level up 1.5 Toggle option to "clean up" as you go 1.6 Add a user input form 1.7 Write results to a Text file] .footnote[Adapted from Thea Knowles's Praat Tutorial] --- ### Step 1: How to get duration of one .wav file? .medium[1. Open one .wav file in Praat **`Open > Read from file`** 1. Select the Sound object, click **`Query > Query time domain > Get total duration`** ] ![:scale 55%](duration.png) > Avoid using `.` in the filename (except in the file extension) --- ### Step 2: Print command history .medium[ 1. At menu bar, **`Praat > New Praat script`** 1. In the script editor, click **`Edit > Paste history`** 1. **`File > Save`**, type `"test.praat"`, and **`Run`** ] ![:scale 55%](history.png) > #### Limitations: > > Query commands may behave differently in scripts than in the GUI (e.g. Praat scripting assumes that you want to handle the query result inside the script) > > Changing scripting environments is not recorded ??? my first praat script --- ### Step 3: Loop over all .wav files .left-co[ ### Update the boilerplate code ### Any problems? ] .right-co[ ```r dir$ = "data/" Create Strings as file list: "file_list", dir$ + "*.wav" nFiles = Get number of strings for i from 1 to nFiles selectObject: "Strings file_list" filename$ = Get string: i basename$ = filename$ - ".wav" Read from file: dir$ + filename$ * selectObject: "Sound 'basename$'" * Get total duration endfor ``` ] --- ### Step 4: Manage output .left-co[ ### Print out result **`printline`** prints the argument to the Praat Info window Contents of a variable enclosed in **`''`** in built-in Praat functions (force Praat to substitute a string value for its variable name) Numeric variable doesn't end in **`$`** ] .right-co[ ```r dir$ = "data/" Create Strings as file list: "file_list", dir$ + "*.wav" nFiles = Get number of strings *printline 'nFiles' for i from 1 to nFiles selectObject: "Strings file_list" filename$ = Get string: i basename$ = filename$ - ".wav" Read from file: dir$ + filename$ * printline 'basename$' selectObject: "Sound 'basename$'" * dur = Get total duration * printline 'dur' endfor ``` ] --- ### Step 5: Calculation in a for loop .left-co[ ### Sum Set up a dummy numeric variable **`total_dur`** and update its value through each loop Numeric variables must start with a lower case letter, and be only letters, digits, and underscores **`:4`**: print with 4 decimal places ] .right-co[ ```r dir$ = "data/" Create Strings as file list: "file_list", dir$ + "*.wav" nFiles = Get number of strings *total_dur = 0 for i from 1 to nFiles selectObject: "Strings file_list" filename$ = Get string: i basename$ = filename$ - ".wav" Read from file: dir$ + filename$ printline 'basename$' selectObject: "Sound 'basename$'" dur = Get total duration printline 'dur' * total_dur = total_dur + dur endfor *printline 'total_dur:4' ``` ] --- ### Level up (optional) .left-col[ ### Clean up There are different methods. Sometimes leaving objects helps debugging. ] .right-col[ ```r *clearinfo for i from 1 to nFiles #### MORE CODE HERE #### * select all * minus Strings file_list * Remove endfor *select all *Remove *printline All finished! ``` ] --- ### Level up (optional) .footnote[More info at [Praat manual](https://www.fon.hum.uva.nl/praat/manual/Scripting_6_1__Arguments_to_the_script.html) and [Phonetics on Speed](https://praatscripting.lingphon.net/simpleinput-1.html)] .left-col[ ### User Input form Input forms are composed of fields, one per line. User provides arguments to the script. Input form code blocks are always processed first. You can't have two forms in one script. ] .right-col[ ```r form Make selection comment Enter directory of files sentence Directory data/ boolean Clean_up 1 endform #### MORE CODE HERE #### ``` ![:scale 60%](form.png) ] --- ### Level up (optional) .left-col[ ### Toggle option Create Boolean variable (TURE/FALSE or 1/0) Nest it in a if statement. ] .right-col[ ```r for i from 1 to nFiles #### MORE CODE HERE #### * if clean_up == 1 select all minus Strings file_list Remove * endif endfor *if clean_up == 1 select all Remove *endif printline All finished! ``` ] --- ### Level up (optional) .left-col[ ### Write output If you write a file to a path that already exists, it will be overwritten, and with **NO UNDO**. Check if the file exists and ask permission before overwriting it. ![Warning message](warning.png) ] .right-col[ ```r nFiles = Get number of strings outFile$ = "duration.txt" *askBeforeDelete = 1 *if askBeforeDelete and fileReadable(outFile$) * pauseScript: "File exists! Overwrite?" *endif *deleteFile: outFile$ for i from 1 to nFiles selectObject: "Strings file_list" filename$ = Get string: i basename$ = filename$ - ".wav" Read from file: dir$ + filename$ selectObject: "Sound 'basename$'" dur = Get total duration * appendInfoLine: basename$, " ", dur * appendFileLine: outFile$, basename$, " ", dur endfor ``` ] --- # Task 2 .pull-left[ ###Basics 1.1 Get the number of .wav files in a directory 1.2 Get pitch/f0 track (and corresponding times) of each .wav file 1.3 Print results in Praat Info window ] .pull-right[ ###Level up 1.4 Add a user input form to specify source and destination directory 1.5 Toggle option to "clean up" as you go 1.6 Save f0 results of each .wav file to a text file ] .fancysmall[Advanced] If we manually corrected some pitch points in the PitchTier of a sound file, or we're only interested in a part of a pitch track, how do we extract and save the desired pitch track? > ### Could you do it yourself now? --- ## Our Goal .big[To know a full range of functions Praat can perform <svg viewBox="0 0 448 512" style="position:relative;display:inline-block;top:.1em;fill:#EFBE43;height:2em;" xmlns="http://www.w3.org/2000/svg"> <path d="M400 480H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h352c26.51 0 48 21.49 48 48v352c0 26.51-21.49 48-48 48zm-204.686-98.059l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.248-16.379-6.249-22.628 0L184 302.745l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.25 16.379 6.25 22.628.001z"></path></svg> ] -- .big[To master how to navigate and use Praat's GUI <svg viewBox="0 0 448 512" style="position:relative;display:inline-block;top:.1em;fill:#EFBE43;height:2em;" xmlns="http://www.w3.org/2000/svg"> <path d="M400 480H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h352c26.51 0 48 21.49 48 48v352c0 26.51-21.49 48-48 48zm-204.686-98.059l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.248-16.379-6.249-22.628 0L184 302.745l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.25 16.379 6.25 22.628.001z"></path></svg>] -- .big[To learn scripting basics, parse praat script, and **start** praat scripting <svg viewBox="0 0 512 512" style="position:relative;display:inline-block;top:.1em;fill:#EFBE43;height:2em;" xmlns="http://www.w3.org/2000/svg"> <path d="M336.174 80c-49.132 0-93.305-32-161.913-32-31.301 0-58.303 6.482-80.721 15.168a48.04 48.04 0 0 0 2.142-20.727C93.067 19.575 74.167 1.594 51.201.104 23.242-1.71 0 20.431 0 48c0 17.764 9.657 33.262 24 41.562V496c0 8.837 7.163 16 16 16h16c8.837 0 16-7.163 16-16v-83.443C109.869 395.28 143.259 384 199.826 384c49.132 0 93.305 32 161.913 32 58.479 0 101.972-22.617 128.548-39.981C503.846 367.161 512 352.051 512 335.855V95.937c0-34.459-35.264-57.768-66.904-44.117C409.193 67.309 371.641 80 336.174 80zM464 336c-21.783 15.412-60.824 32-102.261 32-59.945 0-102.002-32-161.913-32-43.361 0-96.379 9.403-127.826 24V128c21.784-15.412 60.824-32 102.261-32 59.945 0 102.002 32 161.913 32 43.271 0 96.32-17.366 127.826-32v240z"></path></svg> ] -- <br/> > ### We've found a way around Praat scripts? --- class: middle, center > ## Would you like a step-up tutorial about Praat scripting? --- ## Online resources > ### Always check: [Praat Manual](https://www.fon.hum.uva.nl/praat/manual/Intro.html)! <br /> #### References and good resources: If you want to have more solid understanding and more practices, check out: [Phonetics on Speed: Praat Scripting Tutorial](https://praatscripting.lingphon.net/) If you would like to learn more about Praat script basics, check out: [Praat Scripting Tutorial by Eleanor Chodroff](https://www.eleanorchodroff.com/tutorial/PraatScripting.pdf) Recorded tutorial about Praat script by CASA Lab: [Praat Scripting Tutorial by CASA Lab, University at Buffalo](https://bookdown.org/thea_knowles/casa_coding_group/spring-2020.html) --- class: center, middle # Thank you! ## Q & A Slides created via the R packages: [**xaringan**](https://github.com/yihui/xaringan)<br> [gadenbuie/xaringanthemer](https://github.com/gadenbuie/xaringanthemer) The chakra comes from [remark.js](https://remarkjs.com), [**knitr**](http://yihui.name/knitr), and [R Markdown](https://rmarkdown.rstudio.com). Theme design ideas from [Katie Jolly](https://www.katiejolly.io/blog/2021-03-16/designing-slides).