;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<--OGI-->;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                                        ;;
;;             Center for Spoken Language Understanding                   ;;
;;        Oregon Graduate Institute of Science & Technology               ;;
;;                         Portland, OR USA                               ;;
;;                        Copyright (c) 2000                              ;;
;;                                                                        ;;
;;      This module is not part of the CSTR/University of Edinburgh       ;;
;;               release of the Festival TTS system.                      ;;
;;                                                                        ;;
;;  In addition to any conditions disclaimers below, please see the file  ;;
;;  "license_ogi_tts.txt" distributed with this software for information  ;;
;;  on usage and redistribution, and for a DISCLAIMER OF ALL WARRANTIES.  ;;
;;                                                                        ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<--OGI-->;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;   ((name    retname)  ;; should be same as one we asked for
;;;    (db_indx dbindx#)
;;;    (Lindx  Lindx# )
;;;    (segs   (Uinfo1 Uinfo2 ...)))
;;;
;;;	  where each UinfoN is of the form
;;;	    (segname
;;;		 ((dur durval)
;;;		  (featA featAval)    ;; these aren't used yet
;;;		  (featB featBval))
;;;


; loop thru segments, create dbUnit stream, lookup diphone

(define (OGI_di_unitsel utt)
  "(OGI_di_unitsel utt)
Simple unit selection for diphone synthesis: 
constructs name from Segment names and selects first unit
with same name."  	   
  ;; UNIT SELECTION 
  (set! SelectedUnits nil)
  (mapcar
   (lambda (seg)
     (if (equal? (item.next seg) nil)
	 nil    ;; if last segment of utt, don't do anything
	 (begin

	   ;; create the name of the desired unit 
	  (set! Lnm (item.feat seg "allophone_name"))
	  (if (string-equal Lnm "0")
	      (set! Lnm (item.name seg)))
	  (set! Rnm (item.feat (item.next seg) "allophone_name"))
	  (if (string-equal Rnm "0")
	    (set! Rnm (item.name (item.next seg))))

	  (set! n (string-append Lnm "-" Rnm))

	   ;; look up in dbase
	   (set! indx (OGIdbase.unitsel_name n))

;;	  (print (string-append "lookup unit " n " --> " indx))

	   ;; look for alternates if original not found
	   (if (equal? indx nil)
	       (set! indx (OGI_di_alt Lnm Rnm)))

	   ;; lookup info structure for this unit
	   (set! sel (list (OGIdbase.lookup_info indx)))

	   ;; append info to list
	   (set! SelectedUnits (append SelectedUnits sel))
	   )))
   (utt.relation.items utt "Segment"))
  SelectedUnits)


(define (OGI_di_alt L R)
  "(OGI_di_alt L R)
Find alternate fallback diphone when original not found.  Uses global variables
ogi_di_alt_L and ogi_di_alt_R which should be set in the voice definition."

  ;; create a list of potential fallback diphones:
  ;;  (itself + all listed alternates)
  (set! nlist nil)
  (mapcar 
   (lambda (Lseg)     
     (mapcar 
      (lambda (Rseg)
	(set! nlist (append nlist (list (string-append Lseg "-" Rseg))))
	)
      (append (list R) (cadr (assoc (intern R) ogi_di_alt_R)))))
   (append (list L) (cadr (assoc (intern L) ogi_di_alt_L))))
  
  ;; run through the list and take 1st one we can find
  (set! indx nil)  
  (while (equal? indx nil)
    (set! indx (OGIdbase.unitsel_name (car nlist)))
    (set! altname  (car nlist)) ;; just to print
    (set! nlist (cdr nlist))
    (if (and (equal? indx nil) (equal? nlist nil))
	;; if all else fails...
	(begin 
	 (set! indx (OGIdbase.unitsel_name ogi_di_default))
	 ;; if still fails...
	 (if (equal? indx nil)
	     (set! indx 0)))))

;  (print (string-append "  alternate "  altname  " (" indx ") selected for " L "-" R ))
indx)


(define (OGI_demi_unitsel utt)
  "(OGI_demi_unitsel utt)
Does a demiphone selection (similar to diphone synthesis)."
  ;; Note: 1st and last /pau/ will have only 1 demiphone, not 2
  (set! SelectedUnits nil)
  (mapcar
   (lambda (seg)
     (if (equal? (item.next seg) nil)
	 nil    ;; if last seg, don't do anything
	 (begin
	   
	   ;;
	   ;; X>Y - right demiphone X with right context Y
	   ;;
	   (set! n (string-append (item.name seg) ">" (item.name (item.next seg))))
	   (set! indx (OGIdbase.unitsel_name n))
(print "still need to fix alternates mechanism here")
	   ;; look for alternates if original not found
	   ;; may need to change output of lookup_info too!
	   (if (equal? indx nil)
	       (set! indx 0))
	   
	   (set! sel (list (OGIdbase.lookup_info indx)))
	   (set! SelectedUnits (append SelectedUnits sel))
	   
	   ;;
           ;; Y<Z - left demiphone Y with left context Z
	   ;;
	   (set! n (string-append (item.name (item.next seg)) "<" (item.name seg)))
	   (set! indx (OGIdbase.unitsel_name n))


	   ;; look for alternates if original not found
	   ;; may need to change output of lookup_info too!
	   (if (equal? indx nil)
	       (set! indx 1))

	   (set! sel (list (OGIdbase.lookup_info indx)))
	   (set! SelectedUnits (append SelectedUnits sel))
	 )))
   (utt.relation.items utt "Segment"))
  SelectedUnits)


(define (OGI_tri_unitsel utt)
  "(OGI_tri_unitsel utt)
Does a simple unit selection for triphone-context phone-based synthesis,
compatible with code for all selection approaches."  	   
  ;; UNIT SELECTION 
  (set! SelectedUnits nil)
  (mapcar
   (lambda (seg)
     (if (equal? (item.prev seg) nil)
	 (set! L "*")
	 (set! L (item.name (item.prev seg))))
     
     (if (equal? (item.next seg) nil)
	 (set! R "*")
	 (set! R (item.name (item.next seg))))

     (set! n (string-append (item.name seg) "<" L ">" R))
     (set! indx (OGI_dummy_name_unitselect n))
     (set! sel (list (OGIdbase.lookup_info indx)))
     (set! SelectedUnits (append SelectedUnits sel))
     )
   (utt.relation.items utt "Segment"))
  SelectedUnits)


(define (OGI_phone_unitsel utt)
  "(OGI_phone_unitsel utt)
Does a simple unit selection for single-instance phone-based synthesis,
compatible with code for all selection approaches."  	   
  ;; UNIT SELECTION 
  (set! SelectedUnits nil)
  (mapcar
   (lambda (seg)
     (set! n (item.name seg))
     (set! indx (OGI_dummy_name_unitselect n))
     (set! sel (list (OGIdbase.lookup_info indx)))
     (set! SelectedUnits (append SelectedUnits sel))
     )
   (utt.relation.items utt "Segment"))
  SelectedUnits)





(define (OGI_set_dbUnit_feats utt SelectedUnits)
  "(OGI_set_dbUnit_feats utt SelectedUnits)
       Put necessary features into the dbUnit relation for OGI waveform synthesizer.
       SelectedUnits is a list of structures containing necessary dbUnit info."
 
   ;; create dbUnit stream
   (utt.relation.create utt "dbUnit")

   ;; Set FEATURES on the dbUnit for each SelectedUnit
   (mapcar
    (lambda (sel)
      ;; append a new dbUnit
      (set! uttUnit (utt.relation.append utt "dbUnit"))
      
      ;; set its name (for debug)
      (item.set_name uttUnit (cadr (assoc 'name sel)))
      
      ;; index into current dbase
      (item.set_feat uttUnit "db_indx" (cadr (assoc 'db_indx sel)))

       ;; is previous unit this unit's natural neighbor?
      (item.set_feat uttUnit "isNatNbL" 0)

      (if (item.prev uttUnit)
	  (if (equal? (parse-number (item.feat (item.prev uttUnit) "db_indx"))
		  (parse-number (cadr (assoc 'Lindx sel))))
		(item.set_feat uttUnit "isNatNbL" 1)
		(item.set_feat uttUnit "isNatNbL" 0)))

      ;; is previous unit in the same segment as begin of this one?
      (if (equal? (cadr (assoc 'Lbnd sel)) 1)
	  (item.set_feat uttUnit "isSegBndL" 1)
	  (item.set_feat uttUnit "isSegBndL" 0)
	  )

      ;; append daughters to the dbUnit for each segment in the unit
      (mapcar
       (lambda (uinfo)
	 (item.append_daughter uttUnit uinfo))
       (cadr (assoc 'segs sel)))
    )
    SelectedUnits))


(define (OGI_dummy_name_unitselect uname)
  "This is just a dummy - real one in C++..."
(parse-number (intern (string-before (* 99 (rand)) ".")))
)


