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