Switched eSpeak voice and increased speaking speed
[sgc2.git] / MainPage.praat
blob43700b31b004813822be233a27f032748d38c379
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 display_text Grey
180         currentWord -= 1
181         call init_window
182         # Draw the contour
183         call draw_tone_contour
184         call wipeArea 'wipeFeedbackArea$'
185         call display_text Black
186 endproc
188 procedure processMainPageNext .clickX .clickY .pressed$
189         call display_text Grey
190         currentWord += 1
191         call init_window
192         # Draw the contour
193         call draw_tone_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 write_word_list
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 write_word_list
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
243     # Write text (again)
244     call display_word_list_name
245     call display_text Black
246         call add_feedback_to_toneevaluation Feedback
247     call write_feedback Feedback
248         select Table Feedback
249         Remove
250 endproc
253 ###############################################################
255 # Miscelaneous supporting code
257 ###############################################################
259 # The example
260 procedure generate_example
261         select Table 'wordlist$'
262         if currentWord > 0 and currentWord <= numberOfWords
263                 select Table 'wordlist$'
264                 .sound$ = Get value... 'currentWord' Sound
265                 .pinyin$ = Get value... 'currentWord' Pinyin
266                 if .sound$ = "-" or .sound$ = ""
267                         .sound$ = .pinyin$+".wav"
268                 endif
269                 .soundFilePath$ = localWordlistDir$+"/"+wordlistName$+"/"+.sound$
270                 .wordlistDirectory$ = ""
271                 if localWordlistDir$ <> "" and fileReadable("'localWordlistDir$'/'wordlistName$'")
272                         .wordlistDirectory$ = "'localWordlistDir$'/'wordlistName$'"
273                 elsif sgc2wordlists$ <> "" and fileReadable("'sgc2wordlists$'/'wordlistName$'")
274                         .wordlistDirectory$ = "'sgc2wordlists$'/'wordlistName$'"
275                 elsif globalwordlists$ <> "" and fileReadable("'globalwordlists$'/'wordlistName$'")
276                         .wordlistDirectory$ = "'globalwordlists$'/'wordlistName$'"
277                 endif
278                 if .wordlistDirectory$ <> ""
279                         .audioExampleList = Create Strings as file list... AudioList '.wordlistDirectory$'/'.pinyin$'.*
280                         .number_of_examples = Get number of strings
281                         if .number_of_examples > 0
282                                 Randomize
283                                 .sound$ = Get string... 1
284                                 .soundFilePath$ = "'.wordlistDirectory$'/'.sound$'"
285                         endif
286                         Remove
287                 endif
288                 if fileReadable(.soundFilePath$) and config.useSoundExample
289                         Read from file... '.soundFilePath$'
290                         Play
291                         Remove
292                 elsif config.synthesis$ <> "" and config.synthesis$ <> "_DISABLED_"
293                         call synthesize_sound '.pinyin$'
294                 else
295                         call humToneContour '.pinyin$' 'config.register'
296                         call reset_viewport
297                 endif
298         endif
299         demoShow()
300 endproc
302 # Draw a tone contour
303 procedure draw_tone_contour
304     # Wipe screen
305         call reset_viewport
306     call wipeArea 'wipeContourArea$'
307         select Table 'wordlist$'
308         if currentWord > 0 and currentWord <= numberOfWords
309                 .sound$ = Get value... 'currentWord' Sound
310                 .pinyin$ = Get value... 'currentWord' Pinyin
311                 call drawToneContour '.pinyin$' 'config.register'
312                 call reset_viewport
313         endif   
314 endproc
316 procedure recognizeTone
317         select Table 'wordlist$'
318         if currentWord > 0 and currentWord <= numberOfWords
319                 .sound$ = Get value... 'currentWord' Sound
320                 .pinyin$ = Get value... 'currentWord' Pinyin
321                 call align_recordedSound '.pinyin$'
322         call sgc_ToneProt 'recordedSound$' '.pinyin$' 'config.register' 'config.strict' 'config.language$'
323                 call reset_viewport
324         endif
325 endproc
327 procedure write_feedback .table$
328     select Table '.table$'
329     .line1$ = Get value... 1 Text
330     .line2$ = Get value... 2 Text
331     .label$ = Get value... 3 Text
333         # convert numbers to Pinyin if needed
334         if not config.displayNumbers
335                 call numbers2pinyin '.line1$'
336                 .line1$ = numbers2pinyin.pinyin$
337         endif
339     .color$ = "Red"
340     if index(.line1$, "???") > 0
341         .color$ = "Black"
342     elsif .label$ = "Correct"
343         .color$ = "Green"
344         elsif config.strict
345                 .line2$ = .line2$ + " *"
346     endif
348         .currentFeedbackFontSize = 14
349         .maxHeight = 21 - 17
350         call adjustFontSizeOnHeight 'defaultFont$' '.currentFeedbackFontSize' '.maxHeight'
351         .currentFeedbackFontSize = adjustFontSizeOnHeight.newFontSize
352         
353         call wipeArea 'wipeFeedbackArea$'
354     call set_font_size '.currentFeedbackFontSize'
355     demo '.color$'
356     demo Text... 50 Centre 21 Bottom '.line1$'
357     demo Text... 50 Centre 17 Bottom '.line2$'
358         demoShow()
359         demo 'defaultFont$'
360     call set_font_size 'defaultFontSize'
361     
362         # Log performance
363         .splitIndex = index(.line1$, ": ")
364         .pinyin$ = left$(.line1$, (.splitIndex - 1))
365         .choice$ = right$(.line1$, (length(.line1$) - .splitIndex - 1))
366         call log_performance 'recordedSound$' 'config.register' 'config.strict' '.pinyin$' '.choice$'
367 endproc
369 # Text display
370 procedure display_text .color$
371         select Table 'wordlist$'
372         if currentWord < 0 or currentWord > numberOfWords+1
373         if config.shuffleLists
374                     Randomize rows
375         endif
376                 if currentWord < 0
377                         currentWord = numberOfWords
378                 else
379                         currentWord = 1
380                 endif
381         endif
382         
383         if currentWord > 0 and currentWord <= numberOfWords
384                 .displayText$ = ""
385                 .displayPinyin$ = Get value... 'currentWord' Pinyin
386                 .displayChar$ = Get value... 'currentWord' Character
387                 .displayTrans$ = Get value... 'currentWord' Translation
388                 if .displayPinyin$ <> "-" and config.displayPinyin
389                         if not config.displayNumbers
390                                 call numbers2pinyin '.displayPinyin$'
391                                 .displayPinyin$ = numbers2pinyin.pinyin$
392                         endif
393                         # Insert u umlaut
394                         .displayPinyin$ = replace_regex$(.displayPinyin$, "v", "\\u\X22", 0)
395                         .displayText$ = .displayText$ + .displayPinyin$
396                 endif
397                 if .displayChar$ <> "-" and config.displayChar
398                         .displayText$ = .displayText$ + "  "+ .displayChar$
399                 endif
400                 if .displayTrans$ <> "-" and config.displayTrans
401                         .displayText$ = .displayText$ + "  \s{%%"+ .displayTrans$ + "%}"
402                 endif
403         elsif currentWord = 0 or currentWord = numberOfWords+1
404                 .displayText$ = "---"
405         endif
407         # Adapt font size
408         call adjustFontSizeOnHeight 'defaultFont$' 24 15
409         .currentFontSize = adjustFontSizeOnHeight.newFontSize
410         call adjustFontSizeOnWidth 'defaultFont$' '.currentFontSize' 95 '.displayText$'
411         .currentFontSize = adjustFontSizeOnWidth.newFontSize
413         # Actually display text
414         call wipeArea 'wipePinyinArea$'
415         demo '.color$'
416         call set_font_size '.currentFontSize'
417         demo Text... 50 Centre 26 Bottom '.displayText$'
418         demoShow()
419         demo Black
420         demo 'defaultFont$'
421         call set_font_size 'defaultFontSize'
422 endproc
424 procedure numbers2pinyin .numberstext$
425         .intermediatePinyin$ = .numberstext$
426         # Move numbers to the nucleus vowel
427         # Tot he vowel
428         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([^aeuiov0-9]*)([0-9])", "\1\3\2", 0)
429         # Either a/e
430         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([ae])([aeuiov]*)([0-9])", "\1\3\2", 0)
431         # Or the Oo in /ou/
432         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(ou)([0-9])", "o\2u", 0)
433         # or the second vowel
434         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([uiov][aeuiov])([uiov])([0-9])", "\1\3\2", 0)
435         
436         # Convert all to special characters
437         # Tone 1
438         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a1", "ā", 0)
439         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e1", "ē", 0)
440         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u1", "ū", 0)
441         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i1", "ī", 0)
442         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o1", "ō", 0)
443         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v1", "ǖ", 0)
444         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "1", "\\-^", 0)
445         
446         # Tone 2
447         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v2", "ǘ", 0)
448         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])2", "\\\1'", 0)
449         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "2", "\\'^", 0)
450         
451         # Tone 3
452         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a3", "ǎ", 0)
453         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e3", "ě", 0)
454         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u3", "ǔ", 0)
455         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i3", "ǐ", 0)
456         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o3", "ǒ", 0)
457         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v3", "ǚ", 0)
458         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "3", "\\N^", 0)
460         # Tone 4
461         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v4", "ǜ", 0)
462         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])4", "\\\1`", 0)
463         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "4", "\\`^", 0)
464         
465         # Tone 0
466         # Remove tone 0 symbol completely
467         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "", 0)
468         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a0", "å", 0)
469         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e0", "e̊", 0)
470         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u0", "ů", 0)
471         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i0", "i̊", 0)
472         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o0", "o̊", 0)
473         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v0", "ü̊", 0)
474         #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "\\0^", 0)
475         
476         # Pick best vowel symbols available in cases not caught before
477         # Ugly clutch to get the 1, 3, 0 tone diacritics at least in the neighbourhood
478         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i(\\[-N0]\^)", "i\\s{_ }\1", 0)
479         # Insert u umlaut
480         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v", "\\u\X22", 0)
482         .pinyin$ = .intermediatePinyin$
483 endproc
485 # Includes
486 include ToneProt/SGC_ToneProt.praat
487 include ToneProt/DrawToneContour.praat
488 include ToneProt/HumToneContour.praat
489 include ToneProt/ToneRecognition.praat
490 include ToneProt/ToneScript.praat
491 include ToneProt/ToneRules.praat