Institut

Studium

Forschung


 

siehe auch:Festival im Emacs.

Festival starten

Festival benutzt man am besten, indem man ein Terminal aufruft. Danach Festival durch Eintippen von

festival

im Terminal starten. Dadurch ist man im sogenannten interaktiven Modus, und festival nimmt Befehle entgegen.
Alternativ kann man auch Text über standard in direkt synthetisieren lassen, z.B.
echo "Hallo" | festival --tts

In beiden Fällen ist es sehr wichtig, die Kodierung des Terminals auf ISO-8859-1 umzustellen, sonst werden Umlaute nicht korrekt synthetisiert.

Eine Beispielsitzung

Festival in der Shell starten mit: 

festival

festival>(SayText "Hallo")
#<Utterance 0x407e33e8>

Der Befehl "SayText" liefert eine "Utterance"/Auesserung zurück, deren festival-interne ID man in der zweiten Zeile sehen kann.

<<< Anmerkung: Je nach init-File wird als Default eine bestimmte Stimme verwendet. Im interaktiven Modus können Stimmen explizit geladen werden, z.B. mit:

(voice_german_de4)

Welche Stimmen verfügbar sind, kann man sehen, wenn man beginnt, (voice... einzutippen und dann mit dem Tab mögliche Vervollständigungen anzeigen lässt.

Welche Stimme geladen ist, ist in der Variable current-voice gespeichert.

Deren Wert kann man sich anzeigen lassen, indem man tippt:

current-voice

Ende Anmerkung. >>>
 

Die erzeugte Utterance-Struktur anschauen:

im Text-Modus interaktiv:

Die entsprechende Äußerung in einer Variable utt speichern:

(set! utt (SayText "Hallo"))
 

Es werden mehrere "Relationen" erzeugt. Die Relationen verbinden Listen von Elementen miteinander. Alle zu einer Relation gehörenden Elemente sind in einer Liste angeordnet. In manchen Fällen sind die Relationen keine flachen Listen, sondern hierarchisch strukturiert, d.h. die Listen enthalten geschachtelte Listen. Manche Relationen
sind indirekt miteinander verknüpft, weil sie dieselben Elemente enthalten.

Nachsehen, welche Relationen in einer Äußerungsstruktur vorkommen:

festival> (utt.relationnames utt)
(Token
 Word
 Phrase
 Syllable
 Segment
 SylStructure
 IntEvent
 Intonation
 Target
 Wave)

Einzelne Relationen ansehen:

festival> (utt.relation_tree utt 'Word)
((("Hallo" ((id "_2") (name "Hallo") (pbreak "NB") (pos "ITJ")))))

Die Relation "Word" enthält hier also nur ein Element, nämlich das Wort "Hallo". Dieses Element hat außer seinem Namen noch weitere Attribute: eine ID-Nummer, die Information, ob nach dem Wort eine
Phrasengrenze folgt (in diesem Fall nicht: NB für no break), und ein part-of-speech-Tag ("ITJ" für Interjektion). Der Name wird zweimal aufgeführt, einmal in der Liste der Attribute, und einmal als Bezeichnung des übergeordneten Elements (erstes Element der Liste).

festival> (utt.relation_tree utt 'Token)
((("Hallo"
   ((id "_1") (name "Hallo") (whitespace "") (prepunctuation"")))
  (("Hallo" ((id "_2") (name "Hallo") (pbreak "NB") (pos "ITJ"))))))

Die Relation "Token" enthält ebenfalls ein (allerdings geschachteltes) Element, das ebenfalls den Namen "Hallo" trägt. Es ist vermerkt, dass dem Token "Hallo" im Text kein Whitespace voranging, und dass keine Prepunktuation (wie z.B. öffnende Klammern, öffnende Quotes) vorhanden war. Unterhalb dieses Tokens hängt noch das Wort "Hallo", das identisch ist mit dem oben genannten Element in der Wortrelation (es trägt dieselbe ID).

Der Unterschied zwischen diesen 2 Ebenen in der Token-Relation zeigt sich z.B. bei Komposita mit Bindestrich oder bei Abkürzungen:

festival> (set! utt (SayText "Halli-hallo"))
#<Utterance 0x407865a8>
festival> (utt.relation_tree utt 'Token)
((("Halli-hallo"
   ((id "_1")
    (name "Halli-hallo")
    (whitespace "")
    (prepunctuation "")
    (token_pos "comb_abbr")))
  (("Halli" ((id "_2") (name "Halli") (pbreak "NB") (pos "nil"))))
  (("hallo" ((id "_3") (name "hallo") (pbreak "NB") (pos "ITJ"))))))

Hier hängen am übergeordneten Token "Halli-hallo" zwei Wörter, "Halli" und "hallo". Ähnlich bei Abkürzungen: dann findet man auf der Wortebene die Wörter, zu denen die Abkürzung expandiert werden soll.

festival> (set! utt (SayText "Hallo usw."))
#<Utterance 0x407865a8>
festival> (utt.relation_tree utt 'Token)
((("Hallo"
   ((id "_1") (name "Hallo") (whitespace "") (prepunctuation"")))
  (("Hallo" ((id "_3") (name "Hallo") (pbreak "NB") (pos "ITJ")))))
 (("usw"
   ((id "_2")
    (name "usw")
    (punc ".")
    (whitespace " ")
    (prepunctuation "")))
  (("und" ((id "_4") (name "und") (pbreak "NB") (pos "KO"))))
  (("so" ((id "_5") (name "so") (pbreak "NB") (pos "ADV"))))
  (("weiter" ((id "_6") (name "weiter") (pbreak "BB") (pos "ADJ"))))))

Ein weiteres Beispiel für eine hierarchische Relation ist die SylStructure-Relation: Dort gibt es die Wortebene, darunter die Silbenebene, und darunter die Segmentebene:
 

festival> (set! utt (SayText "Hallo"))
#<Utterance 0x407865a8>
festival> (utt.relation_tree utt 'SylStructure)
((("Hallo" ((id "_2") (name "Hallo") (pbreak "NB") (pos "ITJ")))
  (("ha" ((id "_4") (name "ha") (stress 0)))
   (("h"
     ((id "_5")
      (name "h")
      (dur_factor -0.00021387900051195)
      (end 0.43829074501991))))
   (("a"
     ((id "_6")
      (name "a")
      (dur_factor 0.00046763601130806)
      (end 0.558285176754)))))
  (("lo:" ((id "_7") (name "lo:") (stress 1)))
   (("l"
     ((id "_8")
      (name "l")
      (dur_factor -0.00017604799359106)
      (end 0.60260915756226))))
   (("o:"
     ((id "_9")
      (name "o:")
      (dur_factor -7.5191303039901e-05)
      (end 0.70340883731842)))))))
 

Bei der Synthese wird immer eine Reihe von Modulen durchlaufen. In vielen Fällen wird durch ein Modul eine neue Relation erzeugt, manchmal werden auch nur bestehende Relationen modifiziert (z.B. wird die Silbenstruktur durch den Lexikon-Lookup aufgebaut, die Dauerinformation (die end und dur_factor Features im Beispiel oben) kommt aber erst später durch das Dauermodul dazu).

Welche Module durchlaufen werden, wird vom jeweiligen "UttType" bestimmt. Dieser ist, wenn man SayText bzw. den TTS-Modus benutzt, automatisch "Text". Benutzt man die Funktion SayPhones (SayPhones '(h a l o:)), so ist der UttType "Phones". Welche UttTypes definiert sind und welche Module jeweils nacheinander durchlaufen werden, ist in der Variable UttTypes gespeichert. Die Variable kann man sich im interaktiven Modus anschauen, indem man ihren Namen ohne Klammern eingibt:

festival> UttTypes

Man erhält damit eine Liste von Listen: eine pro UttType. In jeder dieser Listen ist das erste Element der UttType, und die danach folgende Liste gibt die Module an, die durchlaufen werden müssen. Für den Text-Modus ist die Abfolge:

 (Text
  (Initialize utt)
  (Text utt)
  (Token_POS utt)
  (Token utt)
  (POS utt)
  (Phrasify utt)
  (Word utt)
  (Pauses utt)
  (Intonation utt)
  (PostLex utt)
  (Duration utt)
  (Int_Targets utt)
  (Wave_Synth utt))

Der Befehl

(set! utt1 (SayText "Hallo"))

ist äquivalent zu

(set! utt1 (Utterance Text "Hallo"))
(utt.synth utt1)
(utt.play utt1)

(In der ersten Zeile wird eine Äußerung vom Typ "Text" in der Variable utt1 gespeichert, diese wird dann mit utt.synth synthetisiert und mit utt.play abgespielt.)

(utt.synth utt) ist im Modus Text wiederum äquivalent zu der im UttTypeText angegebenen Abfolge von Befehlen:

(Initialize utt)
(Text utt)
(Token_POS utt)
(Token utt)
(POS utt)
(Phrasify utt)
(Word utt)
(Pauses utt)
(Intonation utt)
(PostLex utt)
(Duration utt)
(Int_Targets utt)
(Wave_Synth utt)

Das bedeutet, man kann einzelne Module ausführen lassen, indem man nur den entsprechenden Befehl eintippt, mit der Variable für die Äußerung als Argument. Dadurch kann man schrittweise nachvollziehen, welche Module die Äußerungsstrukturen wie modifizieren, durch Aufruf der einzelnen Module Schritt für Schritt und Ansehen der Äußerung zwischendurch.

Die einzelnen Module in Kürze:

Text:

Zerlegt den Text in einzelne Tokens.

Token_POS:

"Rät", zu welchem Typ das Token gehört (z.B. Ordinalzahl, Bruch, Abkürzung, Datum, Uhrzeit, Jahr). Ist besonders wichtig für Abkürzungen und Zahlen, die vom Typ her ambig sind und daher unterschiedlich ausgesprochen werden sollten - Token_POS disambiguiert sie und versieht sie aufgrund des Kontexts mit einem eindeutigen Label für den Typ.

Token:

Fügt die Wort-Relation zur Token-Relation hinzu, d.h., Aufspaltung von Komposita mit Bindestrichen in mehrere Wörter, Espansion von Abkuerzungen, usw.

POS:

Der part-of-speech-Tagger, wenn vorhanden. In den obigen Beispielen wurde keiner verwendet. Er wird z.B. eingesetzt, wenn die Stimme (voice_german_de4_linginto) verwendet wird. Die Tags sind anschließend als Attribute in der Wort-Relation vorhanden.

Phrasify:

Bestimmt, an welchen Stellen Phrasengrenzen eingefügt werden sollen. Das Ergebnis kann man an den Attributen pbreak in der Wortrelation sehen: B steht für kleine Breaks (entspricht intermediaeren Phrasengrenzen), BB für große "big" Breaks (entspricht Intonationsphrasengrenzen), und NB für no break sonst.

Word:

Lexikon-Lookup. Dadurch wird die Silbenstrukturrelation ("SylStructure") sowie die flachen Relationen Segment und Syllable erzeugt. Liegen keine POS-Tags von einem Tagger vor, werden außerdem die Tags aus dem Lexikon übernommen.

Einträge im Lexikon können folgendermaßen abgerufen werden:

festival> (lex.lookup "Hallo")
("hallo" ITJ (((h a) 0) ((l o:) 1)))

Die Phoneme werden in Sampanotation angegeben, pro Silbe eine Liste, die zunächst eine Liste der Phoneme und dann 0 oder 1 für unbetont oder betont enthält.

Neue Einträge können ebenfalls hinzugefügt oder alte überschrieben werden:

(lex.add.entry '("hallo" ITJ (((h a ) 1) ((l o:) 0))))
festival> (lex.lookup "Hallo")
("hallo" ITJ (((h a) 1) ((l o:) 0)))
 

Pauses:

Einfügen von Pausen an den durch Phrasify gekennzeichneten Stellen (Ersichtlich an einem Stillesegment ("_") in der Segmentrelation).
 

Intonation:

Die Intonationsgenerierung (hier nur abstrakte Labels, für o.g. Stimmen ToBI-Labels). Ersichtlich an der Relation "Intonation", in der an jeder akzentuierten Silbe und an jeder Silbe, auf der ein Grenzton realisiert wird, das entsprechende Label hängt.

festival> (utt.relation_tree utt 'Intonation)
((("ha" ((id "_4") (name "ha") (stress 1)))
  (("H*L" ((id "_12") (name "H*L"))))))
 

PostLex:

Postlexikalische Regeln, hier recht unbedeutend. Generell dazu da, um von der kanonischen Aussprache auf die in gesprochener Sprache erwartete Ausprache zu mappen.
 

Duration:

Lautdauer, ersichtlich an den end-Attributen in der Segment-Relation.
 

IntTargets:

Umsetzung der durch Intonation vorgegebenen Labels in tatsächliche F0-Targets. Zu sehen in der Relation "Target" (ein oder mehrere Targets auf verschiedenen Segmenten, angegeben durch F0-Wert und Position innerhalb des Segments).
 

Wave_Synth:

Die tatsächliche Synthese. Nirgends zu sehen, bloß zu hören ;-)
 
 

© AntjeSchweitzer, 28.04.15