First attempt to improve third tone recognition with breaking third tone pitch contours
[sgc2.git] / ToneProt / ToneRecognition.praat
blob1323e0a67a26747b344b5e0ebea0a526d5d8466f
1 #! praat\r
2 #\r
3 # Construct all tone patterns and look for the one closest to the given one\r
4 #\r
5 \r
6 procedure FreeToneRecognition .pinyin$ .test_word$ .exclude$ .upperRegister .freqRange .durScale .startSyllable\r
7     # Clean up input\r
8     if .pinyin$ <> ""\r
9         .pinyin$ = replace_regex$(.pinyin$, "^\s*(.+)\s*$", "\1", 1)\r
10         .pinyin$ = replace_regex$(.pinyin$, "5", "0", 0)\r
11                 # Missing neutral tones\r
12                 call add_missing_neutral_tones '.pinyin$'\r
13                 .pinyin$ = add_missing_neutral_tones.pinyin$\r
14     endif\r
16     .referenceFrequency = 300\r
17     .frequencyFactor = .referenceFrequency / .upperRegister\r
19     .referenceExt$ = "pitch"\r
20     \r
21     # Bias Z-normalized value of the distance difference between smallest and correct\r
22     .biasDistance = 1.1\r
23     if index_regex(config.strict$, "[^0-9]") <= 0\r
24                 .tmp = 'config.strict$'\r
25                 if .tmp = 0\r
26                         .biasDistance = 1.7\r
27                 elsif .tmp = 1\r
28                         .biasDistance = 1.1\r
29                 elsif .tmp = 2\r
30                         .biasDistance = 0.6\r
31                 elsif .tmp = 3\r
32                         .biasDistance = 0.3\r
33                 endif\r
34     endif\r
35     \r
36     # Debugging\r
37     .keepIntermediates = 0\r
38     .debug = 0\r
40     # Generate reference tones\r
41     call toneScript '.pinyin$' '.upperRegister' '.freqRange' '.durScale' Pitch_'.startSyllable'\r
43     # Convert input to Pitch\r
44     if .test_word$ <> "" and .test_word$ <> "REUSEPITCH"\r
45         Read from file... '.test_word$'\r
46         Rename... Source\r
47     endif\r
48     if .test_word$ <> "REUSEPITCH"\r
49         select Sound Source\r
50                 call convert2Pitch 'sgc_ToneProt.minimumPitch' 'sgc_ToneProt.maximumPitch'\r
51                 .sourcePitch = convert2Pitch.object\r
52         Formula... self*'.frequencyFactor'; Normalize Pitch\r
53         Rename... SourcePitch\r
54     endif\r
55     select Pitch SourcePitch\r
57     .countDistance = 0\r
58     .sumDistance = 0\r
59     .sumSqrDistance = 0\r
60     .correctDistance = -1\r
62     .smallestDistance=999999\r
63     sgc_ToneProt.choiceReference$ = "empty"\r
64     select Table ToneList\r
65     .listLength = Get number of rows\r
66     for .i from 1 to .listLength\r
67         select Table ToneList\r
68         .inFile$ = Get value... '.i' Word\r
69         # Broken third tones are still third tones\r
70         .inFile$ = replace$(.inFile$, "9", "3", 0)\r
72         if (.exclude$ = "" or rindex_regex(.inFile$, .exclude$) <= 0) and rindex_regex(.inFile$, "[\d]") > 0 \r
73             referenceName$ = .inFile$\r
74             select Pitch '.inFile$'\r
75             plus Pitch SourcePitch\r
76             .dtw = noprogress To DTW... 24 10 yes yes no restriction\r
77             Rename... DTW'.inFile$'\r
78             distance = Get distance (weighted)\r
79             \r
80             .countDistance = .countDistance + 1\r
81             .sumDistance = .sumDistance + distance\r
82             .sumSqrDistance = .sumSqrDistance + distance^2\r
83             \r
84             if .pinyin$ = .inFile$\r
85                 .correctDistance = distance\r
86             endif\r
88             if .debug > 0\r
89                 # printline 'distance' - '.inFile$'\r
90             endif\r
92             if distance < .smallestDistance\r
93                 .smallestDistance = distance\r
94                 sgc_ToneProt.choiceReference$ = "'.inFile$'"\r
95             endif\r
97             # Clean up\r
98             select DTW DTW'.inFile$'\r
100             if .keepIntermediates = 0\r
101                 Remove\r
102             endif\r
103         endif\r
104     endfor\r
105     \r
106     if .countDistance > 1\r
107         .meanDistance = .sumDistance / .countDistance\r
108         .varDistance = (.sumSqrDistance - .sumDistance^2/.countDistance)/(.countDistance - 1)\r
109         .stdDistance = sqrt(.varDistance)\r
110         .diffDistance = .correctDistance - .smallestDistance\r
111         .zDistance = .diffDistance/.stdDistance\r
113         if .debug > 0\r
114             printline Match: '.pinyin$' <== 'sgc_ToneProt.choiceReference$' small='.smallestDistance' Z='.zDistance'\r
115         endif\r
117         if .zDistance < .biasDistance\r
118             sgc_ToneProt.choiceReference$ = .pinyin$\r
119             .smallestDistance = .correctDistance\r
120         endif\r
121     endif\r
122     \r
124     # Clean up\r
125     for .i from 1 to .listLength\r
126         select Table ToneList\r
127         .inFile$ = Get value... '.i' Word\r
129         if (.exclude$ = "" or rindex_regex(.inFile$, .exclude$) <= 0) and rindex_regex(.inFile$, "[\d]") > 0 \r
131             # Clean up\r
132             select Pitch '.inFile$'\r
133             if .keepIntermediates = 0\r
134                 Remove\r
135             endif\r
136         endif\r
137     endfor\r
139     select Table ToneList\r
140     if .test_word$ <> "" and .test_word$ <> "REUSEPITCH"\r
141         plus Sound Source\r
142     endif\r
143     if .test_word$ <> "" and .test_word$ <> "REUSEPITCH"\r
144         plus Pitch SourcePitch\r
145     endif\r
146     if .keepIntermediates = 0\r
147         Remove\r
148     endif\r
150 endproc\r