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