Skripty v Praatu a demonstrace

Tyto stránky nabízejí podpůrné materiály pro kurzy Akustika řeči I a II a Řečové technologie I.

Základy programování v Praatu

Přehled příkazů a základních programovacích technik v Praatu – Radek Skarnitzl

Stavební kameny skriptů

Komentáře
# Komentář

Řádky začínající znakem # se neprovádějí, slouží k okomentování programu.

Pokud toužíme vložit komentář na řádek obsahující příkaz, použijeme znak ;

clearinfo   ; Komentář

Doporučuje se komentář vkládat:

  • na začátek skriptu – popíšeme, co skript dělá a co předpokládá (např. označení nějakých objektů…)
  • u proměnných – pokud jejich název není dostatečně samovysvětlující
  • k oddělení jednotlivých částí delšího skriptu
Proměnné
Číselné proměnné

Jako proměnná funguje jakýkoliv řetězec složený ze znaků a číslic (a některých dalších znaků, např. podtržítko). Prvním znakem musí být malé písmeno a nesmí obsahovat mezeru.
V Praatu proměnné mohou ukládat výsledné hodnoty příkazů. Př.:

trvani = Get total duration 

Některé proměnné jsou v Praatu předdefinovány, tím pádem jejich hodnotu nelze měnit:

  • e … Eulerovo číslo
  • pi … Ludolfovo číslo
  • undefined … nedefinovaná hodnota

Řetězcové (textové) proměnné

Slouží pro ukládání znakových řetězců. Od číselných proměnných se odliší znakem $ na konci názvu. Pro uložení hodnoty do řetězcové proměnné je třeba použít uvozovky. Př.:

cilove_hlasky$ = "f s š x"
label$ = Get label of interval... 1 1

Některé proměnné jsou opět předdefinovány:

  • tab$ … tabulátor, odsazení (užitečné při výpisu hodnot do oddělených buněk, např. v Excelu)
  • newline$ … skok na nový řádek

Výpis proměnných

Hodnoty uložené v proměnných většinou vypisujeme do okna Info.
Pro výpis slouží příkazy printline (přidá text do okna a skočí na další řádek), print (přidá text do okna) a echo (vyprázdní okno, vypíše text a skočí na další řádek).

Když chceme nechat vypsat hodnotu dané proměnné, zapíšeme ji v jednoduchých uvozovkách (apostrofech). Apostrofy používáme skutečně při výpisu příkazy print, při operacích s proměnnými (výpočty) se nepoužívají. U řetězcových proměnných také nesmíme zapomenout na znak $. Př.:

zacatek = Get start point... 1 1 
konec = Get end point... 1 1 
pulka = zacatek + (konec-zacatek)/2 
printline Polovina hlasky je 'pulka'.
For cyklus
For cyklus dosadí do „počítací“ proměnné (např. „i“ nebo „k“) počáteční hodnotu a postupně ji zvyšuje o jedničku, dokud nepřeroste přes koncovou hodnotu. Pro každou hodnotu proměnné provede tělo. Je-li počáteční hodnota větší než koncová, cyklus se neprovede.

Tělo for cyklu se pro přehlednost doporučuje odsadit (zejména při vnořování více for cyklů do sebe).

for počítací proměnná from počáteční hodnota to koncová hodnota
tělo for cyklu: jeden či více příkazů
endfor

Počítací proměnná („i“, „k“ apod.) je ve skriptech velmi důležitá, protože definuje interval, v němž provádíme měření.

Např. pro zjištění labelu v konkrétním intervalu pomocí příkazu Get label of interval zadáváme dva argumenty: pořadí vrstvy a pořadí intervalu v ní. Při každém průchodu cyklem tak získáme tu následující značku. Př.:

pocet = Get number of intervals... 2
for i from 1 to pocet
      label$ = Get label of interval... 2 i
      printline 'label$'
endfor
Podmínka
if výraz
tělo podmínky: žádný, jeden či více příkazů
endif

Výrazem může být test na rovnost (=), nerovnost (<>), porovnání (> nebo <, >= nebo <=). Je-li podmínka splněna, provede se tělo, není-li, skočí se za endif.

Chceme-li definovat, co se má provést, není-li podmínka splněna, použijeme rozšířenou podobu:

if výraz
1. tělo podmínky: žádný, jeden či více příkazů} … provede se, jen je-li výraz pravdivý
else
2. tělo podmínky: žádný, jeden či více příkazů} … provede se, jen není-li výraz pravdivý
endif

Pokud máme více podmínek, které se navzájem vylučují, můžeme je elegantně zapsat v nejširší formě if. Skript se tak vlastně rozdělí na několik nezávislých větví. Jakmile se jednou větví vydá, už se nemůže vydat po jiné: Praat bere podmínky jednu po druhé a jakmile je nějaká splněna, vydá se do jejího těla a pak pokračuje za endif.

if výraz1
1. tělo podmínky} … provede se, jen je-li výraz1 pravdivý
elsif výraz2
2. tělo podmínky} … provede se, jen není-li výraz1 pravdivý a je pravdivý výraz2


else
poslední tělo podmínky} … provede se, jen když není pravdivý ani jeden z předchozích výrazů
endif
Výběr objektů
Skriptování v Praatu je nejefektivnější pomocí objektových skriptů, v nichž různé typy analýz provádíme na různých typech objektů (Formant, Pitch, Intensity apod.).

Mezi objekty se musíme přepínat, jako kdybychom na ně klikali myší a volili položky z jejich nabídek Query.

Existuje několik možností zvolení objektu. Nejjednodušší (ale nejméně univerzální) je napsat jeho jméno. Př.:

select Sound nahravka1 
select Intensity veta3

Elegantnější je každý právě zvolený objekt „zakódovat“, uložit ho do proměnné. Je konvencí používat v názvu „ID“. Takto většinou na začátku skriptu zakódujeme objekty Sound a TextGrid a později jakékoli další vytvořené objekty. Př.:

textID = selected("TextGrid")

Podobným způsobem můžeme i zjistit jméno daného objektu; použijeme jen textovou proměnnou a znak $ za příkazem selected. Př.:

jmeno$ = selected$("Sound") 

Pokud ve skriptu operujeme s více objekty, bývá třeba na začátku každého cyklu (for cyklu, podmínky) zvolit objekt, který je k dalšímu příkazu potřeba. Př.:

zvukID = selected ("Sound")
textID = selected ("TextGrid")
select zvukID
To Intensity... 100 0 yes
intID = selected ("Intensity")

select textID
no = Get number of intervals... 2

for i from 1 to no
      select textID
      label$ = Get label of interval... 2 i
      if label$ = "a"
            a = Get start point... 2 i
            b = Get end point... 2 i

            select intID
            int = Get mean... a b energy
            printline 'label$''tab$''int:2'
      endif
endfor

Kdybychom na začátku for cyklu nezvolili textID, cyklus by jednou proběhl, „překlikli“ bychom na intID a podruhé by se skript zastavil s hláškou Command „Get label of interval…“ not available for current selection.

Zmíníme ještě jeden způsob volby objektů, a to podle jejich pořadí. Př.:

zvuk_staryID = selected("Sound",1)   ; zvolí první objekt typu Sound v objektovém okně 
zvuk_novyID = selected("Sound",2)    ; zvolí druhý objekt typu Sound
Funkce index
Textovou (řetězcovou) funkci index můžeme využít k hledání cílových hlásek (například všech frikativ) v TextGridu. Základní struktura vypadá takto: index(a$, b$). Zjišťuje, zda se řetězec b$ nachází v řetězci a$.

Na začátku skriptu definujeme cílové hlásky jako textovou proměnnou, jejíž členy budou odděleny mezerami. Př.:

frikativy$ = "f v s z š ž x h"    ; pozn. [x] je symbol po české ch

Po zjištění aktuální hlásky pak vložíme podmínku s použitím funkce index. Zároveň musíme přidat podmínku, která vyloučí prázdné intervaly (protože prázdný řetězec je „nalezen“ vždy). Celá podmínka bude vypadat takto:

if (index (frikativy$, label$)) and (label$ <> "")

Pozor! Funkce index skutečně jen zjišťuje, zda se druhý řetězec nachází v prvním řetězci. Výše uvedený způsob zápisu může být proto velmi nebezpečný v tom, že skript bude ve skutečnosti dělat něco jiného, než jsme zamýšleli. Pokud např. definujeme následujícím způsobem seznam dlouhých vokálů, budeme možná nepříjemně překvapeni, že budou nacházeny i krátké vokály. Ale skutečně je tomu tak, protože samotné znaky i e a o u jsou také součástí tohoto řetězce. A pokud bude label intervalu obsahovat znak mezera, i takový interval bude vyhodnocen jako vyhovující.

vokaly$ = "i: e: a: o: u:"

Použití funkce index proto vyžaduje vysokou obezřetnost a v současné době ho již vyučující předmětu Akustika řeči nedoporučuje, protože může napáchat více škody než užitku. Naprosto bezpečné řešení, přitom ne o moc pracnější (použijeme-li schránku pro kopírování opakujících se částí) je vyjmenovat požadované labely jako samostatné jasně ohraničené řetězce ve vícenásobné podmínce:

if label$ = "i:" or label$ = "e:" or label$ = "a:" or label$ = "o:" or label$ = "u:"

Následující skript měří formanty v prostřední třetině krátkých vokálů (monoftongů):

zvukID = selected ("Sound")
textID = selected ("TextGrid")
select zvukID
To Formant (burg)... 0 3 3000 0.025 50
formantID = selected ("Formant")

vokaly$ = "i i: e e: a a: o o: u u:"

select textID
no = Get number of intervals... 1

for i from 1 to no
      select textID
      label$ = Get label of interval... 1 i
      if label$ = "i" or label$ = "e" or label$ = "a" or label$ = "o" or label$ = "u"
            a = Get start point... 1 i
            b = Get end point... 1 i
            c = a + (b-a)/3
            d = b - (b-a)/3

            select formantID
            f1 = Get mean... 1 c d Hertz
            f2 = Get mean... 2 c d Hertz
            printline 'label$''tab$''f1:1''tab$''f2:1'
      endif
endfor
Pole proměnných
Pole proměnných je struktura, která umožňuje zpracování více souborů najednou. Zahrnuje několik kroků, které se neliší, a proto je nejvhodnější mít pole „připravené“ a kopírovat ho.

Předpokládejme, že pracujeme současně se zvuky a TextGridy:

1. zjistíme počet souborů daného typu

pocet = numberOfSelected("Sound")

2. pomocí for cyklu objekty zakódujeme

for i from 1 to pocet
      soundID'i' = selected("Sound",i)    ; tím zakódujeme první objekt typu Sound jako soundID1, druhý jako soundID2 atd.
      textID'i' = selected("TextGrid",i)  ; první TextGrid bude uložen pod proměnnou textID1, druhý jako textID2 atd.
endfor

3. postupné překódování v dalším for cyklu

for i from 1 to pocet
      soundID = soundID'i'
      select soundID
      …
      …
endfor

Jedná se o nutnou přesmyčku. Bez ní bychom se setkali s příkazy jako printline ‚jmeno$’i“, které ovšem v Praatu neexistují.

Následující skript tedy všem TextGridům přidá vrstvu se jménem morfemy. Kromě samotného příkazu Insert interval tier můžeme strukturu pole kopírovat a měnit pouze typy objektů.

pocet = numberOfSelected("TextGrid")
for i from 1 to pocet
      textID'i' = selected("TextGrid",i)
endfor

for i from 1 to pocet
      textID = textID'i'
      select textID
      Insert interval tier... 1 morfemy
endfor

Jakýkoli skript tedy můžeme poměrně snadno předělat tak, aby fungoval s více objekty (načtenými soubory). Jen je třeba dávat pozor na počítací proměnnou: v rámci jednoho for cyklu nemůžeme dvakrát použít proměnnou se stejným názvem. Buď ve vnitřním nebo vnějším for cyklu musíme použít například jméno k.

Základní struktura skriptů

Ukázkový skript
Struktura většiny skriptů je velmi podobná, můžeme ji shrnout do následujícího „desatera“ (přičemž ne všechny body jsou povinné):

  1. zakódujeme zvolený zvuk a TextGrid
  2. zvolíme zvuk a vytvoříme další potřebné objekty
  3. zjistíme počet intervalů v cílové vrstvě
  4. zahájíme for-cyklus
  5. zjistíme konkrétní hlásku
  6. podmínkou ověříme, zda hláska odpovídá některé z našich cílových hlásek
  7. zjistíme hranice intervalu, případně dopočítáme úsek měření (polovinu, prostřední třetinu)
  8. zvolíme objekt pro analýzy a spočítáme cílové hodnoty
  9. vypíšeme zjištěné hodnoty, ukončíme cykly
  10. uklidíme po sobě

Následující skript je příkladem, který všechny body využívá:

zvukID = selected ("Sound")
textID = selected ("TextGrid")	                      ; 1. kódování
select zvukID
To Harmonicity (cc)... 0.01 75 0.1 1
harmID = selected ("Formant")	                      ; 2. další objekty
select textID
no = Get number of intervals... 1                     ; 3. počet intervalů
for i from 1 to no	                              ; 4. for cyklus
      select textID
      label$ = Get label of interval... 1 i	      ; 5. zjištění hlásky
      if label$ = "m" or label$ = "n" or label$ = "ň" ; 6. porovnání hlásky
            a = Get start point... 1 i
            b = Get end point... 1 i	              ; 7. zjištění hranic
            select harmID
            hnr = Get mean... a b	              ; 8. zjištění hodnot
            printline 'label$''tab$''harm:2'
      endif
endfor	                                              ; 9. výpis hodnot a ukončení cyklů
select harmID                                         ; 10. úklid
Remove
select zvukID
plus textID

Animované skripty

0. Úvod
1. Informace o zvukovém souboru
2. Informace o TextGridu
3. Výpočet formantů
4. Cykly
5. Průchod TextGridem: výpis labelů
6. Podmínky
7. Přepínání objektů: průměrné formanty a-ových vokálů
8. Hromadné zpracování celého adresáře
9. Časté chyby ve skriptech
10. Náměty

Poznámky: ne vždy se načtou všechny stránky interaktivní prezentace. Titulní stránka i poslední strana jsou výrazně odlišné od ostatních. Pokud máte tedy podezření,
že poslední stránka není skutečně tou poslední, použijte tlačítko Refresh v prohlížeči pro znovunačtení celé prezentace. Vyžaduje prohlížeč kompatibilní s HTML5, vyzkoušeno v Chrome.

Zajímavé klávesové zkratky: o nebo g pro rychlý průchod mezi stránkami, f pro zobrazení přes celou obrazovku.

Demonstrace

Fourier Series 3D interaktivní demonstrace principu Fourierových řad

Poděkování

Tyto stránky a demonstrace byly vytvořeny za podpory vnitřního grantu FF UK v Praze, rok 2015: FF_15_TO1_076 Tvorba multimediálních stránek pro předměty Akustika řeči a Řečové technologie.

Úvod > Studium > Stránky kurzů > Skripty v Praatu a demonstrace