New icons
[sgc2.git] / MainPage.praat
blobf3b407665c641c2fb39bf9ffe116ea7ff4c5c286
2 # SpeakGoodChinese 2.0
3
4 # Praat script handling buttons page
6 #     SpeakGoodChinese: MainPage.praat loads the code needed for the 
7 #     main, practice, page of SGC2 and the sound handling and recognition.
8 #     
9 #     Copyright (C) 2007-2010  R.J.J.H. van Son and 2010 the Netherlands Cancer Institute
10 #     The SpeakGoodChinese team are:
11 #     Guangqin Chen, Zhonyan Chen, Stefan de Koning, Eveline van Hagen, 
12 #     Rob van Son, Dennis Vierkant, David Weenink
13
14 #     This program is free software; you can redistribute it and/or modify
15 #     it under the terms of the GNU General Public License as published by
16 #     the Free Software Foundation; either version 2 of the License, or
17 #     (at your option) any later version.
18
19 #     This program is distributed in the hope that it will be useful,
20 #     but WITHOUT ANY WARRANTY; without even the implied warranty of
21 #     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 #     GNU General Public License for more details.
23
24 #     You should have received a copy of the GNU General Public License
25 #     along with this program; if not, write to the Free Software
26 #     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
27
28 # Includes at the bottom
30 ###############################################################
32 # Button Drawing Routines
34 ###############################################################
36 procedure DrawPrevious .color$ .x .y .size
37         demo '.color$'
38         .size *= 2/3
39         call drawTriangle -1 .x .y .size
40         .currentX = drawTriangle.currentX
41         .endX = .currentX - 0.5
42         .lowY = .y - .size
43         .highY = .y + .size
44         demo Paint rectangle... '.color$' '.currentX' '.endX' '.lowY' '.highY'
45 endproc
47 procedure DrawNext .color$ .x .y .size
48         demo '.color$'
49         .size *= 2/3
50         call drawTriangle 1 .x .y .size
51         .currentX = drawTriangle.currentX
52         .endX = .currentX + 0.5
53         .lowY = .y - .size
54         .highY = .y + .size
55         demo Paint rectangle... '.color$' '.currentX' '.endX' '.lowY' '.highY'
56 endproc
58 procedure DrawWordListUp .color$ .x .y .size
59     .xleft = .x - .size
60     .xright = .x + .size
61     .xmidleft = .x + 0.1
62     .xmidright = .x - 0.1
63     .ylow = .y
64     .yhigh = .y + .size
65         demo '.color$'
66         demo Line width... 3
67         demo Draw line... .xleft .ylow .xmidleft .yhigh
68         demo Draw line... .xright .ylow .xmidright .yhigh
69         demo Line width... 'defaultLineWidth'
70         demo Black
71 endproc
73 procedure DrawWordListDown .color$ .x .y .size
74     .xleft = .x - .size
75     .xright = .x + .size
76     .xmidleft = .x + 0.1
77     .xmidright = .x - 0.1
78     .yhigh = .y + .size
79     .ylow = .y
80         demo '.color$'
81         demo Line width... 3
82         demo Draw line... .xleft .yhigh .xmidleft .ylow
83         demo Draw line... .xright .yhigh .xmidright .ylow
84         demo Line width... 'defaultLineWidth'
85         demo Black
86 endproc
88 procedure drawTriangle .direction .x .y .size
89         # Make sure direction = +/- 1
90         if .direction = 0
91                 .direction = 1 
92         endif
93         .direction /= abs(.direction)
94         
95         .offset = 0.01
96         .currentHeight = .size
97         .currentX = .x - .direction*.size
98         
99         demo Line width... 2.0
101         while .currentHeight> 0
102                 .ystart = .y + .currentHeight
103                 .yend = .y - .currentHeight
104                 demo Draw line... .currentX .ystart .currentX .yend
105                 .currentHeight -= .offset *3/4
106                 .currentX += .direction*.offset * 1.5
107         endwhile
108         demo Line width... 'defaultLineWidth'
109 endproc
111 ###############################################################
113 # Obligatory button Drawing Routines
115 # These MUST be defined
117 ###############################################################
119 procedure DrawRecord .color$ .x .y .size
120         .size /= 2
121     demo Paint circle... '.color$' '.x' '.y' '.size'
122 endproc
124 procedure DrawPlay .color$ .x .y .size
125         demo '.color$'
126         call drawTriangle 1 .x .y .size
127 endproc
129 procedure DrawQuit .color$ .x .y .size
130         demo Colour... '.color$'
131         .lineWidth = 0.5*.size**2
132         demo Line width... '.lineWidth'
133         .xstart = .x - .size
134         .ystart = .y + .size
135         .xend = .x + .size
136         .yend = .y - .size
137         demo Draw line... .xstart .ystart .xend .yend
138         .xstart = .x - .size
139         .ystart = .y - .size
140         .xend = .x + .size
141         .yend = .y + .size
142         demo Draw line... .xstart .ystart .xend .yend
143         demo Line width... 'defaultLineWidth'
144         demo Colour... Black
145 endproc
147 procedure DrawConfig .color$ .x .y .size
148         .size *= 1
149         .lineWidth = 0.4*.size
150         demo Arrow size... '.lineWidth'
151         .lineWidth = 0.4*.size**2
152         demo Line width... '.lineWidth'
153         .y += .size/2
154         .xstart = .x - .size
155         .xend = .x + .size
156         demo Draw arrow... .xstart .y .xend .y
157         demo Line width... 'defaultLineWidth'
158 endproc
160 procedure DrawRefresh .color$ .x .y .size
161         .lineWidth = 0.5*.size**2
162         .size /= 2
163         demo Line width... '.lineWidth'
164         demo Draw arc... '.x' '.y' '.size' 0 270
165         demo Line width... 'defaultLineWidth'
166 endproc
168 ###############################################################
170 # Button Processing Routines
172 ###############################################################
174 procedure processMainPageExample .clickX .clickY .pressed$
175         call generate_example
176 endproc
178 procedure processMainPagePrevious .clickX .clickY .pressed$
179         call clean_up_sound
180         call display_text Grey
181         call previous_word
182         # Draw the contour
183         call wipeArea 'wipeFeedbackArea$'
184         call init_window
185         call display_text Black
186         
187         sgc.failedAttempts = 0
188 endproc
190 procedure processMainPageNext .clickX .clickY .pressed$
191         call clean_up_sound
192         call display_text Grey
193         call next_word
194         call wipeArea 'wipeFeedbackArea$'
195         call init_window
196         # Draw the contour
197         call display_text Black
198 endproc
200 procedure processMainPageWordlistUp .clickX .clickY .pressed$
201         call wipeArea 'wipeFeedbackArea$'
202     call load_word_list "'localWordlistDir$'" -1
203         call init_window
204         call display_text Black
205 endproc
207 procedure processMainPageWordlistDown .clickX .clickY .pressed$
208         call wipeArea 'wipeFeedbackArea$'
209     call load_word_list "'localWordlistDir$'" 1
210         call init_window
211         call display_text Black
212 endproc
214 procedure processMainPageGRADE .clickX .clickY .pressed$
215         call setGrade '.pressed$'
216         # Redraw window
217         call init_window
218 endproc
220 procedure processMainPagePinYinArea .clickX .clickY .pressed$
221         # Redraw window
222         sgc.writeAll = 1
223         call display_text Red
224         sgc.writeAll = 0
225 endproc
227 ###############################################################
229 # Obligatory button Processing Routines
231 # These MUST be defined
233 ###############################################################
235 procedure processMainPageQuit .clickX .clickY .pressed$
236         call end_program
237 endproc
239 procedure processMainPageRefresh .clickX .clickY .pressed$
240         call clean_up_sound
241         call init_window
242 endproc
244 procedure processMainPageConfig .clickX .clickY .pressed$
245         call config_page
246 endproc
248 procedure processMainPageHelp .clickX .clickY .pressed$
249         call help_loop 'buttons$' init_window
250 endproc
252 procedure processMainPagePlay .clickX .clickY .pressed$
253         .table$ = "MainPage"
254         .label$ = "Play"
255         if recordedSound$ <> ""
256                 call play_sound 'sgc.recordedSound'
257                 mainPage.play = 0
258         endif
259         te.buttonPressValue = mainPage.play
260 endproc
262 procedure Set_Play_Button
263         mainPage.play = -1
264         if recordedSound$ <> ""
265                 mainPage.play = 0
266     endif       
267         call Draw_button MainPage Play 'mainPage.play'
268 endproc
270 procedure processMainPageRecord .clickX .clickY .pressed$
271         call count_syllables
272         .recordingTime = recordingTime
273         if count_syllables.number > 2
274                 .recordingTime = recordingTime + 1.0*ceiling((count_syllables.number - 2)/2)
275         endif
276     call record_sound '.recordingTime'
277     call recognizeTone
278         mainPage.play = 0
279         call Set_Play_Button
281     # Wipe screen
282     call wipeArea 'wipeContourArea$'
283    
284     call draw_tone_contour
285     # Write text (again)
286     call display_word_list_name
287     call display_text Black
288         call add_feedback_to_toneevaluation Feedback
289     call write_feedback Feedback
290         select Table Feedback
291         Remove
292         
293         # Do not exercise words that are going well (autoSelect)
294     if add_feedback_to_toneevaluation.result > 0
295                 if config.adaptiveLists > 0 and sgc.failedAttempts < 2
296                         # Deselect current word
297                         select Table 'wordlist$'
298                         .i = Search column: "Pinyin", sgc.pinyin$
299                         if .i > 0
300                                 Set string value: .i, "Show", "-"
301                         endif
302                 endif
303                 sgc.failedAttempts = 0
304     else
305                 sgc.failedAttempts += 1
306     endif
307 endproc
310 ###############################################################
312 # Miscelaneous supporting code
314 ###############################################################
316 # The example
317 procedure generate_example
318         select Table 'wordlist$'
319         if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
320                 select Table 'wordlist$'
321                 .sound$ = Get value... 'sgc.currentWord' Sound
322                 call readPinyin 'sgc.currentWord'
323                 sgc.pinyin$ = readPinyin.pinyin$
324                 if .sound$ = "-" or .sound$ = ""
325                         .sound$ = sgc.pinyin$+".wav"
326                 endif
327                 .soundFilePath$ = localWordlistDir$+"/"+wordlistName$+"/"+.sound$
328                 .wordlistDirectory$ = ""
329                 if localWordlistDir$ <> "" and fileReadable("'localWordlistDir$'/'wordlistName$'")
330                         .wordlistDirectory$ = "'localWordlistDir$'/'wordlistName$'"
331                 elsif sgc2wordlists$ <> "" and fileReadable("'sgc2wordlists$'/'wordlistName$'")
332                         .wordlistDirectory$ = "'sgc2wordlists$'/'wordlistName$'"
333                 elsif globalwordlists$ <> "" and fileReadable("'globalwordlists$'/'wordlistName$'")
334                         .wordlistDirectory$ = "'globalwordlists$'/'wordlistName$'"
335                 endif
336                 if .wordlistDirectory$ <> ""
337                         .audioExampleList = Create Strings as file list... AudioList '.wordlistDirectory$'/'sgc.pinyin$'.*
338                         .number_of_examples = Get number of strings
339                         if .number_of_examples > 0
340                                 Randomize
341                                 .sound$ = Get string... 1
342                                 .soundFilePath$ = "'.wordlistDirectory$'/'.sound$'"
343                         endif
344                         Remove
345                 endif
346                 if fileReadable(.soundFilePath$) and config.useSoundExample
347                         .tmp = -1
348                         .tmp = nocheck Read from file... '.soundFilePath$'
349                         if .tmp != undefined and .tmp > 0
350                                 call play_sound '.tmp'
351                                 select .tmp
352                                 Remove
353                         endif
354                 elsif config.synthesis$ <> "" and config.synthesis$ <> "_DISABLED_"
355                         call synthesize_sound 'sgc.pinyin$'
356                 else
357                         call humToneContour 'sgc.pinyin$' 'config.register'
358                         call reset_viewport
359                 endif
360         endif
361         demoShow()
362 endproc
364 # Draw a tone contour
365 procedure draw_tone_contour
366         select Table 'wordlist$'
367         if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
368                 .sound$ = Get value... 'sgc.currentWord' Sound
369                 call readPinyin 'sgc.currentWord'
370                 sgc.pinyin$ = readPinyin.pinyin$
371                 call drawToneContour 'sgc.pinyin$' 'config.register'
372                 call reset_viewport
373                 
374                 if te.recordedPitch > 0
375                         call drawSourceToneContour te.recordedPitch
376                 endif
377         endif
379 endproc
381 procedure recognizeTone
382         select Table 'wordlist$'
383         if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
384                 .strict = 0
385                 if index_regex(config.strict$, "[^0-9]") <= 0
386                         .strict = ('config.strict$' >= sgc.highestLevel)
387                 endif
388                         
389                 .sound$ = Get value... 'sgc.currentWord' Sound
390                 call readPinyin 'sgc.currentWord'
391                 sgc.pinyin$ = readPinyin.pinyin$
392                 call align_recordedSound 'sgc.pinyin$'
393         call sgc_ToneProt 'recordedSound$' 'sgc.pinyin$' 'config.register' '.strict' 'config.language$'
394         # sgc_ToneProt manipulates the sound given. Reconnect
395         select Sound 'recordedSound$'
396         sgc.recordedSound = selected("Sound")
397                 call reset_viewport
398         endif
399 endproc
401 procedure write_feedback .table$
402     select Table '.table$'
403     .line1$ = Get value... 1 Text
404     .line2$ = Get value... 2 Text
405     .label$ = Get value... 3 Text
407         # convert numbers to Pinyin if needed
408         if not config.displayNumbers
409                 call numbers2pinyin '.line1$'
410                 .line1$ = numbers2pinyin.pinyin$
411         endif
413     .color$ = "Red"
414     if index(.line1$, "???") > 0
415         .color$ = "Black"
416     elsif .label$ = "Correct"
417         .color$ = "Green"
418         elsif config.strict$ = "'sgc.highestLevel'"
419                 .line2$ = .line2$ + " *"
420     endif
422         .currentFeedbackFontSize = 14
423         .maxHeight = 21 - 17
424         call adjustFontSizeOnHeight 'defaultFont$' '.currentFeedbackFontSize' '.maxHeight'
425         .currentFeedbackFontSize = adjustFontSizeOnHeight.newFontSize
426         
427         call wipeArea 'wipeFeedbackArea$'
428     call set_font_size '.currentFeedbackFontSize'
429     demo '.color$'
430     demo Text... 50 Centre 21 Bottom '.line1$'
431     demo Text... 50 Centre 17 Bottom '.line2$'
432         demoShow()
433         demo 'defaultFont$'
434     call set_font_size 'defaultFontSize'
435 endproc
437 # Text display
438 procedure display_text .color$
439         select Table 'wordlist$'
440         if sgc.currentWord < 0 or sgc.currentWord > sgc.numberOfWords+1
441                 call clean_up_sound
442         if config.shuffleLists
443                     Randomize rows
444         endif
445                 if sgc.currentWord < 0
446                         sgc.currentWord = sgc.numberOfWords
447                 else
448                         sgc.currentWord = 1
449                 endif
450         endif
451         
452         .changeCJKstyle = 0
453         if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
454                 .displayText$ = ""
455                 call readDisplayPinyin 'sgc.currentWord'
456                 .displayPinyin$ = readDisplayPinyin.pinyin$
457                 .displayChar$ = Get value... 'sgc.currentWord' Character
458                 .displayTrans$ = Get value... 'sgc.currentWord' Translation
459                 if .displayPinyin$ <> "-" and (config.displayPinyin or sgc.writeAll)
460                         if not config.displayNumbers
461                                 call numbers2pinyin '.displayPinyin$'
462                                 .displayPinyin$ = numbers2pinyin.pinyin$
463                         endif
464                         # Insert u umlaut
465                         .displayPinyin$ = replace_regex$(.displayPinyin$, "v", "\\u\X22", 0)
466                         .displayText$ = .displayText$ + .displayPinyin$
467                 endif
468                 if .displayChar$ <> "-" and (config.displayChar or sgc.writeAll)
469                         .displayText$ = .displayText$ + "  "+ .displayChar$
470                         .changeCJKstyle = 1
471                 endif
472                 if .displayTrans$ <> "-" and (config.displayTrans or sgc.writeAll)
473                         .displayText$ = .displayText$ + "  \s{%%"+ .displayTrans$ + "%}"
474                 endif
475         elsif sgc.currentWord = 0 or sgc.currentWord = sgc.numberOfWords+1
476                 call clean_up_sound
477                 .displayText$ = "---"
478         endif
480         # Adapt font size
481         call adjustFontSizeOnHeight 'defaultFont$' 24 15
482         .currentFontSize = adjustFontSizeOnHeight.newFontSize
483         call adjustFontSizeOnWidth 'defaultFont$' '.currentFontSize' 95 '.displayText$'
484         .currentFontSize = adjustFontSizeOnWidth.newFontSize
486         # Clear the writing area
487         call wipeArea 'wipePinyinArea$'
488         # Switch back to Chinese style CJK when in Japanese language mode
489         if .changeCJKstyle and config.language$ = "JA"
490                 CJK font style preferences: "Chinese"
491         endif
492         # Actually display text
493         demo '.color$'
494         call set_font_size '.currentFontSize'
495         demo Text... 50 Centre 26 Bottom '.displayText$'
496         demoShow()
497         demo Black
498         demo 'defaultFont$'
499         call set_font_size 'defaultFontSize'
500         if .changeCJKstyle and config.language$ = "JA"
501                 if config.language$ = "JA"
502                         CJK font style preferences: "Japanese"
503                 elsif config.language$ = "ZH"
504                         CJK font style preferences: "Chinese"
505                 endif
506         endif
507         # Switch back to Japanese style CJK when in Japanese language mode
508         if .changeCJKstyle and config.language$ = "JA"
509                 CJK font style preferences: "Japanese"
510         endif
511 endproc
513 procedure numbers2pinyin .numberstext$
514         .intermediatePinyin$ = .numberstext$
515         # Add a `-quote between vowels
516         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])([aeuiov])", "\1\2'\3", 0)
517         # Move numbers to the nucleus vowel
518         # To the vowel
519         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([^aeuiov0-9]*)([0-9])", "\1\3\2", 0)
520         # Either a/e
521         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([ae])([aeuiov]*)([0-9])", "\1\3\2", 0)
522         # Or the Oo in /ou/
523         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(ou)([0-9])", "o\2u", 0)
524         # or the second vowel
525         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([uiov][aeuiov])([uiov])([0-9])", "\1\3\2", 0)
526         
527         # Convert all tones to special characters
528         # Tone 1
529         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a1", "ā", 0)
530         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e1", "ē", 0)
531         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u1", "ū", 0)
532         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i1", "ī", 0)
533         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o1", "ō", 0)
534         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v1", "ǖ", 0)
535         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "1", "\\-^", 0)
536         
537         # Tone 2
538         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v2", "ǘ", 0)
539         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])2", "\\\1'", 0)
540         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "2", "\\'^", 0)
541         
542         # Tone 3
543         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a3", "ǎ", 0)
544         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e3", "ě", 0)
545         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u3", "ǔ", 0)
546         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i3", "ǐ", 0)
547         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o3", "ǒ", 0)
548         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v3", "ǚ", 0)
549         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "3", "\\N^", 0)
551         # Tone 4
552         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v4", "ǜ", 0)
553         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])4", "\\\1`", 0)
554         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "4", "\\`^", 0)
555         
556         # Tone 0
557         # Remove tone 0 symbol completely
558         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "", 0)
559         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a0", "å", 0)
560         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e0", "e̊", 0)
561         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u0", "ů", 0)
562         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i0", "i̊", 0)
563         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o0", "o̊", 0)
564         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v0", "ü̊", 0)
565         #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "\\0^", 0)
566         
567         # Pick best vowel symbols available in cases not caught before
568         # Ugly clutch to get the 1, 3, 0 tone diacritics at least in the neighbourhood
569         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i(\\[-N0]\^)", "i\\s{_ }\1", 0)
570         # Insert u umlaut
571         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v", "\\u\X22", 0)
573         .pinyin$ = .intermediatePinyin$
574 endproc
576 # NEEDS WORK AND TESTING!!
577 # Convert unicode Pinyin into tone numbers
578 procedure pinyin2numbers .pinyin$
579         .intermediatePinyin$ = .pinyin$
580         # Convert all special characters to numbers
581         # Tone 1
582         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iā)([iaeouü]*)", "a\11", 0)
583         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iē)([iaeouü]*)", "e\11", 0)
584         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iū)([iaeouü]*)", "u\11", 0)
585         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iī)([iaeouü]*)", "i\11", 0)
586         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iō)([iaeouü]*)", "o\11", 0)
587         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǖ)([iaeouü]*)", "v\11", 0)
588         
589         # Tone 2
590         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iá)([iaeouü]*)", "a\12", 0)
591         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ié)([iaeouü]*)", "e\12", 0)
592         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iú)([iaeouü]*)", "u\12", 0)
593         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ií)([iaeouü]*)", "i\12", 0)
594         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ió)([iaeouü]*)", "o\12", 0)
595         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǘ)([iaeouü]*)", "v\12", 0)
596         
597         # Tone 3
598         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǎ)([iaeouü]*)", "a\13", 0)
599         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iě)([iaeouü]*)", "e\13", 0)
600         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǔ)([iaeouü]*)", "u\13", 0)
601         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǐ)([iaeouü]*)", "i\13", 0)
602         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǒ)([iaeouü]*)", "o\13", 0)
603         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǚ)([iaeouü]*)", "v\13", 0)
605         # Tone 4
606         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ià)([iaeouü]*)", "a\14", 0)
607         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iè)([iaeouü]*)", "e\14", 0)
608         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iù)([iaeouü]*)", "u\14", 0)
609         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iì)([iaeouü]*)", "i\14", 0)
610         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iò)([iaeouü]*)", "o\14", 0)
611         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǜ)([iaeouü]*)", "v\14", 0)
612         
613         # Tone 0
614         # Add tone 0
615         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iå)([iaeouü]*)", "a\10", 0)
616         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e̊([iaeouü]*)", "e\10", 0)
617         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iů)([iaeouü]*)", "u\10", 0)
618         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i̊([iaeouü]*)", "i\10", 0)
619         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o̊([iaeouü]*)", "o\10", 0)
620         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ü̊([iaeouü]*)", "v\10", 0)
622         # Syllables without a tone symbol are tone 0
623         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov]+)([^0-9aeuiov]|\W|$)", "\10\2", 0)
625         # Move numbers to the end of the syllable.
626         # Syllables ending in n and start with g. Note that a syllable cannot start with an u or i
627         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(n)(g[aeuiov])", "\1\3\2\4", 0)
628         # Syllables ending in (ng?) followed by something that is not a valid vowel 
629         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(ng?)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
630         # Syllables ending in r
631         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(r)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
632         # Remove quotes etc
633         #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "[\\'\\`]", "", 0)
634         
635         .numberstext$ = .intermediatePinyin$
636 endproc
638 procedure readDisplayPinyin .currentWord
639         select Table 'wordlist$'
640         .pinyin$ = Get value... '.currentWord' Pinyin
641         # Everything to lowercase
643         if index_regex(.pinyin$, "[0-9]") <= 0
644                 call pinyin2numbers '.pinyin$'
645                 .pinyin$ = pinyin2numbers.numberstext$
646         endif 
647 endproc
649 procedure readPinyin .currentWord
650         call readDisplayPinyin '.currentWord'
651         .pinyin$ = replace_regex$(readDisplayPinyin.pinyin$, ".+", "\L&", 0)
652         .pinyin$ = replace_regex$(.pinyin$, "[\\'\\` ]", "", 0)
653 endproc
655 # Includes
656 include ToneProt/SGC_ToneProt.praat
657 include ToneProt/DrawToneContour.praat
658 include ToneProt/HumToneContour.praat
659 include ToneProt/ToneRecognition.praat
660 include ToneProt/ToneScript.praat
661 include ToneProt/ToneRules.praat