Moving SelectWords to MainPage
[sgc2.git] / MainPage.praat
blob12688fdb1ce9a54499979e9d4f0a8dc85a8ccb33
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 DrawSelectWords .color$ .x .y .size
59         .currentFontSize = 48
60         .y -= .size/2
61         .maxHeight = 2*.size
62         call adjustFontSizeOnHeight 'defaultFont$' '.currentFontSize' '.maxHeight'
63         .currentFontSize = adjustFontSizeOnHeight.currentFontSize
64         call set_font_size '.currentFontSize'
65         demo Colour... '.color$'
66         demo Text... '.x' Centre '.y' Bottom ...
67         call set_font_size 'defaultFontSize'
68 endproc
70 procedure DrawWordListUp .color$ .x .y .size
71     .xleft = .x - .size
72     .xright = .x + .size
73     .xmidleft = .x + 0.1
74     .xmidright = .x - 0.1
75     .ylow = .y
76     .yhigh = .y + .size
77         demo '.color$'
78         demo Line width... 3
79         demo Draw line... .xleft .ylow .xmidleft .yhigh
80         demo Draw line... .xright .ylow .xmidright .yhigh
81         demo Line width... 'defaultLineWidth'
82         demo Black
83 endproc
85 procedure DrawWordListDown .color$ .x .y .size
86     .xleft = .x - .size
87     .xright = .x + .size
88     .xmidleft = .x + 0.1
89     .xmidright = .x - 0.1
90     .yhigh = .y + .size
91     .ylow = .y
92         demo '.color$'
93         demo Line width... 3
94         demo Draw line... .xleft .yhigh .xmidleft .ylow
95         demo Draw line... .xright .yhigh .xmidright .ylow
96         demo Line width... 'defaultLineWidth'
97         demo Black
98 endproc
100 procedure drawTriangle .direction .x .y .size
101         # Make sure direction = +/- 1
102         if .direction = 0
103                 .direction = 1 
104         endif
105         .direction /= abs(.direction)
106         
107         .offset = 0.01
108         .currentHeight = .size
109         .currentX = .x - .direction*.size
110         
111         demo Line width... 2.0
113         while .currentHeight> 0
114                 .ystart = .y + .currentHeight
115                 .yend = .y - .currentHeight
116                 demo Draw line... .currentX .ystart .currentX .yend
117                 .currentHeight -= .offset *3/4
118                 .currentX += .direction*.offset * 1.5
119         endwhile
120         demo Line width... 'defaultLineWidth'
121 endproc
123 ###############################################################
125 # Obligatory button Drawing Routines
127 # These MUST be defined
129 ###############################################################
131 procedure DrawRecord .color$ .x .y .size
132         .size /= 2
133     demo Paint circle... '.color$' '.x' '.y' '.size'
134 endproc
136 procedure DrawPlay .color$ .x .y .size
137         demo '.color$'
138         call drawTriangle 1 .x .y .size
139 endproc
141 procedure DrawQuit .color$ .x .y .size
142         demo Colour... '.color$'
143         .lineWidth = 0.5*.size**2
144         demo Line width... '.lineWidth'
145         .xstart = .x - .size
146         .ystart = .y + .size
147         .xend = .x + .size
148         .yend = .y - .size
149         demo Draw line... .xstart .ystart .xend .yend
150         .xstart = .x - .size
151         .ystart = .y - .size
152         .xend = .x + .size
153         .yend = .y + .size
154         demo Draw line... .xstart .ystart .xend .yend
155         demo Line width... 'defaultLineWidth'
156         demo Colour... Black
157 endproc
159 procedure DrawConfig .color$ .x .y .size
160         .size *= 1
161         .lineWidth = 0.4*.size
162         demo Arrow size... '.lineWidth'
163         .lineWidth = 0.4*.size**2
164         demo Line width... '.lineWidth'
165         .y += .size/2
166         .xstart = .x - .size
167         .xend = .x + .size
168         demo Draw arrow... .xstart .y .xend .y
169         demo Line width... 'defaultLineWidth'
170 endproc
172 procedure DrawRefresh .color$ .x .y .size
173         .lineWidth = 0.5*.size**2
174         .size /= 2
175         demo Line width... '.lineWidth'
176         demo Draw arc... '.x' '.y' '.size' 0 270
177         demo Line width... 'defaultLineWidth'
178 endproc
180 ###############################################################
182 # Button Processing Routines
184 ###############################################################
186 procedure processMainPageExample .clickX .clickY .pressed$
187         call generate_example
188 endproc
190 procedure processMainPagePrevious .clickX .clickY .pressed$
191         call clean_up_sound
192         call display_text Grey
193         call previous_word
194         # Draw the contour
195         call wipeArea 'wipeFeedbackArea$'
196         call init_window
197         call display_text Black
198         
199         sgc.failedAttempts = 0
200 endproc
202 procedure processMainPageNext .clickX .clickY .pressed$
203         call clean_up_sound
204         call display_text Grey
205         call next_word
206         call wipeArea 'wipeFeedbackArea$'
207         call init_window
208         # Draw the contour
209         call display_text Black
210 endproc
212 procedure processMainPageWordlistUp .clickX .clickY .pressed$
213         call wipeArea 'wipeFeedbackArea$'
214     call load_word_list "'localWordlistDir$'" -1
215         call init_window
216         call display_text Black
217 endproc
219 procedure processMainPageWordlistDown .clickX .clickY .pressed$
220         call wipeArea 'wipeFeedbackArea$'
221     call load_word_list "'localWordlistDir$'" 1
222         call init_window
223         call display_text Black
224 endproc
226 procedure processMainPageGRADE .clickX .clickY .pressed$
227         call setGrade '.pressed$'
228         # Redraw window
229         call init_window
230 endproc
232 procedure processMainPagePinYinArea .clickX .clickY .pressed$
233         # Redraw window
234         sgc.writeAll = 1
235         call display_text Red
236         sgc.writeAll = 0
237 endproc
239 # Select the words to practise. This is quite a complex piece of code
240 procedure processMainPageSelectWords .clickX .clickY .pressed$
241         .table$ = "MainPage"
242         .label$ = "SelectWords"
243     call Draw_button '.table$' '.label$' 1
245         # Get help text
246         call findLabel '.table$' '.label$'
247         .row = findLabel.row
248         select Table '.table$'
249         .helpText$ = Get value... '.row' Helptext
250         call convert_praat_to_latin1 '.helpText$'
251         .helpText$ = convert_praat_to_latin1.text$
252    
253     # Implement Cancel
254     select Table 'wordlist$'
255     .tmpOriginalWordlist = Copy: "Original_'wordlist$'"
257     
258     # Set current word
259         select Table 'wordlist$'
260         sgc.numberOfWords = Get number of rows
261     .currentWord = sgc.currentWord
262     if .currentWord <= 0 or .currentWord > sgc.numberOfWords or config.shuffleLists
263                 .currentWord = 1
264         endif
265     
266         # The texts
267         call get_feedback_text 'config.language$' Part
268         call convert_praat_to_latin1 'get_feedback_text.text$'
269         .partText$ = convert_praat_to_latin1.text$
270         call get_feedback_text 'config.language$' Tones
271         call convert_praat_to_latin1 'get_feedback_text.text$'
272         .toneText$ = convert_praat_to_latin1.text$
273         call get_feedback_text 'config.language$' Cancel
274         call convert_praat_to_latin1 'get_feedback_text.text$'
275         .cancelText$ = convert_praat_to_latin1.text$
276         call get_feedback_text 'config.language$' Clear
277         call convert_praat_to_latin1 'get_feedback_text.text$'
278         .clearText$ = convert_praat_to_latin1.text$
279         call get_feedback_text 'config.language$' All
280         call convert_praat_to_latin1 'get_feedback_text.text$'
281         .allText$ = convert_praat_to_latin1.text$
282         call get_feedback_text 'config.language$' Previous
283         call convert_praat_to_latin1 'get_feedback_text.text$'
284         .prevWord$ = convert_praat_to_latin1.text$
285         call get_feedback_text 'config.language$' Next
286         call convert_praat_to_latin1 'get_feedback_text.text$'
287         .nextWord$ = convert_praat_to_latin1.text$
288         call get_feedback_text 'config.language$' Continue
289         call convert_praat_to_latin1 'get_feedback_text.text$'
290         .continueText$ = convert_praat_to_latin1.text$
291         call get_feedback_text 'config.language$' Show
292         call convert_praat_to_latin1 'get_feedback_text.text$'
293         .showText$ = convert_praat_to_latin1.text$
295         .pinyinText$ = "Pinyin"
296         .characterText$ = "Character"
297         
298         # Get lesson names
299         select Table 'wordlist$'
300         .lessonCol = Get column index: "Lesson"
301         .lessonList$ = tab$
302         .numLessons = 0
303         # All shown keeps track whether all words are shown
304         # If so, selecting a lesson is preceded by a Clear All
305         .allShown = 0
306         # Sort words for consistent selection interface
307         if config.shuffleLists
308                 # Allow subdivision in lessons
309                 if .lessonCol > 0
310                         Sort rows... Lesson Pinyin
311                 else
312                         Sort rows... Pinyin
313                 endif
314         endif           
315         if .lessonCol > 0
316                 for .i to sgc.numberOfWords
317                         .currentLesson$ = Get value: .i, "Lesson"
318                         if .currentLesson$ <> "" and .currentLesson$ <> "-" and index_regex(.lessonList$, "\t'.currentLesson$'\t") <= 0
319                                 .lessonList$ = .lessonList$ + .currentLesson$ + tab$
320                                 .numLessons += 1
321                                 .lessonName$['.numLessons'] = .currentLesson$
322                         endif
323                         .shown$ = Get value: .i, "Show"
324                         if .shown$ = "-"
325                                 .allShown = 0
326                         endif
327                 endfor
328         endif
329         
330         clicked = -1
331         .numWordsPerScreen = 15
332         while clicked <> 6 and clicked <> 1
333                 .lessonSelected = -1
334                 .toneSelected = -1
335                 .firstShown = -1
336                 
337                 select Table 'wordlist$'
338                 .lessonCol = Get column index: "Lesson"
339                 # Sort words for consistent selection interface
340         if config.shuffleLists
341                         # Allow subdivision in lessons
342                         if .lessonCol > 0
343                                 Sort rows... Lesson Pinyin
344                         else
345                                 Sort rows... Pinyin
346                         endif
347         endif           
348                 .max = .numWordsPerScreen - 1
349                 if .currentWord + .max > sgc.numberOfWords
350                         .max = sgc.numberOfWords - .currentWord
351                 endif
352                 for .i from 0 to .numWordsPerScreen - 1
353                         if .i <= .max
354                                 .currentPinyin$ = Get value: .currentWord+.i, "Pinyin"
355                                 if index_regex(.currentPinyin$, "[0-9]") <= 0
356                                         call pinyin2numbers '.currentPinyin$'
357                                         .currentPinyin$ = replace_regex$(pinyin2numbers.intermediatePinyin$, ".+", "\l&", 0)
358                                         .currentPinyin$ = replace_regex$(.currentPinyin$, "[^a-zA-Z0-9]", "", 0)
359                                 endif
360                                 .pinyin$[.i] = .currentPinyin$
362                                 .character$[.i] = Get value: .currentWord+.i, "Character"
363                                 .lessonNum$[.i] = ""
364                                 if .lessonCol > 0
365                                         .lessonNum$[.i] = Get value: .currentWord+.i, "Lesson"
366                                         .lessonNum$[.i] = " : " + .lessonNum$[.i]
367                                 endif
368                                 .showText$[.i] = .pinyin$['.i']
369                                 if .character$['.i'] <> "-"
370                                         .showText$[.i] = .pinyin$['.i']+" ("+.character$['.i']+.lessonNum$['.i']+")"
371                                 elsif .lessonNum$['.i'] <> ""
372                                         .showText$[.i] = .pinyin$['.i']+" ( -"+.lessonNum$['.i']+")"
373                                 endif
374                                 .showValueText$[.i] = Get value: .currentWord+.i, "Show"
375                                 if .showValueText$[.i] = "-"
376                                         .showValue[.i] = 0
377                                 else
378                                         .showValue[.i] = 1
379                                 endif
380                                 .showVariable$[.i] = .pinyin$[.i]
381                                 .tmp$ = .showVariable$[.i]
382                                 '.tmp$' = .showValue[.i]
383                         else
384                                 .showText$[.i] = "-"
385                                 .showValue[.i] = 0
386                         endif
387                 endfor
389                 # The user text input window (beginPause .... endPause)
390                 beginPause(.helpText$)
391                         boolean (.showText$[0], .showValue[0])
392                         boolean (.showText$[1], .showValue[1])
393                         boolean (.showText$[2], .showValue[2])
394                         boolean (.showText$[3], .showValue[3])
395                         boolean (.showText$[4], .showValue[4])
396                         boolean (.showText$[5], .showValue[5])
397                         boolean (.showText$[6], .showValue[6])
398                         boolean (.showText$[7], .showValue[7])
399                         boolean (.showText$[8], .showValue[8])
400                         boolean (.showText$[9], .showValue[9])
401                         boolean (.showText$[10], .showValue[10])
402                         boolean (.showText$[11], .showValue[11])
403                         boolean (.showText$[12], .showValue[12])
404                         boolean (.showText$[13], .showValue[13])
405                         boolean (.showText$[14], .showValue[14])
406                         if .numLessons > 0
407                                 optionMenu: .partText$, 1
408                                         option: "---"
409                                         .j = 0
410                                         for .j to .numLessons
411                                                 option: .lessonName$['.j']
412                                         endfor
413                         endif
414                         optionMenu: .toneText$, 1
415                                 option: "---"
416                                 option: "0"
417                                 option: "1"
418                                 option: "2"
419                                 option: "3"
420                                 option: "4"
421                 clicked = endPause ("'.cancelText$'", "'.clearText$'", "'.allText$'", "'.prevWord$'", "'.nextWord$'", "'.continueText$'", 6, 1)
422                 
423                 if clicked = 2
424                         for .i to sgc.numberOfWords
425                                 Set string value: .i, "Show", "-"
426                         endfor
427                         .allShown = 0
428                 elsif clicked = 3
429                         for .i to sgc.numberOfWords
430                                 Set string value: .i, "Show", "+"
431                         endfor
432                         .allShown = 1
433                 elsif clicked != 1
434                         # Get selected Part BEFORE we do anything else
435                         if .numLessons > 0
436                                 .tmp$ = replace_regex$(.partText$, "^(.)", "\l\1", 0)
437                                 .lessonSelected = '.tmp$' - 1
438                         endif
439                         if .lessonSelected > 0
440                                 .allShown = 1
441                                 .firstShown = -1
442                                 select Table 'wordlist$'
443                                 for .i to sgc.numberOfWords
444                                         # Keep track of whether all are shown
445                                         .shown$ = Get value: .i, "Show"
446                                         if .shown$ = "-"
447                                                 .allShown = 0
448                                         endif
449                                 endfor
450                                 for .i to sgc.numberOfWords
451                                         # Lessons
452                                         .currentLesson$ = Get value: .i, "Lesson"
453                                         if .currentLesson$ = .lessonName$['.lessonSelected']
454                                                 Set string value: .i, "Show", "+"
455                                         elsif .allShown = 1
456                                                 Set string value: .i, "Show", "-"
457                                         endif
458                                 endfor
459                                 for .i to sgc.numberOfWords
460                                         # Keep track of whether all are shown
461                                         .shown$ = Get value: .i, "Show"
462                                         if .firstShown <=0 and .shown$ <> "-"
463                                                 .firstShown = .i
464                                         endif
465                                 endfor
466                         else
467                                 for .i from 0 to .max
468                                         .tmp$ = .showVariable$['.i']
469                                         .showValue['.i'] = '.tmp$'
470                                         .showWord$['.i'] = "-"
471                                         if .showValue['.i'] <> 0
472                                                 .showWord$['.i'] = "+"
473                                         endif
474                                         Set string value: .currentWord+.i, "Show", .showWord$['.i']
475                                 endfor
476                         endif
477                         .tmp$ = replace_regex$(.toneText$, "^(.)", "\l\1", 0)
478                         .toneSelected = '.tmp$' - 2
479                         if .toneSelected >= 0
480                                 select Table 'wordlist$'
481                                 for .i to sgc.numberOfWords
482                                         .currentPinyin$ = Get value: .i, "Pinyin"
483                                         if index_regex(.currentPinyin$, "[0-9]") <= 0
484                                                 call pinyin2numbers '.currentPinyin$'
485                                                 .currentPinyin$ = replace_regex$(pinyin2numbers.intermediatePinyin$, ".+", "\l&", 0)
486                                                 .currentPinyin$ = replace_regex$(.currentPinyin$, "[^a-zA-Z0-9]", "", 0)
487                                         endif
488                                         .tmp$ = Get value: .i, "Show"
489                                         if .tmp$ <> "-" and index(.currentPinyin$, "'.toneSelected'") > 0
490                                                 Set string value: .i, "Show", "+"
491                                         else
492                                                 Set string value: .i, "Show", "-"
493                                                 .allShown = 0
494                                         endif
495                                 endfor
496                         endif
497                         
498                         if clicked = 4
499                                 if .firstShown > 0
500                                         .currentWord = (.firstShown div .numWordsPerScreen) * .numWordsPerScreen + 1
501                                 elsif .toneSelected < 0
502                                         .currentWord -= .numWordsPerScreen
503                                 endif
504                                 if .currentWord <= 0
505                                         .currentWord = (sgc.numberOfWords div .numWordsPerScreen) * .numWordsPerScreen + 1
506                                 endif
507                         elsif clicked = 5
508                                 if .firstShown > 0
509                                         .currentWord = (.firstShown div .numWordsPerScreen) * .numWordsPerScreen + 1
510                                 elsif .toneSelected < 0
511                                         .currentWord += .numWordsPerScreen
512                                 endif
513                                 if .currentWord > sgc.numberOfWords
514                                         .currentWord = 1
515                                 endif
516                         endif
517                 endif
518                 # Reset and go to the first selected word (can shuffle list)
519                 if clicked = 6
520                         sgc.currentWord = -1
521                         call next_word
522                 endif
523         endwhile
524         
525     # Implement Cancel
526     if clicked = 1
527                 select Table 'wordlist$'
528                 Remove
529                 select .tmpOriginalWordlist
530                 Copy: wordlist$
531         endif
532         select .tmpOriginalWordlist
533         Remove
534     call Draw_button '.table$' '.label$' 0
535 endproc
537 ###############################################################
539 # Obligatory button Processing Routines
541 # These MUST be defined
543 ###############################################################
545 procedure processMainPageQuit .clickX .clickY .pressed$
546         call end_program
547 endproc
549 procedure processMainPageRefresh .clickX .clickY .pressed$
550         call clean_up_sound
551         call init_window
552 endproc
554 procedure processMainPageConfig .clickX .clickY .pressed$
555         call config_page
556 endproc
558 procedure processMainPageHelp .clickX .clickY .pressed$
559         call help_loop 'buttons$' init_window
560 endproc
562 procedure processMainPagePlay .clickX .clickY .pressed$
563         .table$ = "MainPage"
564         .label$ = "Play"
565         if recordedSound$ <> ""
566                 call play_sound 'sgc.recordedSound'
567                 mainPage.play = 0
568         endif
569         te.buttonPressValue = mainPage.play
570 endproc
572 procedure Set_Play_Button
573         mainPage.play = -1
574         if recordedSound$ <> ""
575                 mainPage.play = 0
576     endif       
577         call Draw_button MainPage Play 'mainPage.play'
578 endproc
580 procedure processMainPageRecord .clickX .clickY .pressed$
581         call count_syllables
582         .recordingTime = recordingTime
583         if count_syllables.number > 2
584                 .recordingTime = recordingTime + 1.0*ceiling((count_syllables.number - 2)/2)
585         endif
586     call record_sound '.recordingTime'
587     call recognizeTone
588         mainPage.play = 0
589         call Set_Play_Button
591     # Wipe screen
592     call wipeArea 'wipeContourArea$'
593    
594     call draw_tone_contour
595     # Write text (again)
596     call display_word_list_name
597     call display_text Black
598         call add_feedback_to_toneevaluation Feedback
599     call write_feedback Feedback
600         select Table Feedback
601         Remove
602         
603         # Do not exercise words that are going well (autoSelect)
604     if add_feedback_to_toneevaluation.result > 0
605                 if config.adaptiveLists > 0 and sgc.failedAttempts < 2
606                         # Deselect current word
607                         select Table 'wordlist$'
608                         .i = Search column: "Pinyin", sgc.pinyin$
609                         if .i > 0
610                                 Set string value: .i, "Show", "-"
611                         endif
612                 endif
613                 sgc.failedAttempts = 0
614     else
615                 sgc.failedAttempts += 1
616     endif
617 endproc
620 ###############################################################
622 # Miscelaneous supporting code
624 ###############################################################
626 # The example
627 procedure generate_example
628         select Table 'wordlist$'
629         if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
630                 select Table 'wordlist$'
631                 .sound$ = Get value... 'sgc.currentWord' Sound
632                 call readPinyin 'sgc.currentWord'
633                 sgc.pinyin$ = readPinyin.pinyin$
634                 if .sound$ = "-" or .sound$ = ""
635                         .sound$ = sgc.pinyin$+".wav"
636                 endif
637                 .soundFilePath$ = localWordlistDir$+"/"+wordlistName$+"/"+.sound$
638                 .wordlistDirectory$ = ""
639                 if localWordlistDir$ <> "" and fileReadable("'localWordlistDir$'/'wordlistName$'")
640                         .wordlistDirectory$ = "'localWordlistDir$'/'wordlistName$'"
641                 elsif sgc2wordlists$ <> "" and fileReadable("'sgc2wordlists$'/'wordlistName$'")
642                         .wordlistDirectory$ = "'sgc2wordlists$'/'wordlistName$'"
643                 elsif globalwordlists$ <> "" and fileReadable("'globalwordlists$'/'wordlistName$'")
644                         .wordlistDirectory$ = "'globalwordlists$'/'wordlistName$'"
645                 endif
646                 if .wordlistDirectory$ <> ""
647                         .audioExampleList = Create Strings as file list... AudioList '.wordlistDirectory$'/'sgc.pinyin$'.*
648                         .number_of_examples = Get number of strings
649                         if .number_of_examples > 0
650                                 Randomize
651                                 .sound$ = Get string... 1
652                                 .soundFilePath$ = "'.wordlistDirectory$'/'.sound$'"
653                         endif
654                         Remove
655                 endif
656                 if fileReadable(.soundFilePath$) and config.useSoundExample
657                         .tmp = -1
658                         .tmp = nocheck Read from file... '.soundFilePath$'
659                         if .tmp != undefined and .tmp > 0
660                                 call play_sound '.tmp'
661                                 select .tmp
662                                 Remove
663                         endif
664                 elsif config.synthesis$ <> "" and config.synthesis$ <> "_DISABLED_"
665                         call synthesize_sound 'sgc.pinyin$'
666                 else
667                         call humToneContour 'sgc.pinyin$' 'config.register'
668                         call reset_viewport
669                 endif
670         endif
671         demoShow()
672 endproc
674 # Draw a tone contour
675 procedure draw_tone_contour
676         select Table 'wordlist$'
677         if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
678                 .sound$ = Get value... 'sgc.currentWord' Sound
679                 call readPinyin 'sgc.currentWord'
680                 sgc.pinyin$ = readPinyin.pinyin$
681                 call drawToneContour 'sgc.pinyin$' 'config.register'
682                 call reset_viewport
683                 
684                 if te.recordedPitch > 0
685                         call drawSourceToneContour te.recordedPitch
686                 endif
687         endif
689 endproc
691 procedure recognizeTone
692         select Table 'wordlist$'
693         if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
694                 .strict = 0
695                 if index_regex(config.strict$, "[^0-9]") <= 0
696                         .strict = ('config.strict$' >= sgc.highestLevel)
697                 endif
698                         
699                 .sound$ = Get value... 'sgc.currentWord' Sound
700                 call readPinyin 'sgc.currentWord'
701                 sgc.pinyin$ = readPinyin.pinyin$
702                 call align_recordedSound 'sgc.pinyin$'
703         call sgc_ToneProt 'recordedSound$' 'sgc.pinyin$' 'config.register' '.strict' 'config.language$'
704         # sgc_ToneProt manipulates the sound given. Reconnect
705         select Sound 'recordedSound$'
706         sgc.recordedSound = selected("Sound")
707                 call reset_viewport
708         endif
709 endproc
711 procedure write_feedback .table$
712     select Table '.table$'
713     .line1$ = Get value... 1 Text
714     .line2$ = Get value... 2 Text
715     .label$ = Get value... 3 Text
717         # convert numbers to Pinyin if needed
718         if not config.displayNumbers
719                 call numbers2pinyin '.line1$'
720                 .line1$ = numbers2pinyin.pinyin$
721         endif
723     .color$ = "Red"
724     if index(.line1$, "???") > 0
725         .color$ = "Black"
726     elsif .label$ = "Correct"
727         .color$ = "Green"
728         elsif config.strict$ = "'sgc.highestLevel'"
729                 .line2$ = .line2$ + " *"
730     endif
732         .currentFeedbackFontSize = 14
733         .maxHeight = 21 - 17
734         call adjustFontSizeOnHeight 'defaultFont$' '.currentFeedbackFontSize' '.maxHeight'
735         .currentFeedbackFontSize = adjustFontSizeOnHeight.newFontSize
736         
737         call wipeArea 'wipeFeedbackArea$'
738     call set_font_size '.currentFeedbackFontSize'
739     demo '.color$'
740     demo Text... 50 Centre 21 Bottom '.line1$'
741     demo Text... 50 Centre 17 Bottom '.line2$'
742         demoShow()
743         demo 'defaultFont$'
744     call set_font_size 'defaultFontSize'
745 endproc
747 # Text display
748 procedure display_text .color$
749         select Table 'wordlist$'
750         if sgc.currentWord < 0 or sgc.currentWord > sgc.numberOfWords+1
751                 call clean_up_sound
752         if config.shuffleLists
753                     Randomize rows
754         endif
755                 if sgc.currentWord < 0
756                         sgc.currentWord = sgc.numberOfWords
757                 else
758                         sgc.currentWord = 1
759                 endif
760         endif
761         
762         .changeCJKstyle = 0
763         if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
764                 .displayText$ = ""
765                 call readDisplayPinyin 'sgc.currentWord'
766                 .displayPinyin$ = readDisplayPinyin.pinyin$
767                 .displayChar$ = Get value... 'sgc.currentWord' Character
768                 .displayTrans$ = Get value... 'sgc.currentWord' Translation
769                 if .displayPinyin$ <> "-" and (config.displayPinyin or sgc.writeAll)
770                         if not config.displayNumbers
771                                 call numbers2pinyin '.displayPinyin$'
772                                 .displayPinyin$ = numbers2pinyin.pinyin$
773                         endif
774                         # Insert u umlaut
775                         .displayPinyin$ = replace_regex$(.displayPinyin$, "v", "\\u\X22", 0)
776                         .displayText$ = .displayText$ + .displayPinyin$
777                 endif
778                 if .displayChar$ <> "-" and (config.displayChar or sgc.writeAll)
779                         .displayText$ = .displayText$ + "  "+ .displayChar$
780                         .changeCJKstyle = 1
781                 endif
782                 if .displayTrans$ <> "-" and (config.displayTrans or sgc.writeAll)
783                         .displayText$ = .displayText$ + "  \s{%%"+ .displayTrans$ + "%}"
784                 endif
785         elsif sgc.currentWord = 0 or sgc.currentWord = sgc.numberOfWords+1
786                 call clean_up_sound
787                 .displayText$ = "---"
788         endif
790         # Adapt font size
791         call adjustFontSizeOnHeight 'defaultFont$' 24 15
792         .currentFontSize = adjustFontSizeOnHeight.newFontSize
793         call adjustFontSizeOnWidth 'defaultFont$' '.currentFontSize' 95 '.displayText$'
794         .currentFontSize = adjustFontSizeOnWidth.newFontSize
796         # Clear the writing area
797         call wipeArea 'wipePinyinArea$'
798         # Switch back to Chinese style CJK when in Japanese language mode
799         if .changeCJKstyle and config.language$ = "JA"
800                 CJK font style preferences: "Chinese"
801         endif
802         # Actually display text
803         demo '.color$'
804         call set_font_size '.currentFontSize'
805         demo Text... 50 Centre 26 Bottom '.displayText$'
806         demoShow()
807         demo Black
808         demo 'defaultFont$'
809         call set_font_size 'defaultFontSize'
810         if .changeCJKstyle and config.language$ = "JA"
811                 if config.language$ = "JA"
812                         CJK font style preferences: "Japanese"
813                 elsif config.language$ = "ZH"
814                         CJK font style preferences: "Chinese"
815                 endif
816         endif
817         # Switch back to Japanese style CJK when in Japanese language mode
818         if .changeCJKstyle and config.language$ = "JA"
819                 CJK font style preferences: "Japanese"
820         endif
821 endproc
823 procedure numbers2pinyin .numberstext$
824         .intermediatePinyin$ = .numberstext$
825         # Add a `-quote between vowels
826         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])([aeuiov])", "\1\2'\3", 0)
827         # Move numbers to the nucleus vowel
828         # To the vowel
829         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([^aeuiov0-9]*)([0-9])", "\1\3\2", 0)
830         # Either a/e
831         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([ae])([aeuiov]*)([0-9])", "\1\3\2", 0)
832         # Or the Oo in /ou/
833         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(ou)([0-9])", "o\2u", 0)
834         # or the second vowel
835         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([uiov][aeuiov])([uiov])([0-9])", "\1\3\2", 0)
836         
837         # Convert all tones to special characters
838         # Tone 1
839         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a1", "ā", 0)
840         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e1", "ē", 0)
841         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u1", "ū", 0)
842         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i1", "ī", 0)
843         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o1", "ō", 0)
844         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v1", "ǖ", 0)
845         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "1", "\\-^", 0)
846         
847         # Tone 2
848         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v2", "ǘ", 0)
849         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])2", "\\\1'", 0)
850         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "2", "\\'^", 0)
851         
852         # Tone 3
853         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a3", "ǎ", 0)
854         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e3", "ě", 0)
855         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u3", "ǔ", 0)
856         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i3", "ǐ", 0)
857         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o3", "ǒ", 0)
858         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v3", "ǚ", 0)
859         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "3", "\\N^", 0)
861         # Tone 4
862         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v4", "ǜ", 0)
863         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])4", "\\\1`", 0)
864         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "4", "\\`^", 0)
865         
866         # Tone 0
867         # Remove tone 0 symbol completely
868         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "", 0)
869         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a0", "å", 0)
870         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e0", "e̊", 0)
871         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u0", "ů", 0)
872         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i0", "i̊", 0)
873         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o0", "o̊", 0)
874         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v0", "ü̊", 0)
875         #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "\\0^", 0)
876         
877         # Pick best vowel symbols available in cases not caught before
878         # Ugly clutch to get the 1, 3, 0 tone diacritics at least in the neighbourhood
879         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i(\\[-N0]\^)", "i\\s{_ }\1", 0)
880         # Insert u umlaut
881         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v", "\\u\X22", 0)
883         .pinyin$ = .intermediatePinyin$
884 endproc
886 # NEEDS WORK AND TESTING!!
887 # Convert unicode Pinyin into tone numbers
888 procedure pinyin2numbers .pinyin$
889         .intermediatePinyin$ = .pinyin$
890         # Convert all special characters to numbers
891         # Tone 1
892         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iā)([iaeouü]*)", "a\11", 0)
893         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iē)([iaeouü]*)", "e\11", 0)
894         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iū)([iaeouü]*)", "u\11", 0)
895         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iī)([iaeouü]*)", "i\11", 0)
896         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iō)([iaeouü]*)", "o\11", 0)
897         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǖ)([iaeouü]*)", "v\11", 0)
898         
899         # Tone 2
900         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iá)([iaeouü]*)", "a\12", 0)
901         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ié)([iaeouü]*)", "e\12", 0)
902         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iú)([iaeouü]*)", "u\12", 0)
903         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ií)([iaeouü]*)", "i\12", 0)
904         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ió)([iaeouü]*)", "o\12", 0)
905         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǘ)([iaeouü]*)", "v\12", 0)
906         
907         # Tone 3
908         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǎ)([iaeouü]*)", "a\13", 0)
909         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iě)([iaeouü]*)", "e\13", 0)
910         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǔ)([iaeouü]*)", "u\13", 0)
911         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǐ)([iaeouü]*)", "i\13", 0)
912         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǒ)([iaeouü]*)", "o\13", 0)
913         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǚ)([iaeouü]*)", "v\13", 0)
915         # Tone 4
916         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ià)([iaeouü]*)", "a\14", 0)
917         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iè)([iaeouü]*)", "e\14", 0)
918         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iù)([iaeouü]*)", "u\14", 0)
919         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iì)([iaeouü]*)", "i\14", 0)
920         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iò)([iaeouü]*)", "o\14", 0)
921         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǜ)([iaeouü]*)", "v\14", 0)
922         
923         # Tone 0
924         # Add tone 0
925         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iå)([iaeouü]*)", "a\10", 0)
926         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e̊([iaeouü]*)", "e\10", 0)
927         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iů)([iaeouü]*)", "u\10", 0)
928         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i̊([iaeouü]*)", "i\10", 0)
929         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o̊([iaeouü]*)", "o\10", 0)
930         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ü̊([iaeouü]*)", "v\10", 0)
932         # Syllables without a tone symbol are tone 0
933         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov]+)([^0-9aeuiov]|\W|$)", "\10\2", 0)
935         # Move numbers to the end of the syllable.
936         # Syllables ending in n and start with g. Note that a syllable cannot start with an u or i
937         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(n)(g[aeuiov])", "\1\3\2\4", 0)
938         # Syllables ending in (ng?) followed by something that is not a valid vowel 
939         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(ng?)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
940         # Syllables ending in r
941         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(r)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
942         # Remove quotes etc
943         #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "[\\'\\`]", "", 0)
944         
945         .numberstext$ = .intermediatePinyin$
946 endproc
948 procedure readDisplayPinyin .currentWord
949         select Table 'wordlist$'
950         .pinyin$ = Get value... '.currentWord' Pinyin
951         # Everything to lowercase
953         if index_regex(.pinyin$, "[0-9]") <= 0
954                 call pinyin2numbers '.pinyin$'
955                 .pinyin$ = pinyin2numbers.numberstext$
956         endif 
957 endproc
959 procedure readPinyin .currentWord
960         call readDisplayPinyin '.currentWord'
961         .pinyin$ = replace_regex$(readDisplayPinyin.pinyin$, ".+", "\L&", 0)
962         .pinyin$ = replace_regex$(.pinyin$, "[\\'\\` ]", "", 0)
963 endproc
965 # Includes
966 include ToneProt/SGC_ToneProt.praat
967 include ToneProt/DrawToneContour.praat
968 include ToneProt/HumToneContour.praat
969 include ToneProt/ToneRecognition.praat
970 include ToneProt/ToneScript.praat
971 include ToneProt/ToneRules.praat