3 # Construct all tone patterns and look for the one closest to the given one
\r
6 procedure FreeToneRecognition .pinyin$ .test_word$ .exclude$ .upperRegister .freqRange .durScale .startSyllable
\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
16 .referenceFrequency = 300
\r
17 .frequencyFactor = .referenceFrequency / .upperRegister
\r
19 .referenceExt$ = "pitch"
\r
21 # Bias Z-normalized value of the distance difference between smallest and correct
\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
41 .keepIntermediates = 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
52 if .test_word$ <> "REUSEPITCH"
\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
61 .sourcePitch = convert2Pitch.object
\r
64 Formula... self*'.frequencyFactor'; Normalize Pitch
\r
65 Rename... SourcePitch
\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
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
99 select DTW DTW'.inFile$'
\r
100 .countDistance = .countDistance + 1
\r
101 .sumDistance = .sumDistance + distance
\r
102 .sumSqrDistance = .sumSqrDistance + distance^2
\r
104 .inFile$ = replace$(.inFile$, "9", "3", 0)
\r
105 if .pinyin$ = .inFile$
\r
106 .correctDistance = distance
\r
110 # printline 'distance' - '.inFile$'
\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
122 if .keepIntermediates = 0
\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
136 printline Match: '.pinyin$' <== 'sgc_ToneProt.choiceReference$' small='.smallestDistance' Z='.zDistance'
\r
139 if .zDistance < .biasDistance
\r
140 sgc_ToneProt.choiceReference$ = .pinyin$
\r
141 .smallestDistance = .correctDistance
\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
154 select Pitch '.inFile$'
\r
155 if .keepIntermediates = 0
\r
161 select Table ToneList
\r
162 if .test_word$ <> "" and .test_word$ <> "REUSEPITCH"
\r
165 if .test_word$ <> "" and .test_word$ <> "REUSEPITCH"
\r
166 plus Pitch SourcePitch
\r
168 if .keepIntermediates = 0
\r
175 procedure createJitterShimmerContour .sound
\r
177 .duration = Get total duration
\r
178 .jitshimSound = Create Sound: "JitterShimmer", 0, .duration, 100, "0"
\r
180 # Create pointprocess
\r
182 .pointProc = To PointProcess (periodic, cc): 60, 350
\r
188 while .t < .duration - .dT
\r
190 .jitter = Get jitter (local): .t-.w_half, .t+.w_half, 0.0001, 0.02, 1.3
\r
191 if .jitter = undefined
\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
200 select .jitshimSound
\r
201 Set value at sample number: 0, .sampleNum, 10 * .jitter * .shimmer
\r
210 select .jitshimSound
\r