4 # Praat script handling buttons page
6 # SpeakGoodChinese: Buttons.praat loads the code needed for the
7 # main, practice, page of SGC2 and the sound handling and recognition.
9 # Copyright (C) 2007-2010 R.J.J.H. van Son
10 # The SpeakGoodChinese team are:
11 # Guangqin Chen, Zhonyan Chen, Stefan de Koning, Eveline van Hagen,
12 # Rob van Son, Dennis Vierkant, David Weenink
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.
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.
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
28 # Includes at the bottom
30 ###############################################################
32 # Button Drawing Routines
34 ###############################################################
36 procedure DrawPrevious .color$ .x .y .size
39 call drawTriangle -1 .x .y .size
40 .currentX = drawTriangle.currentX
41 .endX = .currentX - 0.5
44 demo Paint rectangle... '.color$' '.currentX' '.endX' '.lowY' '.highY'
47 procedure DrawNext .color$ .x .y .size
50 call drawTriangle 1 .x .y .size
51 .currentX = drawTriangle.currentX
52 .endX = .currentX + 0.5
55 demo Paint rectangle... '.color$' '.currentX' '.endX' '.lowY' '.highY'
58 procedure DrawWordListUp .color$ .x .y .size
67 demo Draw line... .xleft .ylow .xmidleft .yhigh
68 demo Draw line... .xright .ylow .xmidright .yhigh
69 demo Line width... 'defaultLineWidth'
73 procedure DrawWordListDown .color$ .x .y .size
82 demo Draw line... .xleft .yhigh .xmidleft .ylow
83 demo Draw line... .xright .yhigh .xmidright .ylow
84 demo Line width... 'defaultLineWidth'
88 procedure drawTriangle .direction .x .y .size
89 # Make sure direction = +/- 1
93 .direction /= abs(.direction)
96 .currentHeight = .size
97 .currentX = .x - .direction*.size
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
108 demo Line width... 'defaultLineWidth'
111 ###############################################################
113 # Obligatory button Drawing Routines
115 # These MUST be defined
117 ###############################################################
119 procedure DrawRecord .color$ .x .y .size
121 demo Paint circle... '.color$' '.x' '.y' '.size'
124 procedure DrawPlay .color$ .x .y .size
126 call drawTriangle 1 .x .y .size
129 procedure DrawQuit .color$ .x .y .size
130 demo Colour... '.color$'
131 .lineWidth = 0.5*.size**2
132 demo Line width... '.lineWidth'
137 demo Draw line... .xstart .ystart .xend .yend
142 demo Draw line... .xstart .ystart .xend .yend
143 demo Line width... 'defaultLineWidth'
147 procedure DrawConfig .color$ .x .y .size
149 .lineWidth = 0.4*.size
150 demo Arrow size... '.lineWidth'
151 .lineWidth = 0.4*.size**2
152 demo Line width... '.lineWidth'
156 demo Draw arrow... .xstart .y .xend .y
157 demo Line width... 'defaultLineWidth'
160 procedure DrawRefresh .color$ .x .y .size
161 .lineWidth = 0.5*.size**2
163 demo Line width... '.lineWidth'
164 demo Draw arc... '.x' '.y' '.size' 0 270
165 demo Line width... 'defaultLineWidth'
168 ###############################################################
170 # Button Processing Routines
172 ###############################################################
174 procedure processButtonsExample .clickX .clickY .pressed$
175 call generate_example
178 procedure processButtonsPrevious .clickX .clickY .pressed$
179 call display_text Grey
183 call draw_tone_contour
184 call wipeArea 'wipeFeedbackArea$'
185 call display_text Black
188 procedure processButtonsNext .clickX .clickY .pressed$
189 call display_text Grey
193 call draw_tone_contour
194 call wipeArea 'wipeFeedbackArea$'
195 call display_text Black
198 procedure processButtonsWordlistUp .clickX .clickY .pressed$
199 call wipeArea 'wipeFeedbackArea$'
200 call load_word_list "'localWordlistDir$'" -1
202 call display_text Black
205 procedure processButtonsWordlistDown .clickX .clickY .pressed$
206 call wipeArea 'wipeFeedbackArea$'
207 call load_word_list "'localWordlistDir$'" 1
209 call display_text Black
212 ###############################################################
214 # Obligatory button Processing Routines
216 # These MUST be defined
218 ###############################################################
220 procedure processButtonsQuit .clickX .clickY .pressed$
224 procedure processButtonsRefresh .clickX .clickY .pressed$
228 procedure processButtonsConfig .clickX .clickY .pressed$
232 procedure processButtonsHelp .clickX .clickY .pressed$
233 call help_loop 'buttons$' init_window
236 procedure processButtonsPlay .clickX .clickY .pressed$
237 call play_sound 'recordedSound$'
240 procedure processButtonsRecord .clickX .clickY .pressed$
244 call display_word_list_name
245 call display_text Black
246 call write_feedback Feedback
247 select Table Feedback
252 ###############################################################
254 # Miscelaneous supporting code
256 ###############################################################
259 procedure generate_example
260 select Table 'wordlist$'
261 if currentWord > 0 and currentWord <= numberOfWords
262 select Table 'wordlist$'
263 .sound$ = Get value... 'currentWord' Sound
264 .pinyin$ = Get value... 'currentWord' Pinyin
265 if .sound$ = "-" or .sound$ = ""
266 .sound$ = .pinyin$+".wav"
268 .soundFilePath$ = localWordlistDir$+"/"+wordlistName$+"/"+.sound$
269 .wordlistDirectory$ = ""
270 if localWordlistDir$ <> "" and fileReadable("'localWordlistDir$'/'wordlistName$'")
271 .wordlistDirectory$ = "'localWordlistDir$'/'wordlistName$'"
272 elsif sgc2wordlists$ <> "" and fileReadable("'sgc2wordlists$'/'wordlistName$'")
273 .wordlistDirectory$ = "'sgc2wordlists$'/'wordlistName$'"
274 elsif globalwordlists$ <> "" and fileReadable("'globalwordlists$'/'wordlistName$'")
275 .wordlistDirectory$ = "'globalwordlists$'/'wordlistName$'"
277 if .wordlistDirectory$ <> ""
278 .audioExampleList = Create Strings as file list... AudioList '.wordlistDirectory$'/'.pinyin$'.*
279 .number_of_examples = Get number of strings
280 if .number_of_examples > 0
282 .sound$ = Get string... 1
283 .soundFilePath$ = "'.wordlistDirectory$'/'.sound$'"
287 if fileReadable(.soundFilePath$) and config.useSoundExample
288 Read from file... '.soundFilePath$'
291 elsif fileReadable(speakCommandFile$) and config.synthesis$ <> "" and config.synthesis$ <> "_DISABLED_"
292 call synthesize_sound '.pinyin$'
294 call humToneContour '.pinyin$' 'config.register'
301 # Draw a tone contour
302 procedure draw_tone_contour
305 call wipeArea 'wipeContourArea$'
306 select Table 'wordlist$'
307 if currentWord > 0 and currentWord <= numberOfWords
308 .sound$ = Get value... 'currentWord' Sound
309 .pinyin$ = Get value... 'currentWord' Pinyin
310 call drawToneContour '.pinyin$' 'config.register'
315 procedure recognizeTone
316 select Table 'wordlist$'
317 if currentWord > 0 and currentWord <= numberOfWords
318 .sound$ = Get value... 'currentWord' Sound
319 .pinyin$ = Get value... 'currentWord' Pinyin
320 call sgc_ToneProt 'recordedSound$' '.pinyin$' 'config.register' 'precision' 'config.language$'
325 procedure write_feedback .table$
326 select Table '.table$'
327 .line1$ = Get value... 1 Text
328 .line2$ = Get value... 2 Text
329 .label$ = Get value... 3 Text
331 # convert numbers to Pinyin if needed
332 if not config.displayNumbers
333 call numbers2pinyin '.line1$'
334 .line1$ = numbers2pinyin.pinyin$
338 if index(.line1$, "???") > 0
340 elsif .label$ = "Correct"
343 .line2$ = .line2$ + " *"
346 .currentFeedbackFontSize = 14
348 call adjustFontSizeOnHeight '.currentFeedbackFontSize' '.maxHeight'
349 .currentFeedbackFontSize = adjustFontSizeOnHeight.newFontSize
351 call wipeArea 'wipeFeedbackArea$'
352 call set_font_size '.currentFeedbackFontSize'
354 demo Text... 50 Centre 21 Bottom '.line1$'
355 demo Text... 50 Centre 17 Bottom '.line2$'
358 call set_font_size 'defaultFontSize'
361 .splitIndex = index(.line1$, ": ")
362 .pinyin$ = left$(.line1$, (.splitIndex - 1))
363 .choice$ = right$(.line1$, (length(.line1$) - .splitIndex - 1))
364 call log_performance 'recordedSound$' 'config.register' 'precision' '.pinyin$' '.choice$'
368 procedure display_text .color$
369 select Table 'wordlist$'
370 if currentWord < 0 or currentWord > numberOfWords+1
371 if config.shuffleLists
375 currentWord = numberOfWords
381 if currentWord > 0 and currentWord <= numberOfWords
383 .displayPinyin$ = Get value... 'currentWord' Pinyin
384 .displayChar$ = Get value... 'currentWord' Character
385 .displayTrans$ = Get value... 'currentWord' Translation
386 if .displayPinyin$ <> "-" and config.displayPinyin
387 if not config.displayNumbers
388 call numbers2pinyin '.displayPinyin$'
389 .displayPinyin$ = numbers2pinyin.pinyin$
392 .displayPinyin$ = replace_regex$(.displayPinyin$, "v", "\\u\X22", 0)
393 .displayText$ = .displayText$ + .displayPinyin$
395 if .displayChar$ <> "-" and config.displayChar
396 .displayText$ = .displayText$ + " "+ .displayChar$
398 if .displayTrans$ <> "-" and config.displayTrans
399 .displayText$ = .displayText$ + " \s{%%"+ .displayTrans$ + "%}"
401 elsif currentWord = 0 or currentWord = numberOfWords+1
402 .displayText$ = "---"
406 call adjustFontSizeOnHeight 24 15
407 .currentFontSize = adjustFontSizeOnHeight.newFontSize
408 call adjustFontSizeOnWidth '.currentFontSize' 95 '.displayText$'
409 .currentFontSize = adjustFontSizeOnWidth.newFontSize
411 # Actually display text
412 call wipeArea 'wipePinyinArea$'
414 call set_font_size '.currentFontSize'
415 demo Text... 50 Centre 26 Bottom '.displayText$'
419 call set_font_size 'defaultFontSize'
422 procedure numbers2pinyin .numberstext$
423 .intermediatePinyin$ = .numberstext$
424 # Move numbers to the nucleus vowel
426 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([^aeuiov0-9]*)([0-9])", "\1\3\2", 0)
428 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([ae])([aeuiov]*)([0-9])", "\1\3\2", 0)
430 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(ou)([0-9])", "o\2u", 0)
431 # or the second vowel
432 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([uiov][aeuiov])([uiov])([0-9])", "\1\3\2", 0)
434 # Convert all to special characters
436 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a1", "ā", 0)
437 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e1", "ē", 0)
438 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u1", "ū", 0)
439 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i1", "ī", 0)
440 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o1", "ō", 0)
441 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v1", "ǖ", 0)
442 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "1", "\\-^", 0)
445 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v2", "ǘ", 0)
446 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])2", "\\\1'", 0)
447 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "2", "\\'^", 0)
450 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a3", "ǎ", 0)
451 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e3", "ě", 0)
452 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u3", "ǔ", 0)
453 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i3", "ǐ", 0)
454 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o3", "ǒ", 0)
455 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v3", "ǚ", 0)
456 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "3", "\\N^", 0)
459 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v4", "ǜ", 0)
460 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])4", "\\\1`", 0)
461 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "4", "\\`^", 0)
464 # Remove tone 0 symbol completely
465 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "", 0)
466 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a0", "å", 0)
467 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e0", "e̊", 0)
468 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u0", "ů", 0)
469 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i0", "i̊", 0)
470 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o0", "o̊", 0)
471 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v0", "ü̊", 0)
472 #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "\\0^", 0)
474 # Pick best vowel symbols available in cases not caught before
475 # Ugly clutch to get the 1, 3, 0 tone diacritics at least in the neighbourhood
476 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i(\\[-N0]\^)", "i\\s{_ }\1", 0)
478 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v", "\\u\X22", 0)
480 .pinyin$ = .intermediatePinyin$
484 include ToneProt/SGC_ToneProt.praat
485 include ToneProt/DrawToneContour.praat
486 include ToneProt/HumToneContour.praat
487 include ToneProt/ToneRecognition.praat
488 include ToneProt/ToneScript.praat
489 include ToneProt/ToneRules.praat