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
294 call findLabel '.table$' '.label$'
296 select Table '.table$'
297 .helpText$ = Get value... '.row' Helptext
298 call convert_praat_to_latin1 '.helpText$'
299 .helpText$ = convert_praat_to_latin1.text$
302 select sgc.currentWordlist
303 .tmpOriginalWordlist = Copy: "Original_'wordlist$'"
305 # Remove current list from All wordlists table
306 select sgc.allWordLists
307 .rowNum = Search column: "Name", wordlistName$
309 .numRows = Get number of rows
313 Set string value: 1, "Name", "---"
318 select sgc.currentWordlist
319 sgc.numberOfWords = Get number of rows
320 .currentWord = sgc.currentWord
321 if .currentWord <= 0 or .currentWord > sgc.numberOfWords or config.shuffleLists
326 call get_feedback_text 'config.language$' AddWordlist
327 call convert_praat_to_latin1 'get_feedback_text.text$'
328 .wordlistText$ = convert_praat_to_latin1.text$
329 call get_feedback_text 'config.language$' Part
330 call convert_praat_to_latin1 'get_feedback_text.text$'
331 .partText$ = convert_praat_to_latin1.text$
332 call get_feedback_text 'config.language$' Tones
333 call convert_praat_to_latin1 'get_feedback_text.text$'
334 .toneText$ = convert_praat_to_latin1.text$
335 call get_feedback_text 'config.language$' Cancel
336 call convert_praat_to_latin1 'get_feedback_text.text$'
337 .cancelText$ = convert_praat_to_latin1.text$
338 call get_feedback_text 'config.language$' Clear
339 call convert_praat_to_latin1 'get_feedback_text.text$'
340 .clearText$ = convert_praat_to_latin1.text$
341 call get_feedback_text 'config.language$' All
342 call convert_praat_to_latin1 'get_feedback_text.text$'
343 .allText$ = convert_praat_to_latin1.text$
344 call get_feedback_text 'config.language$' Previous
345 call convert_praat_to_latin1 'get_feedback_text.text$'
346 .prevWord$ = convert_praat_to_latin1.text$
347 call get_feedback_text 'config.language$' Next
348 call convert_praat_to_latin1 'get_feedback_text.text$'
349 .nextWord$ = convert_praat_to_latin1.text$
350 call get_feedback_text 'config.language$' Continue
351 call convert_praat_to_latin1 'get_feedback_text.text$'
352 .continueText$ = convert_praat_to_latin1.text$
353 call get_feedback_text 'config.language$' Show
354 call convert_praat_to_latin1 'get_feedback_text.text$'
355 .showText$ = convert_praat_to_latin1.text$
357 call get_evaluation_text 'config.language$' Pinyin
358 .pinyinText$ = get_evaluation_text.text$
360 call get_evaluation_text 'config.language$' Character
361 .characterText$ = get_evaluation_text.text$
363 call get_evaluation_text 'config.language$' Example
364 .exampleText$ = get_evaluation_text.text$
366 call get_evaluation_text 'config.language$' Translation
367 .translationText$ = get_evaluation_text.text$
369 call get_evaluation_text 'config.language$' ManualEntry
370 .manualEntryText$ = get_evaluation_text.text$
373 select sgc.currentWordlist
374 .lessonCol = Get column index: "Lesson"
376 Append column: "Lesson"
377 .lessonCol = Get column index: "Lesson"
378 .numRows = Get number of rows
380 Set string value: .w, "Lesson", "-"
386 # All shown keeps track whether all words are shown
387 # If so, selecting a lesson is preceded by a Clear All
389 # Sort words for consistent selection interface
390 if config.shuffleLists
391 # Allow subdivision in lessons
393 Sort rows... Lesson Pinyin
399 for .i to sgc.numberOfWords
400 .currentLesson$ = Get value: .i, "Lesson"
401 .matchLesson$ = tab$+.currentLesson$+tab$
402 if .currentLesson$ <> "" and .currentLesson$ <> "-" and .currentLesson$ <> "?" and index(.lessonList$, .matchLesson$) <= 0
403 .lessonList$ = .lessonList$ + .currentLesson$ + tab$
405 .lessonName$['.numLessons'] = .currentLesson$
407 .shown$ = Get value: .i, "Show"
415 .numWordsPerScreen = 15
416 while clicked <> 6 and clicked <> 1
421 select sgc.currentWordlist
422 .lessonCol = Get column index: "Lesson"
423 # Sort words for consistent selection interface
424 if config.shuffleLists
425 # Allow subdivision in lessons
427 Sort rows... Lesson Pinyin
432 .max = .numWordsPerScreen - 1
433 if .currentWord + .max > sgc.numberOfWords
434 .max = sgc.numberOfWords - .currentWord
436 for .i from 0 to .numWordsPerScreen - 1
438 .currentPinyin$ = Get value: .currentWord+.i, "Pinyin"
439 if index_regex(.currentPinyin$, "[0-9]") <= 0
440 call pinyin2numbers '.currentPinyin$'
441 .currentPinyin$ = replace_regex$(pinyin2numbers.intermediatePinyin$, ".+", "\l&", 0)
442 .currentPinyin$ = replace_regex$(.currentPinyin$, "[^a-zA-Z0-9]", "", 0)
444 .pinyin$[.i] = .currentPinyin$
446 .character$[.i] = Get value: .currentWord+.i, "Character"
449 .lessonNum$[.i] = Get value: .currentWord+.i, "Lesson"
450 .lessonNum$[.i] = " : " + .lessonNum$[.i]
452 .showText$[.i] = .pinyin$['.i']
453 if .character$['.i'] <> "-"
454 .showText$[.i] = .pinyin$['.i']+" ("+.character$['.i']+.lessonNum$['.i']+")"
455 elsif .lessonNum$['.i'] <> ""
456 .showText$[.i] = .pinyin$['.i']+" ( -"+.lessonNum$['.i']+")"
458 .showValueText$[.i] = Get value: .currentWord+.i, "Show"
459 if .showValueText$[.i] = "-"
464 .showVariable$[.i] = .pinyin$[.i]
465 .tmp$ = replace_regex$(.showVariable$[.i], "^(.+)$", "\l\1", 0)
466 '.tmp$' = .showValue[.i]
473 # The user text input window (beginPause .... endPause)
474 beginPause(.helpText$)
475 if sgc.allWordLists > 0
476 select sgc.allWordLists
477 .numWordlists = Get number of rows
478 optionMenu: .wordlistText$, 1
480 for .w to .numWordlists
481 select sgc.allWordLists
482 .wordListName$ = Get value: .w, "Name"
483 option: .wordListName$
485 option: "*"+.manualEntryText$+"*"
488 boolean (.showText$[0], .showValue[0])
489 boolean (.showText$[1], .showValue[1])
490 boolean (.showText$[2], .showValue[2])
491 boolean (.showText$[3], .showValue[3])
492 boolean (.showText$[4], .showValue[4])
493 boolean (.showText$[5], .showValue[5])
494 boolean (.showText$[6], .showValue[6])
495 boolean (.showText$[7], .showValue[7])
496 boolean (.showText$[8], .showValue[8])
497 boolean (.showText$[9], .showValue[9])
498 boolean (.showText$[10], .showValue[10])
499 boolean (.showText$[11], .showValue[11])
500 boolean (.showText$[12], .showValue[12])
501 boolean (.showText$[13], .showValue[13])
502 boolean (.showText$[14], .showValue[14])
504 optionMenu: .partText$, 1
507 for .j to .numLessons
508 option: .lessonName$['.j']
511 optionMenu: .toneText$, 1
518 clicked = endPause ("'.cancelText$'", "'.clearText$'", "'.allText$'", "'.prevWord$'", "'.nextWord$'", "'.continueText$'", 6, 1)
520 select sgc.currentWordlist
522 for .i to sgc.numberOfWords
523 Set string value: .i, "Show", "-"
527 for .i to sgc.numberOfWords
528 Set string value: .i, "Show", "+"
532 # Handle added word lists
533 .wordlistText$ = replace_regex$(.wordlistText$, "^(.)", "\l\1", 0)
534 .wordlistText$ = replace_regex$(.wordlistText$, "\s", "_", 0)
535 .tmp$ = '.wordlistText$'$
536 if .tmp$ <> "---" and sgc.allWordLists > 0
537 select sgc.currentWordlist
538 # Add current wordlist name as a lesson name
539 .originalWordList = -1
540 .numRows = Get number of rows
542 select sgc.currentWordlist
543 .currentLesson$ = Get value: .w, "Lesson"
544 if .currentLesson$ = "" or .currentLesson$ = "-"
545 Set string value: .w, "Lesson", wordlist$
549 # Get and merge the selected list
550 # Enter words by hand
551 if .tmp$ = "*"+.manualEntryText$+"*"
553 .currentFilePath$ = .exampleText$
554 .manualText$ = .manualEntryText$
555 .manPinyin$ = .pinyinText$
556 .manCharacter$ = .characterText$
557 .manTranslation$ = .translationText$
558 .manSound$ = .currentFilePath$
559 .manLesson$ = .manualText$
560 while .man_clicked > 1
561 beginPause: .manualEntryText$
562 text: .pinyinText$, .manPinyin$
563 text: .characterText$, .manCharacter$
564 text: .translationText$, .manTranslation$
565 text: .exampleText$, .manSound$
566 text: .manualText$, .manualText$
567 .man_clicked = endPause("'.cancelText$'", "'.exampleText$'", "'.continueText$'", 3, 1)
569 .tmp$ = replace_regex$(.pinyinText$, "\s", "_", 0)
570 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
571 if '.tmp$'$ <> .pinyinText$
572 .manPinyin$ = '.tmp$'$
578 .tmp$ = replace_regex$(.characterText$, "\s", "_", 0)
579 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
580 if '.tmp$'$ <> .characterText$
581 .manCharacter$ = '.tmp$'$
586 .tmp$ = replace_regex$(.translationText$, "\s", "_", 0)
587 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
588 if '.tmp$'$ <> .translationText$
589 .manTranslation$ = '.tmp$'$
591 .manTranslation$ = ""
594 .tmp$ = replace_regex$(.exampleText$, "\s", "_", 0)
595 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
596 if '.tmp$'$ <> .characterText$ and '.tmp$'$ <> ""
597 .manSound$ = '.tmp$'$
600 .tmp$ = replace_regex$(.manualText$, "\s", "_", 0)
601 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
602 .manLesson$ = '.tmp$'$
605 .manSound$ = chooseReadFile$(.exampleText$);
606 elsif .man_clicked = 3
607 # Clean up input string
608 .manPinyin$ = replace_regex$(.manPinyin$, "^[^a-z]+", "", 0)
609 select sgc.currentWordlist
611 .numRows = Get number of rows
613 Set string value: .numRows, "Pinyin", .manPinyin$
614 Set string value: .numRows, "Character", .manCharacter$
615 Set string value: .numRows, "Translation", .manTranslation$
616 Set string value: .numRows, "Sound", .manSound$
617 Set string value: .numRows, "Lesson", .manLesson$
618 Set string value: .numRows, "Show", "+"
620 .manualText$ = .manualEntryText$
621 .manPinyin$ = .pinyinText$
622 .manCharacter$ = .characterText$
623 .manTranslation$ = .translationText$
624 .manSound$ = .currentFilePath$
625 .manLesson$ = .manualText$
631 select sgc.allWordLists
632 .wordlistNum = Search column: "Name", .tmp$
634 .wordlistPath$ = Get value: .wordlistNum, "Directory"
635 .wordlistPath$ = replace_regex$(.wordlistPath$, "[ ]", "&", 0)
636 call read_wordlist "'.tmp$'" '.wordlistPath$'
637 .newList = read_wordlist.wordlistID
638 call merge_into_wordlist '.newList' '.tmp$'
641 # Add wordlistname to Lesson column
642 select sgc.allWordLists
643 .numRows = Get number of rows
645 Remove row: .wordlistNum
647 Set string value: 1, "Name", "---"
651 # Gather Lesson names
652 select sgc.currentWordlist
653 Sort rows... Lesson Pinyin
655 sgc.numberOfWords = Get number of rows
659 for .i to sgc.numberOfWords
660 .currentLesson$ = Get value: .i, "Lesson"
661 .matchLesson$ = tab$+.currentLesson$+tab$
662 if .currentLesson$ <> "" and .currentLesson$ <> "-" and .currentLesson$ <> "?" and index(.lessonList$, .matchLesson$) <= 0
663 .lessonList$ = .lessonList$ + .currentLesson$ + tab$
665 .lessonName$['.numLessons'] = .currentLesson$
667 .shown$ = Get value: .i, "Show"
674 select sgc.currentWordlist
675 # Get selected Part BEFORE we do anything else
677 .tmp$ = replace_regex$(.partText$, "^(.)", "\l\1", 0)
678 .lessonSelected = '.tmp$' - 1
680 if .lessonSelected > 0
683 select sgc.currentWordlist
684 for .i to sgc.numberOfWords
685 # Keep track of whether all are shown
686 .shown$ = Get value: .i, "Show"
692 for .i to sgc.numberOfWords
694 .currentLesson$ = Get value: .i, "Lesson"
695 if .currentLesson$ = .lessonName$['.lessonSelected']
696 Set string value: .i, "Show", "+"
698 Set string value: .i, "Show", "-"
701 for .i to sgc.numberOfWords
702 # Keep track of whether all are shown
703 .shown$ = Get value: .i, "Show"
704 if .firstShown <=0 and .shown$ <> "-"
709 for .i from 0 to .max
710 .tmp$ = replace_regex$(.showVariable$['.i'], "^(.*)$", "\l\1", 0)
711 .showValue['.i'] = '.tmp$'
712 .showWord$['.i'] = "-"
713 if .showValue['.i'] <> 0
714 .showWord$['.i'] = "+"
716 Set string value: .currentWord+.i, "Show", .showWord$['.i']
721 select sgc.currentWordlist
722 .tmp$ = replace_regex$(.toneText$, "^(.)", "\l\1", 0)
723 .toneSelected = '.tmp$' - 2
724 if .toneSelected >= 0
725 select sgc.currentWordlist
726 for .i to sgc.numberOfWords
727 .currentPinyin$ = Get value: .i, "Pinyin"
728 if index_regex(.currentPinyin$, "[0-9]") <= 0
729 call pinyin2numbers '.currentPinyin$'
730 .currentPinyin$ = replace_regex$(pinyin2numbers.intermediatePinyin$, ".+", "\l&", 0)
731 .currentPinyin$ = replace_regex$(.currentPinyin$, "[^a-zA-Z0-9]", "", 0)
733 .tmp$ = Get value: .i, "Show"
734 if .tmp$ <> "-" and index(.currentPinyin$, "'.toneSelected'") > 0
735 Set string value: .i, "Show", "+"
737 Set string value: .i, "Show", "-"
745 .currentWord = (.firstShown div .numWordsPerScreen) * .numWordsPerScreen + 1
746 elsif .toneSelected < 0
747 .currentWord -= .numWordsPerScreen
750 .currentWord = (sgc.numberOfWords div .numWordsPerScreen) * .numWordsPerScreen + 1
754 .currentWord = (.firstShown div .numWordsPerScreen) * .numWordsPerScreen + 1
755 elsif .toneSelected < 0
756 .currentWord += .numWordsPerScreen
758 if .currentWord > sgc.numberOfWords
763 # Reset and go to the first selected word (can shuffle list)
773 select sgc.currentWordlist
775 select .tmpOriginalWordlist
777 sgc.currentWordlist = selected()
779 # Set the values of the number of words shown
780 select sgc.currentWordlist
781 .numWords = Get number of rows
782 sgc.currentWordNum = 1
783 sgc.numberOfDisplayedWords = 0
786 .show$ = Get value: .i, "Show"
788 if sgc.currentWord < 1
791 sgc.numberOfDisplayedWords += 1
795 select .tmpOriginalWordlist
798 call Draw_button '.table$' '.label$' 0
801 ###############################################################
803 # Obligatory button Processing Routines
805 # These MUST be defined
807 ###############################################################
809 procedure processMainPageQuit .clickX .clickY .pressed$
813 procedure processMainPageRefresh .clickX .clickY .pressed$
818 procedure processMainPageConfig .clickX .clickY .pressed$
822 procedure processMainPageHelp .clickX .clickY .pressed$
823 call help_loop 'buttons$' init_window
826 procedure processMainPagePlay .clickX .clickY .pressed$
829 if recordedSound$ <> ""
830 call play_sound 'sgc.recordedSound'
833 te.buttonPressValue = mainPage.play
836 procedure Set_Play_Button
838 if recordedSound$ <> ""
841 call Draw_button MainPage Play 'mainPage.play'
844 procedure processMainPageRecord .clickX .clickY .pressed$
846 .recordingTime = recordingTime
847 if count_syllables.number > 2
848 .recordingTime = recordingTime + 1.0*ceiling((count_syllables.number - 2)/2)
850 call record_sound '.recordingTime'
856 call wipeArea 'wipeContourArea$'
858 call draw_tone_contour
860 call display_word_list_name
861 call display_text Black
862 call add_feedback_to_toneevaluation Feedback
863 call write_feedback Feedback
864 select Table Feedback
867 # Do not exercise words that are going well (autoSelect)
868 if add_feedback_to_toneevaluation.result > 0
869 if config.adaptiveLists > 0 and sgc.failedAttempts < 2
870 # Deselect current word
871 select sgc.currentWordlist
872 .i = Search column: "Pinyin", sgc.pinyin$
874 Set string value: .i, "Show", "-"
877 sgc.failedAttempts = 0
879 sgc.failedAttempts += 1
884 ###############################################################
886 # Miscelaneous supporting code
888 ###############################################################
891 procedure generate_example
892 select sgc.currentWordlist
893 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
894 select sgc.currentWordlist
895 .sound$ = Get value... 'sgc.currentWord' Sound
896 call readPinyin 'sgc.currentWord'
897 sgc.pinyin$ = readPinyin.pinyin$
898 if .sound$ = "-" or .sound$ = ""
899 .sound$ = sgc.pinyin$+".wav"
901 if index_regex(.sound$, "^(/|~/|[A-Z]:\\)") > 0
902 .soundFilePath$ = .sound$
904 .soundFilePath$ = localWordlistDir$+"/"+wordlistName$+"/"+.sound$
905 .wordlistDirectory$ = ""
906 if localWordlistDir$ <> "" and fileReadable("'localWordlistDir$'/'wordlistName$'")
907 .wordlistDirectory$ = "'localWordlistDir$'/'wordlistName$'"
908 elsif sgc2wordlists$ <> "" and fileReadable("'sgc2wordlists$'/'wordlistName$'")
909 .wordlistDirectory$ = "'sgc2wordlists$'/'wordlistName$'"
910 elsif globalwordlists$ <> "" and fileReadable("'globalwordlists$'/'wordlistName$'")
911 .wordlistDirectory$ = "'globalwordlists$'/'wordlistName$'"
913 if .wordlistDirectory$ <> ""
914 .audioExampleList = Create Strings as file list... AudioList '.wordlistDirectory$'/'sgc.pinyin$'.*
915 .number_of_examples = Get number of strings
916 if .number_of_examples > 0
918 .sound$ = Get string... 1
919 .soundFilePath$ = "'.wordlistDirectory$'/'.sound$'"
924 if fileReadable(.soundFilePath$) and config.useSoundExample
926 .tmp = nocheck Read from file... '.soundFilePath$'
927 if .tmp != undefined and .tmp > 0
928 call play_sound '.tmp'
932 elsif config.synthesis$ <> "" and config.synthesis$ <> "_DISABLED_"
933 call synthesize_sound 'sgc.pinyin$'
935 call humToneContour 'sgc.pinyin$' 'config.register'
942 # Draw a tone contour
943 procedure draw_tone_contour
944 select sgc.currentWordlist
945 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
946 .sound$ = Get value... 'sgc.currentWord' Sound
947 call readPinyin 'sgc.currentWord'
948 sgc.pinyin$ = readPinyin.pinyin$
949 call drawToneContour 'sgc.pinyin$' 'config.register'
952 if te.recordedPitch > 0
953 call drawSourceToneContour te.recordedPitch
959 procedure recognizeTone
960 select sgc.currentWordlist
961 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
963 if index_regex(config.strict$, "[^0-9]") <= 0
964 .strict = ('config.strict$' >= sgc.highestLevel)
967 .sound$ = Get value... 'sgc.currentWord' Sound
968 call readPinyin 'sgc.currentWord'
969 sgc.pinyin$ = readPinyin.pinyin$
970 call align_recordedSound 'sgc.pinyin$'
971 call sgc_ToneProt 'recordedSound$' 'sgc.pinyin$' 'config.register' '.strict' 'config.language$'
972 # sgc_ToneProt manipulates the sound given. Reconnect
973 select Sound 'recordedSound$'
974 sgc.recordedSound = selected("Sound")
979 procedure write_feedback .table$
980 select Table '.table$'
981 .line1$ = Get value... 1 Text
982 .line2$ = Get value... 2 Text
983 .label$ = Get value... 3 Text
985 # convert numbers to Pinyin if needed
986 if not config.displayNumbers
987 call numbers2pinyin '.line1$'
988 .line1$ = numbers2pinyin.pinyin$
992 if index(.line1$, "???") > 0
994 elsif .label$ = "Correct"
996 elsif config.strict$ = "'sgc.highestLevel'"
997 .line2$ = .line2$ + " *"
1000 .currentFeedbackFontSize = 14
1001 .maxHeight = 21 - 17
1002 call adjustFontSizeOnHeight 'defaultFont$' '.currentFeedbackFontSize' '.maxHeight'
1003 .currentFeedbackFontSize = adjustFontSizeOnHeight.newFontSize
1005 call wipeArea 'wipeFeedbackArea$'
1006 call set_font_size '.currentFeedbackFontSize'
1008 demo Text... 50 Centre 21 Bottom '.line1$'
1009 demo Text... 50 Centre 17 Bottom '.line2$'
1012 call set_font_size 'defaultFontSize'
1016 procedure display_text .color$
1017 select sgc.currentWordlist
1018 if sgc.currentWord < 0 or sgc.currentWord > sgc.numberOfWords+1
1020 if config.shuffleLists
1023 if sgc.currentWord < 0
1024 sgc.currentWord = sgc.numberOfWords
1031 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
1033 call readDisplayPinyin 'sgc.currentWord'
1034 .displayPinyin$ = readDisplayPinyin.pinyin$
1035 .displayChar$ = Get value... 'sgc.currentWord' Character
1036 .displayTrans$ = Get value... 'sgc.currentWord' Translation
1037 if .displayPinyin$ <> "-" and (config.displayPinyin or sgc.writeAll)
1038 if not config.displayNumbers
1039 call numbers2pinyin '.displayPinyin$'
1040 .displayPinyin$ = numbers2pinyin.pinyin$
1043 .displayPinyin$ = replace_regex$(.displayPinyin$, "v", "\\u\X22", 0)
1044 .displayText$ = .displayText$ + .displayPinyin$
1046 if .displayChar$ <> "-" and (config.displayChar or sgc.writeAll)
1047 .displayText$ = .displayText$ + " "+ .displayChar$
1050 if .displayTrans$ <> "-" and (config.displayTrans or sgc.writeAll)
1051 .displayText$ = .displayText$ + " \s{%%"+ .displayTrans$ + "%}"
1053 elsif sgc.currentWord = 0 or sgc.currentWord = sgc.numberOfWords+1
1055 .displayText$ = "---"
1059 call adjustFontSizeOnHeight 'defaultFont$' 24 15
1060 .currentFontSize = adjustFontSizeOnHeight.newFontSize
1061 call adjustFontSizeOnWidth 'defaultFont$' '.currentFontSize' 95 '.displayText$'
1062 .currentFontSize = adjustFontSizeOnWidth.newFontSize
1064 # Clear the writing area
1065 call wipeArea 'wipePinyinArea$'
1066 # Switch back to Chinese style CJK when in Japanese language mode
1067 if .changeCJKstyle and config.language$ = "JA"
1068 CJK font style preferences: "Chinese"
1070 # Actually display text
1072 call set_font_size '.currentFontSize'
1073 demo Text... 50 Centre 26 Bottom '.displayText$'
1077 call set_font_size 'defaultFontSize'
1078 if .changeCJKstyle and config.language$ = "JA"
1079 if config.language$ = "JA"
1080 CJK font style preferences: "Japanese"
1081 elsif config.language$ = "ZH"
1082 CJK font style preferences: "Chinese"
1085 # Switch back to Japanese style CJK when in Japanese language mode
1086 if .changeCJKstyle and config.language$ = "JA"
1087 CJK font style preferences: "Japanese"
1091 procedure numbers2pinyin .numberstext$
1092 .intermediatePinyin$ = .numberstext$
1093 # Add a `-quote between vowels
1094 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])([aeuiov])", "\1\2'\3", 0)
1095 # Move numbers to the nucleus vowel
1097 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([^aeuiov0-9]*)([0-9])", "\1\3\2", 0)
1099 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([ae])([aeuiov]*)([0-9])", "\1\3\2", 0)
1101 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(ou)([0-9])", "o\2u", 0)
1102 # or the second vowel
1103 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([uiov][aeuiov])([uiov])([0-9])", "\1\3\2", 0)
1105 # Convert all tones to special characters
1107 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a1", "ā", 0)
1108 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e1", "ē", 0)
1109 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u1", "ū", 0)
1110 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i1", "ī", 0)
1111 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o1", "ō", 0)
1112 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v1", "ǖ", 0)
1113 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "1", "\\-^", 0)
1116 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v2", "ǘ", 0)
1117 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])2", "\\\1'", 0)
1118 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "2", "\\'^", 0)
1121 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a3", "ǎ", 0)
1122 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e3", "ě", 0)
1123 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u3", "ǔ", 0)
1124 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i3", "ǐ", 0)
1125 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o3", "ǒ", 0)
1126 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v3", "ǚ", 0)
1127 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "3", "\\N^", 0)
1130 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v4", "ǜ", 0)
1131 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])4", "\\\1`", 0)
1132 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "4", "\\`^", 0)
1135 # Remove tone 0 symbol completely
1136 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "", 0)
1137 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a0", "å", 0)
1138 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e0", "e̊", 0)
1139 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u0", "ů", 0)
1140 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i0", "i̊", 0)
1141 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o0", "o̊", 0)
1142 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v0", "ü̊", 0)
1143 #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "\\0^", 0)
1145 # Pick best vowel symbols available in cases not caught before
1146 # Ugly clutch to get the 1, 3, 0 tone diacritics at least in the neighbourhood
1147 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i(\\[-N0]\^)", "i\\s{_ }\1", 0)
1149 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v", "\\u\X22", 0)
1151 .pinyin$ = .intermediatePinyin$
1154 # NEEDS WORK AND TESTING!!
1155 # Convert unicode Pinyin into tone numbers
1156 procedure pinyin2numbers .pinyin$
1157 .intermediatePinyin$ = .pinyin$
1158 # Convert all special characters to numbers
1160 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iā)([iaeouü]*)", "a\11", 0)
1161 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iē)([iaeouü]*)", "e\11", 0)
1162 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iū)([iaeouü]*)", "u\11", 0)
1163 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iī)([iaeouü]*)", "i\11", 0)
1164 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iō)([iaeouü]*)", "o\11", 0)
1165 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǖ)([iaeouü]*)", "v\11", 0)
1168 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iá)([iaeouü]*)", "a\12", 0)
1169 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ié)([iaeouü]*)", "e\12", 0)
1170 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iú)([iaeouü]*)", "u\12", 0)
1171 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ií)([iaeouü]*)", "i\12", 0)
1172 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ió)([iaeouü]*)", "o\12", 0)
1173 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǘ)([iaeouü]*)", "v\12", 0)
1176 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǎ)([iaeouü]*)", "a\13", 0)
1177 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iě)([iaeouü]*)", "e\13", 0)
1178 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǔ)([iaeouü]*)", "u\13", 0)
1179 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǐ)([iaeouü]*)", "i\13", 0)
1180 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǒ)([iaeouü]*)", "o\13", 0)
1181 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǚ)([iaeouü]*)", "v\13", 0)
1184 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ià)([iaeouü]*)", "a\14", 0)
1185 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iè)([iaeouü]*)", "e\14", 0)
1186 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iù)([iaeouü]*)", "u\14", 0)
1187 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iì)([iaeouü]*)", "i\14", 0)
1188 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iò)([iaeouü]*)", "o\14", 0)
1189 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǜ)([iaeouü]*)", "v\14", 0)
1193 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iå)([iaeouü]*)", "a\10", 0)
1194 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e̊([iaeouü]*)", "e\10", 0)
1195 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iů)([iaeouü]*)", "u\10", 0)
1196 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i̊([iaeouü]*)", "i\10", 0)
1197 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o̊([iaeouü]*)", "o\10", 0)
1198 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ü̊([iaeouü]*)", "v\10", 0)
1200 # Syllables without a tone symbol are tone 0
1201 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov]+)([^0-9aeuiov]|\W|$)", "\10\2", 0)
1203 # Move numbers to the end of the syllable.
1204 # Syllables ending in n and start with g. Note that a syllable cannot start with an u or i
1205 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(n)(g[aeuiov])", "\1\3\2\4", 0)
1206 # Syllables ending in (ng?) followed by something that is not a valid vowel
1207 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(ng?)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
1208 # Syllables ending in r
1209 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(r)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
1211 #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "[\\'\\`]", "", 0)
1213 .numberstext$ = .intermediatePinyin$
1216 procedure readDisplayPinyin .currentWord
1217 select sgc.currentWordlist
1218 .pinyin$ = Get value... '.currentWord' Pinyin
1219 # Everything to lowercase
1221 if index_regex(.pinyin$, "[0-9]") <= 0
1222 call pinyin2numbers '.pinyin$'
1223 .pinyin$ = pinyin2numbers.numberstext$
1227 procedure readPinyin .currentWord
1228 call readDisplayPinyin '.currentWord'
1229 .pinyin$ = replace_regex$(readDisplayPinyin.pinyin$, ".+", "\L&", 0)
1230 .pinyin$ = replace_regex$(.pinyin$, "[\\'\\` ]", "", 0)
1231 # Remove anything that is objectionable
1232 .pinyin$ = replace_regex$(.pinyin$, "[^\w']", "", 0)
1236 include ToneProt/SGC_ToneProt.praat
1237 include ToneProt/DrawToneContour.praat
1238 include ToneProt/HumToneContour.praat
1239 include ToneProt/ToneRecognition.praat
1240 include ToneProt/ToneScript.praat
1241 include ToneProt/ToneRules.praat