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