1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; Centre for Speech Technology Research ;;
4 ;;; University of Edinburgh, UK ;;
5 ;;; Copyright (c) 1996,1997 ;;
6 ;;; All Rights Reserved. ;;
8 ;;; Permission is hereby granted, free of charge, to use and distribute ;;
9 ;;; this software and its documentation without restriction, including ;;
10 ;;; without limitation the rights to use, copy, modify, merge, publish, ;;
11 ;;; distribute, sublicense, and/or sell copies of this work, and to ;;
12 ;;; permit persons to whom this work is furnished to do so, subject to ;;
13 ;;; the following conditions: ;;
14 ;;; 1. The code must retain the above copyright notice, this list of ;;
15 ;;; conditions and the following disclaimer. ;;
16 ;;; 2. Any modifications must be clearly marked as such. ;;
17 ;;; 3. Original authors' names are not deleted. ;;
18 ;;; 4. The authors' names are not used to endorse or promote products ;;
19 ;;; derived from this software without specific prior written ;;
22 ;;; THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK ;;
23 ;;; DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ;;
24 ;;; ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT ;;
25 ;;; SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE ;;
26 ;;; FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ;;
27 ;;; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN ;;
28 ;;; AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ;;
29 ;;; ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF ;;
32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
33 ;;; Authors: Robert A. J. Clark and Alan W Black
34 ;;; Modifications and Checking:
35 ;;; Gregor Moehler (moehler@ims.uni-stuttgart.de)
36 ;;; Matthew Stone (mdstone@cs.rutgers.edu)
37 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
39 ;;; Generate F0 points from tobi labels using rules given in:
40 ;;; Jilka, Moehler & Dogil (forthcomming in Speech Communications)
41 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
43 ;;; *** Converted to new Relation architecture -- but not checked yet -- awb
44 ;;; -> crude (beta) checking: gm in Dec. 98
46 ;;; -> fixed TAKEOVER bug that used time value
47 ;;; as pitch target (!) - MDS 1/02
48 ;;; -> hacked around bunches of target overlap problems - MDS 1/02
49 ;;; -> added primitive pitch range controls
51 ;;; Known problems and bugs:
52 ;;; Can't currently use voicing intervals which cross syllable boundaries,
53 ;;; so pre/post-nuclear tones are currently places 0.2s before/after the
54 ;;; nuclear tone even if no voicing occurs. Failing this they default a
55 ;;; percentage of the voicing for that syllable.
57 ;;; Don't know about target points ahead of the current syllable.
58 ;;; (As you need to know what comes before them to calculate them)
59 ;;; So: post accent tones are placed 0.2 ahead if following syllable exists
60 ;;; ends before 0.2 from starred target and is not accented
61 ;;; The H-target of the H+!H* is 0.2 sec instead of 0.15 sec before
64 ;;; Multi-utterance input has not been tested.
66 ;;; !H- does not generate any targets
68 ;;; Unfortunaltely some other modules may decide to put pauses in the
69 ;;; middle of a phrase
71 ;;; valleys are not tested yet
73 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
75 ;;; To use this in a voice
76 ;;; (require 'tobi_rules)
77 ;;; And in the voice call
78 ;;; (setup_tobi_f0_method)
79 ;;; Set the following for your speaker's F0 range
80 ;;; (Parameter.set 'Default_Topline 146)
81 ;;; (Parameter.set 'Default_Start_Baseline 61)
82 ;;; (Parameter.set 'Valley_Dip 75)
84 ;; level of debug printout
87 (define (setup_tobi_f0_method)
88 "(setup_tobi_f0_method)
89 Set up parameters for current voice to use the implementaion
90 of ToBI labels to F0 targets by rule."
91 (Parameter.set 'Int_Method Intonation_Tree)
92 (Parameter.set 'Int_Target_Method Int_Targets_General)
93 (set! int_accent_cart_tree no_int_cart_tree) ; NONE always
94 (set! int_tone_cart_tree no_int_cart_tree) ; NONE always
95 (set! int_general_params
97 (list 'targ_func tobi_f0_targets))) ; we will return a list of f0 targets here
99 (Parameter.set 'Phrase_Method 'cart_tree)
100 (set! phrase_cart_tree tobi_label_phrase_cart_tree) ; redefines the phrasebreak tree
103 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
105 ;;;;;; Define and set the new f0 rules
107 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
109 ;;; Set global parameters
110 ;;; You may want to reset these for different speakers
112 (Parameter.set 'Default_Topline 146) ;146
113 (Parameter.set 'Default_Start_Baseline 61) ;61
114 (Parameter.set 'Current_Topline (Parameter.get 'Default_Topline))
115 (Parameter.set 'Current_Start_Baseline (Parameter.get 'Default_Start_Baseline))
116 (Parameter.set 'Current_End_Baseline (Parameter.get 'Current_Start_Baseline))
117 (Parameter.set 'Downstep_Factor 0.70)
118 (Parameter.set 'Valley_Dip 75)
119 ;;; function to add target points on a given syllable and fill in
120 ;;; targets where necessary
122 (define (tobi_f0_targets utt syl)
123 "(tobi_f0_targets UTT ITEM)
124 Returns a list of targets for the given syllable."
125 (if (and (>= printdebug 1)
126 (not(equal? 0 (item.feat syl "R:Intonation.daughter1.name"))))
127 (format t "### %l (%.2f %.2f) %l ptarg: %l ###\n" (item.name syl)
128 (item.feat syl "syllable_start")(item.feat syl "syllable_end")
129 (item.feat syl "R:Intonation.daughter1.name") (ttt_last_target_time syl)))
131 ;; only continue if there is a Word related to this syllable
132 ;; I know there always should be, but there might be a bug elsewhere
134 ((not(equal? 0 (item.feat syl "R:SylStructure.parent.name")))
136 ; get current label. This assumes that there is only one accent and
137 ; one endtone on a syllable. Although there can be one of each.
138 (let ((voicing (ttt_get_voice_times syl)) ; voicing interval
139 (pvoicing (ttt_get_voice_times ; previous voicing
140 (item.relation.prev syl 'Syllable)))
141 (nvoicing (ttt_get_voice_times ; next voicing
142 (item.relation.next syl 'Syllable))))
144 ; if first syl of phrase set Phrase_Start and Phrase_End parameters
145 ; and reset downstep (currently does so on big and little breaks.)
146 ; only assignes Default values at this stage
147 ; maybe trained from CART later - first steps now - MDS
148 ; following Moehler and Mayer, SSW 2001
149 (if (eq 0 (item.feat syl 'syl_in)) ;; GM maybe something better needed here?
151 (Parameter.set 'Phrase_Start (item.feat syl 'R:SylStructure.parent.R:Phrase.last.word_start))
152 (Parameter.set 'Phrase_End (item.feat syl 'R:SylStructure.parent.R:Phrase.last.word_end))
153 (Parameter.set 'Current_Topline
154 (/ (* (wagon syl ttt_topline_tree)
155 (Parameter.get 'Default_Topline)) 100))
156 (Parameter.set 'Current_Start_Baseline
157 (/ (* (wagon syl ttt_baseline_tree)
158 (Parameter.get 'Default_Start_Baseline)) 100))
159 (Parameter.set 'Current_End_Baseline
160 (Parameter.get 'Current_Start_Baseline))
161 (if (>= printdebug 3)
163 (print (format nil "new range: %f %f %f"
164 (Parameter.get 'Current_Topline)
165 (Parameter.get 'Current_Start_Baseline)
166 (Parameter.get 'Current_End_Baseline) )))) ))
168 ; do stuff (should go only if there is an accent/boundary?)
170 (ttt_to_targets syl (wagon syl ttt_starttone_tree)
176 (set! new_targets (append new_targets
177 (ttt_to_targets syl (wagon syl ttt_accent_tree)
183 (set! new_targets (append new_targets
184 (ttt_to_targets syl (wagon syl ttt_endtone_tree)
190 (if (and(not(equal? new_targets nil))
193 (format t ">> Targets: %l\n" new_targets)
194 (format t ">> LastTarget: %l\n" (last new_targets))
200 ;;; CART tree to specify no accents
202 (set! no_int_cart_tree
207 ;;; Relate phrasing to boundary tones.
208 ;;; Added downstepped tones - MDS
210 (set! tobi_label_phrase_cart_tree
212 ((tone in ("L-" "H-" "!H-"))
214 ((tone in ("H-H%" "H-L%" "!H-L%" "L-L%" "L-H%"))
219 ;;; The other functions
222 ;;; process a list of relative targets and convert to actual targets
224 (define (ttt_to_targets syl rlist voicing pvoicing nvoicing type)
225 "Takes a list of target sets and returns a list of targets."
226 (if (or (and (>= printdebug 2)
227 rlist (atom (caar rlist))
228 (not (equal? 'NONE (caar rlist))) (not (equal? '(NONE) (caar rlist))))
230 (begin (print "Entering ttt_to_targets with:")
231 (print (format nil "rlist: %l vc: %l pvc: %l nvc: %l type: %s" rlist voicing pvoicing nvoicing type))))
234 ((eq (length rlist) 0) ())
235 ;; a single target set
236 ((atom (car (car rlist)))
239 (ttt_accent_set_to_targets syl rlist voicing pvoicing nvoicing))
240 ((eq type 'Starttones)
241 (ttt_bound_set_to_targets syl rlist voicing pvoicing))
243 (ttt_bound_set_to_targets syl rlist voicing pvoicing))
244 (t (error "unknown target set encountered in ttt_to_targets"))))
245 ;; list of target sets
246 ((atom (car (car (car rlist))))
247 (append (ttt_to_targets syl (cdr rlist) voicing pvoicing nvoicing type)
248 (ttt_to_targets syl (car rlist) voicing pvoicing nvoicing type)))
250 (t (error "something strange has happened in ttt_to_targets"))))
253 ;; process a starttone/endtone target set.
255 (define (ttt_bound_set_to_targets syl tset voicing pvoicing)
256 "takes a start/endtone target set and returns a list of target points."
257 (if (>= printdebug 3) (begin
258 (print "Entering ttt_bound_set_to_targets with:")
259 (pprintf (format nil "tset: %l vc: %l pvc: %l" tset voicing pvoicing))))
261 ;; usually target given is NONE. (also ignore unknown!)
262 ((or (eq (car (car tset)) 'NONE)
263 (eq (car (car tset)) 'UNKNOWN))
265 ;; a pair of target pairs
266 ((eq (length tset) 2)
267 (list (ttt_get_target (car tset) voicing)
268 (ttt_get_target (car (cdr tset)) voicing)))
269 ;; single target pair
270 ((eq (length tset) 1)
272 ;; an actual target pair
273 ((not (null (cdr (car tset))))
274 (list (ttt_get_target (car tset) voicing)))
276 ((eq (car (car tset)) 'TAKEOVER)
277 (list (list (ttt_interval_percent voicing 0)
278 (ttt_last_target_value syl))))
279 (t (error "unknown target pair in ttt_bound_set_to_targets"))))
280 (t (error "unknown target set type in ttt_bound_set_to_targets"))))
283 ;; process an accent target set.
285 (define (ttt_accent_set_to_targets syl tset voicing pvoicing nvoicing)
286 "takes a accent target set and returns a list of target points."
287 (if (>= printdebug 3) (begin
288 (print "Entering ttt_accent_set_to_targets with:")
289 (pprintf (format nil "tset: %l vc: %l pvc: %l nvc: %l" tset voicing pvoicing nvoicing))))
291 ;; single target in set
294 ; target given is NONE.
295 ((or (eq (car (car tset)) 'NONE)
296 (eq (car (car tset)) 'UNKNOWN)) nil)
298 ((eq (car (car tset)) 'V1)
299 (let ((target_time (+ (/ (- (next_accent_start syl)
300 (ttt_last_target_time syl))
302 (ttt_last_target_time syl))))
303 (list (list target_time (ttt_accent_pitch (Parameter.get 'Valley_Dip) target_time)))))
305 ((eq (car (car tset)) 'V2)
306 (let ((target_time (+ (ttt_last_target_time syl) 0.25)))
307 (list (list target_time (ttt_accent_pitch (Parameter.get 'Valley_Dip) target_time)))))
309 ((eq (car (car tset)) 'V3)
310 (let ((target_time (- (next_accent_start syl) 0.25)))
311 (list (list target_time (ttt_accent_pitch (Parameter.get 'Valley_Dip) target_time)))))
313 (t (list (ttt_get_target (car tset) voicing)))))
317 ;; a *ed tone with PRE type tone (as in L+H*)
318 ((eq (car (car tset)) 'PRE)
319 (let ((star_target (ttt_get_target (car (cdr tset)) voicing))
320 (last_target (parse-number(ttt_last_target_time syl))))
322 ; normal 0.2s case (currently doesn't check for voicing)
323 ((and (eqv? 0 (ip_initial syl))
324 (> (- (car star_target) 0.2) last_target))
325 (list (list (- (car star_target) 0.2)
326 (ttt_accent_pitch (car (cdr (car tset)))
327 (- (car star_target) 0.2))) ; the time
330 ; 90% prev voiced if not before last target - Added back in MDS,
331 ; with parse-number added and new check for ip_initial
332 ((and (eqv? 0 (ip_initial syl))
333 (> (parse-number (ttt_interval_percent pvoicing 90))
334 (parse-number (ttt_last_target_time syl))))
335 (list (list (ttt_interval_percent pvoicing 90)
336 (ttt_accent_pitch (car (cdr (car tset)))
337 (ttt_interval_percent pvoicing 90)))
340 ; otherwise (UNTESTED) [NOTE: Voicing for this syllable only]
342 (list (list (ttt_interval_percent voicing 20)
343 (ttt_accent_pitch (car (cdr (car tset)))
344 (ttt_interval_percent voicing 20)))
346 ; a *ed tone with POST type tone (as L*+H)
347 ((eq (car(car(cdr tset))) 'POST)
348 (let ((star_target (ttt_get_target (car tset) voicing))
349 (next_target nil ) ; interesting problem
350 (next_syl (item.next syl)))
353 ; normal 0.2s case (UNTESTED)
354 ((and (not (equal? next_syl nil))
355 (eq 0 (item.feat next_syl "accented")))
357 ((< (+ (car star_target) 0.2) (item.feat next_syl "syllable_end"))
359 (list (+ (car star_target) 0.2)
360 (ttt_accent_pitch (car (cdr (car (cdr tset))))
361 (+ (car star_target) 0.2) ))))
365 (list (ttt_interval_percent nvoicing 90)
366 (ttt_accent_pitch (car (cdr (car (cdr tset))))
367 (ttt_interval_percent nvoicing 90) ))))))
369 ; 20% next voiced (BUG: Can't do this as the next target hasn't been
372 ;otherwise (UNTESTED)
374 (list (ttt_interval_percent voicing 90)
375 (ttt_accent_pitch (car (cdr (car (cdr tset))))
376 (ttt_interval_percent voicing 90) )))))))
379 ;; This case didn't use to happen, but now must
380 ;; to avoid +H's clobbering endtones - MDS's hack.
381 (list (ttt_get_target (car tset) voicing)
382 (ttt_get_target (cadr tset) voicing)))))
386 (t (error (format nil "unknown accent set in ttt_accent_set_to_targets: %l" tset)))))
390 (define (ttt_get_target pair voicing)
391 "Returns actual target pair, usually for a stared tone."
392 (if (>= printdebug 4) (begin
393 (print "Entering ttt_get_target with:")
394 (pprintf pair) (pprintf voicing)))
395 (list (ttt_interval_percent voicing (car pair))
396 (ttt_accent_pitch (car (cdr pair))
397 (ttt_interval_percent voicing (car pair)))))
399 (define (ttt_accent_pitch value time)
400 "Converts a accent pitch entry to a pitch value."
401 (if (>= printdebug 4) (begin
402 (print "Entering ttt_accent_pitch with:")
407 (ttt_interval_percent (list (ttt_get_current_baseline time)
408 (Parameter.get 'Current_Topline))
410 ;; Downstep then Topline
413 (Parameter.set 'Current_Topline (+ (ttt_get_current_baseline time)
414 (* (Parameter.get 'Downstep_Factor)
415 (- (Parameter.get 'Current_Topline)
416 (ttt_get_current_baseline time)))))
417 (ttt_interval_percent (list (ttt_get_current_baseline time)
418 (Parameter.get 'Current_Topline))
422 (t (error "Unknown accent pitch value encountered"))))
425 (define (ttt_get_current_baseline v)
426 "Returns the current declined baseline at time v."
427 (if (>= printdebug 4) (begin
428 (print "Entering ttt_get_current_baseline with:")
430 (let ((h (Parameter.get 'Current_Start_Baseline))
431 (l (Parameter.get 'Current_End_Baseline))
432 (e (Parameter.get 'Phrase_End))
433 (s (Parameter.get 'Phrase_Start)))
434 (- h (* (/ (- h l) (- e s)) (- v s)))))
436 ;;; find the time n% through an inteval
438 (define (ttt_interval_percent pair percent)
439 "Returns the time that is percent percent thought the pair."
440 (if (>= printdebug 4) (begin
441 (print "Entering ttt_interval_percent with:")
442 (pprintf (format nil "%l, %l" pair percent))))
444 ; no pair given: just return nil
446 ; otherwise do the calculation
447 (t (let ((start (car pair))
448 (end (car(cdr pair))))
449 (+ start (* (- end start) (/ percent 100)))))))
452 ;;; Getting start and end voicing times in a syllable
454 (define (ttt_get_voice_times syl_item)
455 "Returns a pair of start time of first voiced phone in syllable and
456 end of last voiced phone in syllable, or nil if syllable is nil"
458 ((null syl_item) nil)
459 (t (let ((segs (item.relation.daughters syl_item "SylStructure")))
461 (item.feat (ttt_first_voiced segs) "segment_start")
462 (item.feat (ttt_first_voiced (reverse segs)) "end"))))))
464 (define (ttt_first_voiced segs)
465 "Returns first segment that is voiced (vowel or voiced consonant)
466 returns last segment if all are unvoiced."
469 (car segs)) ;; last possibility
470 ((equal? "+" (item.feat (car segs) "ph_vc"))
472 ((equal? "+" (item.feat (car segs) "ph_cvox"))
475 (ttt_first_voiced (cdr segs)))))
477 ;;; ttt_last_target has bifurcated into
478 ;;; ttt_last_target_time and
479 ;;; ttt_last_target_value
480 ;;; to fix a place where f0 was set to last target time!
483 (define (ttt_last_target_time syl)
484 "Returns the end of the most recent previous target
485 in the utterance or nil if there is not one present
487 (if (>= printdebug 3)
488 (begin (print "Entering ttt_last_target_time")
491 (let ((target (ttt_last_target syl)))
494 (item.feat target "R:Target.daughter1.pos"))))
496 (define (ttt_last_target_value syl)
497 "Returns the pitch of the most recent previous target
498 in the utterance or nil if there is not one present
500 (if (>= printdebug 3)
501 (begin (print "Entering ttt_last_target_time")
504 (let ((target (ttt_last_target syl)))
507 (item.feat target "R:Target.daughter1.f0"))))
509 ;; Changed to scan through segments in the segment relation,
510 ;; to catch (notional) targets on pauses. - MDS
512 ;;; associated segments are:
513 ;;; - the segments in the word
514 ;;; - subsequent segments not in the syllable structure
515 ;;; and on the first word, preceding segments
516 ;;; not in the syllable structure
518 (define (ttt_collect_following seg accum)
520 (not (null? (item.relation seg 'SylStructure))))
522 (ttt_collect_following (item.next seg)
526 (define (ttt_last_target syl)
527 "Returns the most recent previous target
528 in the utterance or nil if there is not one present
530 (if (>= printdebug 3)
531 (begin (print "Entering ttt_last_target")
534 (let ((prev_syl (item.relation.prev syl 'Syllable)))
536 ; ((symbol-bound? 'new_targets) (last (caar new_targets)))
537 ((null prev_syl) nil)
538 ((ttt_last_target_segs
539 (ttt_collect_following
541 (item.relation.daughtern prev_syl "SylStructure")
543 (reverse (item.relation.daughters prev_syl "SylStructure")))))
544 ;list of segments of prev. syllable
545 ;in reverse order, with pauses
547 (t (ttt_last_target prev_syl)))))
549 (define (ttt_last_target_segs segs)
550 "Returns the first target no earlier than seg
551 or nil if there is not one
553 (if (>= printdebug 4)
554 (begin (print "Entering ttt_last_target_segs with:")
555 (pprintf (format nil "%l" segs))
559 ((and (> (parse-number
560 (item.feat (car segs) "R:Target.daughter1.f0")) 0)
561 (eq 0 (item.feat (car segs) "R:SylStructure.parent.lisp_lh_condition"))
562 (eq 0 (item.feat (car segs) "R:SylStructure.parent.lisp_hl_condition"))
563 (eq 0 (item.feat (car segs) "R:SylStructure.parent.lisp_valley_condition")))
566 (t (ttt_last_target_segs (cdr segs)))))
568 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
570 ;;;;;; CART TREES (ttt - tobi to target)
572 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
575 ;;; Return a list of target lists. A target list comprises of a list
576 ;;; of related targets (ie for the L and H in L+H*), just to confuse
577 ;;; matters each target is also a list! (pos pitch)
581 (set! ttt_endtone_tree ; BUG: does it check the current syl for last accent?
583 ((tobi_endtone is NONE) ; ususally none
585 ((tobi_endtone is "H-H%") ; H-H%
587 ((tobi_endtone is "L-L%") ; L-L%
589 ((tobi_endtone is "L-H%") ; L-H%
590 ((lisp_last_accent > 2)
591 ((lisp_last_accent_type is "L*")
592 ((((0 25) (100 40)))) ; paper says 80 but AWB had 40
593 ((((0 0) (100 40)))))
594 ((lisp_last_accent_type is "L*")
596 ((((50 0) (100 40))))))
597 ((tobi_endtone is "H-L%") ; H-L%
598 ((lisp_last_accent_type is "L*")
599 ((tobi_accent is"L*")
600 ((((50 100) (100 100))))
601 ((((0 100) (100 100)))))
603 ((tobi_endtone is "!H-L%") ; !H-L%
604 ((lisp_last_accent_type is "L*")
605 ((tobi_accent is"L*")
606 ((((50 DHIGH) (100 100))))
607 ((((0 DHIGH) (100 100)))))
609 ((tobi_endtone is "H-")
611 ((tobi_endtone is "!H-")
613 ((tobi_endtone is "L-")
615 ((((UNKNOWN))))))))))))))
617 (set! ttt_starttone_tree
619 ((lisp_ip_initial = 1)
620 ((tobi_endtone is "%H")
622 ((p.tobi_endtone in ("H-" "!H-" "L-"))
623 ((((TAKEOVER)))) ; takeover case
624 ((tobi_accent is NONE)
625 ((lisp_next_accent > 2) ; default cases (dep. on whether next target is low)
626 ((lisp_next_accent_type in ("L*" "L*+H" "L*+!H" "L+H*" "L+!H*" "L-" "L-H%" "L-L%"))
628 ((((0 50)(100 75)))))
629 ((lisp_next_accent_type in ("L*" "L*+H" "L*+!H" "L+H*" "L+!H*" "L-" "L-H%" "L-L%"))
632 ((tobi_accent in ("L*" "L*+H" "L*+!H" "L+H*" "L+!H*" "L-" "L-H%" "L-L%"))
635 ((((NONE)))))) ; otherwise (and usually) nothing.
637 ;; Redone after Jilka, Moehler and Dogil
638 ;; - But treating one-syllable-ip's like
639 ;; last-syllable-of-ip's in cases of
640 ;; two tone switches per syllable (e.g. H* L-H%).
641 ;; - And (hack) a 70% target for the initial
642 ;; H*'s of phrases when the next accent is L+H*
645 (set! ttt_accent_tree
647 ((tobi_accent is "H*" ) ; H*
649 ((lisp_ip_one_syllable_case = 1)
652 ((lisp_hstar_weak_target = 1)
654 ((lisp_ip_initial = 1)
658 ((tobi_accent is "!H*" ) ; !H*
660 ((lisp_ip_one_syllable_case = 1)
663 ((lisp_ip_initial = 1)
667 ((tobi_accent is "L*" ) ; L*
669 ((lisp_ip_one_syllable_case = 1)
672 ((lisp_ip_initial = 1)
676 ((tobi_accent is "L+H*") ; L+H*
678 ((lisp_ip_one_syllable_case = 1)
679 ((((PRE 20) (50 100)))) ; JMD estimated 70
680 ((((PRE 20) (25 100)))))
681 ((lisp_ip_initial = 1)
682 ((((PRE 20) (90 100))))
683 ((((PRE 20) (75 100))))))
685 ((tobi_accent is "L+!H*") ; L+!H*
687 ((lisp_ip_one_syllable_case = 1)
688 ((((PRE 20) (70 DHIGH))))
689 ((((PRE 20) (25 DHIGH)))))
690 ((lisp_ip_initial = 1)
691 ((((PRE 20) (90 DHIGH))))
692 ((((PRE 20) (75 DHIGH))))))
694 ((tobi_accent is "L*+H") ; L*+H
696 ((lisp_ip_one_syllable_case = 1)
697 ((((35 0) (80 100)))) ; POST would clobber endtones
698 ((((15 0) (40 100))))) ; POST would clobber endtones - MDS
699 ((lisp_ip_initial = 1)
700 ((((55 0) (POST 100))))
701 ((((40 0) (POST 100))))))
703 ((tobi_accent is "L*+!H") ; L*+!H
705 ((lisp_ip_one_syllable_case = 1)
706 ((((35 0) (80 DHIGH)))) ; POST would clobber endtones - MDS
707 ((((15 0) (40 DHIGH))))) ; POST would clobber endtones - MDS
708 ((lisp_ip_initial = 1)
709 ((((55 0) (POST DHIGH))))
710 ((((40 0) (POST DHIGH))))))
712 ((tobi_accent is "H+!H*") ; H+!H*
714 ((lisp_ip_one_syllable_case = 1)
715 ((((PRE 143) (60 DHIGH)))) ; the 143 is a hack to level out the downstep
716 ((((PRE 143) (20 DHIGH)))))
717 ((lisp_ip_initial = 1)
718 ((((PRE 143) (90 DHIGH))))
719 ((((PRE 143) (60 DHIGH))))))
721 ((lisp_lh_condition = 1)
723 ((lisp_lh_condition = 2)
725 ((lisp_hl_condition = 1)
727 ((lisp_valley_condition = 1)
729 ((lisp_valley_condition = 2)
731 ((lisp_valley_condition = 3)
733 ((tobi_accent is NONE) ; usually we find no accent
735 ((((UNKNOWN)))))))))))))))))))) ; UNKNOWN TARGET FOUND
737 ;;; Cart tree to "predict" pitch range
738 ;;; Right now just accesses a feature
739 ;;; "register" following Moehler & Mayer 2001.
740 ;;; Register must be one of
741 ;;; H - primary high register (default): 133% lowest, 92% highest
742 ;;; H-H - expanded high register: 134% lowest, 100% highest
743 ;;; H-L - lowered high register: 128% lowest, 87% highest
744 ;;; L - primary low register: 100% lowest, 73% highest
745 ;;; L-L and HL-L - low compressed: 100% lowest, 66% highest
746 ;;; HL - expanded register: 100% lowest, 84% highest
747 ;;; HL-H - complete register: 100% lowest, 96% highest
748 ;;; For their speaker, ,BASELINE was 42% of PEAK
750 (set! ttt_topline_tree
752 ((R:SylStructure.parent.register is "H")
754 ((R:SylStructure.parent.register is "H-H")
756 ((R:SylStructure.parent.register is "H-L")
758 ((R:SylStructure.parent.register is "L")
760 ((R:SylStructure.parent.register is "L-L")
762 ((R:SylStructure.parent.register is "HL")
764 ((R:SylStructure.parent.register is "HL-H")
768 (set! ttt_baseline_tree
770 ((R:SylStructure.parent.register is "H")
772 ((R:SylStructure.parent.register is "H-H")
774 ((R:SylStructure.parent.register is "H-L")
776 ((R:SylStructure.parent.register is "L")
778 ((R:SylStructure.parent.register is "L-L")
780 ((R:SylStructure.parent.register is "HL")
782 ((R:SylStructure.parent.register is "HL-H")
786 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
788 ;;;;;; Lisp Feature functions.
790 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
792 (define (valley_condition syl)
793 "(valley_condition syl)
794 Function to determine if a lowered target between two high target points
795 is needed in this syllable.
796 Returns: 0 - no target required
797 1 - the single target case
798 2 - the first of the two target case
799 3 - the second of the two target case
801 (if (>= printdebug 4)
802 (begin (print "Entering valley_condition")))
804 ((and (eq 0 (item.feat syl 'accented))
805 (string-matches (next_accent_type syl)
806 "\\(H\\*\\|H\\-\\|H\\-L\\%\\|H\\-H\\%\\|\\!H\\*\\|\\!H\\-\\|\\!H\\-L\\%\\|\\!H\\-H\\%\\)")
807 (string-matches (last_accent_type syl)
808 "\\(H\\*\\|L\\+H\\*\\|L\\*\\+H\\\\|\\!H\\*\\|L\\+\\!H\\*\\|L\\*\\+\\!H\\)"))
809 ;GM: excluded %H (returns nil for last target)
810 (let ((nas (next_accent_start syl))
811 (syls (item.feat syl 'syllable_start))
812 (syle (item.feat syl 'syllable_end))
813 (las (ttt_last_target_time syl)))
814 (if (>= printdebug 3)
815 (begin (print (format nil "nas: %l syls: %l syle %l las %l" nas syls syle las))))
817 ((and (< (- nas las) 0.5)
819 (< syls (+ (/ (- nas las) 2.0) (ttt_last_target_time syl)))
820 (> syle (+ (/ (- nas las) 2.0) (ttt_last_target_time syl)))) 1)
821 ((and (> (- nas las) 0.5)
822 (< syls (+ (ttt_last_target_time syl) 0.25))
823 (> syle (+ (ttt_last_target_time syl) 0.25))) 2)
824 ((and (> (- nas las) 0.5)
825 (< syls (- nas 0.25))
826 (> syle (- nas 0.25))) 3)
832 (define (lh_condition syl)
834 Function to determine the need for extra target points between an L and an H
835 Returns: 1 - first extra target required
836 2 - second extra target required
837 0 - no target required.
839 (if (>= printdebug 4)
840 (begin (print "Entering LH_condition")))
842 ((and (eq 0 (item.feat syl 'accented))
843 (string-matches (last_accent_type syl) "\\(L\\*\\)")
844 (string-matches (next_accent_type syl)
845 "\\(H\\*\\|H\\-\\|H\\-L\\%\\|H\\-H\\%\\)"))
847 ((and (eq 1 (last_accent syl))
848 (< 2 (next_accent syl))) 1)
849 ((and (< 2 (last_accent syl))
850 (eq 1 (next_accent syl))) 2)
854 (define (hl_condition syl)
856 Function to determine the need for extra target points between an H and an L
857 Returns: 1 - extra target required
858 0 - no target required.
860 (if (>= printdebug 4)
861 (begin (print "Entering HL_condition")))
863 ((and (eq 0 (item.feat syl 'accented))
864 (string-matches (next_accent_type syl)
865 "\\(L\\*\\|L\\+H\\*\\|L\\+\\!H\\*\\|L\\*\\+H\\|L\\*\\+!H\\|L\\-\\|L\\-L\\%\\|L-H\\%\\)")
866 (string-matches (last_accent_type syl)
867 "\\(H\\*\\|L\\+H\\*\\|L\\*\\+H\\\\|\\!H\\*\\|L\\+\\!H\\*\\|L\\*\\+\\!H\\|\\%H\\)")
869 (eq 1 (last_accent syl))
872 (<= 2 (next_accent syl))) 1)
875 (define (next_accent syl)
877 Wrapper for c++ func ff_next_accent.
878 Returns the number of the syllables to the next accent in the following format.
881 2 - next next syllable
883 (if (>= printdebug 4)
884 (begin (print "Entering next_accent")))
886 ((eq 0 (next_accent_type syl)) 0)
887 (t (+ (item.feat syl 'next_accent) 1))))
889 ;; Fixed bug that crashed complex phrase tones. - MDS
890 ;; Not sure how else to get a big number...
891 (define infinity (/ 1 0))
893 ;; Modified to include current accent as well -MDS
895 (define (last_accent syl)
897 Wrapper for c++ func ff_last_accent.
898 Returns the number of the syllables to the previous accent in the following format.
899 0 - accent on current syllable
901 2 - prev to prev syllable
903 infinity - no previous syllable"
904 (if (>= printdebug 4)
905 (begin (print "Entering last_accent")))
907 ((not (equal? "NONE" (item.feat syl 'tobi_accent))) 0)
908 ((equal? 0 (last_accent_type syl)) infinity)
909 (t (+ (item.feat syl 'last_accent) 1))))
911 (define (next_accent_type syl)
912 "(next_accent_type syl)
913 Returns the type of the next accent."
915 ((not (eq 0 (item.feat syl "n.R:Intonation.daughter1.name")))
916 (item.feat syl "n.R:Intonation.daughter1.name"))
917 ((eq 0 (item.feat syl 'syl_out)) 0) ;;GM real ip_final would be better
918 (t (next_accent_type (item.relation.next syl 'Syllable)))))
920 (define (last_accent_type syl)
921 "(last_accent_type syl)
922 Returns the type of the last (previous) accent."
923 (if (>= printdebug 4)
924 (begin (print "Entering last_accent_type")))
926 ((not (equal? "NONE" (item.feat syl 'p.tobi_endtone)))
927 (item.feat syl 'R:Syllable.p.tobi_endtone))
928 ((not (equal? "NONE" (item.feat syl 'p.tobi_accent)))
929 (item.feat syl 'R:Syllable.p.tobi_accent))
930 ((eq 0 (item.feat syl 'syl_in)) 0) ;;GM real ip_initial would be better
931 (t (last_accent_type (item.prev syl 'Syllable)))))
933 (define (next_accent_start syl)
934 "(next_accent_start syl)
935 Returns the start time of the vowel of next accented syllable"
936 (if (>= printdebug 4)
937 (begin (print "Entering next_accent_start")))
939 ((not (eq 0 (item.feat syl "n.R:Intonation.daughter1.name")))
940 (item.feat syl "R:Syllable.n.syllable_start")) ;;GM vowel start would be better
941 ((eq 0 (item.feat syl 'syl_out)) 0)
942 (t (next_accent_start (item.relation.next syl 'Syllable)))))
944 ; new features (not used yet)
946 (define (ip_final syl)
948 returns 1 if the syllable is the final syllable of an
949 ip (intermediate phrase)"
951 ((or (equal? 0 (item.feat syl "syl_out"))
952 (equal? "L-" (item.feat syl "tobi_endtone"))
953 (equal? "H-" (item.feat syl "tobi_endtone"))
954 (equal? "!H-" (item.feat syl "tobi_endtone"))) 1)
957 (define (ip_initial syl)
959 returns 1 if the syllable is the initial syllable of an
960 ip (intermediate phrase)"
962 ((equal? 0 (item.feat syl "syl_in"))
964 ((equal? 1 (ip_final (item.relation.prev syl 'Syllable)))
968 ;; NEXT TWO FUNCTIONS ARE NEW - MDS
969 (define (ip_one_syllable_case syl)
970 "(ip_one_syllable_case SYL)
971 returns true if the syllable is the initial syllable of an
972 ip (intermediate phrase) and doesn't itself contain a complex
973 tone that starts opposite this syllable's accent"
974 (if (eqv? 0 (ip_initial syl))
976 (let ((accent (item.feat syl "tobi_accent"))
977 (tone (item.feat syl "tobi_endtone")))
979 ((and (equal? tone "L-H%")
980 (or (equal? accent "H*")
981 (equal? accent "!H*")
982 (equal? accent "L+H*")
983 (equal? accent "L+!H*")
984 (equal? accent "L*+H")
985 (equal? accent "L*+!H*")
986 (equal? accent "H+!H*")))
988 ((and (or (equal? tone "H-L%")
989 (equal? tone "!H-L%"))
990 (equal? accent "L*"))
995 (define (hstar_weak_target syl)
996 (if (and (equal? 0 (item.feat syl 'asyl_in))
997 (member (next_accent_type syl)
998 (list "L*" "L*+H" "L*+!H" "L+H*" "L+!H*")))
1002 (provide 'tobi_rules)