1 # The rules for constructing the tone contours.
3 # This procedure works because in Praat, there is no namespace
4 # separation. All variables behave as if they are global
7 # toneScript.toneSyllable is the tone number on the current syllable
8 # 1-4, 0=neutral, 6=Dutch (garbage) intonation
10 # These procedures set the following pareameters
11 # and use them to create a Pitch Tier:
13 # toneScript.toneFactor: Duration scale factor for current tone
14 # toneRules.startPoint: Start of the tone
15 # toneScript.endPoint: end of the tone
16 # toneRules.lowestPoint: bottom of tone 3
17 # toneScript.point: The time of the next pitch value in the contour
18 # ONLY USE AS: toneScript.point = toneScript.point + <fraction> * toneScript.voicedDuration
20 # The following values are given by the calling routine
23 # toneScript.toneSyllable: tone number on the current syllable
24 # toneScript.nextTone: tone number of next syllable or -1
25 # toneScript.prevTone: tone number of previous syllable or -1
26 # toneScript.lastFrequency: end-frequency of the previous syllable
28 # toneScript.topLine: the frequency of the first tone
29 # toneScript.frequency_Range: Range of tone four (1 toneScript.octave)
30 # toneScript.voicedDuration: Duration of voiced part of syllable
33 # Procedure to scale the duration of the current syllable
34 procedure toneDuration
35 if toneScript.toneSyllable = 0
37 if toneScript.prevTone = 2
38 .zeroToneFactor = 0.8 * .zeroToneFactor
39 elsif toneScript.prevTone = 3
40 .zeroToneFactor = 1.1 * .zeroToneFactor
41 elsif toneScript.prevTone = 4
42 .zeroToneFactor = 0.8 * .zeroToneFactor
44 toneScript.toneFactor = .zeroToneFactor * toneScript.toneFactor
45 elsif toneScript.toneSyllable = 2
46 toneScript.toneFactor = 0.8
47 elsif toneScript.toneSyllable = 3
48 toneScript.toneFactor = 1.1
49 elsif toneScript.toneSyllable = 4
50 toneScript.toneFactor = 0.8
53 # Next tone 0, then lengthen first syllable
54 if toneScript.nextTone = 0
55 toneScript.toneFactor = toneScript.toneFactor * 1.2
59 # DO NOT CHANGE toneScript.toneFactor BELOW THIS POINT
61 # Rules to create a tone
63 # Do not mess with the 'Add point...' commands
64 # unless you know what you are doing
65 # The 'toneScript.point =' defines the time of the next pitch value
67 # start * ?Semit is a fall
68 # start / ?Semit is a rise
72 # Tone toneRules.levels 1-5
73 # Defined relative to the topline and the frequency range
74 toneRules.levelFive = toneScript.topLine
75 toneRules.levelOne = toneScript.topLine * toneScript.frequency_Range
76 toneRules.levelThree = toneScript.topLine * sqrt(toneScript.frequency_Range)
77 toneRules.levelTwo = toneScript.topLine * sqrt(sqrt(toneScript.frequency_Range))
78 toneRules.levelFour = toneRules.levelOne / sqrt(sqrt(toneScript.frequency_Range))
81 if toneScript.toneSyllable = 1
82 # Just a straight line
83 toneRules.startPoint = toneRules.levelFive
84 toneScript.endPoint = toneRules.levelFive
86 # Two first tones, make them a little different
87 if toneScript.prevTone = 1
88 toneRules.startPoint = toneRules.startPoint * 0.999
89 toneScript.endPoint = toneScript.endPoint * 0.999
92 # Write toneScript.points
93 Add point... 'toneScript.point' 'toneRules.startPoint'
94 toneScript.point = toneScript.point + toneScript.voicedDuration
95 Add point... 'toneScript.point' 'toneScript.endPoint'
97 elsif toneScript.toneSyllable = 2
98 # Start halfway of the range - 1 semitone
99 toneRules.startPoint = toneRules.levelThree * toneScript.oneSemit
100 # End 1 semitones above the first tone
101 toneScript.endPoint = toneRules.levelFive / toneScript.oneSemit
102 # Special case: 2 followed by 1, stop short of the top-line
103 # ie, 5 semitones above the start
104 if toneScript.nextTone = 1
105 toneScript.endPoint = toneRules.startPoint / toneScript.fiveSemit
107 # Go lower if previous tone is 1
108 if toneScript.prevTone = 1
109 toneRules.startPoint = toneRules.startPoint * toneScript.oneSemit
110 elsif toneScript.prevTone = 4 or toneScript.prevTone = 3
111 # Special case: 2 following 4 or 3
113 toneRules.startPoint = toneScript.lastFrequency / toneScript.oneSemit
114 toneScript.endPoint = toneRules.levelFive
115 elsif toneScript.prevTone = 2
116 # Two consecutive tone 2, start 1 semitone higher
117 toneRules.startPoint = toneRules.startPoint / toneScript.oneSemit
119 # Define a midtoneScript.point at 1/3 of the duration
120 toneRules.midPoint = toneRules.startPoint
122 # Write toneScript.points
123 Add point... 'toneScript.point' 'toneRules.startPoint'
124 # Next toneScript.point a 1/3th of duration
125 toneScript.point = toneScript.point + (toneScript.voicedDuration)/3
126 Add point... 'toneScript.point' 'toneRules.midPoint'
128 toneScript.point = toneScript.point + (toneScript.voicedDuration)*2/3
129 Add point... 'toneScript.point' 'toneScript.endPoint'
131 elsif toneScript.toneSyllable = 3
133 toneRules.startPoint = toneRules.levelThree
134 toneRules.lowestPoint = toneRules.levelOne * toneScript.threeSemit
135 # Protect pitch against "underflow"
136 if toneRules.lowestPoint < toneScript.absoluteMinimum
137 toneRules.lowestPoint = toneScript.absoluteMinimum
140 if toneScript.nextTone < 0
141 toneScript.endPoint = toneRules.startPoint
142 # Anticipate rise in next tone
143 elsif toneScript.nextTone = 1 or toneScript.nextTone = 4
144 toneRules.lowestPoint = toneRules.levelOne / toneScript.twoSemit
145 toneScript.endPoint = toneRules.startPoint
146 # Anticipate rise in next tone and stay low
147 elsif toneScript.nextTone = 2
148 toneRules.lowestPoint = toneRules.levelOne / toneScript.twoSemit
149 toneScript.endPoint = toneRules.lowestPoint
150 # Last one was low, don't go so much lower
151 elsif toneScript.prevTone = 4
152 toneRules.lowestPoint = toneRules.levelOne * toneScript.oneSemit
153 # Anticipate rise in next tone and stay low
154 elsif toneScript.nextTone = 0
155 toneRules.lowestPoint = toneRules.levelOne
156 toneScript.endPoint = toneRules.lowestPoint / toneScript.sixSemit
158 toneScript.endPoint = toneRules.startPoint
161 # Write toneScript.points
162 Add point... 'toneScript.point' 'toneRules.startPoint'
163 # Go 1/3 of the duration down
164 toneScript.point = toneScript.point + (toneScript.voicedDuration)*2/6
165 Add point... 'toneScript.point' 'toneRules.lowestPoint'
166 # Go half the duration low
167 toneScript.point = toneScript.point + (toneScript.voicedDuration)*3/6
168 Add point... 'toneScript.point' 'toneRules.lowestPoint'
169 # Return in 1/6th of the duration
170 toneScript.point = toneScript.point + (toneScript.voicedDuration)*1/6
171 Add point... 'toneScript.point' 'toneScript.endPoint'
172 # Third tone with voice break
173 elsif toneScript.toneSyllable = 9
175 toneRules.startPoint = toneRules.levelThree
176 toneRules.lowestPoint = toneRules.levelOne * toneScript.threeSemit
177 # Protect pitch against "underflow"
178 if toneRules.lowestPoint < toneScript.absoluteMinimum
179 toneRules.lowestPoint = toneScript.absoluteMinimum
182 if toneScript.nextTone < 0
183 toneScript.endPoint = toneRules.startPoint
184 # Anticipate rise in next tone
185 elsif toneScript.nextTone = 1 or toneScript.nextTone = 4
186 toneRules.lowestPoint = toneRules.levelOne / toneScript.twoSemit
187 toneScript.endPoint = toneRules.startPoint
188 # Anticipate rise in next tone and stay low
189 elsif toneScript.nextTone = 2
190 toneRules.lowestPoint = toneRules.levelOne / toneScript.twoSemit
191 toneScript.endPoint = toneRules.lowestPoint
192 # Last one was low, don't go so much lower
193 elsif toneScript.prevTone = 4
194 toneRules.lowestPoint = toneRules.levelOne * toneScript.oneSemit
195 # Anticipate rise in next tone and stay low
196 elsif toneScript.nextTone = 0
197 toneRules.lowestPoint = toneRules.levelOne
198 toneScript.endPoint = toneRules.lowestPoint / toneScript.sixSemit
200 toneScript.endPoint = toneRules.startPoint
203 # Write toneScript.points
204 Add point... 'toneScript.point' 'toneRules.startPoint'
205 # Go 1/3 of the duration down
206 toneScript.point = toneScript.point + (toneScript.voicedDuration)*2/6
207 Add point... 'toneScript.point' 'toneRules.lowestPoint'
210 .delta = 'toneScript.point' + 0.001
211 Add point... '.delta' 0
213 # Go half the duration low
214 toneScript.point = toneScript.point + (toneScript.voicedDuration)*3/6
217 .delta = 'toneScript.point' - 0.001
218 Add point... '.delta' 0
220 Add point... 'toneScript.point' 'toneRules.lowestPoint'
221 # Return in 1/6th of the duration
222 toneScript.point = toneScript.point + (toneScript.voicedDuration)*1/6
224 Add point... 'toneScript.point' 'toneScript.endPoint'
226 elsif toneScript.toneSyllable = 4
227 # Start higher than tone 1 (by 2 semitones)
228 toneRules.startPoint = toneRules.levelFive / toneScript.twoSemit
229 # Go down the full range
230 toneScript.endPoint = toneRules.startPoint * toneScript.frequency_Range
233 # SPECIAL: Fall in following neutral tone
234 if toneScript.nextTone = 0
235 toneScript.endPoint = toneScript.endPoint / toneScript.threeSemit
238 # Write toneScript.points
239 Add point... 'toneScript.point' 'toneRules.startPoint'
240 # A plateau for 1/3th
241 toneScript.point = toneScript.point + toneScript.voicedDuration*1/3
242 Add point... 'toneScript.point' 'toneRules.startPoint'
244 toneScript.point = toneScript.point + toneScript.voicedDuration*2/3
245 Add point... 'toneScript.point' 'toneScript.endPoint'
247 elsif toneScript.toneSyllable = 0
248 if toneScript.lastFrequency > 0
249 toneRules.startPoint = toneScript.lastFrequency
251 toneRules.startPoint = toneRules.levelThree / toneScript.oneSemit
254 if toneScript.prevTone = 1
255 toneRules.startPoint = toneScript.lastFrequency * toneScript.twoSemit
256 elsif toneScript.prevTone = 2
257 toneRules.startPoint = toneScript.lastFrequency
258 elsif toneScript.prevTone = 3
259 toneRules.startPoint = toneScript.lastFrequency / toneScript.oneSemit
260 elsif toneScript.prevTone = 4
261 toneRules.startPoint = toneScript.lastFrequency * toneScript.oneSemit
262 elsif toneScript.lastFrequency > 0
263 toneRules.startPoint = toneScript.lastFrequency * toneScript.oneSemit
267 if toneRules.startPoint <= 0
268 toneRules.startPoint = toneRules.levelThree / toneScript.oneSemit
271 # Add spreading and some small or large de/inclination
272 if toneScript.prevTone = 1
273 toneRules.midPoint = toneRules.startPoint * toneScript.frequency_Range / toneScript.oneSemit
274 toneScript.endPoint = toneRules.midPoint * toneScript.oneSemit
275 elsif toneScript.prevTone = 2
277 toneRules.midPoint = toneRules.startPoint * toneScript.fiveSemit
278 toneScript.endPoint = toneRules.midPoint * toneScript.twoSemit
279 elsif toneScript.prevTone = 3
280 toneRules.midPoint = toneRules.startPoint / toneScript.twoSemit
281 toneScript.endPoint = toneRules.midPoint
282 elsif toneScript.prevTone = 4
283 toneRules.midPoint = toneRules.startPoint * toneScript.threeSemit
284 toneScript.endPoint = toneRules.midPoint / toneScript.oneSemit
286 toneRules.midPoint = toneRules.startPoint * toneScript.oneSemit
287 toneScript.endPoint = toneRules.midPoint
290 # Add a very short break to force (disabled, maybe should be removed)
292 if toneScript.point = undefined
296 Add point... 'toneScript.point' 0
297 toneScript.point = toneScript.point + 1/toneRules.startPoint
298 Add point... 'toneScript.point' 0
299 toneScript.point = toneScript.point + toneScript.delta
302 # Write toneScript.points first 2/3 then decaying 1/3
303 Add point... 'toneScript.point' 'toneRules.startPoint'
304 toneScript.point = toneScript.point + (toneScript.voicedDuration - 1/toneRules.startPoint)*2/3
305 Add point... 'toneScript.point' 'toneRules.midPoint'
306 toneScript.point = toneScript.point + (toneScript.voicedDuration - 1/toneRules.startPoint)*1/3
307 Add point... 'toneScript.point' 'toneScript.endPoint'
310 # Start halfway of the range
311 toneRules.startPoint = toneRules.levelThree
312 # Or continue from last Dutch "tone"
313 if toneScript.prevTone = 6
314 toneRules.startPoint = toneScript.lastFrequency
317 toneScript.endPoint = toneRules.startPoint * toneScript.oneSemit
319 # Write toneScript.points
320 Add point... 'toneScript.point' 'toneRules.startPoint'
321 toneScript.point = toneScript.point + toneScript.voicedDuration
322 Add point... 'toneScript.point' 'toneScript.endPoint'