Merge branch 'master' of ssh://repo.or.cz/srv/git/sgc2
[sgc2.git] / MainPage.praat
blob92c4845b5b8f9a1850c699018e74fc172569e050
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 sgc_ToneProt 'recordedSound$' '.pinyin$' 'config.register' 'config.strict' 'config.language$'
322         call reset_viewport
323         endif
324 endproc
326 procedure write_feedback .table$
327     select Table '.table$'
328     .line1$ = Get value... 1 Text
329     .line2$ = Get value... 2 Text
330     .label$ = Get value... 3 Text
332         # convert numbers to Pinyin if needed
333         if not config.displayNumbers
334                 call numbers2pinyin '.line1$'
335                 .line1$ = numbers2pinyin.pinyin$
336         endif
338     .color$ = "Red"
339     if index(.line1$, "???") > 0
340         .color$ = "Black"
341     elsif .label$ = "Correct"
342         .color$ = "Green"
343         elsif config.strict
344                 .line2$ = .line2$ + " *"
345     endif
347         .currentFeedbackFontSize = 14
348         .maxHeight = 21 - 17
349         call adjustFontSizeOnHeight 'defaultFont$' '.currentFeedbackFontSize' '.maxHeight'
350         .currentFeedbackFontSize = adjustFontSizeOnHeight.newFontSize
351         
352         call wipeArea 'wipeFeedbackArea$'
353     call set_font_size '.currentFeedbackFontSize'
354     demo '.color$'
355     demo Text... 50 Centre 21 Bottom '.line1$'
356     demo Text... 50 Centre 17 Bottom '.line2$'
357         demoShow()
358         demo 'defaultFont$'
359     call set_font_size 'defaultFontSize'
360     
361         # Log performance
362         .splitIndex = index(.line1$, ": ")
363         .pinyin$ = left$(.line1$, (.splitIndex - 1))
364         .choice$ = right$(.line1$, (length(.line1$) - .splitIndex - 1))
365         call log_performance 'recordedSound$' 'config.register' 'config.strict' '.pinyin$' '.choice$'
366 endproc
368 # Text display
369 procedure display_text .color$
370         select Table 'wordlist$'
371         if currentWord < 0 or currentWord > numberOfWords+1
372         if config.shuffleLists
373                     Randomize rows
374         endif
375                 if currentWord < 0
376                         currentWord = numberOfWords
377                 else
378                         currentWord = 1
379                 endif
380         endif
381         
382         if currentWord > 0 and currentWord <= numberOfWords
383                 .displayText$ = ""
384                 .displayPinyin$ = Get value... 'currentWord' Pinyin
385                 .displayChar$ = Get value... 'currentWord' Character
386                 .displayTrans$ = Get value... 'currentWord' Translation
387                 if .displayPinyin$ <> "-" and config.displayPinyin
388                         if not config.displayNumbers
389                                 call numbers2pinyin '.displayPinyin$'
390                                 .displayPinyin$ = numbers2pinyin.pinyin$
391                         endif
392                         # Insert u umlaut
393                         .displayPinyin$ = replace_regex$(.displayPinyin$, "v", "\\u\X22", 0)
394                         .displayText$ = .displayText$ + .displayPinyin$
395                 endif
396                 if .displayChar$ <> "-" and config.displayChar
397                         .displayText$ = .displayText$ + "  "+ .displayChar$
398                 endif
399                 if .displayTrans$ <> "-" and config.displayTrans
400                         .displayText$ = .displayText$ + "  \s{%%"+ .displayTrans$ + "%}"
401                 endif
402         elsif currentWord = 0 or currentWord = numberOfWords+1
403                 .displayText$ = "---"
404         endif
406         # Adapt font size
407         call adjustFontSizeOnHeight 'defaultFont$' 24 15
408         .currentFontSize = adjustFontSizeOnHeight.newFontSize
409         call adjustFontSizeOnWidth 'defaultFont$' '.currentFontSize' 95 '.displayText$'
410         .currentFontSize = adjustFontSizeOnWidth.newFontSize
412         # Actually display text
413         call wipeArea 'wipePinyinArea$'
414         demo '.color$'
415         call set_font_size '.currentFontSize'
416         demo Text... 50 Centre 26 Bottom '.displayText$'
417         demoShow()
418         demo Black
419         demo 'defaultFont$'
420         call set_font_size 'defaultFontSize'
421 endproc
423 procedure numbers2pinyin .numberstext$
424         .intermediatePinyin$ = .numberstext$
425         # Move numbers to the nucleus vowel
426         # Tot he vowel
427         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([^aeuiov0-9]*)([0-9])", "\1\3\2", 0)
428         # Either a/e
429         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([ae])([aeuiov]*)([0-9])", "\1\3\2", 0)
430         # Or the Oo in /ou/
431         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(ou)([0-9])", "o\2u", 0)
432         # or the second vowel
433         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([uiov][aeuiov])([uiov])([0-9])", "\1\3\2", 0)
434         
435         # Convert all to special characters
436         # Tone 1
437         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a1", "ā", 0)
438         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e1", "ē", 0)
439         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u1", "ū", 0)
440         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i1", "ī", 0)
441         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o1", "ō", 0)
442         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v1", "ǖ", 0)
443         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "1", "\\-^", 0)
444         
445         # Tone 2
446         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v2", "ǘ", 0)
447         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])2", "\\\1'", 0)
448         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "2", "\\'^", 0)
449         
450         # Tone 3
451         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a3", "ǎ", 0)
452         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e3", "ě", 0)
453         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u3", "ǔ", 0)
454         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i3", "ǐ", 0)
455         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o3", "ǒ", 0)
456         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v3", "ǚ", 0)
457         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "3", "\\N^", 0)
459         # Tone 4
460         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v4", "ǜ", 0)
461         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])4", "\\\1`", 0)
462         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "4", "\\`^", 0)
463         
464         # Tone 0
465         # Remove tone 0 symbol completely
466         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "", 0)
467         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a0", "å", 0)
468         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e0", "e̊", 0)
469         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u0", "ů", 0)
470         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i0", "i̊", 0)
471         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o0", "o̊", 0)
472         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v0", "ü̊", 0)
473         #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "\\0^", 0)
474         
475         # Pick best vowel symbols available in cases not caught before
476         # Ugly clutch to get the 1, 3, 0 tone diacritics at least in the neighbourhood
477         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i(\\[-N0]\^)", "i\\s{_ }\1", 0)
478         # Insert u umlaut
479         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v", "\\u\X22", 0)
481         .pinyin$ = .intermediatePinyin$
482 endproc
484 # Includes
485 include ToneProt/SGC_ToneProt.praat
486 include ToneProt/DrawToneContour.praat
487 include ToneProt/HumToneContour.praat
488 include ToneProt/ToneRecognition.praat
489 include ToneProt/ToneScript.praat
490 include ToneProt/ToneRules.praat