| Building Synthetic Voices | ||
|---|---|---|
| <<< Previous | A Practical Speech Synthesis System | Next >>> | 
A set of simple access methods exist for utterances, relations, items and features, both in Scheme and C++. As much as possible these access methods are as similar as possible.
As the users of this document will primarily be accessing utterance via Scheme we will describe the basic Scheme functions available for access and give some examples of idioms to achieve various standard functions.
In general the required arguments to a lisp function are reflected in 
the first parts of the name of the function. Thus 
item.relation.next requires an item, and relation name and will 
return the next item in that named relation from the given one. 
A listing a short description of the major utterance access and manipulation functions is given in the Festival manual.
An important notion to be aware of is that an item is always viewed 
through so particular relation. For example, assuming 
a typically utterance called utt1. 
(set! seg1 (utt.relation.first utt1 'Segment))
seg1 is an item viewed from the Segment relation. Calling 
item.next on this will return the next item in the Segment 
relation. A Segment item may also be in the SylStructure 
item. If we traverse it using next in that relation we will hit 
the end when we come to the end of the segments in that syllable. 
You may view a given item from a specified relation by 
requesting a view from that. In Scheme nil will 
be returned if the item is not in the relation. The 
function item.relation takes an item and relation 
name and returns the item as view from that relation. 
Here is a short example to help illustrate the basic structure.
The first segment in(set! utt1 (utt.synth (Utterance Text "A short example.")))
utt! will be silence. 
This item will be a silence as can shown by(set! seg1 (utt.relation.first utt1 'Segment))
If we find the next item we will get the schwa representing the indefinite article.(item.name seg1)
Let us move onto the "sh" to illustrate the different between traversing the(set! seg2 (item.next seg1))
(item.name seg2)
Segment relation as opposed to the 
SylStructure 
Let use define a function which will take an item, print its name name call next on it in the same relation and continue until it reaches the end.(set! seg3 (item.next seg2))
If we call this function on(define (toend item)
(if item
(begin
(print (item.name item))
(toend (item.next item)))))
seg3 which is in the Segment 
relation we will get a list of all segments until the end of the utterance 
However if we first changed the view of seg3 to thefestival> (toend seg3)
"sh"
"oo"
"t"
"i"
"g"
"z"
"aa"
"m"
"p"
"@"
"l"
"#"
nil
festival>
SylStructure 
relation we will be traversing the leaf nodes of the syllable structure 
tree which will terminate at the end of that syllable. 
Note thatfestival> (toend (item.relation seg3 'SylStructure)
"sh"
"oo"
"t"
nil
festival>
item.next returns the item immediately to the next in 
that relation. Thus it return nil when the end of a sub-tree is 
found. item.next is most often used for traversing simple lists 
through it is defined for any of the structure supported by relations. 
The function item.next_item allows traversal of any relation 
returning a next item until it has visiting them all. In the simple 
list case this this equivalent to item.next but in the tree case 
it will traverse the tree in pre-order that is it will visit 
roots before their daughters, and before their next siblings. 
Scheme is particularly adept at using functions as first class 
objects. A typical traversal idiom is to apply so 
function to each item in a a relation. For example support 
we have a function PredictDuration which takes a single item 
and assigns a duration. We can apply this to each item in the 
Segment relation 
The function(mapcar
PredictDuration
(utt.relation.items utt1 'Segment))
utt.relation.items returns all items in the 
relation as a simple lisp list. Another method to traverse the items in a relation is use 
the while looping paradigm which many people are more 
familiar with. 
(let ((f (utt.relation.first utt1 'Segment)))
(while f
(PredictDuration f)
(set! f (item.next_item f))))
If you wish to traverse only the leaves of a tree you 
may call utt.relation.leafs instead of 
utt.relation.items. A leaf is defined to be an item with 
no daughters. Or in the while case, there isn't standardly 
defined a item.next_leaf but code easily be defined 
as 
(define (item.next_leaf i)
(let ((n (item.next_item i)))
(cond
((null n) nil)
((item.daughters n) (item.next_leaf n))
(t n))))
Rather than explicitly calling a set of functions to find your way round an utterance we also allow access through a linear flat pathname mechanism. This mechanism is read-only but can succinctly access not just features on a given item but features on related items too.
For example rather than calling an explicit next function to find the name of the following item thus
You can access it via the pathname(item.name (item.next i))
Festival will interpret the feature name as a pathname. In addition to traversing the current relation you can switch between relations via the element(item.feat i "n.name")
R:relationname. Thus to 
find the stress value of an segment item seg we need 
to switch to the SylStructure relation, find its parent 
and check the stress feature value. 
Feature pathnames make the definition of various prediction models much easier. CART trees for example simply specify a pathname as a feature, dumping features for training is also a simple task. Full function access is still useful when manipulation of the data is required but as most access is simply to find values pathnames are the most efficient way to access information in an utterance.(item.feat seg "R:SylStructure.parent.stress")
For example suppose you wish to traverse each segment in an utterance replace all vowels in unstressed syllables with a schwa (a rather over-aggressive reduction strategy but it servers for this illustrative example.
(define (reduce_vowels utt)
(mapcar
(lambda (segment)
(if (and (string-equal "+" (item.feat segment "ph_vc"))
(string-equal
"1" (item.feat segment "R:SylStructure.parent.stress")))
(item.set_name segment "@")))
(utt.relation.items 'Segment)))
| <<< Previous | Home | Next >>> | 
| Modules | Up | Utterance building |