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 # This prevents some nasty attempts to use language elements as variabels
466 if index_regex(.showVariable$[.i], "[^0-9]$")
467 .showVariable$[.i] = .pinyin$[.i]+"0"
469 .tmp$ = replace_regex$(.showVariable$[.i], "^(.+)$", "\l\1", 0)
470 .tmp$ = replace_regex$(.tmp$, "[^\w]", "_", 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 optionMenu: .partText$, 1
512 for .j to .numLessons
513 option: .lessonName$['.j']
516 optionMenu: .toneText$, 1
523 clicked = endPause ("'.cancelText$'", "'.clearText$'", "'.allText$'", "'.prevWord$'", "'.nextWord$'", "'.continueText$'", 6, 1)
525 select sgc.currentWordlist
527 for .i to sgc.numberOfWords
528 Set string value: .i, "Show", "-"
532 for .i to sgc.numberOfWords
533 Set string value: .i, "Show", "+"
537 # Handle added word lists
538 .wordlistText$ = replace_regex$(.wordlistText$, "^(.)", "\l\1", 0)
539 .wordlistText$ = replace_regex$(.wordlistText$, "[^\w]", "_", 0)
540 .tmp$ = '.wordlistText$'$
541 if .tmp$ <> "---" and sgc.allWordLists > 0
542 select sgc.currentWordlist
543 # Add current wordlist name as a lesson name
544 .originalWordList = -1
545 .numRows = Get number of rows
547 select sgc.currentWordlist
548 .currentLesson$ = Get value: .w, "Lesson"
549 if .currentLesson$ = "" or .currentLesson$ = "-"
550 Set string value: .w, "Lesson", wordlist$
554 # Get and merge the selected list
555 # Enter words by hand
556 if .tmp$ = "*"+.manualEntryText$+"*"
558 .currentFilePath$ = .exampleText$
559 .manualText$ = .manualEntryText$
560 .manPinyin$ = .pinyinText$
561 .manCharacter$ = .characterText$
562 .manTranslation$ = .translationText$
563 .manSound$ = .currentFilePath$
564 .manLesson$ = .manualText$
565 while .man_clicked > 1
566 beginPause: .manualEntryText$
567 text: .pinyinText$, .manPinyin$
568 text: .characterText$, .manCharacter$
569 text: .translationText$, .manTranslation$
570 text: .exampleText$, .manSound$
571 text: .manualText$, .manualText$
572 .man_clicked = endPause("'.cancelText$'", "'.exampleText$'", "'.continueText$'", 3, 1)
574 .tmp$ = replace_regex$(.pinyinText$, "[^\w]", "_", 0)
575 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
576 if '.tmp$'$ <> .pinyinText$
577 .manPinyin$ = '.tmp$'$
583 .tmp$ = replace_regex$(.characterText$, "[^\w]", "_", 0)
584 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
585 if '.tmp$'$ <> .characterText$
586 .manCharacter$ = '.tmp$'$
591 .tmp$ = replace_regex$(.translationText$, "[^\w]", "_", 0)
592 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
593 if '.tmp$'$ <> .translationText$
594 .manTranslation$ = '.tmp$'$
596 .manTranslation$ = ""
599 .tmp$ = replace_regex$(.exampleText$, "[^\w]", "_", 0)
600 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
601 if '.tmp$'$ <> .characterText$ and '.tmp$'$ <> ""
602 .manSound$ = '.tmp$'$
605 .tmp$ = replace_regex$(.manualText$, "[^\w]", "_", 0)
606 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
607 .manLesson$ = '.tmp$'$
610 .manSound$ = chooseReadFile$(.exampleText$);
611 elsif .man_clicked = 3
612 # Clean up input string
613 .manPinyin$ = replace_regex$(.manPinyin$, "^[^a-z]+", "", 0)
614 .manPinyin$ = replace_regex$(.manPinyin$, "[^\w']", "", 0)
616 select sgc.currentWordlist
618 .numRows = Get number of rows
620 Set string value: .numRows, "Pinyin", .manPinyin$
621 Set string value: .numRows, "Character", .manCharacter$
622 Set string value: .numRows, "Translation", .manTranslation$
623 Set string value: .numRows, "Sound", .manSound$
624 Set string value: .numRows, "Lesson", .manLesson$
625 Set string value: .numRows, "Show", "+"
627 .manualText$ = .manualEntryText$
628 .manPinyin$ = .pinyinText$
629 .manCharacter$ = .characterText$
630 .manTranslation$ = .translationText$
631 .manSound$ = .currentFilePath$
632 .manLesson$ = .manualText$
638 select sgc.allWordLists
639 .wordlistNum = Search column: "Name", .tmp$
641 .wordlistPath$ = Get value: .wordlistNum, "Directory"
642 .wordlistPath$ = replace_regex$(.wordlistPath$, "[ ]", "&", 0)
643 call read_wordlist "'.tmp$'" '.wordlistPath$'
644 .newList = read_wordlist.wordlistID
645 call merge_into_wordlist '.newList' '.tmp$'
648 # Add wordlistname to Lesson column
649 select sgc.allWordLists
650 .numRows = Get number of rows
652 Remove row: .wordlistNum
654 Set string value: 1, "Name", "---"
658 # Gather Lesson names
659 select sgc.currentWordlist
660 Sort rows... Lesson Pinyin
662 sgc.numberOfWords = Get number of rows
666 for .i to sgc.numberOfWords
667 .currentLesson$ = Get value: .i, "Lesson"
668 .matchLesson$ = tab$+.currentLesson$+tab$
669 if .currentLesson$ <> "" and .currentLesson$ <> "-" and .currentLesson$ <> "?" and index(.lessonList$, .matchLesson$) <= 0
670 .lessonList$ = .lessonList$ + .currentLesson$ + tab$
672 .lessonName$['.numLessons'] = .currentLesson$
674 .shown$ = Get value: .i, "Show"
681 select sgc.currentWordlist
682 # Get selected Part BEFORE we do anything else
684 .tmp$ = replace_regex$(.partText$, "^(.)", "\l\1", 0)
685 .lessonSelected = '.tmp$' - 1
687 if .lessonSelected > 0
690 select sgc.currentWordlist
691 for .i to sgc.numberOfWords
692 # Keep track of whether all are shown
693 .shown$ = Get value: .i, "Show"
699 for .i to sgc.numberOfWords
701 .currentLesson$ = Get value: .i, "Lesson"
702 if .currentLesson$ = .lessonName$['.lessonSelected']
703 Set string value: .i, "Show", "+"
705 Set string value: .i, "Show", "-"
708 for .i to sgc.numberOfWords
709 # Keep track of whether all are shown
710 .shown$ = Get value: .i, "Show"
711 if .firstShown <=0 and .shown$ <> "-"
716 for .i from 0 to .max
717 .tmp$ = replace_regex$(.showVariable$['.i'], "^(.*)$", "\l\1", 0)
718 .tmp$ = replace_regex$(.tmp$, "[^\w]", "_", 0)
720 .showValue['.i'] = '.tmp$'
721 .showWord$['.i'] = "-"
722 if .showValue['.i'] <> 0
723 .showWord$['.i'] = "+"
725 Set string value: .currentWord+.i, "Show", .showWord$['.i']
730 select sgc.currentWordlist
731 .tmp$ = replace_regex$(.toneText$, "^(.)", "\l\1", 0)
732 .tmp$ = replace_regex$(.tmp$, "[^\w]", "_", 0)
733 .toneSelected = '.tmp$' - 2
734 if .toneSelected >= 0
735 select sgc.currentWordlist
736 for .i to sgc.numberOfWords
737 .currentPinyin$ = Get value: .i, "Pinyin"
738 if index_regex(.currentPinyin$, "[0-9]") <= 0
739 call pinyin2numbers '.currentPinyin$'
740 .currentPinyin$ = replace_regex$(pinyin2numbers.intermediatePinyin$, ".+", "\l&", 0)
741 .currentPinyin$ = replace_regex$(.currentPinyin$, "[^a-zA-Z0-9]", "", 0)
743 .tmp$ = Get value: .i, "Show"
744 if .tmp$ <> "-" and index(.currentPinyin$, "'.toneSelected'") > 0
745 Set string value: .i, "Show", "+"
747 Set string value: .i, "Show", "-"
755 .currentWord = (.firstShown div .numWordsPerScreen) * .numWordsPerScreen + 1
756 elsif .toneSelected < 0
757 .currentWord -= .numWordsPerScreen
760 .currentWord = (sgc.numberOfWords div .numWordsPerScreen) * .numWordsPerScreen + 1
764 .currentWord = (.firstShown div .numWordsPerScreen) * .numWordsPerScreen + 1
765 elsif .toneSelected < 0
766 .currentWord += .numWordsPerScreen
768 if .currentWord > sgc.numberOfWords
773 # Reset and go to the first selected word (can shuffle list)
783 select sgc.currentWordlist
785 select .tmpOriginalWordlist
787 sgc.currentWordlist = selected()
789 # Set the values of the number of words shown
790 select sgc.currentWordlist
791 .numWords = Get number of rows
792 sgc.currentWordNum = 1
793 sgc.numberOfDisplayedWords = 0
796 .show$ = Get value: .i, "Show"
798 if sgc.currentWord < 1
801 sgc.numberOfDisplayedWords += 1
805 select .tmpOriginalWordlist
808 call Draw_button '.table$' '.label$' 0
811 ###############################################################
813 # Obligatory button Processing Routines
815 # These MUST be defined
817 ###############################################################
819 procedure processMainPageQuit .clickX .clickY .pressed$
823 procedure processMainPageRefresh .clickX .clickY .pressed$
828 procedure processMainPageConfig .clickX .clickY .pressed$
832 procedure processMainPageHelp .clickX .clickY .pressed$
833 call help_loop 'buttons$' init_window
836 procedure processMainPagePlay .clickX .clickY .pressed$
839 if recordedSound$ <> ""
840 call play_sound 'sgc.recordedSound'
843 te.buttonPressValue = mainPage.play
846 procedure Set_Play_Button
848 if recordedSound$ <> ""
851 call Draw_button MainPage Play 'mainPage.play'
854 procedure processMainPageRecord .clickX .clickY .pressed$
856 .recordingTime = recordingTime
857 if count_syllables.number > 2
858 .recordingTime = recordingTime + 1.0*ceiling((count_syllables.number - 2)/2)
860 call record_sound '.recordingTime'
866 call wipeArea 'wipeContourArea$'
868 call draw_tone_contour
870 call display_word_list_name
871 call display_text Black
872 call add_feedback_to_toneevaluation Feedback
873 call write_feedback Feedback
874 select Table Feedback
877 # Do not exercise words that are going well (autoSelect)
878 if add_feedback_to_toneevaluation.result > 0
879 if config.adaptiveLists > 0 and sgc.failedAttempts < 2
880 # Deselect current word
881 select sgc.currentWordlist
882 .i = Search column: "Pinyin", sgc.pinyin$
884 Set string value: .i, "Show", "-"
887 sgc.failedAttempts = 0
889 sgc.failedAttempts += 1
894 ###############################################################
896 # Miscelaneous supporting code
898 ###############################################################
901 procedure generate_example
902 select sgc.currentWordlist
903 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
904 select sgc.currentWordlist
905 .sound$ = Get value... 'sgc.currentWord' Sound
906 call readPinyin 'sgc.currentWord'
907 sgc.pinyin$ = readPinyin.pinyin$
908 if .sound$ = "-" or .sound$ = ""
909 .sound$ = sgc.pinyin$+".wav"
911 if index_regex(.sound$, "^(/|~/|[A-Z]:\\)") > 0
912 .soundFilePath$ = .sound$
914 .soundFilePath$ = localWordlistDir$+"/"+wordlistName$+"/"+.sound$
915 .wordlistDirectory$ = ""
916 if localWordlistDir$ <> "" and fileReadable("'localWordlistDir$'/'wordlistName$'")
917 .wordlistDirectory$ = "'localWordlistDir$'/'wordlistName$'"
918 elsif sgc2wordlists$ <> "" and fileReadable("'sgc2wordlists$'/'wordlistName$'")
919 .wordlistDirectory$ = "'sgc2wordlists$'/'wordlistName$'"
920 elsif globalwordlists$ <> "" and fileReadable("'globalwordlists$'/'wordlistName$'")
921 .wordlistDirectory$ = "'globalwordlists$'/'wordlistName$'"
923 if .wordlistDirectory$ <> ""
924 .audioExampleList = Create Strings as file list... AudioList '.wordlistDirectory$'/'sgc.pinyin$'.*
925 .number_of_examples = Get number of strings
926 if .number_of_examples > 0
928 .sound$ = Get string... 1
929 .soundFilePath$ = "'.wordlistDirectory$'/'.sound$'"
934 if fileReadable(.soundFilePath$) and config.useSoundExample
936 .tmp = nocheck Read from file... '.soundFilePath$'
937 if .tmp != undefined and .tmp > 0
938 call play_sound '.tmp'
942 elsif config.synthesis$ <> "" and config.synthesis$ <> "_DISABLED_"
943 call synthesize_sound 'sgc.pinyin$'
945 call humToneContour 'sgc.pinyin$' 'config.register'
952 # Draw a tone contour
953 procedure draw_tone_contour
954 select sgc.currentWordlist
955 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
956 .sound$ = Get value... 'sgc.currentWord' Sound
957 call readPinyin 'sgc.currentWord'
958 sgc.pinyin$ = readPinyin.pinyin$
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 call align_recordedSound 'sgc.pinyin$'
981 call sgc_ToneProt 'recordedSound$' 'sgc.pinyin$' 'config.register' '.strict' 'config.language$'
982 # sgc_ToneProt manipulates the sound given. Reconnect
983 select Sound 'recordedSound$'
984 sgc.recordedSound = selected("Sound")
989 procedure write_feedback .table$
990 select Table '.table$'
991 .line1$ = Get value... 1 Text
992 .line2$ = Get value... 2 Text
993 .label$ = Get value... 3 Text
995 # convert numbers to Pinyin if needed
996 if not config.displayNumbers
997 call numbers2pinyin '.line1$'
998 .line1$ = numbers2pinyin.pinyin$
1002 if index(.line1$, "???") > 0
1004 elsif .label$ = "Correct"
1006 elsif config.strict$ = "'sgc.highestLevel'"
1007 .line2$ = .line2$ + " *"
1010 .currentFeedbackFontSize = 14
1011 .maxHeight = 21 - 17
1012 call adjustFontSizeOnHeight 'defaultFont$' '.currentFeedbackFontSize' '.maxHeight'
1013 .currentFeedbackFontSize = adjustFontSizeOnHeight.newFontSize
1015 call wipeArea 'wipeFeedbackArea$'
1016 call set_font_size '.currentFeedbackFontSize'
1018 demo Text... 50 Centre 21 Bottom '.line1$'
1019 demo Text... 50 Centre 17 Bottom '.line2$'
1022 call set_font_size 'defaultFontSize'
1026 procedure display_text .color$
1027 select sgc.currentWordlist
1028 if sgc.currentWord < 0 or sgc.currentWord > sgc.numberOfWords+1
1030 if config.shuffleLists
1033 if sgc.currentWord < 0
1034 sgc.currentWord = sgc.numberOfWords
1041 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
1043 call readDisplayPinyin 'sgc.currentWord'
1044 .displayPinyin$ = readDisplayPinyin.pinyin$
1045 .displayChar$ = Get value... 'sgc.currentWord' Character
1046 .displayTrans$ = Get value... 'sgc.currentWord' Translation
1047 if .displayPinyin$ <> "-" and (config.displayPinyin or sgc.writeAll)
1048 if not config.displayNumbers
1049 call numbers2pinyin '.displayPinyin$'
1050 .displayPinyin$ = numbers2pinyin.pinyin$
1053 .displayPinyin$ = replace_regex$(.displayPinyin$, "v", "\\u\X22", 0)
1054 .displayText$ = .displayText$ + .displayPinyin$
1056 if .displayChar$ <> "-" and (config.displayChar or sgc.writeAll)
1057 .displayText$ = .displayText$ + " "+ .displayChar$
1060 if .displayTrans$ <> "-" and (config.displayTrans or sgc.writeAll)
1061 .displayText$ = .displayText$ + " \s{%%"+ .displayTrans$ + "%}"
1063 elsif sgc.currentWord = 0 or sgc.currentWord = sgc.numberOfWords+1
1065 .displayText$ = "---"
1069 call adjustFontSizeOnHeight 'defaultFont$' 24 15
1070 .currentFontSize = adjustFontSizeOnHeight.newFontSize
1071 call adjustFontSizeOnWidth 'defaultFont$' '.currentFontSize' 95 '.displayText$'
1072 .currentFontSize = adjustFontSizeOnWidth.newFontSize
1074 # Clear the writing area
1075 call wipeArea 'wipePinyinArea$'
1076 # Switch back to Chinese style CJK when in Japanese language mode
1077 if .changeCJKstyle and config.language$ = "JA"
1078 CJK font style preferences: "Chinese"
1080 # Actually display text
1082 call set_font_size '.currentFontSize'
1083 demo Text... 50 Centre 26 Bottom '.displayText$'
1087 call set_font_size 'defaultFontSize'
1088 if .changeCJKstyle and config.language$ = "JA"
1089 if config.language$ = "JA"
1090 CJK font style preferences: "Japanese"
1091 elsif config.language$ = "ZH"
1092 CJK font style preferences: "Chinese"
1095 # Switch back to Japanese style CJK when in Japanese language mode
1096 if .changeCJKstyle and config.language$ = "JA"
1097 CJK font style preferences: "Japanese"
1101 procedure numbers2pinyin .numberstext$
1102 .intermediatePinyin$ = .numberstext$
1103 # Add a `-quote between vowels
1104 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])([aeuiov])", "\1\2'\3", 0)
1105 # Move numbers to the nucleus vowel
1107 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([^aeuiov0-9]*)([0-9])", "\1\3\2", 0)
1109 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([ae])([aeuiov]*)([0-9])", "\1\3\2", 0)
1111 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(ou)([0-9])", "o\2u", 0)
1112 # or the second vowel
1113 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([uiov][aeuiov])([uiov])([0-9])", "\1\3\2", 0)
1115 # Convert all tones to special characters
1117 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a1", "ā", 0)
1118 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e1", "ē", 0)
1119 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u1", "ū", 0)
1120 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i1", "ī", 0)
1121 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o1", "ō", 0)
1122 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v1", "ǖ", 0)
1123 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "1", "\\-^", 0)
1126 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v2", "ǘ", 0)
1127 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])2", "\\\1'", 0)
1128 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "2", "\\'^", 0)
1131 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a3", "ǎ", 0)
1132 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e3", "ě", 0)
1133 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u3", "ǔ", 0)
1134 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i3", "ǐ", 0)
1135 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o3", "ǒ", 0)
1136 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v3", "ǚ", 0)
1137 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "3", "\\N^", 0)
1140 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v4", "ǜ", 0)
1141 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])4", "\\\1`", 0)
1142 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "4", "\\`^", 0)
1145 # Remove tone 0 symbol completely
1146 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "", 0)
1147 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a0", "å", 0)
1148 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e0", "e̊", 0)
1149 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u0", "ů", 0)
1150 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i0", "i̊", 0)
1151 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o0", "o̊", 0)
1152 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v0", "ü̊", 0)
1153 #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "\\0^", 0)
1155 # Pick best vowel symbols available in cases not caught before
1156 # Ugly clutch to get the 1, 3, 0 tone diacritics at least in the neighbourhood
1157 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i(\\[-N0]\^)", "i\\s{_ }\1", 0)
1159 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v", "\\u\X22", 0)
1161 .pinyin$ = .intermediatePinyin$
1164 # NEEDS WORK AND TESTING!!
1165 # Convert unicode Pinyin into tone numbers
1166 procedure pinyin2numbers .pinyin$
1167 .intermediatePinyin$ = .pinyin$
1168 # Convert all special characters to numbers
1170 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iā)([iaeouü]*)", "a\11", 0)
1171 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iē)([iaeouü]*)", "e\11", 0)
1172 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iū)([iaeouü]*)", "u\11", 0)
1173 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iī)([iaeouü]*)", "i\11", 0)
1174 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iō)([iaeouü]*)", "o\11", 0)
1175 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǖ)([iaeouü]*)", "v\11", 0)
1178 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iá)([iaeouü]*)", "a\12", 0)
1179 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ié)([iaeouü]*)", "e\12", 0)
1180 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iú)([iaeouü]*)", "u\12", 0)
1181 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ií)([iaeouü]*)", "i\12", 0)
1182 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ió)([iaeouü]*)", "o\12", 0)
1183 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǘ)([iaeouü]*)", "v\12", 0)
1186 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǎ)([iaeouü]*)", "a\13", 0)
1187 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iě)([iaeouü]*)", "e\13", 0)
1188 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǔ)([iaeouü]*)", "u\13", 0)
1189 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǐ)([iaeouü]*)", "i\13", 0)
1190 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǒ)([iaeouü]*)", "o\13", 0)
1191 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǚ)([iaeouü]*)", "v\13", 0)
1194 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ià)([iaeouü]*)", "a\14", 0)
1195 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iè)([iaeouü]*)", "e\14", 0)
1196 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iù)([iaeouü]*)", "u\14", 0)
1197 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iì)([iaeouü]*)", "i\14", 0)
1198 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iò)([iaeouü]*)", "o\14", 0)
1199 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǜ)([iaeouü]*)", "v\14", 0)
1203 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iå)([iaeouü]*)", "a\10", 0)
1204 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e̊([iaeouü]*)", "e\10", 0)
1205 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iů)([iaeouü]*)", "u\10", 0)
1206 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i̊([iaeouü]*)", "i\10", 0)
1207 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o̊([iaeouü]*)", "o\10", 0)
1208 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ü̊([iaeouü]*)", "v\10", 0)
1210 # Syllables without a tone symbol are tone 0
1211 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov]+)([^0-9aeuiov]|\W|$)", "\10\2", 0)
1213 # Move numbers to the end of the syllable.
1214 # Syllables ending in n and start with g. Note that a syllable cannot start with an u or i
1215 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(n)(g[aeuiov])", "\1\3\2\4", 0)
1216 # Syllables ending in (ng?) followed by something that is not a valid vowel
1217 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(ng?)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
1218 # Syllables ending in r
1219 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(r)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
1221 #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "[\\'\\`]", "", 0)
1223 .numberstext$ = .intermediatePinyin$
1226 procedure readDisplayPinyin .currentWord
1227 select sgc.currentWordlist
1228 .pinyin$ = Get value... '.currentWord' Pinyin
1229 # Everything to lowercase
1231 if index_regex(.pinyin$, "[0-9]") <= 0
1232 call pinyin2numbers '.pinyin$'
1233 .pinyin$ = pinyin2numbers.numberstext$
1237 procedure readPinyin .currentWord
1238 call readDisplayPinyin '.currentWord'
1239 .pinyin$ = replace_regex$(readDisplayPinyin.pinyin$, ".+", "\L&", 0)
1240 .pinyin$ = replace_regex$(.pinyin$, "[\\'\\` ]", "", 0)
1241 # Remove anything that is objectionable
1242 .pinyin$ = replace_regex$(.pinyin$, "[^\w']", "", 0)
1246 include ToneProt/SGC_ToneProt.praat
1247 include ToneProt/DrawToneContour.praat
1248 include ToneProt/HumToneContour.praat
1249 include ToneProt/ToneRecognition.praat
1250 include ToneProt/ToneScript.praat
1251 include ToneProt/ToneRules.praat