First step to replace creacky voice frames with low F0. Added createJitterShimmerContour
[sgc2.git] / ToneProt / ToneRecognition.praat
blobd591f0d094dfcea4c2621d34d8ae44858d01c710
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                 # Be lenient with longer words\r
26             if .startSyllable > 0\r
27                         .tmp -= 1\r
28             endif\r
29                 if .tmp <= 0\r
30                         .biasDistance = 1.7\r
31                 elsif .tmp = 1\r
32                         .biasDistance = 1.1\r
33                 elsif .tmp = 2\r
34                         .biasDistance = 0.6\r
35                 elsif .tmp = 3\r
36                         .biasDistance = 0.3\r
37                 endif\r
38     endif\r
39     \r
40     # Debugging\r
41     .keepIntermediates = 0\r
42     .debug = 0\r
44     # Generate reference tones\r
45     call toneScript '.pinyin$' '.upperRegister' '.freqRange' '.durScale' Pitch_'.startSyllable'\r
47     # Convert input to Pitch\r
48     if .test_word$ <> "" and .test_word$ <> "REUSEPITCH"\r
49         Read from file... '.test_word$'\r
50         Rename... Source\r
51     endif\r
52     if .test_word$ <> "REUSEPITCH"\r
53         select Sound Source\r
54                 call convert2Pitch 'sgc_ToneProt.minimumPitch' 'sgc_ToneProt.maximumPitch'\r
55                 if index(.pinyin$, "3") > 0\r
56                         select convert2Pitch.object\r
57                         .sourcePitch = Kill octave jumps\r
58                         select convert2Pitch.object\r
59                         Remove\r
60                 else\r
61                         .sourcePitch = convert2Pitch.object\r
62                 endif\r
63                 select .sourcePitch\r
64         Formula... self*'.frequencyFactor'; Normalize Pitch\r
65         Rename... SourcePitch\r
66     endif\r
68         \r
69         # Reassign creacky voice parts\r
70         # select Sound Source\r
71         # .sound = selected("Sound")\r
72         # call createJitterShimmerContour .sound\r
73         # .jitterShimmer = selected("Sound")\r
75     select Pitch SourcePitch\r
77     .countDistance = 0\r
78     .sumDistance = 0\r
79     .sumSqrDistance = 0\r
80     .correctDistance = -1\r
82     .smallestDistance=999999\r
83     sgc_ToneProt.choiceReference$ = "empty"\r
84     select Table ToneList\r
85     .listLength = Get number of rows\r
86     for .i from 1 to .listLength\r
87         select Table ToneList\r
88         .inFile$ = Get value... '.i' Word\r
89         # Broken third tones are still third tones\r
91         if (.exclude$ = "" or rindex_regex(.inFile$, .exclude$) <= 0) and rindex_regex(.inFile$, "[\d]") > 0 \r
92             referenceName$ = .inFile$\r
93             select Pitch '.inFile$'\r
94             plus Pitch SourcePitch\r
95             .dtw = noprogress To DTW... 24 10 yes yes no restriction\r
96             Rename... DTW'.inFile$'\r
97             distance = Get distance (weighted)\r
98             # Clean up\r
99             select DTW DTW'.inFile$'\r
100             .countDistance = .countDistance + 1\r
101             .sumDistance = .sumDistance + distance\r
102             .sumSqrDistance = .sumSqrDistance + distance^2\r
103             \r
104                         .inFile$ = replace$(.inFile$, "9", "3", 0)\r
105             if .pinyin$ = .inFile$\r
106                 .correctDistance = distance\r
107             endif\r
109             if .debug > 0\r
110                 # printline 'distance' - '.inFile$'\r
111             endif\r
113             if distance < .smallestDistance\r
114                                 # You cannot have a large range and misidentify it as 00\r
115                                 if not (.freqRange >= 0.5 and index_regex(.inFile$, "0[^0-9]+0") > 0 and index_regex(.test_word$, "0[^0-9]+0") <= 0)\r
116                         .smallestDistance = distance\r
117                         sgc_ToneProt.choiceReference$ = "'.inFile$'"\r
118                 endif\r
119             endif\r
122             if .keepIntermediates = 0\r
123                 Remove\r
124             endif\r
125         endif\r
126     endfor\r
127     \r
128     if .countDistance > 1\r
129         .meanDistance = .sumDistance / .countDistance\r
130         .varDistance = (.sumSqrDistance - .sumDistance^2/.countDistance)/(.countDistance - 1)\r
131         .stdDistance = sqrt(.varDistance)\r
132         .diffDistance = .correctDistance - .smallestDistance\r
133         .zDistance = .diffDistance/.stdDistance\r
135         if .debug > 0\r
136             printline Match: '.pinyin$' <== 'sgc_ToneProt.choiceReference$' small='.smallestDistance' Z='.zDistance'\r
137         endif\r
139         if .zDistance < .biasDistance\r
140             sgc_ToneProt.choiceReference$ = .pinyin$\r
141             .smallestDistance = .correctDistance\r
142         endif\r
143     endif\r
144     \r
146     # Clean up\r
147     for .i from 1 to .listLength\r
148         select Table ToneList\r
149         .inFile$ = Get value... '.i' Word\r
151         if (.exclude$ = "" or rindex_regex(.inFile$, .exclude$) <= 0) and rindex_regex(.inFile$, "[\d]") > 0 \r
153             # Clean up\r
154             select Pitch '.inFile$'\r
155             if .keepIntermediates = 0\r
156                 Remove\r
157             endif\r
158         endif\r
159     endfor\r
161     select Table ToneList\r
162     if .test_word$ <> "" and .test_word$ <> "REUSEPITCH"\r
163         plus Sound Source\r
164     endif\r
165     if .test_word$ <> "" and .test_word$ <> "REUSEPITCH"\r
166         plus Pitch SourcePitch\r
167     endif\r
168     if .keepIntermediates = 0\r
169         Remove\r
170     endif\r
172 endproc\r
174 # Use ~0.03 cutoff\r
175 procedure createJitterShimmerContour .sound\r
176         select .sound\r
177         .duration = Get total duration\r
178         .jitshimSound = Create Sound: "JitterShimmer", 0, .duration, 100, "0"\r
179         \r
180         # Create pointprocess\r
181         select .sound\r
182         .pointProc = To PointProcess (periodic, cc): 60, 350\r
183         \r
184         .dT = 0.01\r
185         .w_half = 0.1/2\r
186         .t = 0.0\r
187         .sampleNum = 1\r
188         while .t < .duration - .dT\r
189                 select .pointProc\r
190                 .jitter = Get jitter (local): .t-.w_half, .t+.w_half, 0.0001, 0.02, 1.3\r
191                 if .jitter = undefined\r
192                         .jitter = 0\r
193                 endif\r
194                 select .sound\r
195                 plus .pointProc\r
196                 .shimmer = Get shimmer (local): .t-.w_half, .t+.w_half, 0.0001, 0.02, 1.3, 1.6\r
197                 if .shimmer = undefined\r
198                         .shimmer = 0\r
199                 endif\r
200                 select .jitshimSound\r
201                 Set value at sample number: 0, .sampleNum, 10 * .jitter * .shimmer\r
202         \r
203                 .t += .dT\r
204                 .sampleNum += 1\r
205         endwhile\r
206         \r
207         select .pointProc\r
208         Remove\r
209         \r
210         select .jitshimSound\r
211 endproc\r