Fully implemented wordlist support, including legacy
[sgc2.git] / sgc2.praat
blob437c951e08177929928fb747482b35e6f10d7002
2 # SpeakGoodChinese 2.0
3
4 # Master Praat script
6 #     SpeakGoodChinese: sgc2.praat is the master GUI of SpeakGoodChinese
7 #     It is written in Praat script for the Demo window 
8 #     
9 #     Copyright (C) 2007-2010  R.J.J.H. van Son
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 include ToneProt/ToneRecognition.praat
30 demo Select outer viewport... 0 100 0 100
31 demo Axes... 0 100 0 100
33 # Initialize parameters
34 currentWord = 1
35 pinyin$ = ""
36 character$ = ""
37 sampleSound$ = ""
38 buttons$ = ""
39 config$ = ""
40 wordlistNum = 1
41 wordlistName$ = ""
42 wordlist$ = ""
43 wordlistDir$ = "wordlists"
44 displayPinyin = 1
45 displayChar = 1
46 useSoundExample = 1
48 language$ = "EN"
49 register = 180
50 precision = 3
51 logPerformance = 0
52 logDir$ = "'preferencesDirectory$'/log"
53 sgc2wordlists$ = "'preferencesDirectory$'/sgc2/wordlists"
54 shuffleLists = 1
55 defaultFontSize = 10
56 defaultFont$ = "Helvetica"
57 defaultLineWidth = 1
59 call set_up_directories
60 call read_preferences ""
62 # Set inital language
63 call set_language 'language$'
64 # Get the word-list
65 call load_word_list "'wordlistDir$'" "'preferencesDirectory$'/sgc2/wordlists" 0
66 # Draw inital window
67 call init_window
69 while demoWaitForInput()
70         .label$ = ""
71         if demoClicked()
72                 .clickX = demoX()
73                 .clickY = demoY()
74                 call buttonClicked 'buttons$' '.clickX' '.clickY'
75                 .label$ = buttonClicked.label$
76         elsif demoKeyPressed()
77                 .pressed$ = demoKey$()
78                 call keyPressed 'buttons$' '.pressed$'
79                 .label$ = keyPressed.label$
80         endif
81         
82         # Do things
83         if .label$ != ""
84                 # Push button down
85                 call Draw_button 'buttons$' '.label$' 1
86                 call process_label '.label$'
87                 # push button up
88                 call Draw_button 'buttons$' '.label$' 0
89         endif
90 endwhile
92 call end_program
95 ########################################################
96
97 # Definitions of procedures
98
99 ########################################################
101 # Do what is asked
102 procedure process_label .label$
103         if .label$ = "Quit"
104                 call end_program
105         elsif .label$ = "Config"
106                 call config_page
107         elsif .label$ = "Refresh"
108                 call init_window
109         elsif .label$ = "Record"
110         call record_sound
111         call recognizeTone
112         call write_feedback Feedback
113         elsif .label$ = "Play"
114         call play_sound 'sampleSound$'
115         elsif .label$ = "Example"
116                 call generate_example
117         elsif .label$ = "Previous"
118                 call display_text Grey
119                 currentWord -= 1
120                 call display_text Black
121                 # Draw the contour
122                 call draw_tone_contour
123         elsif .label$ = "Next"
124                 call display_text Grey
125                 currentWord += 1
126                 call display_text Black
127                 # Draw the contour
128                 call draw_tone_contour
129         elsif .label$ = "Wordlist"
130         call load_word_list "'wordlistDir$'" "'preferencesDirectory$'/sgc2/wordlists" 1
131                 call write_word_list
132         endif
133 endproc
137 # Initialize Demo Window
138 procedure init_window
139     demo Erase all
140     demoWindowTitle("Speak Good Chinese: Practice your tones")
141         demo Line width... 'defaultLineWidth'
142         demo 'defaultFont$'
143         demo 'defaultFontSize'
144         demo Black
145     demo Select outer viewport... 0 100 0 100
146     demo Axes... 0 100 0 100
147     # Define buttons in a table
148     call init_buttons
149         # Display the word-list
150         call write_word_list
151 endproc
153 # Intialize buttons
154 procedure init_buttons
155         call Draw_all_buttons 'buttons$'
156 endproc
158 # Draw all buttons
159 procedure Draw_all_buttons .table$
160         select Table '.table$'
161         .numRows = Get number of rows
162         
163         for .row to .numRows
164                 .label$ = Get value... '.row' Label
165                 call Draw_button '.table$' '.label$' 0
166         endfor
167 endproc
169 # Draw a button from a predefined button table
170 procedure Draw_button .table$ .label$ .push
171     select Table '.table$'
172     .row = Search column... Label '.label$'
173         if .row < 1
174                 exit Button Table '.table$' does not have a row with label '.label$'
175         endif
176         .buttonBackGround$ = "{0.97,0.97,0.97}"
177         .buttonShift$ = "Black"
179     .leftX = Get value... '.row' LeftX
180     .rightX = Get value... '.row' RightX
181     .lowY = Get value... '.row' LowY
182     .highY = Get value... '.row' HighY
183         # Reset and erase button area
184     demo Select outer viewport... 0 100 0 100
185     demo Axes... 0 100 0 100
186     demo Line width... 'defaultLineWidth'
187         demo Paint rectangle... White .leftX .rightX .lowY .highY
188         
189     # Give some depth to button: Draw outline
190     .shiftX = -0.10
191     .shiftY = -0.20
192     .shiftLeftX = .leftX + .shiftX
193     .shiftRightX = .rightX + .shiftX
194     .shiftLowY = .lowY + .shiftY
195     .shiftHighY = .highY + .shiftY
196         demo Black
197     demo Draw rounded rectangle... .shiftLeftX .shiftRightX .shiftLowY .shiftHighY 3
198         
199     .buttonText$ = Get value... '.row' Text
200     .buttonColor$ = Get value... '.row' Color
201     .buttonDraw$ = Get value... '.row' Draw
202     .buttonKey$ = Get value... '.row' Key
203         .newText$ = replace_regex$(.buttonText$, "['.buttonKey$']", "#%&", 1)
204         if .newText$ = ""
205                 .newText$ = .buttonText$
206         endif
207         if .push > 0
208                 .buttonBackGround$ = "{0.92,0.92,0.92}"
209                 .buttonShift$ = "{0.98,0.98,0.98}"
210         endif
211         if .push = 1
212                 demo Grey
213                 if .buttonColor$ = "Red"
214                         .buttonColor$ = "Pink"
215                 else
216                         .buttonColor$ = "Grey"
217                 endif
218     elsif .push = 2
219         .buttonColor$ = "Maroon"
220         else
221         demo Black
222         endif
223     
224     # Give some depth to button
225     demo Paint rounded rectangle... '.buttonShift$' .shiftLeftX .shiftRightX .shiftLowY .shiftHighY 3
226     demo Paint rounded rectangle... '.buttonBackGround$' .leftX .rightX .lowY .highY 3
227    
228     # The real button
229     demo Draw rounded rectangle... .leftX .rightX .lowY .highY 3
230     .centerX = (.leftX + .rightX)/2
231     .centerY = (.lowY + .highY)/2
232     .radius = (.highY - .lowY )/4
233     demo '.buttonColor$'
234     demo Text... '.centerX' Centre '.lowY' Bottom '.newText$'
235     .centerY += 1
236     call '.buttonDraw$' '.buttonColor$' '.centerX' '.centerY' '.radius' 
237     demo Black
238         demoShow()
239 endproc
241 # Text display
242 procedure display_text .color$
243         select Table 'wordlist$'
244         if currentWord < 0 or currentWord > numberOfWords+1
245         if shuffleLists
246                     Randomize rows
247         endif
248                 if currentWord < 0
249                         currentWord = numberOfWords
250                 else
251                         currentWord = 1
252                 endif
253         endif
254         
255         if currentWord > 0 and currentWord <= numberOfWords
256                 .displayText$ = ""
257                 .displayPinyin$ = Get value... 'currentWord' Pinyin
258                 .displayChar$ = Get value... 'currentWord' Character
259                 if .displayPinyin$ <> "-" and displayPinyin
260                         .displayText$ = .displayText$ + .displayPinyin$
261                 endif
262                 if .displayChar$ <> "-" and displayChar
263                         .displayText$ = .displayText$ + " "+ .displayChar$
264                 endif
265         elsif currentWord = 0 or currentWord = numberOfWords+1
266                 .displayText$ = "---"
267         endif
268         demo Paint rectangle... White 20 80 25 40
269     demo Paint rectangle... White 10 90 19 30
270         demo '.color$'
271         demo Font size... 24
272         demo Text... 50 Centre 25 Bottom '.displayText$'
273         demo Black
274         demo 'defaultFont$'
275         demo 'defaultFontSize'
276         demoShow()
277 endproc
279 # The example
280 procedure generate_example
281         select Table 'wordlist$'
282         if currentWord > 0 and currentWord <= numberOfWords
283                 select Table 'wordlist$'
284                 .sound$ = Get value... 'currentWord' Sound
285                 .pinyin$ = Get value... 'currentWord' Pinyin
286                 .soundFilePath$ = wordlistDir$+"/"+wordlistName$+"/"+.sound$
287                 if fileReadable("'sgc2wordlists$'/'wordlistName$'/'.sound$'")
288                         .soundFilePath$ = "'sgc2wordlists$'/'wordlistName$'/'.sound$'"
289                 endif
290                 if fileReadable(.soundFilePath$) and useSoundExample
291                         Read from file... '.soundFilePath$'
292                         Play
293                         Remove
294                 else
295                         execute "ToneProt/HumToneContour.praat" '.pinyin$' 'register'
296                 endif
297         endif
298         demoShow()
299 endproc
302 ###############################################################
304 # Button Drawing Routines
306 ###############################################################
308 # A stub for buttons that do not have a drawing routine (yet)
309 procedure DrawNull .color$ .x .y .size
310 endproc
312 procedure DrawRecord .color$ .x .y .size
313         .size /= 2
314     demo Paint circle... '.color$' '.x' '.y' '.size'
315 endproc
317 procedure DrawPlay .color$ .x .y .size
318         demo '.color$'
319         call drawTriangle 1 .x .y .size
320 endproc
322 procedure DrawPrevious .color$ .x .y .size
323         demo '.color$'
324         .size *= 2/3
325         call drawTriangle -1 .x .y .size
326         .currentX = drawTriangle.currentX
327         .endX = .currentX - 0.5
328         .lowY = .y - .size
329         .highY = .y + .size
330         demo Paint rectangle... '.color$' '.currentX' '.endX' '.lowY' '.highY'
331 endproc
333 procedure DrawNext .color$ .x .y .size
334         demo '.color$'
335         .size *= 2/3
336         call drawTriangle 1 .x .y .size
337         .currentX = drawTriangle.currentX
338         .endX = .currentX + 0.5
339         .lowY = .y - .size
340         .highY = .y + .size
341         demo Paint rectangle... '.color$' '.currentX' '.endX' '.lowY' '.highY'
342 endproc
344 procedure DrawQuit .color$ .x .y .size
345         demo Line width... 4.0
346         .xstart = .x - .size
347         .ystart = .y + .size
348         .xend = .x + .size
349         .yend = .y - .size
350         demo Draw line... .xstart .ystart .xend .yend
351         .xstart = .x - .size
352         .ystart = .y - .size
353         .xend = .x + .size
354         .yend = .y + .size
355         demo Draw line... .xstart .ystart .xend .yend
356         demo Line width... 'defaultLineWidth'
357 endproc
359 procedure DrawConfig .color$ .x .y .size
360         .size *= 1
361         demo Line width... 3.0
362         .xstart = .x - .size
363         .xend = .x + .size
364         demo Draw arrow... .xstart .y .xend .y
365         demo Line width... 'defaultLineWidth'
366 endproc
368 procedure DrawRefresh .color$ .x .y .size
369         .size /= 2
370         demo Line width... 4.0
371         demo Draw arc... '.x' '.y' '.size' 0 270
372         demo Line width... 'defaultLineWidth'
373 endproc
375 procedure DrawWordList .color$ .x .y .size
376     .xleft = .x - .size
377     .xright = .x + .size
378     .xmidleft = .x + 0.1
379     .xmidright = .x - 0.1
380     .yhigh = .y + .size
381     .yhigh = .y + .size
382         demo '.color$'
383         demo Line width... 3
384         demo Draw line... .xleft .yhigh .xmidleft .y
385         demo Draw line... .xright .yhigh .xmidright .y
386         demo Line width... 'defaultLineWidth'
387         demo Black
388 endproc
390 procedure drawTriangle .direction .x .y .size
391         # Make sure direction = +/- 1
392         if .direction = 0
393                 .direction = 1 
394         endif
395         .direction /= abs(.direction)
396         
397         .offset = 0.01
398         .currentHeight = .size
399         .currentX = .x - .direction*.size
400         
401         demo Line width... 2.0
403         while .currentHeight> 0
404                 .ystart = .y + .currentHeight
405                 .yend = .y - .currentHeight
406                 demo Draw line... .currentX .ystart .currentX .yend
407                 .currentHeight -= .offset *3/4
408                 .currentX += .direction*.offset * 1.5
409         endwhile
410         demo Line width... 'defaultLineWidth'
411 endproc
413 ###############################################################
415 # Button Processing Routines
417 ###############################################################
419 # Search row in table on label
420 procedure findLabel .table$ .label$
421         .row = 0
422         select Table '.table$'
423         .to$ = selected$("Table")
424         .to$ = "Table_"+.to$
425         .numRows = Get number of rows
426         for .i to .numRows
427                 .currentKey$ = '.to$'$[.i, "Key"]
428                 if .label$ = .currentKey$
429                         .row = .i
430                         goto FOUND
431                 endif
432         endfor
433         label FOUND
434 endproc
436 # Get the label
437 procedure buttonClicked table$ .x .y
438         .label$ = ""
439         select Table 'table$'
440         .bo$ = selected$("Table")
441         .bo$ = "Table_"+.bo$
442         .numRows = Get number of rows
443         for .i to .numRows
444                 if .label$ = ""
445                         .leftX = '.bo$'[.i, "LeftX"]
446                         .rightX = '.bo$'[.i, "RightX"]
447                         .lowY = '.bo$'[.i, "LowY"]
448                         .highY = '.bo$'[.i, "HighY"]
449                         if .x > .leftX and .x < .rightX and .y > .lowY and .y < .highY
450                                 .label$ = '.bo$'$[.i, "Label"]
451                         endif
452                 endif
453         endfor
454 endproc
456 procedure keyPressed table$ .pressed$
457         .label$ = ""
458         .lowerPressed$ = replace_regex$(.pressed$, ".", "\L&", 0)
459         .upperPressed$ = replace_regex$(.pressed$, ".", "\U&", 0)
460         select Table 'table$'
461         .bo$ = selected$("Table")
462         .bo$ = "Table_"+.bo$
463         .numRows = Get number of rows
464         for .i to .numRows
465                 if .label$ = ""
466                         .key$ = '.bo$'$[.i, "Key"]
467                         if .key$ = .lowerPressed$ or .key$ = .upperPressed$
468                                 .label$ = '.bo$'$[.i, "Label"]
469                         endif
470                 endif
471         endfor
472 endproc
474 procedure record_sound
475     if sampleSound$ != ""
476         select Sound 'sampleSound$'
477         Remove
478         sampleSound$ = ""
479     endif
480         # Recording light
481     demo Paint rectangle... White 10 90 15 25
482     demo Paint circle... Red 5 85 2.5
483     demoShow()
484     nowarn Record Sound (fixed time)... Microphone 0.99 1 44100 4
485     demo Paint circle... White 5 85 3
486     demoShow()
487     Rename... Tmp
488     Resample... 10000 50
489     Rename... Source
490     sampleSound$ = selected$("Sound")
491     select Sound Tmp
492     Remove
493     select Sound 'sampleSound$'
494 endproc
496 # Draw a tone contour
497 procedure draw_tone_contour
498     # Wipe screen
499     demo Select inner viewport... 0 100 0 100
500     demo Paint rectangle... White 20 80 40 100
501     demo Select outer viewport... 0 100 0 100
502     demo Paint rectangle... White 20 80 40 100
503     demo Paint rectangle... White 0 100 16 26
504         select Table 'wordlist$'
505         if currentWord > 0 and currentWord <= numberOfWords
506                 .sound$ = Get value... 'currentWord' Sound
507                 .pinyin$ = Get value... 'currentWord' Pinyin
508                 execute "ToneProt/DrawToneContour.praat" '.pinyin$' 'register'
509         endif   
510 endproc
512 procedure recognizeTone
513         select Table 'wordlist$'
514         if currentWord > 0 and currentWord <= numberOfWords
515                 .sound$ = Get value... 'currentWord' Sound
516                 .pinyin$ = Get value... 'currentWord' Pinyin
517         execute "ToneProt/SGC_ToneProt.praat" 'sampleSound$' '.pinyin$' 'register' 'precision' Pictures 'language$'
518         endif
519 endproc
521 procedure write_feedback .table$
522     select Table '.table$'
523     .line1$ = Get value... 1 Text
524     .line2$ = Get value... 2 Text
525     .label$ = Get value... 3 Text
527     .color$ = "Red"
528     if index(.line1$, "???") > 0
529         .color$ = "Black"
530     elsif .label$ = "Correct"
531         .color$ = "Green"
532     endif
534     demo 14
535     demo '.color$'
536     demo Paint rectangle... White 0 100 16 26
537     demo Text... 50 Centre 21 Bottom '.line1$'
538     demo Text... 50 Centre 17 Bottom '.line2$'
539         demo 'defaultFont$'
540     demo 'defaultFontSize'
541         demoShow()
542     
543         # Log performance
544         .splitIndex = index(.line1$, ": ")
545         .pinyin$ = left$(.line1$, (.splitIndex - 1))
546         .choice$ = right$(.line1$, (length(.line1$) - .splitIndex - 1))
547         call log_performance 'sampleSound$' 'register' 'precision' '.pinyin$' '.choice$'
548 endproc
550 procedure play_sound .sound$
551     if .sound$ <> ""
552         select Sound '.sound$'
553         Play
554     endif
555 endproc
557 procedure end_program
558         call write_preferences "" 
559         demo Erase all
560         select all
561         Remove
562         exit
563 endproc
565 ######################################################
567 # Configuration Page
569 ######################################################
570 procedure config_page
571     demo Erase all
572     demoWindowTitle("Speak Good Chinese: Change settings")
573     .label$ = ""
574     call Draw_config_page
575     
576     while (.label$ <> "Return") and demoWaitForInput() 
577             .label$ = ""
578             if demoClicked()
579                     .clickX = demoX()
580                     .clickY = demoY()
581                     call buttonClicked 'config$' '.clickX' '.clickY'
582                     .label$ = buttonClicked.label$
583             elsif demoKeyPressed()
584                     .pressed$ = demoKey$()
585                     call keyPressed 'config$' '.pressed$'
586                     .label$ = keyPressed.label$
587             endif
589             # Do things
590             if .label$ != ""
591                     # Handle push button in process_config
592                     call process_config '.label$'
593             endif
594         
595         if .label$ = "Return"
596             goto GOBACK
597         endif
598     endwhile
600     # Go back
601     label GOBACK
602     call init_window
603 endproc
605 procedure Draw_config_page
606     call Draw_all_buttons 'config$'
607     # Set correct buttons (alert)
608     call Draw_button 'config$' Lang'language$' 2
609     call Draw_button 'config$' Register_'register' 2
610         if displayPinyin
611         call Draw_button 'config$' DisplayPinyin 2
612         endif
613         if displayChar
614         call Draw_button 'config$' DisplayChar 2
615         endif
616         if shuffleLists
617         call Draw_button 'config$' Shuffle 2
618         endif
619         if useSoundExample
620         call Draw_button 'config$' SndExample 2
621         endif
622 endproc
624 # Draw symbols
625 procedure DrawReturn .color$ .x .y .size
626     .xleft = .x - .size
627     .xright = .x + .size
628         demo Line width... 4.0
629         demo Draw arrow... '.xleft' '.y' '.xright' '.y'
630         demo Line width... 'defaultLineWidth'
631         demoShow()
632 endproc
635 # Do what is asked
636 procedure process_config .label$
637         if .label$ = "Return"
638         call Draw_button 'config$' '.label$' 1
639                 call write_preferences ""
640         elsif .label$ = "Shuffle"
641                 shuffleLists = not shuffleLists
642                 .displayButton = 2*shuffleLists
643         call Draw_button 'config$' '.label$' '.displayButton'
644         elsif .label$ = "SndExample"
645                 useSoundExample = not useSoundExample
646                 .displayButton = 2*useSoundExample
647         call Draw_button 'config$' '.label$' '.displayButton'
648         elsif startsWith(.label$, "Lang")
649         call Draw_button 'config$' Lang'language$' 0
650         call Draw_button 'config$' '.label$' 2
651         # Someone might have to use more than 2 chars for the language code
652         .numChars = length(.label$) - length("Lang")
653                 .lang$ = right$(.label$, .numChars)
654         # Load new tables
655         call set_language '.lang$'
656         elsif startsWith(.label$, "Register_")
657         call Draw_button 'config$' Register_'register' 0
658         call Draw_button 'config$' '.label$' 2
659         # Someone might have to use more than 3 chars for the register code
660         .numChars = length(.label$) - length("Register_")
661                 .registerText$ = right$(.label$, .numChars)
662                 register = '.registerText$'
663         elsif startsWith(.label$, "Display")
664                 .displayButton = 0
665                 if .label$ = "DisplayPinyin"
666                         displayPinyin = not displayPinyin
667                         .displayButton = 2*displayPinyin
668                 endif
669                 if .label$ = "DisplayChar"
670                         displayChar = not displayChar
671                         .displayButton = 2*displayChar
672                 endif
673         call Draw_button 'config$' '.label$' '.displayButton'
674         endif
675 endproc
677 procedure set_language .lang$
678         .redraw_config = 0
679     # Remove old tables
680     if buttons$ <> ""
681         select Table 'buttons$'
682         Remove
683                 .redraw_config = 1
684     endif
685     if config$ <> ""
686         select Table 'config$'
687         Remove
688                 .redraw_config = 1
689     endif
690     
691     # Set languege
692     language$ = .lang$
693     
694     # Load buttons tables
695     Read from file... Data/Buttons.Table
696     buttons$ = selected$("Table")
697     Append column... Text
698     Append column... Key
699     .numLabels = Get number of rows
700     Read from file... Data/Buttons_'language$'.Table
701     .buttonsLang$ = selected$("Table")
702     for .row to .numLabels
703         select Table '.buttonsLang$'
704         .valueText$ = Get value... '.row' Text
705         .valueKey$ = Get value... '.row' Key
706         select Table 'buttons$'
707         Set string value... '.row' Text '.valueText$'
708         Set string value... '.row' Key '.valueKey$'
709     endfor
710     select Table '.buttonsLang$'
711     Remove
712     
713     # Load configuration table
714     Read from file... Data/Config.Table
715     config$ = selected$("Table")
716     Append column... Text
717     Append column... Key
718     .numLabels = Get number of rows
719     Read from file... Data/Config_'language$'.Table
720     .configLang$ = selected$("Table")
721     for .row to .numLabels
722         select Table '.configLang$'
723         .valueText$ = Get value... '.row' Text
724         .valueKey$ = Get value... '.row' Key
725         select Table 'config$'
726         Set string value... '.row' Text '.valueText$'
727         Set string value... '.row' Key '.valueKey$'
728     endfor
729     select Table '.configLang$'
730     Remove
732         # Make language change visible
733         if .redraw_config
734                 call Draw_config_page
735         endif
737 endproc
739 procedure load_word_list .dir1$ .dir2$ .relnumber
740     # Remove old word list
741     if wordlist$ <> ""
742         select Table 'wordlist$'
743         Remove
744     endif
745     
746     Create Strings as directory list... WordList1 '.dir1$'
747         Copy... DirWordList1
748     .numLists = Get number of strings
749     for .i to .numLists
750         select Strings WordList1
751         .currentName$ = Get string... '.i'
752                 .currentName$ = .dir1$+"/"+.currentName$
753                 select Strings DirWordList1
754                 Set string... '.i' '.currentName$'
755     endfor
757     Create Strings as directory list... WordList2 '.dir2$'
758     .numLists = Get number of strings
759         if .numLists > 0
760                 Copy... DirWordList2
761         for .i to .numLists
762                 select Strings WordList2
763                 .currentName$ = Get string... '.i'
764                         .currentName$ = .dir2$+"/"+.currentName$
765                         select Strings DirWordList2
766                         Set string... '.i' '.currentName$'
767         endfor
769                 select Strings WordList1
770                 plus Strings WordList2
771                 Append
772                 Rename... WordList
773                 select Strings WordList1
774                 plus Strings WordList2
775                 Remove
777                 select Strings DirWordList1
778                 plus Strings DirWordList2
779                 Append
780                 Rename... DirWordList
781                 select Strings DirWordList1
782                 plus Strings DirWordList2
783                 Remove
784         else
785                 select Strings WordList2
786                 Remove
787                 select Strings WordList1
788                 Rename... WordList
789                 select Strings DirWordList1
790                 Rename... DirWordList
791         endif
792         
793         # Get the position of the current word list
794         select Strings WordList
795         .currentNumber = 1
796     .numLists = Get number of strings
797         if wordlistName$ <> ""
798                 for .i to .numLists
799                 select Strings WordList
800                 .currentName$ = Get string... '.i'
801                         if .currentName$ = wordlistName$
802                                 .currentNumber = .i
803                         endif
804                 endfor
805         endif
806     wordlistNum = .currentNumber + .relnumber
807     if wordlistNum > .numLists
808         wordlistNum = 1
809     endif
810     select Strings WordList
811     wordlistName$ = Get string... 'wordlistNum'
812     select Strings DirWordList
813         .dirWordlistName$ = Get string... 'wordlistNum'
814     .dirString$ = replace_regex$(.dirWordlistName$, "[ ]", "&", 0)
815         
816         # Read in full tables
817         if fileReadable("'.dirString$'/wordlist.Table")
818         Read from file... '.dirString$'/wordlist.Table
819         Rename... 'wordlistName$'
820         # Praat wil change the name if it feels like it
821         wordlist$ = selected$("Table")
822         # Handle (legacy) simple word lists
823         elsif fileReadable("'.dirString$'/wordlist.txt")
824                 Create Table with column names... 'wordlistName$' 0 Pinyin Character Sound
825         wordlist$ = selected$("Table")
826                 Read Strings from raw text file... '.dirString$'/wordlist.txt
827                 Rename... RawWordList
828                 .numWordStrings = Get number of strings
829                 for .i to .numWordStrings
830                         select Strings RawWordList
831                         .currentLine$ = Get string... '.i'
832                         .currentPinyin$ = extractWord$(.currentLine$, "")
833                         if length(.currentLine$) > length(.currentPinyin$)+1
834                                 .currentFile$ = right$(.currentLine$, length(.currentPinyin$)+1)
835                         elsif fileReadable("'.dirString$'/'.currentPinyin$'.spx")
836                                 .currentFile$ = .currentPinyin$+".spx"
837                         elsif fileReadable("'.dirString$'/'.currentPinyin$'.flac")
838                                 .currentFile$ = .currentPinyin$+".flac"
839                         elsif fileReadable("'.dirString$'/'.currentPinyin$'.wav")
840                                 .currentFile$ = .currentPinyin$+".wav"
841                         elsif fileReadable("'.dirString$'/'.currentPinyin$'.mp3")
842                                 .currentFile$ = .currentPinyin$+".mp3"
843                         else
844                                 .currentFile$ = "-"
845                         endif
846                         select Table 'wordlist$'
847                         Append row
848                         Set string value... '.i' Pinyin '.currentPinyin$'
849                         Set string value... '.i' Character -
850                         Set string value... '.i' Sound '.currentFile$'
851                 endfor
852                 select Strings RawWordList
853                 Remove
854                 
855                 select Table 'wordlistName$'
856         else
857                 Create Table with column names... 'wordlistName$' 0 Pinyin Character Sound
858         wordlist$ = selected$("Table")
859                 Create Strings as file list... RawWordList '.dirString$'/*
860                 .numWordStrings = Get number of strings
861                 .i = 0
862                 for .j to .numWordStrings
863                         select Strings RawWordList
864                         .currentLine$ = Get string... '.j'
865                         .currentFile$ = extractWord$(.currentLine$, "")
866                         if index_regex(.currentFile$, "\.(spx|flac|wav|mp3)")
867                                 .currentPinyin$ = left$(.currentFile$, index(.currentFile$, ".")-1)
868                                 select Table 'wordlist$'
869                                 Append row
870                                 .i += 1
871                                 Set string value... '.i' Pinyin '.currentPinyin$'
872                                 Set string value... '.i' Character -
873                                 Set string value... '.i' Sound '.currentFile$'
874                         endif
875                 endfor
876                 select Strings RawWordList
877                 Remove
878                 
879                 select Table 'wordlistName$'
880         endif
881     numberOfWords = Get number of rows
882     if shuffleLists
883         Randomize rows
884     endif
885         
886         # Clean up
887     select Strings WordList
888         plus Strings DirWordList
889     Remove
890 endproc
892 procedure write_word_list
893     .xtext = 50
894     .ytext = 12
895     .ytextTop = .ytext + 5
896     .displayWordList$ = replace_regex$(wordlistName$, "[_]", " ", 0)
897     demo Blue
898     demo Paint rectangle... White 20 80 '.ytext' '.ytextTop'
899     demo Blue
900     demo Text... '.xtext' Centre '.ytext' Bottom '.displayWordList$'
901     demo Black
902         demoShow()
904         # Write current Pinyin text
905         call display_text Black
907         # Draw the contour
908         call draw_tone_contour
910 endproc
912 procedure log_performance .sampleSound$ .register .precision .pinyin$ .choice$
913         if not logPerformance
914                 logPerformance = fileReadable(logDir$+"/logPerformance.txt")
915         endif
916         # Log files
917         .currentDate$ = date$()
918         .timeStamp$ = replace_regex$(.currentDate$, "[^a-zA-Z0-9\-_]", "-", 0)
919         .choiceText$ = replace_regex$(.choice$, "[^a-zA-Z0-9\-_]", "-", 0)
921         if logPerformance
922            .outfilename$ = .pinyin$+"_"+.choice$+"_'.register'_"+.timeStamp$+".wav"
923            .logtext$ = .pinyin$+tab$+.choice$+tab$+"'.register'Hz"+tab$+.currentDate$+tab$+.outfilename$+newline$
924            fileappend 'logDir$'/logFile.txt '.logtext$'
925            select Sound 'sampleSound$'
926            Write to WAV file... 'logDir$'/'.outfilename$'
927         endif
928 endproc
930 # Make sure all Preferences directories are available
931 procedure set_up_directories
932         .dirPath$ = replace_regex$("'preferencesDirectory$'/sgc2", "[ ]", "\\&", 0);
933         if macintosh or unix
934                 system mkdir -p '.dirPath$'/wordlists
935                 system mkdir -p '.dirPath$'/log
936         elsif windows
937         endif
938 endproc
941 # Retrieve and store setting between sessions
943 procedure read_preferences .preferencesFile$
944         if not fileReadable(.preferencesFile$)
945                 .preferencesFile$ = preferencesDirectory$+"/sgc2/sgc2rc.txt"
946         endif
947         if fileReadable(.preferencesFile$)
948                 Read from file... 'preferencesDirectory$'/sgc2/sgc2rc.txt
949                 .preferenceTable$ = selected$("Table")
950                 .numPefKeys = Get number of rows
952                 call findLabel '.preferenceTable$' language
953                 if findLabel.row > 0
954                         select Table '.preferenceTable$'
955                         language$ = Get value... 'findLabel.row' Value
956                 endif
958                 call findLabel '.preferenceTable$' register
959                 if findLabel.row > 0
960                         select Table '.preferenceTable$'
961                         register = Get value... 'findLabel.row' Value
962                 endif
964                 call findLabel '.preferenceTable$' precision
965                 if findLabel.row > 0
966                         select Table '.preferenceTable$'
967                         precision = Get value... 'findLabel.row' Value
968                 endif
970                 call findLabel '.preferenceTable$' shuffleLists
971                 if findLabel.row > 0
972                         select Table '.preferenceTable$'
973                         shuffleLists = Get value... 'findLabel.row' Value
974                 endif
976                 call findLabel '.preferenceTable$' useSoundExample
977                 if findLabel.row > 0
978                         select Table '.preferenceTable$'
979                         useSoundExample = Get value... 'findLabel.row' Value
980                 endif
982                 call findLabel '.preferenceTable$' displayPinyin
983                 if findLabel.row > 0
984                         select Table '.preferenceTable$'
985                         displayPinyin = Get value... 'findLabel.row' Value
986                 endif
988                 call findLabel '.preferenceTable$' displayChar
989                 if findLabel.row > 0
990                         select Table '.preferenceTable$'
991                         displayChar = Get value... 'findLabel.row' Value
992                 endif
994                 call findLabel '.preferenceTable$' wordlistDir
995                 if findLabel.row > 0
996                         select Table '.preferenceTable$'
997                         wordlistDir$ = Get value... 'findLabel.row' Value
998                 endif
1000                 call findLabel '.preferenceTable$' wordlistName
1001                 if findLabel.row > 0
1002                         select Table '.preferenceTable$'
1003                         wordlistName$ = Get value... 'findLabel.row' Value
1004                 endif
1006                 call findLabel '.preferenceTable$' logdir
1007                 if findLabel.row > 0
1008                         select Table '.preferenceTable$'
1009                         logDir$ = Get value... 'findLabel.row' Value
1010                 endif
1011                 
1012                 select Table '.preferenceTable$'
1013                 Remove
1014         endif
1015 endproc
1017 procedure write_preferences .preferencesFile$
1018         Create Table with column names... Preferences 0 Key Value
1019         if index_regex(.preferencesFile$, "[a-zA-Z0-9]") <= 0
1020                 .preferencesFile$ = preferencesDirectory$ + "/sgc2/sgc2rc.txt"
1021         endif
1022         .row = 0
1023         select Table Preferences
1024         Append row
1025         .row += 1
1026         Set string value... '.row' Key language
1027         Set string value... '.row' Value 'language$'
1028         
1030         select Table Preferences
1031         Append row
1032         .row += 1
1033         Set string value... '.row' Key register
1034         Set numeric value... '.row' Value 'register'
1037         select Table Preferences
1038         Append row
1039         .row += 1
1040         Set string value... '.row' Key precision
1041         Set numeric value... '.row' Value 'precision'
1043         select Table Preferences
1044         Append row
1045         .row += 1
1046         Set string value... '.row' Key shuffleLists
1047         Set numeric value... '.row' Value 'shuffleLists'
1049         select Table Preferences
1050         Append row
1051         .row += 1
1052         Set string value... '.row' Key useSoundExample
1053         Set numeric value... '.row' Value 'useSoundExample'
1055         select Table Preferences
1056         Append row
1057         .row += 1
1058         Set string value... '.row' Key displayPinyin
1059         Set numeric value... '.row' Value 'displayPinyin'
1061         select Table Preferences
1062         Append row
1063         .row += 1
1064         Set string value... '.row' Key displayChar
1065         Set numeric value... '.row' Value 'displayChar'
1067         select Table Preferences
1068         Append row
1069         .row += 1
1070         Set string value... '.row' Key wordlistDir
1071         Set string value... '.row' Value 'wordlistDir$'
1073         select Table Preferences
1074         Append row
1075         .row += 1
1076         Set string value... '.row' Key wordlistName
1077         Set string value... '.row' Value 'wordlistName$'
1079         select Table Preferences
1080         Append row
1081         .row += 1
1082         Set string value... '.row' Key logdir
1083         Set string value... '.row' Value 'logDir$'
1084         
1085         select Table Preferences
1086         Write to table file... '.preferencesFile$'
1087         Remove
1089 endproc