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
431 optionMenu: .wordlistText$, 1
433 for .w to .numWordlists
434 select sgc.allWordLists
435 .wordListName$ = Get value: .w, "Name"
436 option: .wordListName$
438 option: "*"+.manualEntryText$+"*"
442 boolean (.showText$[0], .showValue[0])
443 boolean (.showText$[1], .showValue[1])
444 boolean (.showText$[2], .showValue[2])
445 boolean (.showText$[3], .showValue[3])
446 boolean (.showText$[4], .showValue[4])
447 boolean (.showText$[5], .showValue[5])
448 boolean (.showText$[6], .showValue[6])
449 boolean (.showText$[7], .showValue[7])
450 boolean (.showText$[8], .showValue[8])
451 boolean (.showText$[9], .showValue[9])
452 boolean (.showText$[10], .showValue[10])
453 boolean (.showText$[11], .showValue[11])
454 boolean (.showText$[12], .showValue[12])
455 boolean (.showText$[13], .showValue[13])
456 boolean (.showText$[14], .showValue[14])
458 optionMenu: .partText$, 1
461 for .j to .numLessons
462 option: .lessonName$['.j']
465 optionMenu: .toneText$, 1
472 clicked = endPause ("'.cancelText$'", "'.clearText$'", "'.allText$'", "'.prevWord$'", "'.nextWord$'", "'.continueText$'", 6, 1)
474 select sgc.currentWordlist
476 for .i to sgc.numberOfWords
477 Set string value: .i, "Show", "-"
481 for .i to sgc.numberOfWords
482 Set string value: .i, "Show", "+"
486 # Handle added word lists
487 .wordlistText$ = replace_regex$(.wordlistText$, "^(.)", "\l\1", 0)
488 .wordlistText$ = replace_regex$(.wordlistText$, "\s", "_", 0)
489 .tmp$ = '.wordlistText$'$
490 if .tmp$ <> "---" and sgc.allWordLists > 0
491 select sgc.currentWordlist
492 # Add current wordlist name as a lesson name
493 .originalWordList = -1
494 .numRows = Get number of rows
496 select sgc.currentWordlist
497 .currentLesson$ = Get value: .w, "Lesson"
498 if .currentLesson$ = "" or .currentLesson$ = "-"
499 Set string value: .w, "Lesson", wordlist$
503 # Get and merge the selected list
504 # Enter words by hand
505 if .tmp$ = "*"+.manualEntryText$+"*"
507 .currentFilePath$ = .exampleText$
508 .manualText$ = .manualEntryText$
509 .manPinyin$ = .pinyinText$
510 .manCharacter$ = .characterText$
511 .manTranslation$ = .translationText$
512 .manSound$ = .currentFilePath$
513 .manLesson$ = .manualText$
514 while .man_clicked > 1
515 beginPause: .manualEntryText$
516 text: .pinyinText$, .manPinyin$
517 text: .characterText$, .manCharacter$
518 text: .translationText$, .manTranslation$
519 text: .exampleText$, .manSound$
520 text: .manualText$, .manualText$
521 .man_clicked = endPause("'.cancelText$'", "'.exampleText$'", "'.continueText$'", 3, 1)
523 .tmp$ = replace_regex$(.pinyinText$, "\s", "_", 0)
524 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
525 if '.tmp$'$ <> .pinyinText$
526 .manPinyin$ = '.tmp$'$
532 .tmp$ = replace_regex$(.characterText$, "\s", "_", 0)
533 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
534 if '.tmp$'$ <> .characterText$
535 .manCharacter$ = '.tmp$'$
538 .tmp$ = replace_regex$(.translationText$, "\s", "_", 0)
539 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
540 if '.tmp$'$ <> .translationText$
541 .manTranslation$ = '.tmp$'$
544 .tmp$ = replace_regex$(.exampleText$, "\s", "_", 0)
545 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
546 if '.tmp$'$ <> .characterText$ and '.tmp$'$ <> ""
547 .manSound$ = '.tmp$'$
550 .tmp$ = replace_regex$(.manualText$, "\s", "_", 0)
551 .tmp$ = replace_regex$(.tmp$, "^(.+)$", "\l\1", 0)
552 .manLesson$ = '.tmp$'$
555 .manSound$ = chooseReadFile$(.exampleText$);
556 elsif .man_clicked = 3
557 select sgc.currentWordlist
559 .numRows = Get number of rows
561 Set string value: .numRows, "Pinyin", .manPinyin$
562 Set string value: .numRows, "Character", .manCharacter$
563 Set string value: .numRows, "Translation", .manTranslation$
564 Set string value: .numRows, "Sound", .manSound$
565 Set string value: .numRows, "Lesson", .manLesson$
567 .manualText$ = .manualEntryText$
568 .manPinyin$ = .pinyinText$
569 .manCharacter$ = .characterText$
570 .manTranslation$ = .translationText$
571 .manSound$ = .currentFilePath$
572 .manLesson$ = .manualText$
578 select sgc.allWordLists
579 .wordlistNum = Search column: "Name", .tmp$
581 .wordlistPath$ = Get value: .wordlistNum, "Directory"
582 .wordlistPath$ = replace_regex$(.wordlistPath$, "[ ]", "&", 0)
583 call read_wordlist "'.tmp$'" '.wordlistPath$'
584 .newList = read_wordlist.wordlistID
585 call merge_into_wordlist '.newList' '.tmp$'
588 # Add wordlistname to Lesson column
589 select sgc.allWordLists
590 .numRows = Get number of rows
592 Remove row: .wordlistNum
594 Set string value: 1, "Name", "---"
598 # Gather Lesson names
599 select sgc.currentWordlist
600 Sort rows... Lesson Pinyin
602 sgc.numberOfWords = Get number of rows
606 for .i to sgc.numberOfWords
607 .currentLesson$ = Get value: .i, "Lesson"
608 .matchLesson$ = tab$+.currentLesson$+tab$
609 if .currentLesson$ <> "" and .currentLesson$ <> "-" and .currentLesson$ <> "?" and index(.lessonList$, .matchLesson$) <= 0
610 .lessonList$ = .lessonList$ + .currentLesson$ + tab$
612 .lessonName$['.numLessons'] = .currentLesson$
614 .shown$ = Get value: .i, "Show"
621 select sgc.currentWordlist
622 # Get selected Part BEFORE we do anything else
624 .tmp$ = replace_regex$(.partText$, "^(.)", "\l\1", 0)
625 .lessonSelected = '.tmp$' - 1
627 if .lessonSelected > 0
630 select sgc.currentWordlist
631 for .i to sgc.numberOfWords
632 # Keep track of whether all are shown
633 .shown$ = Get value: .i, "Show"
639 for .i to sgc.numberOfWords
641 .currentLesson$ = Get value: .i, "Lesson"
642 if .currentLesson$ = .lessonName$['.lessonSelected']
643 Set string value: .i, "Show", "+"
645 Set string value: .i, "Show", "-"
648 for .i to sgc.numberOfWords
649 # Keep track of whether all are shown
650 .shown$ = Get value: .i, "Show"
651 if .firstShown <=0 and .shown$ <> "-"
656 for .i from 0 to .max
657 .tmp$ = replace_regex$(.showVariable$['.i'], "^(.*)$", "\l\1", 0)
658 .showValue['.i'] = '.tmp$'
659 .showWord$['.i'] = "-"
660 if .showValue['.i'] <> 0
661 .showWord$['.i'] = "+"
663 Set string value: .currentWord+.i, "Show", .showWord$['.i']
668 select sgc.currentWordlist
669 .tmp$ = replace_regex$(.toneText$, "^(.)", "\l\1", 0)
670 .toneSelected = '.tmp$' - 2
671 if .toneSelected >= 0
672 select sgc.currentWordlist
673 for .i to sgc.numberOfWords
674 .currentPinyin$ = Get value: .i, "Pinyin"
675 if index_regex(.currentPinyin$, "[0-9]") <= 0
676 call pinyin2numbers '.currentPinyin$'
677 .currentPinyin$ = replace_regex$(pinyin2numbers.intermediatePinyin$, ".+", "\l&", 0)
678 .currentPinyin$ = replace_regex$(.currentPinyin$, "[^a-zA-Z0-9]", "", 0)
680 .tmp$ = Get value: .i, "Show"
681 if .tmp$ <> "-" and index(.currentPinyin$, "'.toneSelected'") > 0
682 Set string value: .i, "Show", "+"
684 Set string value: .i, "Show", "-"
692 .currentWord = (.firstShown div .numWordsPerScreen) * .numWordsPerScreen + 1
693 elsif .toneSelected < 0
694 .currentWord -= .numWordsPerScreen
697 .currentWord = (sgc.numberOfWords div .numWordsPerScreen) * .numWordsPerScreen + 1
701 .currentWord = (.firstShown div .numWordsPerScreen) * .numWordsPerScreen + 1
702 elsif .toneSelected < 0
703 .currentWord += .numWordsPerScreen
705 if .currentWord > sgc.numberOfWords
710 # Reset and go to the first selected word (can shuffle list)
720 select sgc.currentWordlist
722 select .tmpOriginalWordlist
724 sgc.currentWordlist = selected()
726 select .tmpOriginalWordlist
728 call Draw_button '.table$' '.label$' 0
731 ###############################################################
733 # Obligatory button Processing Routines
735 # These MUST be defined
737 ###############################################################
739 procedure processMainPageQuit .clickX .clickY .pressed$
743 procedure processMainPageRefresh .clickX .clickY .pressed$
748 procedure processMainPageConfig .clickX .clickY .pressed$
752 procedure processMainPageHelp .clickX .clickY .pressed$
753 call help_loop 'buttons$' init_window
756 procedure processMainPagePlay .clickX .clickY .pressed$
759 if recordedSound$ <> ""
760 call play_sound 'sgc.recordedSound'
763 te.buttonPressValue = mainPage.play
766 procedure Set_Play_Button
768 if recordedSound$ <> ""
771 call Draw_button MainPage Play 'mainPage.play'
774 procedure processMainPageRecord .clickX .clickY .pressed$
776 .recordingTime = recordingTime
777 if count_syllables.number > 2
778 .recordingTime = recordingTime + 1.0*ceiling((count_syllables.number - 2)/2)
780 call record_sound '.recordingTime'
786 call wipeArea 'wipeContourArea$'
788 call draw_tone_contour
790 call display_word_list_name
791 call display_text Black
792 call add_feedback_to_toneevaluation Feedback
793 call write_feedback Feedback
794 select Table Feedback
797 # Do not exercise words that are going well (autoSelect)
798 if add_feedback_to_toneevaluation.result > 0
799 if config.adaptiveLists > 0 and sgc.failedAttempts < 2
800 # Deselect current word
801 select sgc.currentWordlist
802 .i = Search column: "Pinyin", sgc.pinyin$
804 Set string value: .i, "Show", "-"
807 sgc.failedAttempts = 0
809 sgc.failedAttempts += 1
814 ###############################################################
816 # Miscelaneous supporting code
818 ###############################################################
821 procedure generate_example
822 select sgc.currentWordlist
823 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
824 select sgc.currentWordlist
825 .sound$ = Get value... 'sgc.currentWord' Sound
826 call readPinyin 'sgc.currentWord'
827 sgc.pinyin$ = readPinyin.pinyin$
828 if .sound$ = "-" or .sound$ = ""
829 .sound$ = sgc.pinyin$+".wav"
831 if index_regex(.sound$, "^(/|~/|[A-Z]:\\)") > 0
832 .soundFilePath$ = .sound$
834 .soundFilePath$ = localWordlistDir$+"/"+wordlistName$+"/"+.sound$
835 .wordlistDirectory$ = ""
836 if localWordlistDir$ <> "" and fileReadable("'localWordlistDir$'/'wordlistName$'")
837 .wordlistDirectory$ = "'localWordlistDir$'/'wordlistName$'"
838 elsif sgc2wordlists$ <> "" and fileReadable("'sgc2wordlists$'/'wordlistName$'")
839 .wordlistDirectory$ = "'sgc2wordlists$'/'wordlistName$'"
840 elsif globalwordlists$ <> "" and fileReadable("'globalwordlists$'/'wordlistName$'")
841 .wordlistDirectory$ = "'globalwordlists$'/'wordlistName$'"
843 if .wordlistDirectory$ <> ""
844 .audioExampleList = Create Strings as file list... AudioList '.wordlistDirectory$'/'sgc.pinyin$'.*
845 .number_of_examples = Get number of strings
846 if .number_of_examples > 0
848 .sound$ = Get string... 1
849 .soundFilePath$ = "'.wordlistDirectory$'/'.sound$'"
854 if fileReadable(.soundFilePath$) and config.useSoundExample
856 .tmp = nocheck Read from file... '.soundFilePath$'
857 if .tmp != undefined and .tmp > 0
858 call play_sound '.tmp'
862 elsif config.synthesis$ <> "" and config.synthesis$ <> "_DISABLED_"
863 call synthesize_sound 'sgc.pinyin$'
865 call humToneContour 'sgc.pinyin$' 'config.register'
872 # Draw a tone contour
873 procedure draw_tone_contour
874 select sgc.currentWordlist
875 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
876 .sound$ = Get value... 'sgc.currentWord' Sound
877 call readPinyin 'sgc.currentWord'
878 sgc.pinyin$ = readPinyin.pinyin$
879 call drawToneContour 'sgc.pinyin$' 'config.register'
882 if te.recordedPitch > 0
883 call drawSourceToneContour te.recordedPitch
889 procedure recognizeTone
890 select sgc.currentWordlist
891 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
893 if index_regex(config.strict$, "[^0-9]") <= 0
894 .strict = ('config.strict$' >= sgc.highestLevel)
897 .sound$ = Get value... 'sgc.currentWord' Sound
898 call readPinyin 'sgc.currentWord'
899 sgc.pinyin$ = readPinyin.pinyin$
900 call align_recordedSound 'sgc.pinyin$'
901 call sgc_ToneProt 'recordedSound$' 'sgc.pinyin$' 'config.register' '.strict' 'config.language$'
902 # sgc_ToneProt manipulates the sound given. Reconnect
903 select Sound 'recordedSound$'
904 sgc.recordedSound = selected("Sound")
909 procedure write_feedback .table$
910 select Table '.table$'
911 .line1$ = Get value... 1 Text
912 .line2$ = Get value... 2 Text
913 .label$ = Get value... 3 Text
915 # convert numbers to Pinyin if needed
916 if not config.displayNumbers
917 call numbers2pinyin '.line1$'
918 .line1$ = numbers2pinyin.pinyin$
922 if index(.line1$, "???") > 0
924 elsif .label$ = "Correct"
926 elsif config.strict$ = "'sgc.highestLevel'"
927 .line2$ = .line2$ + " *"
930 .currentFeedbackFontSize = 14
932 call adjustFontSizeOnHeight 'defaultFont$' '.currentFeedbackFontSize' '.maxHeight'
933 .currentFeedbackFontSize = adjustFontSizeOnHeight.newFontSize
935 call wipeArea 'wipeFeedbackArea$'
936 call set_font_size '.currentFeedbackFontSize'
938 demo Text... 50 Centre 21 Bottom '.line1$'
939 demo Text... 50 Centre 17 Bottom '.line2$'
942 call set_font_size 'defaultFontSize'
946 procedure display_text .color$
947 select sgc.currentWordlist
948 if sgc.currentWord < 0 or sgc.currentWord > sgc.numberOfWords+1
950 if config.shuffleLists
953 if sgc.currentWord < 0
954 sgc.currentWord = sgc.numberOfWords
961 if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
963 call readDisplayPinyin 'sgc.currentWord'
964 .displayPinyin$ = readDisplayPinyin.pinyin$
965 .displayChar$ = Get value... 'sgc.currentWord' Character
966 .displayTrans$ = Get value... 'sgc.currentWord' Translation
967 if .displayPinyin$ <> "-" and (config.displayPinyin or sgc.writeAll)
968 if not config.displayNumbers
969 call numbers2pinyin '.displayPinyin$'
970 .displayPinyin$ = numbers2pinyin.pinyin$
973 .displayPinyin$ = replace_regex$(.displayPinyin$, "v", "\\u\X22", 0)
974 .displayText$ = .displayText$ + .displayPinyin$
976 if .displayChar$ <> "-" and (config.displayChar or sgc.writeAll)
977 .displayText$ = .displayText$ + " "+ .displayChar$
980 if .displayTrans$ <> "-" and (config.displayTrans or sgc.writeAll)
981 .displayText$ = .displayText$ + " \s{%%"+ .displayTrans$ + "%}"
983 elsif sgc.currentWord = 0 or sgc.currentWord = sgc.numberOfWords+1
985 .displayText$ = "---"
989 call adjustFontSizeOnHeight 'defaultFont$' 24 15
990 .currentFontSize = adjustFontSizeOnHeight.newFontSize
991 call adjustFontSizeOnWidth 'defaultFont$' '.currentFontSize' 95 '.displayText$'
992 .currentFontSize = adjustFontSizeOnWidth.newFontSize
994 # Clear the writing area
995 call wipeArea 'wipePinyinArea$'
996 # Switch back to Chinese style CJK when in Japanese language mode
997 if .changeCJKstyle and config.language$ = "JA"
998 CJK font style preferences: "Chinese"
1000 # Actually display text
1002 call set_font_size '.currentFontSize'
1003 demo Text... 50 Centre 26 Bottom '.displayText$'
1007 call set_font_size 'defaultFontSize'
1008 if .changeCJKstyle and config.language$ = "JA"
1009 if config.language$ = "JA"
1010 CJK font style preferences: "Japanese"
1011 elsif config.language$ = "ZH"
1012 CJK font style preferences: "Chinese"
1015 # Switch back to Japanese style CJK when in Japanese language mode
1016 if .changeCJKstyle and config.language$ = "JA"
1017 CJK font style preferences: "Japanese"
1021 procedure numbers2pinyin .numberstext$
1022 .intermediatePinyin$ = .numberstext$
1023 # Add a `-quote between vowels
1024 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])([aeuiov])", "\1\2'\3", 0)
1025 # Move numbers to the nucleus vowel
1027 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([^aeuiov0-9]*)([0-9])", "\1\3\2", 0)
1029 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([ae])([aeuiov]*)([0-9])", "\1\3\2", 0)
1031 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(ou)([0-9])", "o\2u", 0)
1032 # or the second vowel
1033 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([uiov][aeuiov])([uiov])([0-9])", "\1\3\2", 0)
1035 # Convert all tones to special characters
1037 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a1", "ā", 0)
1038 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e1", "ē", 0)
1039 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u1", "ū", 0)
1040 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i1", "ī", 0)
1041 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o1", "ō", 0)
1042 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v1", "ǖ", 0)
1043 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "1", "\\-^", 0)
1046 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v2", "ǘ", 0)
1047 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])2", "\\\1'", 0)
1048 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "2", "\\'^", 0)
1051 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a3", "ǎ", 0)
1052 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e3", "ě", 0)
1053 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u3", "ǔ", 0)
1054 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i3", "ǐ", 0)
1055 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o3", "ǒ", 0)
1056 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v3", "ǚ", 0)
1057 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "3", "\\N^", 0)
1060 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v4", "ǜ", 0)
1061 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])4", "\\\1`", 0)
1062 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "4", "\\`^", 0)
1065 # Remove tone 0 symbol completely
1066 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "", 0)
1067 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a0", "å", 0)
1068 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e0", "e̊", 0)
1069 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u0", "ů", 0)
1070 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i0", "i̊", 0)
1071 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o0", "o̊", 0)
1072 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v0", "ü̊", 0)
1073 #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "\\0^", 0)
1075 # Pick best vowel symbols available in cases not caught before
1076 # Ugly clutch to get the 1, 3, 0 tone diacritics at least in the neighbourhood
1077 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i(\\[-N0]\^)", "i\\s{_ }\1", 0)
1079 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v", "\\u\X22", 0)
1081 .pinyin$ = .intermediatePinyin$
1084 # NEEDS WORK AND TESTING!!
1085 # Convert unicode Pinyin into tone numbers
1086 procedure pinyin2numbers .pinyin$
1087 .intermediatePinyin$ = .pinyin$
1088 # Convert all special characters to numbers
1090 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iā)([iaeouü]*)", "a\11", 0)
1091 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iē)([iaeouü]*)", "e\11", 0)
1092 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iū)([iaeouü]*)", "u\11", 0)
1093 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iī)([iaeouü]*)", "i\11", 0)
1094 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iō)([iaeouü]*)", "o\11", 0)
1095 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǖ)([iaeouü]*)", "v\11", 0)
1098 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iá)([iaeouü]*)", "a\12", 0)
1099 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ié)([iaeouü]*)", "e\12", 0)
1100 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iú)([iaeouü]*)", "u\12", 0)
1101 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ií)([iaeouü]*)", "i\12", 0)
1102 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ió)([iaeouü]*)", "o\12", 0)
1103 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǘ)([iaeouü]*)", "v\12", 0)
1106 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǎ)([iaeouü]*)", "a\13", 0)
1107 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iě)([iaeouü]*)", "e\13", 0)
1108 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǔ)([iaeouü]*)", "u\13", 0)
1109 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǐ)([iaeouü]*)", "i\13", 0)
1110 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǒ)([iaeouü]*)", "o\13", 0)
1111 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǚ)([iaeouü]*)", "v\13", 0)
1114 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ià)([iaeouü]*)", "a\14", 0)
1115 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iè)([iaeouü]*)", "e\14", 0)
1116 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iù)([iaeouü]*)", "u\14", 0)
1117 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iì)([iaeouü]*)", "i\14", 0)
1118 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iò)([iaeouü]*)", "o\14", 0)
1119 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǜ)([iaeouü]*)", "v\14", 0)
1123 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iå)([iaeouü]*)", "a\10", 0)
1124 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e̊([iaeouü]*)", "e\10", 0)
1125 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iů)([iaeouü]*)", "u\10", 0)
1126 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i̊([iaeouü]*)", "i\10", 0)
1127 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o̊([iaeouü]*)", "o\10", 0)
1128 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ü̊([iaeouü]*)", "v\10", 0)
1130 # Syllables without a tone symbol are tone 0
1131 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov]+)([^0-9aeuiov]|\W|$)", "\10\2", 0)
1133 # Move numbers to the end of the syllable.
1134 # Syllables ending in n and start with g. Note that a syllable cannot start with an u or i
1135 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(n)(g[aeuiov])", "\1\3\2\4", 0)
1136 # Syllables ending in (ng?) followed by something that is not a valid vowel
1137 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(ng?)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
1138 # Syllables ending in r
1139 .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(r)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
1141 #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "[\\'\\`]", "", 0)
1143 .numberstext$ = .intermediatePinyin$
1146 procedure readDisplayPinyin .currentWord
1147 select sgc.currentWordlist
1148 .pinyin$ = Get value... '.currentWord' Pinyin
1149 # Everything to lowercase
1151 if index_regex(.pinyin$, "[0-9]") <= 0
1152 call pinyin2numbers '.pinyin$'
1153 .pinyin$ = pinyin2numbers.numberstext$
1157 procedure readPinyin .currentWord
1158 call readDisplayPinyin '.currentWord'
1159 .pinyin$ = replace_regex$(readDisplayPinyin.pinyin$, ".+", "\L&", 0)
1160 .pinyin$ = replace_regex$(.pinyin$, "[\\'\\` ]", "", 0)
1164 include ToneProt/SGC_ToneProt.praat
1165 include ToneProt/DrawToneContour.praat
1166 include ToneProt/HumToneContour.praat
1167 include ToneProt/ToneRecognition.praat
1168 include ToneProt/ToneScript.praat
1169 include ToneProt/ToneRules.praat