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$' Apply
345 call convert_praat_to_latin1 'get_feedback_text.text$'
346 .applySelection$ = 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 # This prevents some nasty attempts to use language elements as variables
466 if index_regex(.showVariable$[.i], "[^0-9r]$") or index_regex(.showVariable$[.i], "[0-9]") <= 0
467 .showVariable$[.i] = .pinyin$[.i]+"0"
469 .tmp$ = replace_regex$(.showVariable$[.i], "^(.+)$", "\l\1", 0)
470 .tmp$ = replace_regex$(.tmp$, "\s", "_", 0)
471 '.tmp$' = .showValue[.i]
478 # The user text input window (beginPause .... endPause)
479 beginPause(.helpText$)
480 if sgc.allWordLists > 0
481 select sgc.allWordLists
482 .numWordlists = Get number of rows
483 optionMenu: .wordlistText$, 1
485 for .w to .numWordlists
486 select sgc.allWordLists
487 .wordListName$ = Get value: .w, "Name"
488 option: .wordListName$
490 option: "*"+.manualEntryText$+"*"
493 boolean (.showText$[0], .showValue[0])
494 boolean (.showText$[1], .showValue[1])
495 boolean (.showText$[2], .showValue[2])
496 boolean (.showText$[3], .showValue[3])
497 boolean (.showText$[4], .showValue[4])
498 boolean (.showText$[5], .showValue[5])
499 boolean (.showText$[6], .showValue[6])
500 boolean (.showText$[7], .showValue[7])
501 boolean (.showText$[8], .showValue[8])
502 boolean (.showText$[9], .showValue[9])
503 boolean (.showText$[10], .showValue[10])
504 boolean (.showText$[11], .showValue[11])
505 boolean (.showText$[12], .showValue[12])
506 boolean (.showText$[13], .showValue[13])
507 boolean (.showText$[14], .showValue[14])
509 .selectMenu$ = .toneText$
511 .selectMenu$ = .selectMenu$ + " " + .partText$
513 optionMenu: .selectMenu$, 1
521 # Display Lesson text if available
525 for .j to .numLessons
526 option: .partText$+": "+.lessonName$['.j']
529 clicked = endPause ("'.cancelText$'", "'.clearText$'", "'.allText$'", "'.applySelection$'", "'.nextWord$'", "'.continueText$'", 6, 1)
531 select sgc.currentWordlist
533 for .i to sgc.numberOfWords
534 Set string value: .i, "Show", "-"
538 for .i to sgc.numberOfWords
539 Set string value: .i, "Show", "+"
543 # Handle added word lists
544 .tmp$ = replace_regex$(.wordlistText$, "^(.)", "\l\1", 0)
545 .tmp$ = replace_regex$(.tmp$, "\s", "_", 0)
547 if .tmp$ <> "---" and sgc.allWordLists > 0
548 select sgc.currentWordlist
549 # Add current wordlist name as a lesson name
550 .originalWordList = -1
551 .numRows = Get number of rows
553 select sgc.currentWordlist
554 .currentLesson$ = Get value: .w, "Lesson"
555 if .currentLesson$ = "" or .currentLesson$ = "-"
556 Set string value: .w, "Lesson", wordlist$
560 # Get and merge the selected list
561 # Enter words by hand
562 if .tmp$ = "*"+.manualEntryText$+"*"
564 .currentFilePath$ = .exampleText$
565 .manualText$ = .manualEntryText$
566 .manPinyin$ = .pinyinText$
567 .manCharacter$ = .characterText$
568 .manTranslation$ = .translationText$
569 .manSound$ = .currentFilePath$
570 .manLesson$ = .manualText$
571 while .man_clicked > 1
572 beginPause: .manualEntryText$
573 text: .pinyinText$, .manPinyin$
574 text: .characterText$, .manCharacter$
575 text: .translationText$, .manTranslation$
576 text: .exampleText$, .manSound$
577 text: .manualText$, .manualText$
578 .man_clicked = endPause("'.cancelText$'", "'.exampleText$'", "'.continueText$'", 3, 1)
580 .tmp$ = replace_regex$(.pinyinText$, "\s", "_", 0)
581 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
582 if '.tmp$'$ <> .pinyinText$
583 .manPinyin$ = '.tmp$'$
589 .tmp$ = replace_regex$(.characterText$, "\s", "_", 0)
590 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
591 if '.tmp$'$ <> .characterText$
592 .manCharacter$ = '.tmp$'$
597 .tmp$ = replace_regex$(.translationText$, "\s", "_", 0)
598 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
599 if '.tmp$'$ <> .translationText$
600 .manTranslation$ = '.tmp$'$
602 .manTranslation$ = ""
605 .tmp$ = replace_regex$(.exampleText$, "\s", "_", 0)
606 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
607 if '.tmp$'$ <> .characterText$ and '.tmp$'$ <> ""
608 .manSound$ = '.tmp$'$
611 .tmp$ = replace_regex$(.manualText$, "\s", "_", 0)
612 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
613 .manLesson$ = '.tmp$'$
616 .manSound$ = chooseReadFile$(.exampleText$);
617 elsif .man_clicked = 3
618 # Clean up input string
619 .manPinyin$ = replace_regex$(.manPinyin$, "^[^a-z]+", "", 0)
620 .manPinyin$ = replace_regex$(.manPinyin$, "[^\w']", "", 0)
622 select sgc.currentWordlist
624 .numRows = Get number of rows
626 Set string value: .numRows, "Pinyin", .manPinyin$
627 Set string value: .numRows, "Character", .manCharacter$
628 Set string value: .numRows, "Translation", .manTranslation$
629 Set string value: .numRows, "Sound", .manSound$
630 Set string value: .numRows, "Lesson", .manLesson$
631 Set string value: .numRows, "Show", "+"
633 .manualText$ = .manualEntryText$
634 .manPinyin$ = .pinyinText$
635 .manCharacter$ = .characterText$
636 .manTranslation$ = .translationText$
637 .manSound$ = .currentFilePath$
638 .manLesson$ = .manualText$
644 select sgc.allWordLists
645 .wordlistNum = Search column: "Name", .tmp$
647 .wordlistPath$ = Get value: .wordlistNum, "Directory"
648 .wordlistPath$ = replace_regex$(.wordlistPath$, "[ ]", "&", 0)
649 call read_wordlist "'.tmp$'" '.wordlistPath$'
650 .newList = read_wordlist.wordlistID
651 call merge_into_wordlist '.newList' '.tmp$'
654 # Add wordlistname to Lesson column
655 select sgc.allWordLists
656 .numRows = Get number of rows
658 Remove row: .wordlistNum
660 Set string value: 1, "Name", "---"
664 # Gather Lesson names
665 select sgc.currentWordlist
666 Sort rows... Lesson Pinyin
668 sgc.numberOfWords = Get number of rows
672 for .i to sgc.numberOfWords
673 .currentLesson$ = Get value: .i, "Lesson"
674 .matchLesson$ = tab$+.currentLesson$+tab$
675 if .currentLesson$ <> "" and .currentLesson$ <> "-" and .currentLesson$ <> "?" and index(.lessonList$, .matchLesson$) <= 0
676 .lessonList$ = .lessonList$ + .currentLesson$ + tab$
678 .lessonName$['.numLessons'] = .currentLesson$
680 .shown$ = Get value: .i, "Show"
687 for .i from 0 to .max
688 .tmp$ = replace_regex$(.showVariable$['.i'], "^(.*)$", "\l\1", 0)
689 .tmp$ = replace_regex$(.tmp$, "\s", "_", 0)
691 .showValue['.i'] = '.tmp$'
692 .showWord$['.i'] = "-"
693 if .showValue['.i'] <> 0
694 .showWord$['.i'] = "+"
696 Set string value: .currentWord+.i, "Show", .showWord$['.i']
700 select sgc.currentWordlist
701 .tmp$ = replace_regex$(.selectMenu$, "^(.)", "\l\1", 0)
702 .tmp$ = replace_regex$(.tmp$, "\s", "_", 0)
703 .toneSelected = '.tmp$' - 2
704 if .toneSelected >= 0 and .toneSelected < 5
705 select sgc.currentWordlist
706 for .i to sgc.numberOfWords
707 .currentPinyin$ = Get value: .i, "Pinyin"
708 if index_regex(.currentPinyin$, "[0-9]") <= 0
709 call pinyin2numbers '.currentPinyin$'
710 .currentPinyin$ = replace_regex$(pinyin2numbers.intermediatePinyin$, ".+", "\l&", 0)
711 .currentPinyin$ = replace_regex$(.currentPinyin$, "[^a-zA-Z0-9]", "", 0)
713 .tmp$ = Get value: .i, "Show"
714 if .tmp$ <> "-" and index(.currentPinyin$, "'.toneSelected'") > 0
715 Set string value: .i, "Show", "+"
717 Set string value: .i, "Show", "-"
721 elsif .toneSelected > 5
722 # .toneSelected = 5 is the Part text
723 .lessonSelected = .toneSelected - 5
724 if .lessonSelected > 0
727 select sgc.currentWordlist
728 for .i to sgc.numberOfWords
729 # Keep track of whether all are shown
730 .shown$ = Get value: .i, "Show"
736 for .i to sgc.numberOfWords
738 .currentLesson$ = Get value: .i, "Lesson"
739 if .currentLesson$ = .lessonName$['.lessonSelected']
740 Set string value: .i, "Show", "+"
742 Set string value: .i, "Show", "-"
745 for .i to sgc.numberOfWords
746 # Keep track of whether all are shown
747 .shown$ = Get value: .i, "Show"
748 if .firstShown <=0 and .shown$ <> "-"
757 .currentWord = (sgc.numberOfWords div .numWordsPerScreen) * .numWordsPerScreen + 1
761 .currentWord = (.firstShown div .numWordsPerScreen) * .numWordsPerScreen + 1
763 .currentWord += .numWordsPerScreen
764 if .currentWord > sgc.numberOfWords
769 # Reset and go to the first selected word (can shuffle list)
779 select sgc.currentWordlist
781 select .tmpOriginalWordlist
783 sgc.currentWordlist = selected()
785 # Set the values of the number of words shown
786 select sgc.currentWordlist
787 .numWords = Get number of rows
788 sgc.currentWordNum = 1
789 sgc.numberOfDisplayedWords = 0
792 .show$ = Get value: .i, "Show"
794 if sgc.currentWord < 1
797 sgc.numberOfDisplayedWords += 1
801 select .tmpOriginalWordlist
804 label SELECTWORDSFAIL
806 call Draw_button '.table$' '.label$' 0
809 ###############################################################
811 # Obligatory button Processing Routines
813 # These MUST be defined
815 ###############################################################
817 procedure processMainPageQuit .clickX .clickY .pressed$
821 procedure processMainPageRefresh .clickX .clickY .pressed$
826 procedure processMainPageConfig .clickX .clickY .pressed$
830 procedure processMainPageHelp .clickX .clickY .pressed$
831 call help_loop 'buttons$' init_window
834 procedure processMainPagePlay .clickX .clickY .pressed$
837 if recordedSound$ <> ""
838 call play_sound 'sgc.recordedSound'
841 te.buttonPressValue = mainPage.play
844 procedure Set_Play_Button
846 if recordedSound$ <> ""
849 call Draw_button MainPage Play 'mainPage.play'
852 procedure processMainPageRecord .clickX .clickY .pressed$
854 .recordingTime = recordingTime
855 if count_syllables.number > 2
856 .recordingTime = recordingTime + 1.0*ceiling((count_syllables.number - 2)/2)
858 call record_sound '.recordingTime'
864 call wipeArea 'wipeContourArea$'
866 call draw_tone_contour
868 call display_word_list_name
869 call display_text Black
870 call add_feedback_to_toneevaluation Feedback
871 call write_feedback Feedback
872 select Table Feedback
875 # Do not exercise words that are going well (autoSelect)
876 if add_feedback_to_toneevaluation.result > 0
877 if config.adaptiveLists > 0 and sgc.failedAttempts < 2
878 # Deselect current word
879 select sgc.currentWordlist
880 .i = Search column: "Pinyin", sgc.pinyin$
882 Set string value: .i, "Show", "-"
885 sgc.failedAttempts = 0
887 sgc.failedAttempts += 1
892 ###############################################################
894 # Miscelaneous supporting code
896 ###############################################################
899 procedure generate_example
900 select sgc.currentWordlist
901 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
902 select sgc.currentWordlist
903 .sound$ = Get value... 'sgc.currentWord' Sound
904 call readPinyin 'sgc.currentWord'
905 sgc.pinyin$ = readPinyin.pinyin$
906 sgc.character$ = readPinyin.character$
907 if .sound$ = "-" or .sound$ = ""
908 .sound$ = sgc.pinyin$+".wav"
910 if index_regex(.sound$, "^(/|~/|[A-Z]:\\)") > 0
911 .soundFilePath$ = .sound$
913 .soundFilePath$ = localWordlistDir$+"/"+wordlistName$+"/"+.sound$
914 .wordlistDirectory$ = ""
915 if localWordlistDir$ <> "" and fileReadable("'localWordlistDir$'/'wordlistName$'")
916 .wordlistDirectory$ = "'localWordlistDir$'/'wordlistName$'"
917 elsif sgc2wordlists$ <> "" and fileReadable("'sgc2wordlists$'/'wordlistName$'")
918 .wordlistDirectory$ = "'sgc2wordlists$'/'wordlistName$'"
919 elsif globalwordlists$ <> "" and fileReadable("'globalwordlists$'/'wordlistName$'")
920 .wordlistDirectory$ = "'globalwordlists$'/'wordlistName$'"
922 if .wordlistDirectory$ <> ""
923 .audioExampleList = Create Strings as file list... AudioList '.wordlistDirectory$'/'sgc.pinyin$'.*
924 .number_of_examples = Get number of strings
925 if .number_of_examples > 0
927 .sound$ = Get string... 1
928 .soundFilePath$ = "'.wordlistDirectory$'/'.sound$'"
933 if fileReadable(.soundFilePath$) and config.useSoundExample
935 .tmp = nocheck Read from file... '.soundFilePath$'
936 if .tmp != undefined and .tmp > 0
937 call play_sound '.tmp'
941 elsif config.synthesis$ <> "" and config.synthesis$ <> "_DISABLED_"
942 call synthesize_sound "'sgc.pinyin$'" "'sgc.character$'"
944 call humToneContour 'sgc.pinyin$' 'config.register'
951 # Draw a tone contour
952 procedure draw_tone_contour
953 select sgc.currentWordlist
954 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
955 .sound$ = Get value... 'sgc.currentWord' Sound
956 call readPinyin 'sgc.currentWord'
957 sgc.pinyin$ = readPinyin.pinyin$
958 sgc.character$ = readPinyin.character$
959 call drawToneContour 'sgc.pinyin$' 'config.register'
962 if te.recordedPitch > 0
963 call drawSourceToneContour te.recordedPitch
969 procedure recognizeTone
970 select sgc.currentWordlist
971 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
973 if index_regex(config.strict$, "[^0-9]") <= 0
974 .strict = ('config.strict$' >= sgc.highestLevel)
977 .sound$ = Get value... 'sgc.currentWord' Sound
978 call readPinyin 'sgc.currentWord'
979 sgc.pinyin$ = readPinyin.pinyin$
980 sgc.character$ = readPinyin.character$
981 call align_recordedSound 'sgc.pinyin$'
982 call sgc_ToneProt 'recordedSound$' 'sgc.pinyin$' 'config.register' '.strict' 'config.language$'
983 # sgc_ToneProt manipulates the sound given. Reconnect
984 select Sound 'recordedSound$'
985 sgc.recordedSound = selected("Sound")
990 procedure write_feedback .table$
991 select Table '.table$'
992 .line1$ = Get value... 1 Text
993 .line2$ = Get value... 2 Text
994 .label$ = Get value... 3 Text
996 # convert numbers to Pinyin if needed
997 if not config.displayNumbers
998 call numbers2pinyin '.line1$'
999 .line1$ = numbers2pinyin.pinyin$
1003 if index(.line1$, "???") > 0
1005 elsif .label$ = "Correct"
1007 elsif config.strict$ = "'sgc.highestLevel'"
1008 .line2$ = .line2$ + " *"
1011 .currentFeedbackFontSize = 14
1012 .maxHeight = 21 - 17
1013 call adjustFontSizeOnHeight 'defaultFont$' '.currentFeedbackFontSize' '.maxHeight'
1014 .currentFeedbackFontSize = adjustFontSizeOnHeight.newFontSize
1016 call wipeArea 'wipeFeedbackArea$'
1017 call set_font_size '.currentFeedbackFontSize'
1019 demo Text... 50 Centre 21 Bottom '.line1$'
1020 demo Text... 50 Centre 17 Bottom '.line2$'
1023 call set_font_size 'defaultFontSize'
1027 procedure display_text .color$
1028 select sgc.currentWordlist
1029 if sgc.currentWord < 0 or sgc.currentWord > sgc.numberOfWords+1
1031 if config.shuffleLists
1034 if sgc.currentWord < 0
1035 sgc.currentWord = sgc.numberOfWords
1042 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
1044 call readDisplayPinyin 'sgc.currentWord'
1045 .displayPinyin$ = readDisplayPinyin.pinyin$
1046 .displayChar$ = Get value... 'sgc.currentWord' Character
1047 .displayTrans$ = Get value... 'sgc.currentWord' Translation
1048 if .displayPinyin$ <> "-" and (config.displayPinyin or sgc.writeAll)
1049 if not config.displayNumbers
1050 call numbers2pinyin '.displayPinyin$'
1051 .displayPinyin$ = numbers2pinyin.pinyin$
1054 .displayPinyin$ = replace_regex$(.displayPinyin$, "v", "\\u\X22", 0)
1055 .displayText$ = .displayText$ + .displayPinyin$
1057 if .displayChar$ <> "-" and (config.displayChar or sgc.writeAll)
1058 .displayText$ = .displayText$ + " "+ .displayChar$
1061 if .displayTrans$ <> "-" and (config.displayTrans or sgc.writeAll)
1062 .displayText$ = .displayText$ + " \s{%%"+ .displayTrans$ + "%}"
1064 elsif sgc.currentWord = 0 or sgc.currentWord = sgc.numberOfWords+1
1066 .displayText$ = "---"
1070 call adjustFontSizeOnHeight 'defaultFont$' 24 15
1071 .currentFontSize = adjustFontSizeOnHeight.newFontSize
1072 call adjustFontSizeOnWidth 'defaultFont$' '.currentFontSize' 95 '.displayText$'
1073 .currentFontSize = adjustFontSizeOnWidth.newFontSize
1075 # Clear the writing area
1076 call wipeArea 'wipePinyinArea$'
1077 # Switch back to Chinese style CJK when in Japanese language mode
1078 if .changeCJKstyle and config.language$ = "JA"
1079 CJK font style preferences: "Chinese"
1081 # Actually display text
1083 call set_font_size '.currentFontSize'
1084 demo Text... 50 Centre 26 Bottom '.displayText$'
1088 call set_font_size 'defaultFontSize'
1089 if .changeCJKstyle and config.language$ = "JA"
1090 if config.language$ = "JA"
1091 CJK font style preferences: "Japanese"
1092 elsif config.language$ = "ZH"
1093 CJK font style preferences: "Chinese"
1096 # Switch back to Japanese style CJK when in Japanese language mode
1097 if .changeCJKstyle and config.language$ = "JA"
1098 CJK font style preferences: "Japanese"
1102 procedure numbers2pinyin .numberstext$
1103 .intermediatePinyin$ = .numberstext$
1104 # Add a `-quote between vowels
1105 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])([aeuiov])", "\1\2'\3", 0)
1106 # Move numbers to the nucleus vowel
1108 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([^aeuiov0-9]*)([0-9])", "\1\3\2", 0)
1110 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([ae])([aeuiov]*)([0-9])", "\1\3\2", 0)
1112 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(ou)([0-9])", "o\2u", 0)
1113 # or the second vowel
1114 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([uiov][aeuiov])([uiov])([0-9])", "\1\3\2", 0)
1116 # Convert all tones to special characters
1118 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a1", "ā", 0)
1119 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e1", "ē", 0)
1120 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u1", "ū", 0)
1121 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i1", "ī", 0)
1122 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o1", "ō", 0)
1123 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v1", "ǖ", 0)
1124 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "1", "\\-^", 0)
1127 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v2", "ǘ", 0)
1128 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])2", "\\\1'", 0)
1129 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "2", "\\'^", 0)
1132 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a3", "ǎ", 0)
1133 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e3", "ě", 0)
1134 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u3", "ǔ", 0)
1135 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i3", "ǐ", 0)
1136 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o3", "ǒ", 0)
1137 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v3", "ǚ", 0)
1138 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "3", "\\N^", 0)
1141 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v4", "ǜ", 0)
1142 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])4", "\\\1`", 0)
1143 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "4", "\\`^", 0)
1146 # Remove tone 0 symbol completely
1147 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "", 0)
1148 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a0", "å", 0)
1149 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e0", "e̊", 0)
1150 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u0", "ů", 0)
1151 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i0", "i̊", 0)
1152 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o0", "o̊", 0)
1153 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v0", "ü̊", 0)
1154 #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "\\0^", 0)
1156 # Pick best vowel symbols available in cases not caught before
1157 # Ugly clutch to get the 1, 3, 0 tone diacritics at least in the neighbourhood
1158 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i(\\[-N0]\^)", "i\\s{_ }\1", 0)
1160 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v", "\\u\X22", 0)
1162 .pinyin$ = .intermediatePinyin$
1165 # NEEDS WORK AND TESTING!!
1166 # Convert unicode Pinyin into tone numbers
1167 procedure pinyin2numbers .pinyin$
1168 .intermediatePinyin$ = .pinyin$
1169 # Convert all special characters to numbers
1171 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iā)([iaeouü]*)", "a\11", 0)
1172 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iē)([iaeouü]*)", "e\11", 0)
1173 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iū)([iaeouü]*)", "u\11", 0)
1174 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iī)([iaeouü]*)", "i\11", 0)
1175 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iō)([iaeouü]*)", "o\11", 0)
1176 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǖ)([iaeouü]*)", "v\11", 0)
1179 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iá)([iaeouü]*)", "a\12", 0)
1180 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ié)([iaeouü]*)", "e\12", 0)
1181 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iú)([iaeouü]*)", "u\12", 0)
1182 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ií)([iaeouü]*)", "i\12", 0)
1183 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ió)([iaeouü]*)", "o\12", 0)
1184 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǘ)([iaeouü]*)", "v\12", 0)
1187 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǎ)([iaeouü]*)", "a\13", 0)
1188 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iě)([iaeouü]*)", "e\13", 0)
1189 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǔ)([iaeouü]*)", "u\13", 0)
1190 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǐ)([iaeouü]*)", "i\13", 0)
1191 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǒ)([iaeouü]*)", "o\13", 0)
1192 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǚ)([iaeouü]*)", "v\13", 0)
1195 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ià)([iaeouü]*)", "a\14", 0)
1196 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iè)([iaeouü]*)", "e\14", 0)
1197 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iù)([iaeouü]*)", "u\14", 0)
1198 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iì)([iaeouü]*)", "i\14", 0)
1199 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iò)([iaeouü]*)", "o\14", 0)
1200 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǜ)([iaeouü]*)", "v\14", 0)
1204 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iå)([iaeouü]*)", "a\10", 0)
1205 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e̊([iaeouü]*)", "e\10", 0)
1206 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iů)([iaeouü]*)", "u\10", 0)
1207 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i̊([iaeouü]*)", "i\10", 0)
1208 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o̊([iaeouü]*)", "o\10", 0)
1209 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ü̊([iaeouü]*)", "v\10", 0)
1211 # Syllables without a tone symbol are tone 0
1212 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov]+)([^0-9aeuiov]|\W|$)", "\10\2", 0)
1214 # Move numbers to the end of the syllable.
1215 # Syllables ending in n and start with g. Note that a syllable cannot start with an u or i
1216 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(n)(g[aeuiov])", "\1\3\2\4", 0)
1217 # Syllables ending in (ng?) followed by something that is not a valid vowel
1218 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(ng?)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
1219 # Syllables ending in r
1220 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(r)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
1222 #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "[\\'\\`]", "", 0)
1224 .numberstext$ = .intermediatePinyin$
1227 procedure readDisplayPinyin .currentWord
1228 select sgc.currentWordlist
1229 .pinyin$ = Get value... '.currentWord' Pinyin
1230 .character$ = Get value... '.currentWord' Character
1231 # Everything to lowercase
1233 if index_regex(.pinyin$, "[0-9]") <= 0
1234 call pinyin2numbers '.pinyin$'
1235 .pinyin$ = pinyin2numbers.numberstext$
1239 procedure readPinyin .currentWord
1240 call readDisplayPinyin '.currentWord'
1241 .character$ = readDisplayPinyin.character$
1242 .pinyin$ = replace_regex$(readDisplayPinyin.pinyin$, ".+", "\L&", 0)
1243 .pinyin$ = replace_regex$(.pinyin$, "[\\'\\` ]", "", 0)
1244 # Remove anything that is objectionable
1245 .pinyin$ = replace_regex$(.pinyin$, "[^\w']", "", 0)
1249 include ToneProt/SGC_ToneProt.praat
1250 include ToneProt/DrawToneContour.praat
1251 include ToneProt/HumToneContour.praat
1252 include ToneProt/ToneRecognition.praat
1253 include ToneProt/ToneScript.praat
1254 include ToneProt/ToneRules.praat