Worked on adding wordlists to current wordlist
[sgc2.git] / MainPage.praat
blob46c53627dd3f75e7f8ef77d7f81039666b98b969
2 # SpeakGoodChinese 2.0
3
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.
8 #     
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
13
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.
18
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.
23
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
27
28 # Includes at the bottom
30 ###############################################################
32 # Button Drawing Routines
34 ###############################################################
36 procedure DrawPrevious .color$ .x .y .size
37         demo '.color$'
38         .size *= 2/3
39         call drawTriangle -1 .x .y .size
40         .currentX = drawTriangle.currentX
41         .endX = .currentX - 0.5
42         .lowY = .y - .size
43         .highY = .y + .size
44         demo Paint rectangle... '.color$' '.currentX' '.endX' '.lowY' '.highY'
45 endproc
47 procedure DrawNext .color$ .x .y .size
48         demo '.color$'
49         .size *= 2/3
50         call drawTriangle 1 .x .y .size
51         .currentX = drawTriangle.currentX
52         .endX = .currentX + 0.5
53         .lowY = .y - .size
54         .highY = .y + .size
55         demo Paint rectangle... '.color$' '.currentX' '.endX' '.lowY' '.highY'
56 endproc
58 procedure DrawSelectWords .color$ .x .y .size
59         .currentFontSize = 48
60         .y -= .size/2 + 0.5
61         .maxHeight = 2*.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'
68 endproc
70 procedure DrawWordListUp .color$ .x .y .size
71     .xleft = .x - .size
72     .xright = .x + .size
73     .xmidleft = .x + 0.1
74     .xmidright = .x - 0.1
75     .ylow = .y
76     .yhigh = .y + .size
77         demo '.color$'
78         demo Line width... 3
79         demo Draw line... .xleft .ylow .xmidleft .yhigh
80         demo Draw line... .xright .ylow .xmidright .yhigh
81         demo Line width... 'defaultLineWidth'
82         demo Black
83 endproc
85 procedure DrawWordListDown .color$ .x .y .size
86     .xleft = .x - .size
87     .xright = .x + .size
88     .xmidleft = .x + 0.1
89     .xmidright = .x - 0.1
90     .yhigh = .y + .size
91     .ylow = .y
92         demo '.color$'
93         demo Line width... 3
94         demo Draw line... .xleft .yhigh .xmidleft .ylow
95         demo Draw line... .xright .yhigh .xmidright .ylow
96         demo Line width... 'defaultLineWidth'
97         demo Black
98 endproc
100 procedure drawTriangle .direction .x .y .size
101         # Make sure direction = +/- 1
102         if .direction = 0
103                 .direction = 1 
104         endif
105         .direction /= abs(.direction)
106         
107         .offset = 0.01
108         .currentHeight = .size
109         .currentX = .x - .direction*.size
110         
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
119         endwhile
120         demo Line width... 'defaultLineWidth'
121 endproc
123 ###############################################################
125 # Obligatory button Drawing Routines
127 # These MUST be defined
129 ###############################################################
131 procedure DrawRecord .color$ .x .y .size
132         .size /= 2
133     demo Paint circle... '.color$' '.x' '.y' '.size'
134 endproc
136 procedure DrawPlay .color$ .x .y .size
137         demo '.color$'
138         call drawTriangle 1 .x .y .size
139 endproc
141 procedure DrawQuit .color$ .x .y .size
142         demo Colour... '.color$'
143         .lineWidth = 0.5*.size**2
144         demo Line width... '.lineWidth'
145         .xstart = .x - .size
146         .ystart = .y + .size
147         .xend = .x + .size
148         .yend = .y - .size
149         demo Draw line... .xstart .ystart .xend .yend
150         .xstart = .x - .size
151         .ystart = .y - .size
152         .xend = .x + .size
153         .yend = .y + .size
154         demo Draw line... .xstart .ystart .xend .yend
155         demo Line width... 'defaultLineWidth'
156         demo Colour... Black
157 endproc
159 procedure DrawConfig .color$ .x .y .size
160         .size *= 1
161         .lineWidth = 0.4*.size
162         demo Arrow size... '.lineWidth'
163         .lineWidth = 0.4*.size**2
164         demo Line width... '.lineWidth'
165         .y += .size/2
166         .xstart = .x - .size
167         .xend = .x + .size
168         demo Draw arrow... .xstart .y .xend .y
169         demo Line width... 'defaultLineWidth'
170 endproc
172 procedure DrawRefresh .color$ .x .y .size
173         .lineWidth = 0.5*.size**2
174         .size /= 2
175         demo Line width... '.lineWidth'
176         demo Draw arc... '.x' '.y' '.size' 0 270
177         demo Line width... 'defaultLineWidth'
178 endproc
180 ###############################################################
182 # Button Processing Routines
184 ###############################################################
186 procedure processMainPageExample .clickX .clickY .pressed$
187         call generate_example
188 endproc
190 procedure processMainPagePrevious .clickX .clickY .pressed$
191         call clean_up_sound
192         call display_text Grey
193         call previous_word
194         # Draw the contour
195         call wipeArea 'wipeFeedbackArea$'
196         call init_window
197         call display_text Black
198         
199         sgc.failedAttempts = 0
200 endproc
202 procedure processMainPageNext .clickX .clickY .pressed$
203         call clean_up_sound
204         call display_text Grey
205         call next_word
206         call wipeArea 'wipeFeedbackArea$'
207         call init_window
208         # Draw the contour
209         call display_text Black
210 endproc
212 procedure processMainPageWordlistUp .clickX .clickY .pressed$
213         call wipeArea 'wipeFeedbackArea$'
214     call load_word_list "'localWordlistDir$'" -1
215         call init_window
216         call display_text Black
217 endproc
219 procedure processMainPageWordlistDown .clickX .clickY .pressed$
220         call wipeArea 'wipeFeedbackArea$'
221     call load_word_list "'localWordlistDir$'" 1
222         call init_window
223         call display_text Black
224 endproc
226 procedure processMainPageGRADE .clickX .clickY .pressed$
227         call setGrade '.pressed$'
228         # Redraw window
229         call init_window
230 endproc
232 procedure processMainPagePinYinArea .clickX .clickY .pressed$
233         # Redraw window
234         sgc.writeAll = 1
235         call display_text Red
236         sgc.writeAll = 0
237 endproc
239 # Select the words to practise. This is quite a complex piece of code
240 procedure processMainPageSelectWords .clickX .clickY .pressed$
241         .table$ = "MainPage"
242         .label$ = "SelectWords"
243     call Draw_button '.table$' '.label$' 1
245         # Get help text
246         call findLabel '.table$' '.label$'
247         .row = findLabel.row
248         select Table '.table$'
249         .helpText$ = Get value... '.row' Helptext
250         call convert_praat_to_latin1 '.helpText$'
251         .helpText$ = convert_praat_to_latin1.text$
252    
253     # Implement Cancel
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$
260         if .rowNum > 0
261                 .numRows = Get number of rows
262                 if .numRows > 1
263                         Remove row: .rowNum
264                 else
265                         Set string value: 1, "Name", "---"
266                 endif
267         endif
268     
269     # Set current word
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
274                 .currentWord = 1
275         endif
276     
277         # The texts
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         .pinyinText$ = "Pinyin"
310         .characterText$ = "Character"
311         
312         # Get lesson names
313         select sgc.currentWordlist
314         .lessonCol = Get column index: "Lesson"
315         if .lessonCol <= 0
316                 Append column: "Lesson"
317                 .lessonCol = Get column index: "Lesson"
318                 .numRows = Get number of rows
319                 for .w to .numRows
320                         Set string value: .w, "Lesson", "-"
321                 endfor
322         endif
323         .lessonList$ = tab$
324         .numLessons = 0
325         # All shown keeps track whether all words are shown
326         # If so, selecting a lesson is preceded by a Clear All
327         .allShown = 0
328         # Sort words for consistent selection interface
329         if config.shuffleLists
330                 # Allow subdivision in lessons
331                 if .lessonCol > 0
332                         Sort rows... Lesson Pinyin
333                 else
334                         Sort rows... Pinyin
335                 endif
336         endif           
337         if .lessonCol > 0
338                 for .i to sgc.numberOfWords
339                         .currentLesson$ = Get value: .i, "Lesson"
340                         if .currentLesson$ <> "" and .currentLesson$ <> "-" and .currentLesson$ <> "?" and index_regex(.lessonList$, "\t'.currentLesson$'\t") <= 0
341                                 .lessonList$ = .lessonList$ + .currentLesson$ + tab$
342                                 .numLessons += 1
343                                 .lessonName$['.numLessons'] = .currentLesson$
344                         endif
345                         .shown$ = Get value: .i, "Show"
346                         if .shown$ = "-"
347                                 .allShown = 0
348                         endif
349                 endfor
350         endif
351         
352         clicked = -1
353         .numWordsPerScreen = 15
354         while clicked <> 6 and clicked <> 1
355                 .lessonSelected = -1
356                 .toneSelected = -1
357                 .firstShown = -1
358                 
359                 select sgc.currentWordlist
360                 .lessonCol = Get column index: "Lesson"
361                 # Sort words for consistent selection interface
362         if config.shuffleLists
363                         # Allow subdivision in lessons
364                         if .numLessons > 1
365                                 Sort rows... Lesson Pinyin
366                         else
367                                 Sort rows... Pinyin
368                         endif
369         endif           
370                 .max = .numWordsPerScreen - 1
371                 if .currentWord + .max > sgc.numberOfWords
372                         .max = sgc.numberOfWords - .currentWord
373                 endif
374                 for .i from 0 to .numWordsPerScreen - 1
375                         if .i <= .max
376                                 .currentPinyin$ = Get value: .currentWord+.i, "Pinyin"
377                                 if index_regex(.currentPinyin$, "[0-9]") <= 0
378                                         call pinyin2numbers '.currentPinyin$'
379                                         .currentPinyin$ = replace_regex$(pinyin2numbers.intermediatePinyin$, ".+", "\l&", 0)
380                                         .currentPinyin$ = replace_regex$(.currentPinyin$, "[^a-zA-Z0-9]", "", 0)
381                                 endif
382                                 .pinyin$[.i] = .currentPinyin$
384                                 .character$[.i] = Get value: .currentWord+.i, "Character"
385                                 .lessonNum$[.i] = ""
386                                 if .numLessons > 0
387                                         .lessonNum$[.i] = Get value: .currentWord+.i, "Lesson"
388                                         .lessonNum$[.i] = " : " + .lessonNum$[.i]
389                                 endif
390                                 .showText$[.i] = .pinyin$['.i']
391                                 if .character$['.i'] <> "-"
392                                         .showText$[.i] = .pinyin$['.i']+" ("+.character$['.i']+.lessonNum$['.i']+")"
393                                 elsif .lessonNum$['.i'] <> ""
394                                         .showText$[.i] = .pinyin$['.i']+" ( -"+.lessonNum$['.i']+")"
395                                 endif
396                                 .showValueText$[.i] = Get value: .currentWord+.i, "Show"
397                                 if .showValueText$[.i] = "-"
398                                         .showValue[.i] = 0
399                                 else
400                                         .showValue[.i] = 1
401                                 endif
402                                 .showVariable$[.i] = .pinyin$[.i]
403                                 .tmp$ = .showVariable$[.i]
404                                 '.tmp$' = .showValue[.i]
405                         else
406                                 .showText$[.i] = "-"
407                                 .showValue[.i] = 0
408                         endif
409                 endfor
411                 # The user text input window (beginPause .... endPause)
412                 beginPause(.helpText$)
413                         if sgc.allWordLists > 0
414                                 select sgc.allWordLists
415                                 .numWordlists = Get number of rows
416                                 if .numWordlists > 0
417                                         optionMenu: .wordlistText$, 1
418                                                 option: "---"
419                                                 for .w to .numWordlists
420                                                         select sgc.allWordLists
421                                                         .wordListName$ = Get value: .w, "Name"
422                                                         option: .wordListName$
423                                                 endfor
424                                 endif
425                         endif
426                         
427                         boolean (.showText$[0], .showValue[0])
428                         boolean (.showText$[1], .showValue[1])
429                         boolean (.showText$[2], .showValue[2])
430                         boolean (.showText$[3], .showValue[3])
431                         boolean (.showText$[4], .showValue[4])
432                         boolean (.showText$[5], .showValue[5])
433                         boolean (.showText$[6], .showValue[6])
434                         boolean (.showText$[7], .showValue[7])
435                         boolean (.showText$[8], .showValue[8])
436                         boolean (.showText$[9], .showValue[9])
437                         boolean (.showText$[10], .showValue[10])
438                         boolean (.showText$[11], .showValue[11])
439                         boolean (.showText$[12], .showValue[12])
440                         boolean (.showText$[13], .showValue[13])
441                         boolean (.showText$[14], .showValue[14])
442                         if .numLessons > 0
443                                 optionMenu: .partText$, 1
444                                         option: "---"
445                                         .j = 0
446                                         for .j to .numLessons
447                                                 option: .lessonName$['.j']
448                                         endfor
449                         endif
450                         optionMenu: .toneText$, 1
451                                 option: "---"
452                                 option: "0"
453                                 option: "1"
454                                 option: "2"
455                                 option: "3"
456                                 option: "4"
457                 clicked = endPause ("'.cancelText$'", "'.clearText$'", "'.allText$'", "'.prevWord$'", "'.nextWord$'", "'.continueText$'", 6, 1)
458                 
459                 select sgc.currentWordlist
460                 if clicked = 2
461                         for .i to sgc.numberOfWords
462                                 Set string value: .i, "Show", "-"
463                         endfor
464                         .allShown = 0
465                 elsif clicked = 3
466                         for .i to sgc.numberOfWords
467                                 Set string value: .i, "Show", "+"
468                         endfor
469                         .allShown = 1
470                 elsif clicked != 1
471                         # Handle added word lists
472                         .wordlistText$ = replace_regex$(.wordlistText$, "^(.)", "\l\1", 0)
473                         .wordlistText$ = replace_regex$(.wordlistText$, "\s", "_", 0)
474                         .tmp$ = '.wordlistText$'$
475                         if .tmp$ <> "---" and sgc.allWordLists > 0
476                                 select sgc.currentWordlist
477                                 # Add current wordlist name as  a lesson name
478                                 .originalWordList = -1
479                                 .numRows = Get number of rows
480                                 for .w to .numRows
481                                         select sgc.currentWordlist
482                                         .currentLesson$ = Get value: .w, "Lesson"
483                                         if .currentLesson$ = "" or .currentLesson$ = "-"
484                                                 Set string value: .w, "Lesson", wordlist$
485                                         endif
486                                 endfor
487                                 
488                                 # Get and merge the selected list
489                                 select sgc.allWordLists
490                                 .wordlistNum = Search column: "Name", .tmp$
491                                 .wordlistPath$ = Get value: .wordlistNum, "Directory"
492                                 .wordlistPath$ = replace_regex$(.wordlistPath$, "[ ]", "&", 0)
493                                 call read_wordlist "'.tmp$'" '.wordlistPath$'
494                                 .newList = read_wordlist.wordlistID
495                                 call merge_into_wordlist '.newList' '.tmp$'
496                                 select .newList
497                                 Remove
498                                 # Add wordlistname to Lesson column
499                                 select sgc.allWordLists
500                                 .numRows = Get number of rows
501                                 if .numRows > 1
502                                         Remove row: .wordlistNum
503                                 else
504                                         Set string value: 1, "Name", "---"
505                                 endif
506                                 # Gather Lesson names
507                                 select sgc.currentWordlist
508                                 Sort rows... Lesson Pinyin
509                                 if .lessonCol > 0
510                                         sgc.numberOfWords = Get number of rows
511                                         .lessonList$ = tab$
512                                         .numLessons = 0
513                                         .lessonName$ = ""
514                                         for .i to sgc.numberOfWords
515                                                 .currentLesson$ = Get value: .i, "Lesson"
516                                                 .matchLesson$ = tab$+.currentLesson$+tab$
517                                                 if .currentLesson$ <> "" and .currentLesson$ <> "-" and .currentLesson$ <> "?" and index(.lessonList$, .matchLesson$) <= 0
518                                                         .lessonList$ = .lessonList$ + .currentLesson$ + tab$
519                                                         .numLessons += 1
520                                                         .lessonName$['.numLessons'] = .currentLesson$
521                                                 endif
522                                                 .shown$ = Get value: .i, "Show"
523                                                 if .shown$ = "-"
524                                                         .allShown = 0
525                                                 endif
526                                         endfor
527                                 endif
528                         else                    
529                                 select sgc.currentWordlist
530                                 # Get selected Part BEFORE we do anything else
531                                 if .numLessons > 0
532                                         .tmp$ = replace_regex$(.partText$, "^(.)", "\l\1", 0)
533                                         .lessonSelected = '.tmp$' - 1
534                                 endif
535                                 if .lessonSelected > 0
536                                         .allShown = 1
537                                         .firstShown = -1
538                                         select sgc.currentWordlist
539                                         for .i to sgc.numberOfWords
540                                                 # Keep track of whether all are shown
541                                                 .shown$ = Get value: .i, "Show"
542                                                 if .shown$ = "-"
543                                                         .allShown = 0
544                                                 endif
545                                         endfor
546                                         for .i to sgc.numberOfWords
547                                                 # Lessons
548                                                 .currentLesson$ = Get value: .i, "Lesson"
549                                                 if .currentLesson$ = .lessonName$['.lessonSelected']
550                                                         Set string value: .i, "Show", "+"
551                                                 elsif .allShown = 1
552                                                         Set string value: .i, "Show", "-"
553                                                 endif
554                                         endfor
555                                         for .i to sgc.numberOfWords
556                                                 # Keep track of whether all are shown
557                                                 .shown$ = Get value: .i, "Show"
558                                                 if .firstShown <=0 and .shown$ <> "-"
559                                                         .firstShown = .i
560                                                 endif
561                                         endfor
562                                 else
563                                         for .i from 0 to .max
564                                                 .tmp$ = replace_regex$(.showVariable$['.i'], "^(.*)$", "\l\1", 0)
565                                                 .showValue['.i'] = '.tmp$'
566                                                 .showWord$['.i'] = "-"
567                                                 if .showValue['.i'] <> 0
568                                                         .showWord$['.i'] = "+"
569                                                 endif
570                                                 Set string value: .currentWord+.i, "Show", .showWord$['.i']
571                                         endfor
572                                 endif
573                         endif
574                         
575                         select sgc.currentWordlist
576                         .tmp$ = replace_regex$(.toneText$, "^(.)", "\l\1", 0)
577                         .toneSelected = '.tmp$' - 2
578                         if .toneSelected >= 0
579                                 select sgc.currentWordlist
580                                 for .i to sgc.numberOfWords
581                                         .currentPinyin$ = Get value: .i, "Pinyin"
582                                         if index_regex(.currentPinyin$, "[0-9]") <= 0
583                                                 call pinyin2numbers '.currentPinyin$'
584                                                 .currentPinyin$ = replace_regex$(pinyin2numbers.intermediatePinyin$, ".+", "\l&", 0)
585                                                 .currentPinyin$ = replace_regex$(.currentPinyin$, "[^a-zA-Z0-9]", "", 0)
586                                         endif
587                                         .tmp$ = Get value: .i, "Show"
588                                         if .tmp$ <> "-" and index(.currentPinyin$, "'.toneSelected'") > 0
589                                                 Set string value: .i, "Show", "+"
590                                         else
591                                                 Set string value: .i, "Show", "-"
592                                                 .allShown = 0
593                                         endif
594                                 endfor
595                         endif
596                         
597                         if clicked = 4
598                                 if .firstShown > 0
599                                         .currentWord = (.firstShown div .numWordsPerScreen) * .numWordsPerScreen + 1
600                                 elsif .toneSelected < 0
601                                         .currentWord -= .numWordsPerScreen
602                                 endif
603                                 if .currentWord <= 0
604                                         .currentWord = (sgc.numberOfWords div .numWordsPerScreen) * .numWordsPerScreen + 1
605                                 endif
606                         elsif clicked = 5
607                                 if .firstShown > 0
608                                         .currentWord = (.firstShown div .numWordsPerScreen) * .numWordsPerScreen + 1
609                                 elsif .toneSelected < 0
610                                         .currentWord += .numWordsPerScreen
611                                 endif
612                                 if .currentWord > sgc.numberOfWords
613                                         .currentWord = 1
614                                 endif
615                         endif
616                 endif
617                 # Reset and go to the first selected word (can shuffle list)
618                 if clicked = 6
619                         sgc.currentWord = -1
620                         call next_word
621                         call init_window
622                 endif
623         endwhile
624         
625     # Implement Cancel
626     if clicked = 1
627                 select sgc.currentWordlist
628                 Remove
629                 select .tmpOriginalWordlist
630                 Copy: wordlist$
631         endif
632         select .tmpOriginalWordlist
633         Remove
634     call Draw_button '.table$' '.label$' 0
635 endproc
637 ###############################################################
639 # Obligatory button Processing Routines
641 # These MUST be defined
643 ###############################################################
645 procedure processMainPageQuit .clickX .clickY .pressed$
646         call end_program
647 endproc
649 procedure processMainPageRefresh .clickX .clickY .pressed$
650         call clean_up_sound
651         call init_window
652 endproc
654 procedure processMainPageConfig .clickX .clickY .pressed$
655         call config_page
656 endproc
658 procedure processMainPageHelp .clickX .clickY .pressed$
659         call help_loop 'buttons$' init_window
660 endproc
662 procedure processMainPagePlay .clickX .clickY .pressed$
663         .table$ = "MainPage"
664         .label$ = "Play"
665         if recordedSound$ <> ""
666                 call play_sound 'sgc.recordedSound'
667                 mainPage.play = 0
668         endif
669         te.buttonPressValue = mainPage.play
670 endproc
672 procedure Set_Play_Button
673         mainPage.play = -1
674         if recordedSound$ <> ""
675                 mainPage.play = 0
676     endif       
677         call Draw_button MainPage Play 'mainPage.play'
678 endproc
680 procedure processMainPageRecord .clickX .clickY .pressed$
681         call count_syllables
682         .recordingTime = recordingTime
683         if count_syllables.number > 2
684                 .recordingTime = recordingTime + 1.0*ceiling((count_syllables.number - 2)/2)
685         endif
686     call record_sound '.recordingTime'
687     call recognizeTone
688         mainPage.play = 0
689         call Set_Play_Button
691     # Wipe screen
692     call wipeArea 'wipeContourArea$'
693    
694     call draw_tone_contour
695     # Write text (again)
696     call display_word_list_name
697     call display_text Black
698         call add_feedback_to_toneevaluation Feedback
699     call write_feedback Feedback
700         select Table Feedback
701         Remove
702         
703         # Do not exercise words that are going well (autoSelect)
704     if add_feedback_to_toneevaluation.result > 0
705                 if config.adaptiveLists > 0 and sgc.failedAttempts < 2
706                         # Deselect current word
707                         select sgc.currentWordlist
708                         .i = Search column: "Pinyin", sgc.pinyin$
709                         if .i > 0
710                                 Set string value: .i, "Show", "-"
711                         endif
712                 endif
713                 sgc.failedAttempts = 0
714     else
715                 sgc.failedAttempts += 1
716     endif
717 endproc
720 ###############################################################
722 # Miscelaneous supporting code
724 ###############################################################
726 # The example
727 procedure generate_example
728         select sgc.currentWordlist
729         if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
730                 select sgc.currentWordlist
731                 .sound$ = Get value... 'sgc.currentWord' Sound
732                 call readPinyin 'sgc.currentWord'
733                 sgc.pinyin$ = readPinyin.pinyin$
734                 if .sound$ = "-" or .sound$ = ""
735                         .sound$ = sgc.pinyin$+".wav"
736                 endif
737                 if index_regex(.sound$, "^(/|~/|[A-Z]:\\)") > 0
738                         .soundFilePath$ = .sound$
739                 else
740                         .soundFilePath$ = localWordlistDir$+"/"+wordlistName$+"/"+.sound$
741                         .wordlistDirectory$ = ""
742                         if localWordlistDir$ <> "" and fileReadable("'localWordlistDir$'/'wordlistName$'")
743                                 .wordlistDirectory$ = "'localWordlistDir$'/'wordlistName$'"
744                         elsif sgc2wordlists$ <> "" and fileReadable("'sgc2wordlists$'/'wordlistName$'")
745                                 .wordlistDirectory$ = "'sgc2wordlists$'/'wordlistName$'"
746                         elsif globalwordlists$ <> "" and fileReadable("'globalwordlists$'/'wordlistName$'")
747                                 .wordlistDirectory$ = "'globalwordlists$'/'wordlistName$'"
748                         endif
749                         if .wordlistDirectory$ <> ""
750                                 .audioExampleList = Create Strings as file list... AudioList '.wordlistDirectory$'/'sgc.pinyin$'.*
751                                 .number_of_examples = Get number of strings
752                                 if .number_of_examples > 0
753                                         Randomize
754                                         .sound$ = Get string... 1
755                                         .soundFilePath$ = "'.wordlistDirectory$'/'.sound$'"
756                                 endif
757                                 Remove
758                         endif
759                 endif
760                 if fileReadable(.soundFilePath$) and config.useSoundExample
761                         .tmp = -1
762                         .tmp = nocheck Read from file... '.soundFilePath$'
763                         if .tmp != undefined and .tmp > 0
764                                 call play_sound '.tmp'
765                                 select .tmp
766                                 Remove
767                         endif
768                 elsif config.synthesis$ <> "" and config.synthesis$ <> "_DISABLED_"
769                         call synthesize_sound 'sgc.pinyin$'
770                 else
771                         call humToneContour 'sgc.pinyin$' 'config.register'
772                         call reset_viewport
773                 endif
774         endif
775         demoShow()
776 endproc
778 # Draw a tone contour
779 procedure draw_tone_contour
780         select sgc.currentWordlist
781         if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
782                 .sound$ = Get value... 'sgc.currentWord' Sound
783                 call readPinyin 'sgc.currentWord'
784                 sgc.pinyin$ = readPinyin.pinyin$
785                 call drawToneContour 'sgc.pinyin$' 'config.register'
786                 call reset_viewport
787                 
788                 if te.recordedPitch > 0
789                         call drawSourceToneContour te.recordedPitch
790                 endif
791         endif
793 endproc
795 procedure recognizeTone
796         select sgc.currentWordlist
797         if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
798                 .strict = 0
799                 if index_regex(config.strict$, "[^0-9]") <= 0
800                         .strict = ('config.strict$' >= sgc.highestLevel)
801                 endif
802                         
803                 .sound$ = Get value... 'sgc.currentWord' Sound
804                 call readPinyin 'sgc.currentWord'
805                 sgc.pinyin$ = readPinyin.pinyin$
806                 call align_recordedSound 'sgc.pinyin$'
807         call sgc_ToneProt 'recordedSound$' 'sgc.pinyin$' 'config.register' '.strict' 'config.language$'
808         # sgc_ToneProt manipulates the sound given. Reconnect
809         select Sound 'recordedSound$'
810         sgc.recordedSound = selected("Sound")
811                 call reset_viewport
812         endif
813 endproc
815 procedure write_feedback .table$
816     select Table '.table$'
817     .line1$ = Get value... 1 Text
818     .line2$ = Get value... 2 Text
819     .label$ = Get value... 3 Text
821         # convert numbers to Pinyin if needed
822         if not config.displayNumbers
823                 call numbers2pinyin '.line1$'
824                 .line1$ = numbers2pinyin.pinyin$
825         endif
827     .color$ = "Red"
828     if index(.line1$, "???") > 0
829         .color$ = "Black"
830     elsif .label$ = "Correct"
831         .color$ = "Green"
832         elsif config.strict$ = "'sgc.highestLevel'"
833                 .line2$ = .line2$ + " *"
834     endif
836         .currentFeedbackFontSize = 14
837         .maxHeight = 21 - 17
838         call adjustFontSizeOnHeight 'defaultFont$' '.currentFeedbackFontSize' '.maxHeight'
839         .currentFeedbackFontSize = adjustFontSizeOnHeight.newFontSize
840         
841         call wipeArea 'wipeFeedbackArea$'
842     call set_font_size '.currentFeedbackFontSize'
843     demo '.color$'
844     demo Text... 50 Centre 21 Bottom '.line1$'
845     demo Text... 50 Centre 17 Bottom '.line2$'
846         demoShow()
847         demo 'defaultFont$'
848     call set_font_size 'defaultFontSize'
849 endproc
851 # Text display
852 procedure display_text .color$
853         select sgc.currentWordlist
854         if sgc.currentWord < 0 or sgc.currentWord > sgc.numberOfWords+1
855                 call clean_up_sound
856         if config.shuffleLists
857                     Randomize rows
858         endif
859                 if sgc.currentWord < 0
860                         sgc.currentWord = sgc.numberOfWords
861                 else
862                         sgc.currentWord = 1
863                 endif
864         endif
865         
866         .changeCJKstyle = 0
867         if sgc.currentWord > 0 and sgc.currentWord <= sgc.numberOfWords
868                 .displayText$ = ""
869                 call readDisplayPinyin 'sgc.currentWord'
870                 .displayPinyin$ = readDisplayPinyin.pinyin$
871                 .displayChar$ = Get value... 'sgc.currentWord' Character
872                 .displayTrans$ = Get value... 'sgc.currentWord' Translation
873                 if .displayPinyin$ <> "-" and (config.displayPinyin or sgc.writeAll)
874                         if not config.displayNumbers
875                                 call numbers2pinyin '.displayPinyin$'
876                                 .displayPinyin$ = numbers2pinyin.pinyin$
877                         endif
878                         # Insert u umlaut
879                         .displayPinyin$ = replace_regex$(.displayPinyin$, "v", "\\u\X22", 0)
880                         .displayText$ = .displayText$ + .displayPinyin$
881                 endif
882                 if .displayChar$ <> "-" and (config.displayChar or sgc.writeAll)
883                         .displayText$ = .displayText$ + "  "+ .displayChar$
884                         .changeCJKstyle = 1
885                 endif
886                 if .displayTrans$ <> "-" and (config.displayTrans or sgc.writeAll)
887                         .displayText$ = .displayText$ + "  \s{%%"+ .displayTrans$ + "%}"
888                 endif
889         elsif sgc.currentWord = 0 or sgc.currentWord = sgc.numberOfWords+1
890                 call clean_up_sound
891                 .displayText$ = "---"
892         endif
894         # Adapt font size
895         call adjustFontSizeOnHeight 'defaultFont$' 24 15
896         .currentFontSize = adjustFontSizeOnHeight.newFontSize
897         call adjustFontSizeOnWidth 'defaultFont$' '.currentFontSize' 95 '.displayText$'
898         .currentFontSize = adjustFontSizeOnWidth.newFontSize
900         # Clear the writing area
901         call wipeArea 'wipePinyinArea$'
902         # Switch back to Chinese style CJK when in Japanese language mode
903         if .changeCJKstyle and config.language$ = "JA"
904                 CJK font style preferences: "Chinese"
905         endif
906         # Actually display text
907         demo '.color$'
908         call set_font_size '.currentFontSize'
909         demo Text... 50 Centre 26 Bottom '.displayText$'
910         demoShow()
911         demo Black
912         demo 'defaultFont$'
913         call set_font_size 'defaultFontSize'
914         if .changeCJKstyle and config.language$ = "JA"
915                 if config.language$ = "JA"
916                         CJK font style preferences: "Japanese"
917                 elsif config.language$ = "ZH"
918                         CJK font style preferences: "Chinese"
919                 endif
920         endif
921         # Switch back to Japanese style CJK when in Japanese language mode
922         if .changeCJKstyle and config.language$ = "JA"
923                 CJK font style preferences: "Japanese"
924         endif
925 endproc
927 procedure numbers2pinyin .numberstext$
928         .intermediatePinyin$ = .numberstext$
929         # Add a `-quote between vowels
930         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])([aeuiov])", "\1\2'\3", 0)
931         # Move numbers to the nucleus vowel
932         # To the vowel
933         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([^aeuiov0-9]*)([0-9])", "\1\3\2", 0)
934         # Either a/e
935         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([ae])([aeuiov]*)([0-9])", "\1\3\2", 0)
936         # Or the Oo in /ou/
937         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(ou)([0-9])", "o\2u", 0)
938         # or the second vowel
939         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([uiov][aeuiov])([uiov])([0-9])", "\1\3\2", 0)
940         
941         # Convert all tones to special characters
942         # Tone 1
943         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a1", "ā", 0)
944         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e1", "ē", 0)
945         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u1", "ū", 0)
946         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i1", "ī", 0)
947         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o1", "ō", 0)
948         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v1", "ǖ", 0)
949         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "1", "\\-^", 0)
950         
951         # Tone 2
952         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v2", "ǘ", 0)
953         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])2", "\\\1'", 0)
954         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "2", "\\'^", 0)
955         
956         # Tone 3
957         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a3", "ǎ", 0)
958         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e3", "ě", 0)
959         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u3", "ǔ", 0)
960         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i3", "ǐ", 0)
961         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o3", "ǒ", 0)
962         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v3", "ǚ", 0)
963         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "3", "\\N^", 0)
965         # Tone 4
966         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v4", "ǜ", 0)
967         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([iaeou])4", "\\\1`", 0)
968         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "4", "\\`^", 0)
969         
970         # Tone 0
971         # Remove tone 0 symbol completely
972         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "", 0)
973         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "a0", "å", 0)
974         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e0", "e̊", 0)
975         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "u0", "ů", 0)
976         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i0", "i̊", 0)
977         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o0", "o̊", 0)
978         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v0", "ü̊", 0)
979         #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "0", "\\0^", 0)
980         
981         # Pick best vowel symbols available in cases not caught before
982         # Ugly clutch to get the 1, 3, 0 tone diacritics at least in the neighbourhood
983         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i(\\[-N0]\^)", "i\\s{_ }\1", 0)
984         # Insert u umlaut
985         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "v", "\\u\X22", 0)
987         .pinyin$ = .intermediatePinyin$
988 endproc
990 # NEEDS WORK AND TESTING!!
991 # Convert unicode Pinyin into tone numbers
992 procedure pinyin2numbers .pinyin$
993         .intermediatePinyin$ = .pinyin$
994         # Convert all special characters to numbers
995         # Tone 1
996         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iā)([iaeouü]*)", "a\11", 0)
997         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iē)([iaeouü]*)", "e\11", 0)
998         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iū)([iaeouü]*)", "u\11", 0)
999         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iī)([iaeouü]*)", "i\11", 0)
1000         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iō)([iaeouü]*)", "o\11", 0)
1001         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǖ)([iaeouü]*)", "v\11", 0)
1002         
1003         # Tone 2
1004         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iá)([iaeouü]*)", "a\12", 0)
1005         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ié)([iaeouü]*)", "e\12", 0)
1006         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iú)([iaeouü]*)", "u\12", 0)
1007         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ií)([iaeouü]*)", "i\12", 0)
1008         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ió)([iaeouü]*)", "o\12", 0)
1009         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǘ)([iaeouü]*)", "v\12", 0)
1010         
1011         # Tone 3
1012         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǎ)([iaeouü]*)", "a\13", 0)
1013         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iě)([iaeouü]*)", "e\13", 0)
1014         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǔ)([iaeouü]*)", "u\13", 0)
1015         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǐ)([iaeouü]*)", "i\13", 0)
1016         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǒ)([iaeouü]*)", "o\13", 0)
1017         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǚ)([iaeouü]*)", "v\13", 0)
1019         # Tone 4
1020         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?ià)([iaeouü]*)", "a\14", 0)
1021         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iè)([iaeouü]*)", "e\14", 0)
1022         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iù)([iaeouü]*)", "u\14", 0)
1023         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iì)([iaeouü]*)", "i\14", 0)
1024         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iò)([iaeouü]*)", "o\14", 0)
1025         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iǜ)([iaeouü]*)", "v\14", 0)
1026         
1027         # Tone 0
1028         # Add tone 0
1029         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iå)([iaeouü]*)", "a\10", 0)
1030         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "e̊([iaeouü]*)", "e\10", 0)
1031         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "(?iů)([iaeouü]*)", "u\10", 0)
1032         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "i̊([iaeouü]*)", "i\10", 0)
1033         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "o̊([iaeouü]*)", "o\10", 0)
1034         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "ü̊([iaeouü]*)", "v\10", 0)
1036         # Syllables without a tone symbol are tone 0
1037         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov]+)([^0-9aeuiov]|\W|$)", "\10\2", 0)
1039         # Move numbers to the end of the syllable.
1040         # Syllables ending in n and start with g. Note that a syllable cannot start with an u or i
1041         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(n)(g[aeuiov])", "\1\3\2\4", 0)
1042         # Syllables ending in (ng?) followed by something that is not a valid vowel 
1043         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(ng?)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
1044         # Syllables ending in r
1045         .intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "([aeuiov])([0-9])(r)([^aeuiov]|\W|$)", "\1\3\2\4", 0)
1046         # Remove quotes etc
1047         #.intermediatePinyin$ = replace_regex$(.intermediatePinyin$, "[\\'\\`]", "", 0)
1048         
1049         .numberstext$ = .intermediatePinyin$
1050 endproc
1052 procedure readDisplayPinyin .currentWord
1053         select sgc.currentWordlist
1054         .pinyin$ = Get value... '.currentWord' Pinyin
1055         # Everything to lowercase
1057         if index_regex(.pinyin$, "[0-9]") <= 0
1058                 call pinyin2numbers '.pinyin$'
1059                 .pinyin$ = pinyin2numbers.numberstext$
1060         endif 
1061 endproc
1063 procedure readPinyin .currentWord
1064         call readDisplayPinyin '.currentWord'
1065         .pinyin$ = replace_regex$(readDisplayPinyin.pinyin$, ".+", "\L&", 0)
1066         .pinyin$ = replace_regex$(.pinyin$, "[\\'\\` ]", "", 0)
1067 endproc
1069 # Includes
1070 include ToneProt/SGC_ToneProt.praat
1071 include ToneProt/DrawToneContour.praat
1072 include ToneProt/HumToneContour.praat
1073 include ToneProt/ToneRecognition.praat
1074 include ToneProt/ToneScript.praat
1075 include ToneProt/ToneRules.praat