Added a check on the extension of tsv files in SavePerf
[sgc2.git] / MainPage.praat
blobea7869f06cac22c5ecd8710e0600a4910b1f3dec
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         call init_window
183         # Draw the contour
184         call wipeArea 'wipeFeedbackArea$'
185         call display_text Black
186 endproc
188 procedure processMainPageNext .clickX .clickY .pressed$
189         call clean_up_sound
190         call display_text Grey
191         call next_word
192         call init_window
193         # Draw the contour
194         call wipeArea 'wipeFeedbackArea$'
195         call display_text Black
196 endproc
198 procedure processMainPageWordlistUp .clickX .clickY .pressed$
199         call wipeArea 'wipeFeedbackArea$'
200     call load_word_list "'localWordlistDir$'" -1
201         call init_window
202         call display_text Black
203 endproc
205 procedure processMainPageWordlistDown .clickX .clickY .pressed$
206         call wipeArea 'wipeFeedbackArea$'
207     call load_word_list "'localWordlistDir$'" 1
208         call init_window
209         call display_text Black
210 endproc
212 procedure processMainPageGRADE .clickX .clickY .pressed$
213         call setGrade '.pressed$'
214         # Redraw window
215         call init_window
216 endproc
218 ###############################################################
220 # Obligatory button Processing Routines
222 # These MUST be defined
224 ###############################################################
226 procedure processMainPageQuit .clickX .clickY .pressed$
227         call end_program
228 endproc
230 procedure processMainPageRefresh .clickX .clickY .pressed$
231         call init_window
232 endproc
234 procedure processMainPageConfig .clickX .clickY .pressed$
235         call config_page
236 endproc
238 procedure processMainPageHelp .clickX .clickY .pressed$
239         call help_loop 'buttons$' init_window
240 endproc
242 procedure processMainPagePlay .clickX .clickY .pressed$
243         .table$ = "MainPage"
244         .label$ = "Play"
245         if recordedSound$ <> ""
246                 call play_sound 'recordedSound$'
247                 mainPage.play = 0
248         endif
249         te.buttonPressValue = mainPage.play
250 endproc
252 procedure Set_Play_Button
253         mainPage.play = -1
254         if recordedSound$ <> ""
255                 mainPage.play = 0
256     endif       
257         call Draw_button MainPage Play 'mainPage.play'
258 endproc
260 procedure processMainPageRecord .clickX .clickY .pressed$
261         call count_syllables
262         .recordingTime = recordingTime
263         if count_syllables.number > 2
264                 .recordingTime = recordingTime + 1.0*ceiling((count_syllables.number - 2)/2)
265         endif
266     call record_sound '.recordingTime'
267     call recognizeTone
268         mainPage.play = 0
269         call Set_Play_Button
271     # Wipe screen
272     call wipeArea 'wipeContourArea$'
273    
274     call draw_tone_contour
275     # Write text (again)
276     call display_word_list_name
277     call display_text Black
278         call add_feedback_to_toneevaluation Feedback
279     call write_feedback Feedback
280         select Table Feedback
281         Remove
282 endproc
285 ###############################################################
287 # Miscelaneous supporting code
289 ###############################################################
291 # The example
292 procedure generate_example
293         select Table 'wordlist$'
294         if te.currentWord > 0 and te.currentWord <= te.numberOfWords
295                 select Table 'wordlist$'
296                 .sound$ = Get value... 'te.currentWord' Sound
297                 sgc.pinyin$ = Get value... 'te.currentWord' Pinyin
298                 if .sound$ = "-" or .sound$ = ""
299                         .sound$ = sgc.pinyin$+".wav"
300                 endif
301                 .soundFilePath$ = localWordlistDir$+"/"+wordlistName$+"/"+.sound$
302                 .wordlistDirectory$ = ""
303                 if localWordlistDir$ <> "" and fileReadable("'localWordlistDir$'/'wordlistName$'")
304                         .wordlistDirectory$ = "'localWordlistDir$'/'wordlistName$'"
305                 elsif sgc2wordlists$ <> "" and fileReadable("'sgc2wordlists$'/'wordlistName$'")
306                         .wordlistDirectory$ = "'sgc2wordlists$'/'wordlistName$'"
307                 elsif globalwordlists$ <> "" and fileReadable("'globalwordlists$'/'wordlistName$'")
308                         .wordlistDirectory$ = "'globalwordlists$'/'wordlistName$'"
309                 endif
310                 if .wordlistDirectory$ <> ""
311                         .audioExampleList = Create Strings as file list... AudioList '.wordlistDirectory$'/'sgc.pinyin$'.*
312                         .number_of_examples = Get number of strings
313                         if .number_of_examples > 0
314                                 Randomize
315                                 .sound$ = Get string... 1
316                                 .soundFilePath$ = "'.wordlistDirectory$'/'.sound$'"
317                         endif
318                         Remove
319                 endif
320                 if fileReadable(.soundFilePath$) and config.useSoundExample
321                         .tmp = -1
322                         .tmp = nocheck Read from file... '.soundFilePath$'
323                         if .tmp != undefined and .tmp > 0
324                                 Play
325                                 Remove
326                         endif
327                 elsif config.synthesis$ <> "" and config.synthesis$ <> "_DISABLED_"
328                         call synthesize_sound 'sgc.pinyin$'
329                 else
330                         call humToneContour 'sgc.pinyin$' 'config.register'
331                         call reset_viewport
332                 endif
333         endif
334         demoShow()
335 endproc
337 # Draw a tone contour
338 procedure draw_tone_contour
339         select Table 'wordlist$'
340         if te.currentWord > 0 and te.currentWord <= te.numberOfWords
341                 .sound$ = Get value... 'te.currentWord' Sound
342                 sgc.pinyin$ = Get value... 'te.currentWord' Pinyin
343                 call drawToneContour 'sgc.pinyin$' 'config.register'
344                 call reset_viewport
345                 
346                 if te.recordedPitch > 0
347                         call drawSourceToneContour te.recordedPitch
348                 endif
349         endif
351 endproc
353 procedure recognizeTone
354         select Table 'wordlist$'
355         if te.currentWord > 0 and te.currentWord <= te.numberOfWords
356                 .sound$ = Get value... 'te.currentWord' Sound
357                 sgc.pinyin$ = Get value... 'te.currentWord' Pinyin
358                 call align_recordedSound 'sgc.pinyin$'
359         call sgc_ToneProt 'recordedSound$' 'sgc.pinyin$' 'config.register' 'config.strict' 'config.language$'
360         # sgc_ToneProt manipulates the sound given. Reconnect
361         select Sound 'recordedSound$'
362         te.recordedSound = selected("Sound")
363                 call reset_viewport
364         endif
365 endproc
367 procedure write_feedback .table$
368     select Table '.table$'
369     .line1$ = Get value... 1 Text
370     .line2$ = Get value... 2 Text
371     .label$ = Get value... 3 Text
373         # convert numbers to Pinyin if needed
374         if not config.displayNumbers
375                 call numbers2pinyin '.line1$'
376                 .line1$ = numbers2pinyin.pinyin$
377         endif
379     .color$ = "Red"
380     if index(.line1$, "???") > 0
381         .color$ = "Black"
382     elsif .label$ = "Correct"
383         .color$ = "Green"
384         elsif config.strict
385                 .line2$ = .line2$ + " *"
386     endif
388         .currentFeedbackFontSize = 14
389         .maxHeight = 21 - 17
390         call adjustFontSizeOnHeight 'defaultFont$' '.currentFeedbackFontSize' '.maxHeight'
391         .currentFeedbackFontSize = adjustFontSizeOnHeight.newFontSize
392         
393         call wipeArea 'wipeFeedbackArea$'
394     call set_font_size '.currentFeedbackFontSize'
395     demo '.color$'
396     demo Text... 50 Centre 21 Bottom '.line1$'
397     demo Text... 50 Centre 17 Bottom '.line2$'
398         demoShow()
399         demo 'defaultFont$'
400     call set_font_size 'defaultFontSize'
401 endproc
403 # Text display
404 procedure display_text .color$
405         select Table 'wordlist$'
406         if te.currentWord < 0 or te.currentWord > te.numberOfWords+1
407                 call clean_up_sound
408         if config.shuffleLists
409                     Randomize rows
410         endif
411                 if te.currentWord < 0
412                         te.currentWord = te.numberOfWords
413                 else
414                         te.currentWord = 1
415                 endif
416         endif
417         
418         if te.currentWord > 0 and te.currentWord <= te.numberOfWords
419                 .displayText$ = ""
420                 .displayPinyin$ = Get value... 'te.currentWord' Pinyin
421                 .displayChar$ = Get value... 'te.currentWord' Character
422                 .displayTrans$ = Get value... 'te.currentWord' Translation
423                 if .displayPinyin$ <> "-" and config.displayPinyin
424                         if not config.displayNumbers
425                                 call numbers2pinyin '.displayPinyin$'
426                                 .displayPinyin$ = numbers2pinyin.pinyin$
427                         endif
428                         # Insert u umlaut
429                         .displayPinyin$ = replace_regex$(.displayPinyin$, "v", "\\u\X22", 0)
430                         .displayText$ = .displayText$ + .displayPinyin$
431                 endif
432                 if .displayChar$ <> "-" and config.displayChar
433                         .displayText$ = .displayText$ + "  "+ .displayChar$
434                 endif
435                 if .displayTrans$ <> "-" and config.displayTrans
436                         .displayText$ = .displayText$ + "  \s{%%"+ .displayTrans$ + "%}"
437                 endif
438         elsif te.currentWord = 0 or te.currentWord = te.numberOfWords+1
439                 call clean_up_sound
440                 .displayText$ = "---"
441         endif
443         # Adapt font size
444         call adjustFontSizeOnHeight 'defaultFont$' 24 15
445         .currentFontSize = adjustFontSizeOnHeight.newFontSize
446         call adjustFontSizeOnWidth 'defaultFont$' '.currentFontSize' 95 '.displayText$'
447         .currentFontSize = adjustFontSizeOnWidth.newFontSize
449         # Clear the writing area
450         call wipeArea 'wipePinyinArea$'
451         # Actually display text
452         demo '.color$'
453         call set_font_size '.currentFontSize'
454         demo Text... 50 Centre 26 Bottom '.displayText$'
455         demoShow()
456         demo Black
457         demo 'defaultFont$'
458         call set_font_size 'defaultFontSize'
459 endproc
461 procedure numbers2pinyin .numberstext$
462         .intermediatePinyin$ = .numberstext$
463         # Move numbers to the nucleus vowel
464         # Tot he vowel
465         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([^aeuiov0-9]*)([0-9])", "\1\3\2", 0)
466         # Either a/e
467         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([ae])([aeuiov]*)([0-9])", "\1\3\2", 0)
468         # Or the Oo in /ou/
469         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(ou)([0-9])", "o\2u", 0)
470         # or the second vowel
471         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([uiov][aeuiov])([uiov])([0-9])", "\1\3\2", 0)
472         
473         # Convert all to special characters
474         # Tone 1
475         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a1", "ā", 0)
476         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e1", "ē", 0)
477         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u1", "ū", 0)
478         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i1", "ī", 0)
479         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o1", "ō", 0)
480         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v1", "ǖ", 0)
481         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "1", "\\-^", 0)
482         
483         # Tone 2
484         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v2", "ǘ", 0)
485         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])2", "\\\1'", 0)
486         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "2", "\\'^", 0)
487         
488         # Tone 3
489         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a3", "ǎ", 0)
490         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e3", "ě", 0)
491         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u3", "ǔ", 0)
492         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i3", "ǐ", 0)
493         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o3", "ǒ", 0)
494         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v3", "ǚ", 0)
495         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "3", "\\N^", 0)
497         # Tone 4
498         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v4", "ǜ", 0)
499         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])4", "\\\1`", 0)
500         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "4", "\\`^", 0)
501         
502         # Tone 0
503         # Remove tone 0 symbol completely
504         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "", 0)
505         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a0", "å", 0)
506         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e0", "e̊", 0)
507         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u0", "ů", 0)
508         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i0", "i̊", 0)
509         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o0", "o̊", 0)
510         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v0", "ü̊", 0)
511         #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "\\0^", 0)
512         
513         # Pick best vowel symbols available in cases not caught before
514         # Ugly clutch to get the 1, 3, 0 tone diacritics at least in the neighbourhood
515         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i(\\[-N0]\^)", "i\\s{_ }\1", 0)
516         # Insert u umlaut
517         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v", "\\u\X22", 0)
519         .pinyin$ = .intermediatePinyin$
520 endproc
522 # NEEDS WORK AND TESTING!!
523 # Convert unicode Pinyin into tone numbers
524 procedure pinyin2numbers .pinyin$
525         .intermediatePinyin$ = .pinyin$
526         # Convert all special characters to numbers
527         # Tone 1
528         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ā([iaeouü]*)", "a\11", 0)
529         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ē([iaeouü]*)", "e\11", 0)
530         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ū([iaeouü]*)", "u\11", 0)
531         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ī([iaeouü]*)", "i\11", 0)
532         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ō([iaeouü]*)", "o\11", 0)
533         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ǖ([iaeouü]*)", "v\11", 0)
534         
535         # Tone 2
536         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "á([iaeouü]*)", "a\12", 0)
537         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "é([iaeouü]*)", "e\12", 0)
538         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ú([iaeouü]*)", "u\12", 0)
539         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "í([iaeouü]*)", "i\12", 0)
540         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ó([iaeouü]*)", "o\12", 0)
541         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ǘ([iaeouü]*)", "v\12", 0)
542         
543         # Tone 3
544         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ǎ([iaeouü]*)", "a\13", 0)
545         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ě([iaeouü]*)", "e\13", 0)
546         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ǔ([iaeouü]*)", "u\13", 0)
547         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ǐ([iaeouü]*)", "i\13", 0)
548         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ǒ([iaeouü]*)", "o\13", 0)
549         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ǚ([iaeouü]*)", "v\13", 0)
551         # Tone 4
552         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "à([iaeouü]*)", "a\14", 0)
553         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "è([iaeouü]*)", "e\14", 0)
554         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ù([iaeouü]*)", "u\14", 0)
555         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ì([iaeouü]*)", "i\14", 0)
556         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ò([iaeouü]*)", "o\14", 0)
557         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ǜ([iaeouü]*)", "v\14", 0)
558         
559         # Tone 0
560         # Add tone 0
561         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "å([iaeouü]*)", "a\10", 0)
562         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e̊([iaeouü]*)", "e\10", 0)
563         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ů([iaeouü]*)", "u\10", 0)
564         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i̊([iaeouü]*)", "i\10", 0)
565         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o̊([iaeouü]*)", "o\10", 0)
566         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ü̊([iaeouü]*)", "v\10", 0)
568         # Syllables without a tone symbol are tone 0
569         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov]+)([^0-9aeuiov]|$)", "\10\2", 0)
571         # Move numbers to the end of the syllable
572         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])((ng?)([^aeuiov]|$))?", "\1\3\2\4", 0)
573         
574         .numberstext$ = .intermediatePinyin$
575 endproc
577 # Includes
578 include ToneProt/SGC_ToneProt.praat
579 include ToneProt/DrawToneContour.praat
580 include ToneProt/HumToneContour.praat
581 include ToneProt/ToneRecognition.praat
582 include ToneProt/ToneScript.praat
583 include ToneProt/ToneRules.praat