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.
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
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
40 if sgc.numberOfDisplayedWords > 0
41 .fraction = sgc.currentWordNum/sgc.numberOfDisplayedWords
43 call drawProgressTriangle -1 .x .y .size .fraction '.color$' Green
44 .currentX = drawProgressTriangle.currentX
45 .endX = .currentX - 0.5
48 .displayColor$ = .color$
49 if sgc.currentWordNum >= sgc.numberOfDisplayedWords
50 .displayColor$ = "Green"
52 demo Paint rectangle... '.displayColor$' '.currentX' '.endX' '.lowY' '.highY'
55 procedure DrawNext .color$ .x .y .size
59 if sgc.numberOfDisplayedWords > 0
60 .fraction = sgc.currentWordNum/sgc.numberOfDisplayedWords
62 call drawProgressTriangle 1 .x .y .size .fraction '.color$' Green
63 .currentX = drawProgressTriangle.currentX
64 .endX = .currentX + 0.5
67 .displayColor$ = .color$
68 if sgc.currentWordNum >= sgc.numberOfDisplayedWords
69 .displayColor$ = "Green"
71 demo Paint rectangle... '.displayColor$' '.currentX' '.endX' '.lowY' '.highY'
74 procedure DrawSelectWords .color$ .x .y .size
78 call adjustFontSizeOnHeight 'defaultFont$' '.currentFontSize' '.maxHeight'
79 .currentFontSize = adjustFontSizeOnHeight.currentFontSize
80 call set_font_size '.currentFontSize'
81 demo Colour... '.color$'
82 demo Text... '.x' Centre '.y' Bottom \bu\bu\bu
83 call set_font_size 'defaultFontSize'
86 procedure DrawWordListUp .color$ .x .y .size
95 demo Draw line... .xleft .ylow .xmidleft .yhigh
96 demo Draw line... .xright .ylow .xmidright .yhigh
97 demo Line width... 'defaultLineWidth'
101 procedure DrawWordListDown .color$ .x .y .size
105 .xmidright = .x - 0.1
110 demo Draw line... .xleft .yhigh .xmidleft .ylow
111 demo Draw line... .xright .yhigh .xmidright .ylow
112 demo Line width... 'defaultLineWidth'
116 procedure drawTriangle .direction .x .y .size
117 # Make sure direction = +/- 1
121 .direction /= abs(.direction)
124 .currentHeight = .size
125 .currentX = .x - .direction*.size
127 demo Line width... 2.0
129 while .currentHeight> 0
130 .ystart = .y + .currentHeight
131 .yend = .y - .currentHeight
132 demo Draw line... .currentX .ystart .currentX .yend
133 .currentHeight -= .offset *3/4
134 .currentX += .direction*.offset * 1.5
136 demo Line width... 'defaultLineWidth'
139 procedure drawProgressTriangle .direction .x .y .size .fraction .color1$ .color2$
140 # Make sure direction = +/- 1
144 .direction /= abs(.direction)
147 .currentHeight = .size
148 .startX = .x - .direction*.size
151 demo Line width... 2.0
153 while .currentHeight> 0
154 # Implement progress bar in .color2$
155 if .direction*(.currentX - .startX)/.size <= 2*.fraction
161 .ystart = .y + .currentHeight
162 .yend = .y - .currentHeight
163 demo Draw line... .currentX .ystart .currentX .yend
164 .currentHeight -= .offset *3/4
165 .currentX += .direction*.offset * 1.5
167 demo Line width... 'defaultLineWidth'
171 ###############################################################
173 # Obligatory button Drawing Routines
175 # These MUST be defined
177 ###############################################################
179 procedure DrawRecord .color$ .x .y .size
181 demo Paint circle... '.color$' '.x' '.y' '.size'
184 procedure DrawPlay .color$ .x .y .size
186 call drawTriangle 1 .x .y .size
189 procedure DrawQuit .color$ .x .y .size
190 demo Colour... '.color$'
191 .lineWidth = 0.5*.size**2
192 demo Line width... '.lineWidth'
197 demo Draw line... .xstart .ystart .xend .yend
202 demo Draw line... .xstart .ystart .xend .yend
203 demo Line width... 'defaultLineWidth'
207 procedure DrawConfig .color$ .x .y .size
209 .lineWidth = 0.4*.size
210 demo Arrow size... '.lineWidth'
211 .lineWidth = 0.4*.size**2
212 demo Line width... '.lineWidth'
216 demo Draw arrow... .xstart .y .xend .y
217 demo Line width... 'defaultLineWidth'
220 procedure DrawRefresh .color$ .x .y .size
221 .lineWidth = 0.5*.size**2
223 demo Line width... '.lineWidth'
224 demo Draw arc... '.x' '.y' '.size' 0 270
225 demo Line width... 'defaultLineWidth'
228 ###############################################################
230 # Button Processing Routines
232 ###############################################################
234 procedure processMainPageExample .clickX .clickY .pressed$
235 call generate_example
238 procedure processMainPagePrevious .clickX .clickY .pressed$
240 call display_text Grey
243 call wipeArea 'wipeFeedbackArea$'
245 call display_text Black
247 sgc.failedAttempts = 0
250 procedure processMainPageNext .clickX .clickY .pressed$
252 call display_text Grey
254 call wipeArea 'wipeFeedbackArea$'
257 call display_text Black
260 procedure processMainPageWordlistUp .clickX .clickY .pressed$
261 call wipeArea 'wipeFeedbackArea$'
262 call load_word_list "'localWordlistDir$'" -1
264 call display_text Black
267 procedure processMainPageWordlistDown .clickX .clickY .pressed$
268 call wipeArea 'wipeFeedbackArea$'
269 call load_word_list "'localWordlistDir$'" 1
271 call display_text Black
274 procedure processMainPageGRADE .clickX .clickY .pressed$
275 call setGrade '.pressed$'
280 procedure processMainPagePinYinArea .clickX .clickY .pressed$
283 call display_text Red
287 # Select the words to practise. This is quite a complex piece of code
288 procedure processMainPageSelectWords .clickX .clickY .pressed$
290 .label$ = "SelectWords"
291 call Draw_button '.table$' '.label$' 1
293 # Panick button! No full UTF langauge is supported!
294 if config.language$ = "JA" or config.language$ = "ZH"
295 beginPause: "WARNING: Language not supported!"
296 comment: "This function is currently not available for your language"
297 comment: "Please, switch to English if you need this function"
298 comment: "We are very sorry and hope to enable your language soon"
299 endPause: "Continue", 1
304 call findLabel '.table$' '.label$'
306 select Table '.table$'
307 .helpText$ = Get value... '.row' Helptext
308 call convert_praat_to_latin1 '.helpText$'
309 .helpText$ = convert_praat_to_latin1.text$
312 select sgc.currentWordlist
313 .tmpOriginalWordlist = Copy: "Original_'wordlist$'"
315 # Remove current list from All wordlists table
316 select sgc.allWordLists
317 .rowNum = Search column: "Name", wordlistName$
319 .numRows = Get number of rows
323 Set string value: 1, "Name", "---"
328 select sgc.currentWordlist
329 sgc.numberOfWords = Get number of rows
330 .currentWord = sgc.currentWord
331 if .currentWord <= 0 or .currentWord > sgc.numberOfWords or config.shuffleLists
336 call get_feedback_text 'config.language$' AddWordlist
337 call convert_praat_to_latin1 'get_feedback_text.text$'
338 .wordlistText$ = convert_praat_to_latin1.text$
339 call get_feedback_text 'config.language$' Part
340 call convert_praat_to_latin1 'get_feedback_text.text$'
341 .partText$ = convert_praat_to_latin1.text$
342 call get_feedback_text 'config.language$' Tones
343 call convert_praat_to_latin1 'get_feedback_text.text$'
344 .toneText$ = convert_praat_to_latin1.text$
345 call get_feedback_text 'config.language$' Cancel
346 call convert_praat_to_latin1 'get_feedback_text.text$'
347 .cancelText$ = convert_praat_to_latin1.text$
348 call get_feedback_text 'config.language$' Clear
349 call convert_praat_to_latin1 'get_feedback_text.text$'
350 .clearText$ = convert_praat_to_latin1.text$
351 call get_feedback_text 'config.language$' All
352 call convert_praat_to_latin1 'get_feedback_text.text$'
353 .allText$ = convert_praat_to_latin1.text$
354 call get_feedback_text 'config.language$' Apply
355 call convert_praat_to_latin1 'get_feedback_text.text$'
356 .applySelection$ = convert_praat_to_latin1.text$
357 call get_feedback_text 'config.language$' Next
358 call convert_praat_to_latin1 'get_feedback_text.text$'
359 .nextWord$ = convert_praat_to_latin1.text$
360 call get_feedback_text 'config.language$' Continue
361 call convert_praat_to_latin1 'get_feedback_text.text$'
362 .continueText$ = convert_praat_to_latin1.text$
363 call get_feedback_text 'config.language$' Show
364 call convert_praat_to_latin1 'get_feedback_text.text$'
365 .showText$ = convert_praat_to_latin1.text$
367 call get_evaluation_text 'config.language$' Pinyin
368 .pinyinText$ = get_evaluation_text.text$
370 call get_evaluation_text 'config.language$' Character
371 .characterText$ = get_evaluation_text.text$
373 call get_evaluation_text 'config.language$' Example
374 .exampleText$ = get_evaluation_text.text$
376 call get_evaluation_text 'config.language$' Translation
377 .translationText$ = get_evaluation_text.text$
379 call get_evaluation_text 'config.language$' ManualEntry
380 .manualEntryText$ = get_evaluation_text.text$
383 select sgc.currentWordlist
384 .lessonCol = Get column index: "Lesson"
386 Append column: "Lesson"
387 .lessonCol = Get column index: "Lesson"
388 .numRows = Get number of rows
390 Set string value: .w, "Lesson", "-"
396 # All shown keeps track whether all words are shown
397 # If so, selecting a lesson is preceded by a Clear All
399 # Sort words for consistent selection interface
400 if config.shuffleLists
401 # Allow subdivision in lessons
403 Sort rows... Lesson Pinyin
409 for .i to sgc.numberOfWords
410 .currentLesson$ = Get value: .i, "Lesson"
411 .matchLesson$ = tab$+.currentLesson$+tab$
412 if .currentLesson$ <> "" and .currentLesson$ <> "-" and .currentLesson$ <> "?" and index(.lessonList$, .matchLesson$) <= 0
413 .lessonList$ = .lessonList$ + .currentLesson$ + tab$
415 .lessonName$['.numLessons'] = .currentLesson$
417 .shown$ = Get value: .i, "Show"
425 .numWordsPerScreen = 15
426 while clicked <> 6 and clicked <> 1
431 select sgc.currentWordlist
432 .lessonCol = Get column index: "Lesson"
433 # Sort words for consistent selection interface
434 if config.shuffleLists
435 # Allow subdivision in lessons
437 Sort rows... Lesson Pinyin
442 .max = .numWordsPerScreen - 1
443 if .currentWord + .max > sgc.numberOfWords
444 .max = sgc.numberOfWords - .currentWord
446 for .i from 0 to .numWordsPerScreen - 1
448 .currentPinyin$ = Get value: .currentWord+.i, "Pinyin"
449 if index_regex(.currentPinyin$, "[0-9]") <= 0
450 call pinyin2numbers '.currentPinyin$'
451 .currentPinyin$ = replace_regex$(pinyin2numbers.intermediatePinyin$, ".+", "\l&", 0)
452 .currentPinyin$ = replace_regex$(.currentPinyin$, "[^a-zA-Z0-9]", "", 0)
454 .pinyin$[.i] = .currentPinyin$
456 .character$[.i] = Get value: .currentWord+.i, "Character"
459 .lessonNum$[.i] = Get value: .currentWord+.i, "Lesson"
460 .lessonNum$[.i] = " : " + .lessonNum$[.i]
462 .showText$[.i] = .pinyin$['.i']
463 if .character$['.i'] <> "-"
464 .showText$[.i] = .pinyin$['.i']+" ("+.character$['.i']+.lessonNum$['.i']+")"
465 elsif .lessonNum$['.i'] <> ""
466 .showText$[.i] = .pinyin$['.i']+" ( -"+.lessonNum$['.i']+")"
468 .showValueText$[.i] = Get value: .currentWord+.i, "Show"
469 if .showValueText$[.i] = "-"
474 .showVariable$[.i] = .pinyin$[.i]
475 # This prevents some nasty attempts to use language elements as variables
476 if index_regex(.showVariable$[.i], "[^0-9r]$") or index_regex(.showVariable$[.i], "[0-9]") <= 0
477 .showVariable$[.i] = .pinyin$[.i]+"0"
479 .tmp$ = replace_regex$(.showVariable$[.i], "^(.+)$", "\l\1", 0)
480 .tmp$ = replace_regex$(.tmp$, "[^\w]", "_", 0)
481 '.tmp$' = .showValue[.i]
488 # The user text input window (beginPause .... endPause)
489 beginPause(.helpText$)
490 if sgc.allWordLists > 0
491 select sgc.allWordLists
492 .numWordlists = Get number of rows
493 optionMenu: .wordlistText$, 1
495 for .w to .numWordlists
496 select sgc.allWordLists
497 .wordListName$ = Get value: .w, "Name"
498 option: .wordListName$
500 option: "*"+.manualEntryText$+"*"
503 boolean (.showText$[0], .showValue[0])
504 boolean (.showText$[1], .showValue[1])
505 boolean (.showText$[2], .showValue[2])
506 boolean (.showText$[3], .showValue[3])
507 boolean (.showText$[4], .showValue[4])
508 boolean (.showText$[5], .showValue[5])
509 boolean (.showText$[6], .showValue[6])
510 boolean (.showText$[7], .showValue[7])
511 boolean (.showText$[8], .showValue[8])
512 boolean (.showText$[9], .showValue[9])
513 boolean (.showText$[10], .showValue[10])
514 boolean (.showText$[11], .showValue[11])
515 boolean (.showText$[12], .showValue[12])
516 boolean (.showText$[13], .showValue[13])
517 boolean (.showText$[14], .showValue[14])
519 .selectMenu$ = .toneText$
521 .selectMenu$ = .selectMenu$ + " " + .partText$
523 optionMenu: .selectMenu$, 1
531 # Display Lesson text if available
535 for .j to .numLessons
536 option: .partText$+": "+.lessonName$['.j']
539 clicked = endPause ("'.cancelText$'", "'.clearText$'", "'.allText$'", "'.applySelection$'", "'.nextWord$'", "'.continueText$'", 6, 1)
541 select sgc.currentWordlist
543 for .i to sgc.numberOfWords
544 Set string value: .i, "Show", "-"
548 for .i to sgc.numberOfWords
549 Set string value: .i, "Show", "+"
553 # Handle added word lists
554 .wordlistText$ = replace_regex$(.wordlistText$, "^(.)", "\l\1", 0)
555 .wordlistText$ = replace_regex$(.wordlistText$, "[^\w]", "_", 0)
556 .tmp$ = '.wordlistText$'$
557 if .tmp$ <> "---" and sgc.allWordLists > 0
558 select sgc.currentWordlist
559 # Add current wordlist name as a lesson name
560 .originalWordList = -1
561 .numRows = Get number of rows
563 select sgc.currentWordlist
564 .currentLesson$ = Get value: .w, "Lesson"
565 if .currentLesson$ = "" or .currentLesson$ = "-"
566 Set string value: .w, "Lesson", wordlist$
570 # Get and merge the selected list
571 # Enter words by hand
572 if .tmp$ = "*"+.manualEntryText$+"*"
574 .currentFilePath$ = .exampleText$
575 .manualText$ = .manualEntryText$
576 .manPinyin$ = .pinyinText$
577 .manCharacter$ = .characterText$
578 .manTranslation$ = .translationText$
579 .manSound$ = .currentFilePath$
580 .manLesson$ = .manualText$
581 while .man_clicked > 1
582 beginPause: .manualEntryText$
583 text: .pinyinText$, .manPinyin$
584 text: .characterText$, .manCharacter$
585 text: .translationText$, .manTranslation$
586 text: .exampleText$, .manSound$
587 text: .manualText$, .manualText$
588 .man_clicked = endPause("'.cancelText$'", "'.exampleText$'", "'.continueText$'", 3, 1)
590 .tmp$ = replace_regex$(.pinyinText$, "[^\w]", "_", 0)
591 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
592 if '.tmp$'$ <> .pinyinText$
593 .manPinyin$ = '.tmp$'$
599 .tmp$ = replace_regex$(.characterText$, "[^\w]", "_", 0)
600 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
601 if '.tmp$'$ <> .characterText$
602 .manCharacter$ = '.tmp$'$
607 .tmp$ = replace_regex$(.translationText$, "[^\w]", "_", 0)
608 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
609 if '.tmp$'$ <> .translationText$
610 .manTranslation$ = '.tmp$'$
612 .manTranslation$ = ""
615 .tmp$ = replace_regex$(.exampleText$, "[^\w]", "_", 0)
616 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
617 if '.tmp$'$ <> .characterText$ and '.tmp$'$ <> ""
618 .manSound$ = '.tmp$'$
621 .tmp$ = replace_regex$(.manualText$, "[^\w]", "_", 0)
622 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
623 .manLesson$ = '.tmp$'$
626 .manSound$ = chooseReadFile$(.exampleText$);
627 elsif .man_clicked = 3
628 # Clean up input string
629 .manPinyin$ = replace_regex$(.manPinyin$, "^[^a-z]+", "", 0)
630 .manPinyin$ = replace_regex$(.manPinyin$, "[^\w']", "", 0)
632 select sgc.currentWordlist
634 .numRows = Get number of rows
636 Set string value: .numRows, "Pinyin", .manPinyin$
637 Set string value: .numRows, "Character", .manCharacter$
638 Set string value: .numRows, "Translation", .manTranslation$
639 Set string value: .numRows, "Sound", .manSound$
640 Set string value: .numRows, "Lesson", .manLesson$
641 Set string value: .numRows, "Show", "+"
643 .manualText$ = .manualEntryText$
644 .manPinyin$ = .pinyinText$
645 .manCharacter$ = .characterText$
646 .manTranslation$ = .translationText$
647 .manSound$ = .currentFilePath$
648 .manLesson$ = .manualText$
654 select sgc.allWordLists
655 .wordlistNum = Search column: "Name", .tmp$
657 .wordlistPath$ = Get value: .wordlistNum, "Directory"
658 .wordlistPath$ = replace_regex$(.wordlistPath$, "[ ]", "&", 0)
659 call read_wordlist "'.tmp$'" '.wordlistPath$'
660 .newList = read_wordlist.wordlistID
661 call merge_into_wordlist '.newList' '.tmp$'
664 # Add wordlistname to Lesson column
665 select sgc.allWordLists
666 .numRows = Get number of rows
668 Remove row: .wordlistNum
670 Set string value: 1, "Name", "---"
674 # Gather Lesson names
675 select sgc.currentWordlist
676 Sort rows... Lesson Pinyin
678 sgc.numberOfWords = Get number of rows
682 for .i to sgc.numberOfWords
683 .currentLesson$ = Get value: .i, "Lesson"
684 .matchLesson$ = tab$+.currentLesson$+tab$
685 if .currentLesson$ <> "" and .currentLesson$ <> "-" and .currentLesson$ <> "?" and index(.lessonList$, .matchLesson$) <= 0
686 .lessonList$ = .lessonList$ + .currentLesson$ + tab$
688 .lessonName$['.numLessons'] = .currentLesson$
690 .shown$ = Get value: .i, "Show"
697 for .i from 0 to .max
698 .tmp$ = replace_regex$(.showVariable$['.i'], "^(.*)$", "\l\1", 0)
699 .tmp$ = replace_regex$(.tmp$, "[^\w]", "_", 0)
701 .showValue['.i'] = '.tmp$'
702 .showWord$['.i'] = "-"
703 if .showValue['.i'] <> 0
704 .showWord$['.i'] = "+"
706 Set string value: .currentWord+.i, "Show", .showWord$['.i']
710 select sgc.currentWordlist
711 .tmp$ = replace_regex$(.selectMenu$, "^(.)", "\l\1", 0)
712 .tmp$ = replace_regex$(.tmp$, "[^\w]", "_", 0)
713 .toneSelected = '.tmp$' - 2
714 if .toneSelected >= 0 and .toneSelected < 5
715 select sgc.currentWordlist
716 for .i to sgc.numberOfWords
717 .currentPinyin$ = Get value: .i, "Pinyin"
718 if index_regex(.currentPinyin$, "[0-9]") <= 0
719 call pinyin2numbers '.currentPinyin$'
720 .currentPinyin$ = replace_regex$(pinyin2numbers.intermediatePinyin$, ".+", "\l&", 0)
721 .currentPinyin$ = replace_regex$(.currentPinyin$, "[^a-zA-Z0-9]", "", 0)
723 .tmp$ = Get value: .i, "Show"
724 if .tmp$ <> "-" and index(.currentPinyin$, "'.toneSelected'") > 0
725 Set string value: .i, "Show", "+"
727 Set string value: .i, "Show", "-"
731 elsif .toneSelected > 5
732 # .toneSelected = 5 is the Part text
733 .lessonSelected = .toneSelected - 5
734 if .lessonSelected > 0
737 select sgc.currentWordlist
738 for .i to sgc.numberOfWords
739 # Keep track of whether all are shown
740 .shown$ = Get value: .i, "Show"
746 for .i to sgc.numberOfWords
748 .currentLesson$ = Get value: .i, "Lesson"
749 if .currentLesson$ = .lessonName$['.lessonSelected']
750 Set string value: .i, "Show", "+"
752 Set string value: .i, "Show", "-"
755 for .i to sgc.numberOfWords
756 # Keep track of whether all are shown
757 .shown$ = Get value: .i, "Show"
758 if .firstShown <=0 and .shown$ <> "-"
767 .currentWord = (sgc.numberOfWords div .numWordsPerScreen) * .numWordsPerScreen + 1
771 .currentWord = (.firstShown div .numWordsPerScreen) * .numWordsPerScreen + 1
773 .currentWord += .numWordsPerScreen
774 if .currentWord > sgc.numberOfWords
779 # Reset and go to the first selected word (can shuffle list)
789 select sgc.currentWordlist
791 select .tmpOriginalWordlist
793 sgc.currentWordlist = selected()
795 # Set the values of the number of words shown
796 select sgc.currentWordlist
797 .numWords = Get number of rows
798 sgc.currentWordNum = 1
799 sgc.numberOfDisplayedWords = 0
802 .show$ = Get value: .i, "Show"
804 if sgc.currentWord < 1
807 sgc.numberOfDisplayedWords += 1
811 select .tmpOriginalWordlist
814 label SELECTWORDSFAIL
816 call Draw_button '.table$' '.label$' 0
819 ###############################################################
821 # Obligatory button Processing Routines
823 # These MUST be defined
825 ###############################################################
827 procedure processMainPageQuit .clickX .clickY .pressed$
831 procedure processMainPageRefresh .clickX .clickY .pressed$
836 procedure processMainPageConfig .clickX .clickY .pressed$
840 procedure processMainPageHelp .clickX .clickY .pressed$
841 call help_loop 'buttons$' init_window
844 procedure processMainPagePlay .clickX .clickY .pressed$
847 if recordedSound$ <> ""
848 call play_sound 'sgc.recordedSound'
851 te.buttonPressValue = mainPage.play
854 procedure Set_Play_Button
856 if recordedSound$ <> ""
859 call Draw_button MainPage Play 'mainPage.play'
862 procedure processMainPageRecord .clickX .clickY .pressed$
864 .recordingTime = recordingTime
865 if count_syllables.number > 2
866 .recordingTime = recordingTime + 1.0*ceiling((count_syllables.number - 2)/2)
868 call record_sound '.recordingTime'
874 call wipeArea 'wipeContourArea$'
876 call draw_tone_contour
878 call display_word_list_name
879 call display_text Black
880 call add_feedback_to_toneevaluation Feedback
881 call write_feedback Feedback
882 select Table Feedback
885 # Do not exercise words that are going well (autoSelect)
886 if add_feedback_to_toneevaluation.result > 0
887 if config.adaptiveLists > 0 and sgc.failedAttempts < 2
888 # Deselect current word
889 select sgc.currentWordlist
890 .i = Search column: "Pinyin", sgc.pinyin$
892 Set string value: .i, "Show", "-"
895 sgc.failedAttempts = 0
897 sgc.failedAttempts += 1
902 ###############################################################
904 # Miscelaneous supporting code
906 ###############################################################
909 procedure generate_example
910 select sgc.currentWordlist
911 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
912 select sgc.currentWordlist
913 .sound$ = Get value... 'sgc.currentWord' Sound
914 call readPinyin 'sgc.currentWord'
915 sgc.pinyin$ = readPinyin.pinyin$
916 sgc.character$ = readPinyin.character$
917 if .sound$ = "-" or .sound$ = ""
918 .sound$ = sgc.pinyin$+".wav"
920 if index_regex(.sound$, "^(/|~/|[A-Z]:\\)") > 0
921 .soundFilePath$ = .sound$
923 .soundFilePath$ = localWordlistDir$+"/"+wordlistName$+"/"+.sound$
924 .wordlistDirectory$ = ""
925 if localWordlistDir$ <> "" and fileReadable("'localWordlistDir$'/'wordlistName$'")
926 .wordlistDirectory$ = "'localWordlistDir$'/'wordlistName$'"
927 elsif sgc2wordlists$ <> "" and fileReadable("'sgc2wordlists$'/'wordlistName$'")
928 .wordlistDirectory$ = "'sgc2wordlists$'/'wordlistName$'"
929 elsif globalwordlists$ <> "" and fileReadable("'globalwordlists$'/'wordlistName$'")
930 .wordlistDirectory$ = "'globalwordlists$'/'wordlistName$'"
932 if .wordlistDirectory$ <> ""
933 .audioExampleList = Create Strings as file list... AudioList '.wordlistDirectory$'/'sgc.pinyin$'.*
934 .number_of_examples = Get number of strings
935 if .number_of_examples > 0
937 .sound$ = Get string... 1
938 .soundFilePath$ = "'.wordlistDirectory$'/'.sound$'"
943 if fileReadable(.soundFilePath$) and config.useSoundExample
945 .tmp = nocheck Read from file... '.soundFilePath$'
946 if .tmp != undefined and .tmp > 0
947 call play_sound '.tmp'
951 elsif config.synthesis$ <> "" and config.synthesis$ <> "_DISABLED_"
952 call synthesize_sound "'sgc.pinyin$'" "'sgc.character$'"
954 call humToneContour 'sgc.pinyin$' 'config.register'
961 # Draw a tone contour
962 procedure draw_tone_contour
963 select sgc.currentWordlist
964 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
965 .sound$ = Get value... 'sgc.currentWord' Sound
966 call readPinyin 'sgc.currentWord'
967 sgc.pinyin$ = readPinyin.pinyin$
968 sgc.character$ = readPinyin.character$
969 call drawToneContour 'sgc.pinyin$' 'config.register'
972 if te.recordedPitch > 0
973 call drawSourceToneContour te.recordedPitch
979 procedure recognizeTone
980 select sgc.currentWordlist
981 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
983 if index_regex(config.strict$, "[^0-9]") <= 0
984 .strict = ('config.strict$' >= sgc.highestLevel)
987 .sound$ = Get value... 'sgc.currentWord' Sound
988 call readPinyin 'sgc.currentWord'
989 sgc.pinyin$ = readPinyin.pinyin$
990 sgc.character$ = readPinyin.character$
991 call align_recordedSound 'sgc.pinyin$'
992 call sgc_ToneProt 'recordedSound$' 'sgc.pinyin$' 'config.register' '.strict' 'config.language$'
993 # sgc_ToneProt manipulates the sound given. Reconnect
994 select Sound 'recordedSound$'
995 sgc.recordedSound = selected("Sound")
1000 procedure write_feedback .table$
1001 select Table '.table$'
1002 .line1$ = Get value... 1 Text
1003 .line2$ = Get value... 2 Text
1004 .label$ = Get value... 3 Text
1006 # convert numbers to Pinyin if needed
1007 if not config.displayNumbers
1008 call numbers2pinyin '.line1$'
1009 .line1$ = numbers2pinyin.pinyin$
1013 if index(.line1$, "???") > 0
1015 elsif .label$ = "Correct"
1017 elsif config.strict$ = "'sgc.highestLevel'"
1018 .line2$ = .line2$ + " *"
1021 .currentFeedbackFontSize = 14
1022 .maxHeight = 21 - 17
1023 call adjustFontSizeOnHeight 'defaultFont$' '.currentFeedbackFontSize' '.maxHeight'
1024 .currentFeedbackFontSize = adjustFontSizeOnHeight.newFontSize
1026 call wipeArea 'wipeFeedbackArea$'
1027 call set_font_size '.currentFeedbackFontSize'
1029 demo Text... 50 Centre 21 Bottom '.line1$'
1030 demo Text... 50 Centre 17 Bottom '.line2$'
1033 call set_font_size 'defaultFontSize'
1037 procedure display_text .color$
1038 select sgc.currentWordlist
1039 if sgc.currentWord < 0 or sgc.currentWord > sgc.numberOfWords+1
1041 if config.shuffleLists
1044 if sgc.currentWord < 0
1045 sgc.currentWord = sgc.numberOfWords
1052 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
1054 call readDisplayPinyin 'sgc.currentWord'
1055 .displayPinyin$ = readDisplayPinyin.pinyin$
1056 .displayChar$ = Get value... 'sgc.currentWord' Character
1057 .displayTrans$ = Get value... 'sgc.currentWord' Translation
1058 if .displayPinyin$ <> "-" and (config.displayPinyin or sgc.writeAll)
1059 if not config.displayNumbers
1060 call numbers2pinyin '.displayPinyin$'
1061 .displayPinyin$ = numbers2pinyin.pinyin$
1064 .displayPinyin$ = replace_regex$(.displayPinyin$, "v", "\\u\X22", 0)
1065 .displayText$ = .displayText$ + .displayPinyin$
1067 if .displayChar$ <> "-" and (config.displayChar or sgc.writeAll)
1068 .displayText$ = .displayText$ + " "+ .displayChar$
1071 if .displayTrans$ <> "-" and (config.displayTrans or sgc.writeAll)
1072 .displayText$ = .displayText$ + " \s{%%"+ .displayTrans$ + "%}"
1074 elsif sgc.currentWord = 0 or sgc.currentWord = sgc.numberOfWords+1
1076 .displayText$ = "---"
1080 call adjustFontSizeOnHeight 'defaultFont$' 24 15
1081 .currentFontSize = adjustFontSizeOnHeight.newFontSize
1082 call adjustFontSizeOnWidth 'defaultFont$' '.currentFontSize' 95 '.displayText$'
1083 .currentFontSize = adjustFontSizeOnWidth.newFontSize
1085 # Clear the writing area
1086 call wipeArea 'wipePinyinArea$'
1087 # Switch back to Chinese style CJK when in Japanese language mode
1088 if .changeCJKstyle and config.language$ = "JA"
1089 CJK font style preferences: "Chinese"
1091 # Actually display text
1093 call set_font_size '.currentFontSize'
1094 demo Text... 50 Centre 26 Bottom '.displayText$'
1098 call set_font_size 'defaultFontSize'
1099 if .changeCJKstyle and config.language$ = "JA"
1100 if config.language$ = "JA"
1101 CJK font style preferences: "Japanese"
1102 elsif config.language$ = "ZH"
1103 CJK font style preferences: "Chinese"
1106 # Switch back to Japanese style CJK when in Japanese language mode
1107 if .changeCJKstyle and config.language$ = "JA"
1108 CJK font style preferences: "Japanese"
1112 procedure numbers2pinyin .numberstext$
1113 .intermediatePinyin$ = .numberstext$
1114 # Add a `-quote between vowels
1115 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])([aeuiov])", "\1\2'\3", 0)
1116 # Move numbers to the nucleus vowel
1118 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([^aeuiov0-9]*)([0-9])", "\1\3\2", 0)
1120 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([ae])([aeuiov]*)([0-9])", "\1\3\2", 0)
1122 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(ou)([0-9])", "o\2u", 0)
1123 # or the second vowel
1124 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([uiov][aeuiov])([uiov])([0-9])", "\1\3\2", 0)
1126 # Convert all tones to special characters
1128 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a1", "ā", 0)
1129 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e1", "ē", 0)
1130 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u1", "ū", 0)
1131 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i1", "ī", 0)
1132 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o1", "ō", 0)
1133 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v1", "ǖ", 0)
1134 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "1", "\\-^", 0)
1137 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v2", "ǘ", 0)
1138 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])2", "\\\1'", 0)
1139 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "2", "\\'^", 0)
1142 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a3", "ǎ", 0)
1143 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e3", "ě", 0)
1144 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u3", "ǔ", 0)
1145 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i3", "ǐ", 0)
1146 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o3", "ǒ", 0)
1147 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v3", "ǚ", 0)
1148 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "3", "\\N^", 0)
1151 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v4", "ǜ", 0)
1152 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])4", "\\\1`", 0)
1153 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "4", "\\`^", 0)
1156 # Remove tone 0 symbol completely
1157 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "", 0)
1158 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a0", "å", 0)
1159 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e0", "e̊", 0)
1160 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u0", "ů", 0)
1161 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i0", "i̊", 0)
1162 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o0", "o̊", 0)
1163 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v0", "ü̊", 0)
1164 #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "\\0^", 0)
1166 # Pick best vowel symbols available in cases not caught before
1167 # Ugly clutch to get the 1, 3, 0 tone diacritics at least in the neighbourhood
1168 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i(\\[-N0]\^)", "i\\s{_ }\1", 0)
1170 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v", "\\u\X22", 0)
1172 .pinyin$ = .intermediatePinyin$
1175 # NEEDS WORK AND TESTING!!
1176 # Convert unicode Pinyin into tone numbers
1177 procedure pinyin2numbers .pinyin$
1178 .intermediatePinyin$ = .pinyin$
1179 # Convert all special characters to numbers
1181 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iā)([iaeouü]*)", "a\11", 0)
1182 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iē)([iaeouü]*)", "e\11", 0)
1183 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iū)([iaeouü]*)", "u\11", 0)
1184 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iī)([iaeouü]*)", "i\11", 0)
1185 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iō)([iaeouü]*)", "o\11", 0)
1186 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǖ)([iaeouü]*)", "v\11", 0)
1189 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iá)([iaeouü]*)", "a\12", 0)
1190 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ié)([iaeouü]*)", "e\12", 0)
1191 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iú)([iaeouü]*)", "u\12", 0)
1192 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ií)([iaeouü]*)", "i\12", 0)
1193 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ió)([iaeouü]*)", "o\12", 0)
1194 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǘ)([iaeouü]*)", "v\12", 0)
1197 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǎ)([iaeouü]*)", "a\13", 0)
1198 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iě)([iaeouü]*)", "e\13", 0)
1199 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǔ)([iaeouü]*)", "u\13", 0)
1200 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǐ)([iaeouü]*)", "i\13", 0)
1201 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǒ)([iaeouü]*)", "o\13", 0)
1202 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǚ)([iaeouü]*)", "v\13", 0)
1205 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ià)([iaeouü]*)", "a\14", 0)
1206 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iè)([iaeouü]*)", "e\14", 0)
1207 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iù)([iaeouü]*)", "u\14", 0)
1208 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iì)([iaeouü]*)", "i\14", 0)
1209 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iò)([iaeouü]*)", "o\14", 0)
1210 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǜ)([iaeouü]*)", "v\14", 0)
1214 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iå)([iaeouü]*)", "a\10", 0)
1215 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e̊([iaeouü]*)", "e\10", 0)
1216 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iů)([iaeouü]*)", "u\10", 0)
1217 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i̊([iaeouü]*)", "i\10", 0)
1218 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o̊([iaeouü]*)", "o\10", 0)
1219 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ü̊([iaeouü]*)", "v\10", 0)
1221 # Syllables without a tone symbol are tone 0
1222 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov]+)([^0-9aeuiov]|\W|$)", "\10\2", 0)
1224 # Move numbers to the end of the syllable.
1225 # Syllables ending in n and start with g. Note that a syllable cannot start with an u or i
1226 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(n)(g[aeuiov])", "\1\3\2\4", 0)
1227 # Syllables ending in (ng?) followed by something that is not a valid vowel
1228 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(ng?)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
1229 # Syllables ending in r
1230 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(r)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
1232 #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "[\\'\\`]", "", 0)
1234 .numberstext$ = .intermediatePinyin$
1237 procedure readDisplayPinyin .currentWord
1238 select sgc.currentWordlist
1239 .pinyin$ = Get value... '.currentWord' Pinyin
1240 .character$ = Get value... '.currentWord' Character
1241 # Everything to lowercase
1243 if index_regex(.pinyin$, "[0-9]") <= 0
1244 call pinyin2numbers '.pinyin$'
1245 .pinyin$ = pinyin2numbers.numberstext$
1249 procedure readPinyin .currentWord
1250 call readDisplayPinyin '.currentWord'
1251 .character$ = readDisplayPinyin.character$
1252 .pinyin$ = replace_regex$(readDisplayPinyin.pinyin$, ".+", "\L&", 0)
1253 .pinyin$ = replace_regex$(.pinyin$, "[\\'\\` ]", "", 0)
1254 # Remove anything that is objectionable
1255 .pinyin$ = replace_regex$(.pinyin$, "[^\w']", "", 0)
1259 include ToneProt/SGC_ToneProt.praat
1260 include ToneProt/DrawToneContour.praat
1261 include ToneProt/HumToneContour.praat
1262 include ToneProt/ToneRecognition.praat
1263 include ToneProt/ToneScript.praat
1264 include ToneProt/ToneRules.praat