Ran tables2scripts.praat
[sgc2.git] / Buttons.praat
blobbfd52391b57d8214dac54cb3a1e835e4d69a7328
2 # SpeakGoodChinese 2.0
3
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.
8 #     
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
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 processButtonsExample .clickX .clickY .pressed$
175         call generate_example
176 endproc
178 procedure processButtonsPrevious .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 processButtonsNext .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 processButtonsWordlistUp .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 processButtonsWordlistDown .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 processButtonsQuit .clickX .clickY .pressed$
221         call end_program
222 endproc
224 procedure processButtonsRefresh .clickX .clickY .pressed$
225         call init_window
226 endproc
228 procedure processButtonsConfig .clickX .clickY .pressed$
229         call config_page
230 endproc
232 procedure processButtonsHelp .clickX .clickY .pressed$
233         call help_loop 'buttons$' init_window
234 endproc
236 procedure processButtonsPlay .clickX .clickY .pressed$
237         call play_sound 'recordedSound$'
238 endproc
240 procedure processButtonsRecord .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 write_feedback Feedback
247         select Table Feedback
248         Remove
249 endproc
252 ###############################################################
254 # Miscelaneous supporting code
256 ###############################################################
258 # The example
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"
267                 endif
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$'"
276                 endif
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
281                                 Randomize
282                                 .sound$ = Get string... 1
283                                 .soundFilePath$ = "'.wordlistDirectory$'/'.sound$'"
284                         endif
285                         Remove
286                 endif
287                 if fileReadable(.soundFilePath$) and config.useSoundExample
288                         Read from file... '.soundFilePath$'
289                         Play
290                         Remove
291                 elsif fileReadable(speakCommandFile$) and config.synthesis$ <> "" and config.synthesis$ <> "_DISABLED_"
292                         call synthesize_sound '.pinyin$'
293                 else
294                         call humToneContour '.pinyin$' 'config.register'
295                         call reset_viewport
296                 endif
297         endif
298         demoShow()
299 endproc
301 # Draw a tone contour
302 procedure draw_tone_contour
303     # Wipe screen
304         call reset_viewport
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'
311                 call reset_viewport
312         endif   
313 endproc
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$'
321         call reset_viewport
322         endif
323 endproc
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$
335         endif
337     .color$ = "Red"
338     if index(.line1$, "???") > 0
339         .color$ = "Black"
340     elsif .label$ = "Correct"
341         .color$ = "Green"
342         elsif precision < 3
343                 .line2$ = .line2$ + " *"
344     endif
346         .currentFeedbackFontSize = 14
347         .maxHeight = 21 - 17
348         call adjustFontSizeOnHeight '.currentFeedbackFontSize' '.maxHeight'
349         .currentFeedbackFontSize = adjustFontSizeOnHeight.newFontSize
350         
351         call wipeArea 'wipeFeedbackArea$'
352     call set_font_size '.currentFeedbackFontSize'
353     demo '.color$'
354     demo Text... 50 Centre 21 Bottom '.line1$'
355     demo Text... 50 Centre 17 Bottom '.line2$'
356         demoShow()
357         demo 'defaultFont$'
358     call set_font_size 'defaultFontSize'
359     
360         # Log performance
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$'
365 endproc
367 # Text display
368 procedure display_text .color$
369         select Table 'wordlist$'
370         if currentWord < 0 or currentWord > numberOfWords+1
371         if config.shuffleLists
372                     Randomize rows
373         endif
374                 if currentWord < 0
375                         currentWord = numberOfWords
376                 else
377                         currentWord = 1
378                 endif
379         endif
380         
381         if currentWord > 0 and currentWord <= numberOfWords
382                 .displayText$ = ""
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$
390                         endif
391                         # Insert u umlaut
392                         .displayPinyin$ = replace_regex$(.displayPinyin$, "v", "\\u\X22", 0)
393                         .displayText$ = .displayText$ + .displayPinyin$
394                 endif
395                 if .displayChar$ <> "-" and config.displayChar
396                         .displayText$ = .displayText$ + "  "+ .displayChar$
397                 endif
398                 if .displayTrans$ <> "-" and config.displayTrans
399                         .displayText$ = .displayText$ + "  \s{%%"+ .displayTrans$ + "%}"
400                 endif
401         elsif currentWord = 0 or currentWord = numberOfWords+1
402                 .displayText$ = "---"
403         endif
405         # Adapt font size
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$'
413         demo '.color$'
414         call set_font_size '.currentFontSize'
415         demo Text... 50 Centre 26 Bottom '.displayText$'
416         demoShow()
417         demo Black
418         demo 'defaultFont$'
419         call set_font_size 'defaultFontSize'
420 endproc
422 procedure numbers2pinyin .numberstext$
423         .intermediatePinyin$ = .numberstext$
424         # Move numbers to the nucleus vowel
425         # Tot he vowel
426         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([^aeuiov0-9]*)([0-9])", "\1\3\2", 0)
427         # Either a/e
428         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([ae])([aeuiov]*)([0-9])", "\1\3\2", 0)
429         # Or the Oo in /ou/
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)
433         
434         # Convert all to special characters
435         # Tone 1
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)
443         
444         # Tone 2
445         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v2", "ǘ", 0)
446         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])2", "\\\1'", 0)
447         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "2", "\\'^", 0)
448         
449         # Tone 3
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)
458         # Tone 4
459         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v4", "ǜ", 0)
460         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])4", "\\\1`", 0)
461         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "4", "\\`^", 0)
462         
463         # Tone 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)
473         
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)
477         # Insert u umlaut
478         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v", "\\u\X22", 0)
480         .pinyin$ = .intermediatePinyin$
481 endproc
483 # Includes
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