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
39 call drawTriangle -1 .x .y .size
40 .currentX = drawTriangle.currentX
41 .endX = .currentX - 0.5
44 demo Paint rectangle... '.color$' '.currentX' '.endX' '.lowY' '.highY'
47 procedure DrawNext .color$ .x .y .size
50 call drawTriangle 1 .x .y .size
51 .currentX = drawTriangle.currentX
52 .endX = .currentX + 0.5
55 demo Paint rectangle... '.color$' '.currentX' '.endX' '.lowY' '.highY'
58 procedure DrawSelectWords .color$ .x .y .size
62 call adjustFontSizeOnHeight 'defaultFont$' '.currentFontSize' '.maxHeight'
63 .currentFontSize = adjustFontSizeOnHeight.currentFontSize
64 call set_font_size '.currentFontSize'
65 demo Colour... '.color$'
66 demo Text... '.x' Centre '.y' Bottom \bu\bu\bu
67 call set_font_size 'defaultFontSize'
70 procedure DrawWordListUp .color$ .x .y .size
79 demo Draw line... .xleft .ylow .xmidleft .yhigh
80 demo Draw line... .xright .ylow .xmidright .yhigh
81 demo Line width... 'defaultLineWidth'
85 procedure DrawWordListDown .color$ .x .y .size
94 demo Draw line... .xleft .yhigh .xmidleft .ylow
95 demo Draw line... .xright .yhigh .xmidright .ylow
96 demo Line width... 'defaultLineWidth'
100 procedure drawTriangle .direction .x .y .size
101 # Make sure direction = +/- 1
105 .direction /= abs(.direction)
108 .currentHeight = .size
109 .currentX = .x - .direction*.size
111 demo Line width... 2.0
113 while .currentHeight> 0
114 .ystart = .y + .currentHeight
115 .yend = .y - .currentHeight
116 demo Draw line... .currentX .ystart .currentX .yend
117 .currentHeight -= .offset *3/4
118 .currentX += .direction*.offset * 1.5
120 demo Line width... 'defaultLineWidth'
123 ###############################################################
125 # Obligatory button Drawing Routines
127 # These MUST be defined
129 ###############################################################
131 procedure DrawRecord .color$ .x .y .size
133 demo Paint circle... '.color$' '.x' '.y' '.size'
136 procedure DrawPlay .color$ .x .y .size
138 call drawTriangle 1 .x .y .size
141 procedure DrawQuit .color$ .x .y .size
142 demo Colour... '.color$'
143 .lineWidth = 0.5*.size**2
144 demo Line width... '.lineWidth'
149 demo Draw line... .xstart .ystart .xend .yend
154 demo Draw line... .xstart .ystart .xend .yend
155 demo Line width... 'defaultLineWidth'
159 procedure DrawConfig .color$ .x .y .size
161 .lineWidth = 0.4*.size
162 demo Arrow size... '.lineWidth'
163 .lineWidth = 0.4*.size**2
164 demo Line width... '.lineWidth'
168 demo Draw arrow... .xstart .y .xend .y
169 demo Line width... 'defaultLineWidth'
172 procedure DrawRefresh .color$ .x .y .size
173 .lineWidth = 0.5*.size**2
175 demo Line width... '.lineWidth'
176 demo Draw arc... '.x' '.y' '.size' 0 270
177 demo Line width... 'defaultLineWidth'
180 ###############################################################
182 # Button Processing Routines
184 ###############################################################
186 procedure processMainPageExample .clickX .clickY .pressed$
187 call generate_example
190 procedure processMainPagePrevious .clickX .clickY .pressed$
192 call display_text Grey
195 call wipeArea 'wipeFeedbackArea$'
197 call display_text Black
199 sgc.failedAttempts = 0
202 procedure processMainPageNext .clickX .clickY .pressed$
204 call display_text Grey
206 call wipeArea 'wipeFeedbackArea$'
209 call display_text Black
212 procedure processMainPageWordlistUp .clickX .clickY .pressed$
213 call wipeArea 'wipeFeedbackArea$'
214 call load_word_list "'localWordlistDir$'" -1
216 call display_text Black
219 procedure processMainPageWordlistDown .clickX .clickY .pressed$
220 call wipeArea 'wipeFeedbackArea$'
221 call load_word_list "'localWordlistDir$'" 1
223 call display_text Black
226 procedure processMainPageGRADE .clickX .clickY .pressed$
227 call setGrade '.pressed$'
232 procedure processMainPagePinYinArea .clickX .clickY .pressed$
235 call display_text Red
239 # Select the words to practise. This is quite a complex piece of code
240 procedure processMainPageSelectWords .clickX .clickY .pressed$
242 .label$ = "SelectWords"
243 call Draw_button '.table$' '.label$' 1
246 call findLabel '.table$' '.label$'
248 select Table '.table$'
249 .helpText$ = Get value... '.row' Helptext
250 call convert_praat_to_latin1 '.helpText$'
251 .helpText$ = convert_praat_to_latin1.text$
254 select sgc.currentWordlist
255 .tmpOriginalWordlist = Copy: "Original_'wordlist$'"
257 # Remove current list from All wordlists table
258 select sgc.allWordLists
259 .rowNum = Search column: "Name", wordlistName$
261 .numRows = Get number of rows
265 Set string value: 1, "Name", "---"
270 select sgc.currentWordlist
271 sgc.numberOfWords = Get number of rows
272 .currentWord = sgc.currentWord
273 if .currentWord <= 0 or .currentWord > sgc.numberOfWords or config.shuffleLists
278 call get_feedback_text 'config.language$' AddWordlist
279 call convert_praat_to_latin1 'get_feedback_text.text$'
280 .wordlistText$ = convert_praat_to_latin1.text$
281 call get_feedback_text 'config.language$' Part
282 call convert_praat_to_latin1 'get_feedback_text.text$'
283 .partText$ = convert_praat_to_latin1.text$
284 call get_feedback_text 'config.language$' Tones
285 call convert_praat_to_latin1 'get_feedback_text.text$'
286 .toneText$ = convert_praat_to_latin1.text$
287 call get_feedback_text 'config.language$' Cancel
288 call convert_praat_to_latin1 'get_feedback_text.text$'
289 .cancelText$ = convert_praat_to_latin1.text$
290 call get_feedback_text 'config.language$' Clear
291 call convert_praat_to_latin1 'get_feedback_text.text$'
292 .clearText$ = convert_praat_to_latin1.text$
293 call get_feedback_text 'config.language$' All
294 call convert_praat_to_latin1 'get_feedback_text.text$'
295 .allText$ = convert_praat_to_latin1.text$
296 call get_feedback_text 'config.language$' Previous
297 call convert_praat_to_latin1 'get_feedback_text.text$'
298 .prevWord$ = convert_praat_to_latin1.text$
299 call get_feedback_text 'config.language$' Next
300 call convert_praat_to_latin1 'get_feedback_text.text$'
301 .nextWord$ = convert_praat_to_latin1.text$
302 call get_feedback_text 'config.language$' Continue
303 call convert_praat_to_latin1 'get_feedback_text.text$'
304 .continueText$ = convert_praat_to_latin1.text$
305 call get_feedback_text 'config.language$' Show
306 call convert_praat_to_latin1 'get_feedback_text.text$'
307 .showText$ = convert_praat_to_latin1.text$
309 call get_evaluation_text 'config.language$' Pinyin
310 .pinyinText$ = get_evaluation_text.text$
312 call get_evaluation_text 'config.language$' Character
313 .characterText$ = get_evaluation_text.text$
315 call get_evaluation_text 'config.language$' Example
316 .exampleText$ = get_evaluation_text.text$
318 call get_evaluation_text 'config.language$' Translation
319 .translationText$ = get_evaluation_text.text$
321 call get_evaluation_text 'config.language$' ManualEntry
322 .manualEntryText$ = get_evaluation_text.text$
325 select sgc.currentWordlist
326 .lessonCol = Get column index: "Lesson"
328 Append column: "Lesson"
329 .lessonCol = Get column index: "Lesson"
330 .numRows = Get number of rows
332 Set string value: .w, "Lesson", "-"
338 # All shown keeps track whether all words are shown
339 # If so, selecting a lesson is preceded by a Clear All
341 # Sort words for consistent selection interface
342 if config.shuffleLists
343 # Allow subdivision in lessons
345 Sort rows... Lesson Pinyin
351 for .i to sgc.numberOfWords
352 .currentLesson$ = Get value: .i, "Lesson"
353 .matchLesson$ = tab$+.currentLesson$+tab$
354 if .currentLesson$ <> "" and .currentLesson$ <> "-" and .currentLesson$ <> "?" and index(.lessonList$, .matchLesson$) <= 0
355 .lessonList$ = .lessonList$ + .currentLesson$ + tab$
357 .lessonName$['.numLessons'] = .currentLesson$
359 .shown$ = Get value: .i, "Show"
367 .numWordsPerScreen = 15
368 while clicked <> 6 and clicked <> 1
373 select sgc.currentWordlist
374 .lessonCol = Get column index: "Lesson"
375 # Sort words for consistent selection interface
376 if config.shuffleLists
377 # Allow subdivision in lessons
379 Sort rows... Lesson Pinyin
384 .max = .numWordsPerScreen - 1
385 if .currentWord + .max > sgc.numberOfWords
386 .max = sgc.numberOfWords - .currentWord
388 for .i from 0 to .numWordsPerScreen - 1
390 .currentPinyin$ = Get value: .currentWord+.i, "Pinyin"
391 if index_regex(.currentPinyin$, "[0-9]") <= 0
392 call pinyin2numbers '.currentPinyin$'
393 .currentPinyin$ = replace_regex$(pinyin2numbers.intermediatePinyin$, ".+", "\l&", 0)
394 .currentPinyin$ = replace_regex$(.currentPinyin$, "[^a-zA-Z0-9]", "", 0)
396 .pinyin$[.i] = .currentPinyin$
398 .character$[.i] = Get value: .currentWord+.i, "Character"
401 .lessonNum$[.i] = Get value: .currentWord+.i, "Lesson"
402 .lessonNum$[.i] = " : " + .lessonNum$[.i]
404 .showText$[.i] = .pinyin$['.i']
405 if .character$['.i'] <> "-"
406 .showText$[.i] = .pinyin$['.i']+" ("+.character$['.i']+.lessonNum$['.i']+")"
407 elsif .lessonNum$['.i'] <> ""
408 .showText$[.i] = .pinyin$['.i']+" ( -"+.lessonNum$['.i']+")"
410 .showValueText$[.i] = Get value: .currentWord+.i, "Show"
411 if .showValueText$[.i] = "-"
416 .showVariable$[.i] = .pinyin$[.i]
417 .tmp$ = replace_regex$(.showVariable$[.i], "^(.+)$", "\l\1", 0)
418 '.tmp$' = .showValue[.i]
425 # The user text input window (beginPause .... endPause)
426 beginPause(.helpText$)
427 if sgc.allWordLists > 0
428 select sgc.allWordLists
429 .numWordlists = Get number of rows
430 optionMenu: .wordlistText$, 1
432 for .w to .numWordlists
433 select sgc.allWordLists
434 .wordListName$ = Get value: .w, "Name"
435 option: .wordListName$
437 option: "*"+.manualEntryText$+"*"
440 boolean (.showText$[0], .showValue[0])
441 boolean (.showText$[1], .showValue[1])
442 boolean (.showText$[2], .showValue[2])
443 boolean (.showText$[3], .showValue[3])
444 boolean (.showText$[4], .showValue[4])
445 boolean (.showText$[5], .showValue[5])
446 boolean (.showText$[6], .showValue[6])
447 boolean (.showText$[7], .showValue[7])
448 boolean (.showText$[8], .showValue[8])
449 boolean (.showText$[9], .showValue[9])
450 boolean (.showText$[10], .showValue[10])
451 boolean (.showText$[11], .showValue[11])
452 boolean (.showText$[12], .showValue[12])
453 boolean (.showText$[13], .showValue[13])
454 boolean (.showText$[14], .showValue[14])
456 optionMenu: .partText$, 1
459 for .j to .numLessons
460 option: .lessonName$['.j']
463 optionMenu: .toneText$, 1
470 clicked = endPause ("'.cancelText$'", "'.clearText$'", "'.allText$'", "'.prevWord$'", "'.nextWord$'", "'.continueText$'", 6, 1)
472 select sgc.currentWordlist
474 for .i to sgc.numberOfWords
475 Set string value: .i, "Show", "-"
479 for .i to sgc.numberOfWords
480 Set string value: .i, "Show", "+"
484 # Handle added word lists
485 .wordlistText$ = replace_regex$(.wordlistText$, "^(.)", "\l\1", 0)
486 .wordlistText$ = replace_regex$(.wordlistText$, "\s", "_", 0)
487 .tmp$ = '.wordlistText$'$
488 if .tmp$ <> "---" and sgc.allWordLists > 0
489 select sgc.currentWordlist
490 # Add current wordlist name as a lesson name
491 .originalWordList = -1
492 .numRows = Get number of rows
494 select sgc.currentWordlist
495 .currentLesson$ = Get value: .w, "Lesson"
496 if .currentLesson$ = "" or .currentLesson$ = "-"
497 Set string value: .w, "Lesson", wordlist$
501 # Get and merge the selected list
502 # Enter words by hand
503 if .tmp$ = "*"+.manualEntryText$+"*"
505 .currentFilePath$ = .exampleText$
506 .manualText$ = .manualEntryText$
507 .manPinyin$ = .pinyinText$
508 .manCharacter$ = .characterText$
509 .manTranslation$ = .translationText$
510 .manSound$ = .currentFilePath$
511 .manLesson$ = .manualText$
512 while .man_clicked > 1
513 beginPause: .manualEntryText$
514 text: .pinyinText$, .manPinyin$
515 text: .characterText$, .manCharacter$
516 text: .translationText$, .manTranslation$
517 text: .exampleText$, .manSound$
518 text: .manualText$, .manualText$
519 .man_clicked = endPause("'.cancelText$'", "'.exampleText$'", "'.continueText$'", 3, 1)
521 .tmp$ = replace_regex$(.pinyinText$, "\s", "_", 0)
522 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
523 if '.tmp$'$ <> .pinyinText$
524 .manPinyin$ = '.tmp$'$
530 .tmp$ = replace_regex$(.characterText$, "\s", "_", 0)
531 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
532 if '.tmp$'$ <> .characterText$
533 .manCharacter$ = '.tmp$'$
536 .tmp$ = replace_regex$(.translationText$, "\s", "_", 0)
537 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
538 if '.tmp$'$ <> .translationText$
539 .manTranslation$ = '.tmp$'$
542 .tmp$ = replace_regex$(.exampleText$, "\s", "_", 0)
543 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
544 if '.tmp$'$ <> .characterText$ and '.tmp$'$ <> ""
545 .manSound$ = '.tmp$'$
548 .tmp$ = replace_regex$(.manualText$, "\s", "_", 0)
549 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
550 .manLesson$ = '.tmp$'$
553 .manSound$ = chooseReadFile$(.exampleText$);
554 elsif .man_clicked = 3
555 select sgc.currentWordlist
557 .numRows = Get number of rows
559 Set string value: .numRows, "Pinyin", .manPinyin$
560 Set string value: .numRows, "Character", .manCharacter$
561 Set string value: .numRows, "Translation", .manTranslation$
562 Set string value: .numRows, "Sound", .manSound$
563 Set string value: .numRows, "Lesson", .manLesson$
565 .manualText$ = .manualEntryText$
566 .manPinyin$ = .pinyinText$
567 .manCharacter$ = .characterText$
568 .manTranslation$ = .translationText$
569 .manSound$ = .currentFilePath$
570 .manLesson$ = .manualText$
576 select sgc.allWordLists
577 .wordlistNum = Search column: "Name", .tmp$
579 .wordlistPath$ = Get value: .wordlistNum, "Directory"
580 .wordlistPath$ = replace_regex$(.wordlistPath$, "[ ]", "&", 0)
581 call read_wordlist "'.tmp$'" '.wordlistPath$'
582 .newList = read_wordlist.wordlistID
583 call merge_into_wordlist '.newList' '.tmp$'
586 # Add wordlistname to Lesson column
587 select sgc.allWordLists
588 .numRows = Get number of rows
590 Remove row: .wordlistNum
592 Set string value: 1, "Name", "---"
596 # Gather Lesson names
597 select sgc.currentWordlist
598 Sort rows... Lesson Pinyin
600 sgc.numberOfWords = Get number of rows
604 for .i to sgc.numberOfWords
605 .currentLesson$ = Get value: .i, "Lesson"
606 .matchLesson$ = tab$+.currentLesson$+tab$
607 if .currentLesson$ <> "" and .currentLesson$ <> "-" and .currentLesson$ <> "?" and index(.lessonList$, .matchLesson$) <= 0
608 .lessonList$ = .lessonList$ + .currentLesson$ + tab$
610 .lessonName$['.numLessons'] = .currentLesson$
612 .shown$ = Get value: .i, "Show"
619 select sgc.currentWordlist
620 # Get selected Part BEFORE we do anything else
622 .tmp$ = replace_regex$(.partText$, "^(.)", "\l\1", 0)
623 .lessonSelected = '.tmp$' - 1
625 if .lessonSelected > 0
628 select sgc.currentWordlist
629 for .i to sgc.numberOfWords
630 # Keep track of whether all are shown
631 .shown$ = Get value: .i, "Show"
637 for .i to sgc.numberOfWords
639 .currentLesson$ = Get value: .i, "Lesson"
640 if .currentLesson$ = .lessonName$['.lessonSelected']
641 Set string value: .i, "Show", "+"
643 Set string value: .i, "Show", "-"
646 for .i to sgc.numberOfWords
647 # Keep track of whether all are shown
648 .shown$ = Get value: .i, "Show"
649 if .firstShown <=0 and .shown$ <> "-"
654 for .i from 0 to .max
655 .tmp$ = replace_regex$(.showVariable$['.i'], "^(.*)$", "\l\1", 0)
656 .showValue['.i'] = '.tmp$'
657 .showWord$['.i'] = "-"
658 if .showValue['.i'] <> 0
659 .showWord$['.i'] = "+"
661 Set string value: .currentWord+.i, "Show", .showWord$['.i']
666 select sgc.currentWordlist
667 .tmp$ = replace_regex$(.toneText$, "^(.)", "\l\1", 0)
668 .toneSelected = '.tmp$' - 2
669 if .toneSelected >= 0
670 select sgc.currentWordlist
671 for .i to sgc.numberOfWords
672 .currentPinyin$ = Get value: .i, "Pinyin"
673 if index_regex(.currentPinyin$, "[0-9]") <= 0
674 call pinyin2numbers '.currentPinyin$'
675 .currentPinyin$ = replace_regex$(pinyin2numbers.intermediatePinyin$, ".+", "\l&", 0)
676 .currentPinyin$ = replace_regex$(.currentPinyin$, "[^a-zA-Z0-9]", "", 0)
678 .tmp$ = Get value: .i, "Show"
679 if .tmp$ <> "-" and index(.currentPinyin$, "'.toneSelected'") > 0
680 Set string value: .i, "Show", "+"
682 Set string value: .i, "Show", "-"
690 .currentWord = (.firstShown div .numWordsPerScreen) * .numWordsPerScreen + 1
691 elsif .toneSelected < 0
692 .currentWord -= .numWordsPerScreen
695 .currentWord = (sgc.numberOfWords div .numWordsPerScreen) * .numWordsPerScreen + 1
699 .currentWord = (.firstShown div .numWordsPerScreen) * .numWordsPerScreen + 1
700 elsif .toneSelected < 0
701 .currentWord += .numWordsPerScreen
703 if .currentWord > sgc.numberOfWords
708 # Reset and go to the first selected word (can shuffle list)
718 select sgc.currentWordlist
720 select .tmpOriginalWordlist
722 sgc.currentWordlist = selected()
724 select .tmpOriginalWordlist
726 call Draw_button '.table$' '.label$' 0
729 ###############################################################
731 # Obligatory button Processing Routines
733 # These MUST be defined
735 ###############################################################
737 procedure processMainPageQuit .clickX .clickY .pressed$
741 procedure processMainPageRefresh .clickX .clickY .pressed$
746 procedure processMainPageConfig .clickX .clickY .pressed$
750 procedure processMainPageHelp .clickX .clickY .pressed$
751 call help_loop 'buttons$' init_window
754 procedure processMainPagePlay .clickX .clickY .pressed$
757 if recordedSound$ <> ""
758 call play_sound 'sgc.recordedSound'
761 te.buttonPressValue = mainPage.play
764 procedure Set_Play_Button
766 if recordedSound$ <> ""
769 call Draw_button MainPage Play 'mainPage.play'
772 procedure processMainPageRecord .clickX .clickY .pressed$
774 .recordingTime = recordingTime
775 if count_syllables.number > 2
776 .recordingTime = recordingTime + 1.0*ceiling((count_syllables.number - 2)/2)
778 call record_sound '.recordingTime'
784 call wipeArea 'wipeContourArea$'
786 call draw_tone_contour
788 call display_word_list_name
789 call display_text Black
790 call add_feedback_to_toneevaluation Feedback
791 call write_feedback Feedback
792 select Table Feedback
795 # Do not exercise words that are going well (autoSelect)
796 if add_feedback_to_toneevaluation.result > 0
797 if config.adaptiveLists > 0 and sgc.failedAttempts < 2
798 # Deselect current word
799 select sgc.currentWordlist
800 .i = Search column: "Pinyin", sgc.pinyin$
802 Set string value: .i, "Show", "-"
805 sgc.failedAttempts = 0
807 sgc.failedAttempts += 1
812 ###############################################################
814 # Miscelaneous supporting code
816 ###############################################################
819 procedure generate_example
820 select sgc.currentWordlist
821 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
822 select sgc.currentWordlist
823 .sound$ = Get value... 'sgc.currentWord' Sound
824 call readPinyin 'sgc.currentWord'
825 sgc.pinyin$ = readPinyin.pinyin$
826 if .sound$ = "-" or .sound$ = ""
827 .sound$ = sgc.pinyin$+".wav"
829 if index_regex(.sound$, "^(/|~/|[A-Z]:\\)") > 0
830 .soundFilePath$ = .sound$
832 .soundFilePath$ = localWordlistDir$+"/"+wordlistName$+"/"+.sound$
833 .wordlistDirectory$ = ""
834 if localWordlistDir$ <> "" and fileReadable("'localWordlistDir$'/'wordlistName$'")
835 .wordlistDirectory$ = "'localWordlistDir$'/'wordlistName$'"
836 elsif sgc2wordlists$ <> "" and fileReadable("'sgc2wordlists$'/'wordlistName$'")
837 .wordlistDirectory$ = "'sgc2wordlists$'/'wordlistName$'"
838 elsif globalwordlists$ <> "" and fileReadable("'globalwordlists$'/'wordlistName$'")
839 .wordlistDirectory$ = "'globalwordlists$'/'wordlistName$'"
841 if .wordlistDirectory$ <> ""
842 .audioExampleList = Create Strings as file list... AudioList '.wordlistDirectory$'/'sgc.pinyin$'.*
843 .number_of_examples = Get number of strings
844 if .number_of_examples > 0
846 .sound$ = Get string... 1
847 .soundFilePath$ = "'.wordlistDirectory$'/'.sound$'"
852 if fileReadable(.soundFilePath$) and config.useSoundExample
854 .tmp = nocheck Read from file... '.soundFilePath$'
855 if .tmp != undefined and .tmp > 0
856 call play_sound '.tmp'
860 elsif config.synthesis$ <> "" and config.synthesis$ <> "_DISABLED_"
861 call synthesize_sound 'sgc.pinyin$'
863 call humToneContour 'sgc.pinyin$' 'config.register'
870 # Draw a tone contour
871 procedure draw_tone_contour
872 select sgc.currentWordlist
873 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
874 .sound$ = Get value... 'sgc.currentWord' Sound
875 call readPinyin 'sgc.currentWord'
876 sgc.pinyin$ = readPinyin.pinyin$
877 call drawToneContour 'sgc.pinyin$' 'config.register'
880 if te.recordedPitch > 0
881 call drawSourceToneContour te.recordedPitch
887 procedure recognizeTone
888 select sgc.currentWordlist
889 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
891 if index_regex(config.strict$, "[^0-9]") <= 0
892 .strict = ('config.strict$' >= sgc.highestLevel)
895 .sound$ = Get value... 'sgc.currentWord' Sound
896 call readPinyin 'sgc.currentWord'
897 sgc.pinyin$ = readPinyin.pinyin$
898 call align_recordedSound 'sgc.pinyin$'
899 call sgc_ToneProt 'recordedSound$' 'sgc.pinyin$' 'config.register' '.strict' 'config.language$'
900 # sgc_ToneProt manipulates the sound given. Reconnect
901 select Sound 'recordedSound$'
902 sgc.recordedSound = selected("Sound")
907 procedure write_feedback .table$
908 select Table '.table$'
909 .line1$ = Get value... 1 Text
910 .line2$ = Get value... 2 Text
911 .label$ = Get value... 3 Text
913 # convert numbers to Pinyin if needed
914 if not config.displayNumbers
915 call numbers2pinyin '.line1$'
916 .line1$ = numbers2pinyin.pinyin$
920 if index(.line1$, "???") > 0
922 elsif .label$ = "Correct"
924 elsif config.strict$ = "'sgc.highestLevel'"
925 .line2$ = .line2$ + " *"
928 .currentFeedbackFontSize = 14
930 call adjustFontSizeOnHeight 'defaultFont$' '.currentFeedbackFontSize' '.maxHeight'
931 .currentFeedbackFontSize = adjustFontSizeOnHeight.newFontSize
933 call wipeArea 'wipeFeedbackArea$'
934 call set_font_size '.currentFeedbackFontSize'
936 demo Text... 50 Centre 21 Bottom '.line1$'
937 demo Text... 50 Centre 17 Bottom '.line2$'
940 call set_font_size 'defaultFontSize'
944 procedure display_text .color$
945 select sgc.currentWordlist
946 if sgc.currentWord < 0 or sgc.currentWord > sgc.numberOfWords+1
948 if config.shuffleLists
951 if sgc.currentWord < 0
952 sgc.currentWord = sgc.numberOfWords
959 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
961 call readDisplayPinyin 'sgc.currentWord'
962 .displayPinyin$ = readDisplayPinyin.pinyin$
963 .displayChar$ = Get value... 'sgc.currentWord' Character
964 .displayTrans$ = Get value... 'sgc.currentWord' Translation
965 if .displayPinyin$ <> "-" and (config.displayPinyin or sgc.writeAll)
966 if not config.displayNumbers
967 call numbers2pinyin '.displayPinyin$'
968 .displayPinyin$ = numbers2pinyin.pinyin$
971 .displayPinyin$ = replace_regex$(.displayPinyin$, "v", "\\u\X22", 0)
972 .displayText$ = .displayText$ + .displayPinyin$
974 if .displayChar$ <> "-" and (config.displayChar or sgc.writeAll)
975 .displayText$ = .displayText$ + " "+ .displayChar$
978 if .displayTrans$ <> "-" and (config.displayTrans or sgc.writeAll)
979 .displayText$ = .displayText$ + " \s{%%"+ .displayTrans$ + "%}"
981 elsif sgc.currentWord = 0 or sgc.currentWord = sgc.numberOfWords+1
983 .displayText$ = "---"
987 call adjustFontSizeOnHeight 'defaultFont$' 24 15
988 .currentFontSize = adjustFontSizeOnHeight.newFontSize
989 call adjustFontSizeOnWidth 'defaultFont$' '.currentFontSize' 95 '.displayText$'
990 .currentFontSize = adjustFontSizeOnWidth.newFontSize
992 # Clear the writing area
993 call wipeArea 'wipePinyinArea$'
994 # Switch back to Chinese style CJK when in Japanese language mode
995 if .changeCJKstyle and config.language$ = "JA"
996 CJK font style preferences: "Chinese"
998 # Actually display text
1000 call set_font_size '.currentFontSize'
1001 demo Text... 50 Centre 26 Bottom '.displayText$'
1005 call set_font_size 'defaultFontSize'
1006 if .changeCJKstyle and config.language$ = "JA"
1007 if config.language$ = "JA"
1008 CJK font style preferences: "Japanese"
1009 elsif config.language$ = "ZH"
1010 CJK font style preferences: "Chinese"
1013 # Switch back to Japanese style CJK when in Japanese language mode
1014 if .changeCJKstyle and config.language$ = "JA"
1015 CJK font style preferences: "Japanese"
1019 procedure numbers2pinyin .numberstext$
1020 .intermediatePinyin$ = .numberstext$
1021 # Add a `-quote between vowels
1022 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])([aeuiov])", "\1\2'\3", 0)
1023 # Move numbers to the nucleus vowel
1025 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([^aeuiov0-9]*)([0-9])", "\1\3\2", 0)
1027 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([ae])([aeuiov]*)([0-9])", "\1\3\2", 0)
1029 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(ou)([0-9])", "o\2u", 0)
1030 # or the second vowel
1031 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([uiov][aeuiov])([uiov])([0-9])", "\1\3\2", 0)
1033 # Convert all tones to special characters
1035 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a1", "ā", 0)
1036 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e1", "ē", 0)
1037 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u1", "ū", 0)
1038 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i1", "ī", 0)
1039 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o1", "ō", 0)
1040 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v1", "ǖ", 0)
1041 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "1", "\\-^", 0)
1044 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v2", "ǘ", 0)
1045 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])2", "\\\1'", 0)
1046 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "2", "\\'^", 0)
1049 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a3", "ǎ", 0)
1050 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e3", "ě", 0)
1051 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u3", "ǔ", 0)
1052 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i3", "ǐ", 0)
1053 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o3", "ǒ", 0)
1054 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v3", "ǚ", 0)
1055 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "3", "\\N^", 0)
1058 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v4", "ǜ", 0)
1059 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])4", "\\\1`", 0)
1060 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "4", "\\`^", 0)
1063 # Remove tone 0 symbol completely
1064 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "", 0)
1065 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a0", "å", 0)
1066 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e0", "e̊", 0)
1067 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u0", "ů", 0)
1068 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i0", "i̊", 0)
1069 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o0", "o̊", 0)
1070 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v0", "ü̊", 0)
1071 #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "\\0^", 0)
1073 # Pick best vowel symbols available in cases not caught before
1074 # Ugly clutch to get the 1, 3, 0 tone diacritics at least in the neighbourhood
1075 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i(\\[-N0]\^)", "i\\s{_ }\1", 0)
1077 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v", "\\u\X22", 0)
1079 .pinyin$ = .intermediatePinyin$
1082 # NEEDS WORK AND TESTING!!
1083 # Convert unicode Pinyin into tone numbers
1084 procedure pinyin2numbers .pinyin$
1085 .intermediatePinyin$ = .pinyin$
1086 # Convert all special characters to numbers
1088 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iā)([iaeouü]*)", "a\11", 0)
1089 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iē)([iaeouü]*)", "e\11", 0)
1090 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iū)([iaeouü]*)", "u\11", 0)
1091 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iī)([iaeouü]*)", "i\11", 0)
1092 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iō)([iaeouü]*)", "o\11", 0)
1093 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǖ)([iaeouü]*)", "v\11", 0)
1096 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iá)([iaeouü]*)", "a\12", 0)
1097 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ié)([iaeouü]*)", "e\12", 0)
1098 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iú)([iaeouü]*)", "u\12", 0)
1099 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ií)([iaeouü]*)", "i\12", 0)
1100 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ió)([iaeouü]*)", "o\12", 0)
1101 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǘ)([iaeouü]*)", "v\12", 0)
1104 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǎ)([iaeouü]*)", "a\13", 0)
1105 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iě)([iaeouü]*)", "e\13", 0)
1106 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǔ)([iaeouü]*)", "u\13", 0)
1107 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǐ)([iaeouü]*)", "i\13", 0)
1108 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǒ)([iaeouü]*)", "o\13", 0)
1109 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǚ)([iaeouü]*)", "v\13", 0)
1112 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ià)([iaeouü]*)", "a\14", 0)
1113 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iè)([iaeouü]*)", "e\14", 0)
1114 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iù)([iaeouü]*)", "u\14", 0)
1115 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iì)([iaeouü]*)", "i\14", 0)
1116 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iò)([iaeouü]*)", "o\14", 0)
1117 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǜ)([iaeouü]*)", "v\14", 0)
1121 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iå)([iaeouü]*)", "a\10", 0)
1122 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e̊([iaeouü]*)", "e\10", 0)
1123 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iů)([iaeouü]*)", "u\10", 0)
1124 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i̊([iaeouü]*)", "i\10", 0)
1125 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o̊([iaeouü]*)", "o\10", 0)
1126 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ü̊([iaeouü]*)", "v\10", 0)
1128 # Syllables without a tone symbol are tone 0
1129 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov]+)([^0-9aeuiov]|\W|$)", "\10\2", 0)
1131 # Move numbers to the end of the syllable.
1132 # Syllables ending in n and start with g. Note that a syllable cannot start with an u or i
1133 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(n)(g[aeuiov])", "\1\3\2\4", 0)
1134 # Syllables ending in (ng?) followed by something that is not a valid vowel
1135 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(ng?)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
1136 # Syllables ending in r
1137 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(r)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
1139 #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "[\\'\\`]", "", 0)
1141 .numberstext$ = .intermediatePinyin$
1144 procedure readDisplayPinyin .currentWord
1145 select sgc.currentWordlist
1146 .pinyin$ = Get value... '.currentWord' Pinyin
1147 # Everything to lowercase
1149 if index_regex(.pinyin$, "[0-9]") <= 0
1150 call pinyin2numbers '.pinyin$'
1151 .pinyin$ = pinyin2numbers.numberstext$
1155 procedure readPinyin .currentWord
1156 call readDisplayPinyin '.currentWord'
1157 .pinyin$ = replace_regex$(readDisplayPinyin.pinyin$, ".+", "\L&", 0)
1158 .pinyin$ = replace_regex$(.pinyin$, "[\\'\\` ]", "", 0)
1162 include ToneProt/SGC_ToneProt.praat
1163 include ToneProt/DrawToneContour.praat
1164 include ToneProt/HumToneContour.praat
1165 include ToneProt/ToneRecognition.praat
1166 include ToneProt/ToneScript.praat
1167 include ToneProt/ToneRules.praat