Letzte Änderung dieses Dokuments: 06.04.2008, 11:34:15. Text-To-Speech
1. Inhalt
2. Einleitung
3. Einführung
3.1. Allgemeines
3.2. Wo gibt's was?
4. Installation
4.1. mbrola Binaries
4.2. txt2pho
5. Konfiguration
5.1. mbrola
5.2. txt2pho
5.3. Erster Test: "Hallo Welt"
6. Verwendungsbeispiele
6.1. Das Skript speak
6.2. Begrüssung bei Login
6.3. Mailbenachrichtigung
6.4. /dev/speech - speechd oder Named Pipe mit speakd
mbrola ist eine Software zur Sprachsynthese. Sie ist ein möglicher
Bestandteil eines Text-To-Speech (kurz: TTS) Systems.
Die Ziel ist es, den Computer dazu zu bewegen, normalen Text als Sprache
zu synthetisieren, also vorzulesen.
Diese Anleitung beschreibt, wie man mithilfe von mbrola und einigen dazu
passenden Hilfsprogrammen ein solches System auf Linux aufsetzt.
Wie üblich bin ich für Verbesserungsvorschläge und Hinweise auf Fehler
überaus dankbar.
Wie bei Unices üblich, so gibt es auch hier keine eierlegende
Wollmilchsau, die alles in einem macht. Also nix mit 'mbrola "Sag mal
was"'.
Das macht die Einrichtung auf den ersten Blick komplizierter, aber man
gewinnt dafür auch deutlich an Flexibilität.
Bei der Sprachsynthese geht das so:
Auf der einen Seite habe ich meinen ganz normalen Text, den ich gerne
vorgelesen bekommen möchte. Das ist das linke Ende. :-)
Darauf lasse ich als allererstes meinen Preprozessor los. Das muss ich zwar
nicht machen, denn der Phonemgenerator, der im nächsten Schritt kommt, arbeitet
auch so, aber besser ist das! Warum? Nun, der Text kann Abschnitte enthalten,
die für einen Menschen klar und deutlich interpretierbar sind, einem Programm
aber Schwierigkeiten machen.
Einfach Beispiel - Betrachten wir einmal folgenden Text:
Tagesordnung zur Sitzung Nr. 123 der anonymen Windows-User
1. Begrüssung, Einleitung, Verlesesung der Tagesordnung
2. Neustart wegen allgemeiner Schutzverletzung
3. Vorstellung neuer Software
4. Neustart wegen allgemeiner Schutzverletzung
5. Besprechen der bisherigen Erfahrungen mit Windows XP
6. Neustart wegen schweren Ausnahmefehlers 0D
Die Punkte hinter Zahlen bedeuten hier nicht, dass ein Satz zuende ist, sondern
dass es eine Aufzählung ist. Und die Abkürzung "Nr." soll natürlich nicht
"En-Er" ausgesprochen werden, sondern eigentlich "Nummer" heissen. Dafür ist ein
Preprozessor da. Er ersetzt diesen Text, formt ihn so um, dass er hinterher
eindeutig formuliert ist. Beispielsweise so:
Tagesordnung zur Sitzung Nummer Einhundertdreiundzwanzig der anonymen
Windows-User
Erstens Begrüssung, Einleitung, Verlesesung der Tagesordnung
Zweitens Neustart wegen allgemeiner Schutzverletzung
...
Wir erhalten vom Preprozessor also einen Text, der frei von solchen
Abkürzungen ist und exakt das enthält, was hinterher synthetisiert werden
soll.
Diesen Text schicken wir nun zunächst durch einen Phonemgenerator. Wozu?
Nun, Sprache im Allgemeinen und die deutsche im Speziellen hat das Problem,
dass ein keine eindeutige Zuordnung gibt, wie welche Schriftzeichen
auszusprechen sind. Der Buchstabe 'E' beispielsweise wird je nachdem, mit
welchen anderen Buchstaben er zusammensteht, anders ausgesprochen (vgl.
"Bett", "Beet" und "Bein").
Deshalb muss der normale Text erstmal in Phoneme, also quasi in Lautschrift
übersetzt werden, die beschreibt, wie sich das ganze hinterher anhören soll.
Letztlich ist auch nur der Phonemgenerator und die Stimme sprachspezifisch. Die
vom Generator erzeugten Phoneme sind immer gleich und werden vom Synthetisierer
verarbeitet.
Der Synthetisierer wiederum erhält die Phoneme zugeschoben und macht
daraus dann den eigentlichen Klang, also einen Audiodatenstrom. Dabei
bedient er sich einer Stimme. Diese stehen meistens als zusätzliche Dateien
zur Verfügung, so dass man schnell und leicht Stimmen auswählen und
hinzufügen kann. Diese "Voices" erzeugen dann für die betreffende Sprache
(deutsch, englisch, franzöisch, usw.) einen passenden Klang. Dies ist das rechte
Ende. :-)
Es ergibt sich also folgendes Bild:
Nachdem wir uns nun mit dem grundlegenden Funktionsprinzip vertraut
haben, machen wir uns an die Praxis. Wie ich schon schrieb, verwenden wir
als Synthetisierer das Programm mbrola, welches man sich
hier
kostenlos herunterladen kann.
Sie benötigen die mbrola Binaries, also die Datei mbr301h.zip bzw.
eine aktuellere Version und die von Ihnen gewünschten Sprachstimmen. Ich habe
bei mir alle drei deutschen Stimmen (de1, de2 und de3) installiert, verwende
aber meistens de3.
Als Phonemgenerator bleibt, wenn man sich für mbrola als Synthetisierer
entschieden hat, dann für die deutsche Sprache nur noch txt2pho übrig,
welches man sich hier herunterladen kann.
Am besten ist es, sich für mbrola ein eigenes Verzeichnis anzulegen und
dort dann alles Daten abzulegen. Wer mag, kann sich auch an den FHS halten und
es passend nach share, bin, usw. sortieren. Ich habe mir die Mühe nicht
gemacht.
Wie üblich, wenn man selbst etwas an seinem System hinzufügt, das nicht
von der Distribution verwaltet wird, packt man es nach /usr/local.
Also entpacken wir mbrola und seine Voices:
bash# cd /usr/local
bash# mkdir mbrola
bash# cd mbrola
bash# unzip /pfad/zu/mbr301h.zip
bash# unzip /pfad/zu/de1-980227.zip
...
bash# unzip /pfad/zu/de3-000307.zip
Damit zum einen später das richtige Binary im Suchpfad liegt und zum
anderen nicht jedesmal der komplette Name eingegeben werden muss, legen Sie
am besten noch einen Symlink darauf an:
bash# cd /usr/local/bin
bash# ln -s /usr/local/mbrola/mbrola-linux-i386 mbrola
Für txt2pho gehen wir im Grunde analog vor. Erst entpacken:
bash# cd /usr/local
bash# unzip /pfad/zu/txt2pho
...
Dann die Beispieldatei mit den Einstellungen ins Homeverzeichnis verschieben
und deren Besitz übernehmen:
bash# mv txt2phorc ~
bash# chown <ihrusername> ~/.txt2phorc
Eventuell ist das Binary txt2pho noch nicht ausführbar, dies
können Sie aber ändern:
bash# chmod +x txt2pho
Und zu guter Letzt noch einen Symlink im Suchpfad anlegen:
bash# cd /usr/local/bin
bash# ln -s /usr/local/txt2pho/txt2pho
Ausserdem enthält das txt2pho-Paket auch noch zwei Filter und
einen Preprozessor. Diese müssen ebenfalls entpackt und teilweise kompiliert
werden:
Zunächst numfilt, ein Programm, dass Zahlen im Text durch ihre Worte
ersetzt und Aufzählungen richtig behandelt.
Das Archiv numfilt-0.1.tar.gz, welches im txt2pho-Archiv enthalten ist,
enthält zwar schon ein Linux-Binary, dieses machte aber bei mir zumindest
Probleme, deshalb kompilieren wir uns lieber selber:
bash# cd /usr/local/txt2pho
bash# tar xvzf numfilt-0.1.tar.gz
numfilt-0.1/
numfilt-0.1/numfilt.c
numfilt-0.1/README
numfilt-0.1/Linux/
numfilt-0.1/Linux/numfilt
bash# cd numfilt-0.1
bash# cc -o numfilt numfilt.c
numfilt.c: In function `main':
numfilt.c:24: warning: return type of `main' is not `int'
Dann ist pipefilt an der Reihe. Dieses Programm erzeugt die
notwendigen Pausen nach Satzendezeichen (.:;!?), indem einfach einen
Zeilenumbruch (Newline) hinzufügt, der später dann als "Pause" interpretiert
wird. Damit die normalen Zeilenumbrüche, die in Textdateien ja durchaus auch
mitten im Satz vorkommen können, keine falschen Pausen erzeugen, werden
diese zuerst entfernt.
Pipefilt wird mit dem C++ Compiler kompiliert:
bash# cd /usr/local/txt2pho
bash# c++ -o pipefilt pipefilt.cc
Als letztes ist noch preproc, der eigentliche Preprozessor dran.
Preproc kann ganz frei konfiguriert werden, indem man eigene
Regeln erstellt (siehe Datei MANUAL). Regelsätze für das Ersetzen
von Abkürzungen, Kommazahlen, Geldbeträgen, Uhrzeiten und vieles mehr sind jedoch
schon vorhanden.
bash# cd /usr/local/txt2pho
bash# unzip preproc.zip
...
bash# cd preproc
bash# mkdir obj
bash# make
...
Das war's, die Installation des Systems ist soweit abgeschlossen.
Eigentlich muss mbrola nicht wirklich konfiguriert werden, es läuft
out-of-the-box. Aber man kann eine sogenannte Initialization
File anlegen, damit man nicht immer alle Optionen per Kommandozeile
übergeben muss.
Die Datei ist einfach aufgebaut: Pro Zeile kann ein Kommando verwendet
werden, gültige Befehle sind: CLONE, RENAME, VOICE, TIME, FREQ, VOLUME, FLUSH,
COMMENT ind IGNORE.
Ich habe bei mir keine solche Datei angelegt, sondern stelle mbrola immer
über Parameter ein, welche in meinem Wrapper-Skript speak
'versteckt' sind. Das finde ich persönlich sinnvoller. Infos zu besagtem
Skript gibt es weiter unten.
Wichtig ist hingegen die korrekte Konfiguration von txt2pho. Ohne ein
gültige Konfigurationsdatei erhält man beim Aufruf den Fehler:
Panic, check your pitch!
Bei der Installation haben wir allerdings schon eine Konfigurationsdatei
installiert und zwar als wir die Datei .txt2phorc ins
Homeverzeichnis verschoben haben.
Jeder Benutzer, der txt2pho verwenden soll, benötigt in seinem
Homeverzeichnis eine solche .txt2phorc. Alternativ kann man auch
eine globale Konfigurationsdatei namens /etc/txt2pho anlegen,
welche jedoch immer von den benutzereigenen Einstellungen überschrieben
wird.
Hier nun meine ~/.txt2phorc. Ich erkläre mit eingefügten
Kommentaren die Bedeutung der einzelnen Werte.
# --------------------------------------
#
# PATH variables
#
# All path names must end with a separator
#
# Path to data files (default: ./data/)
DATAPATH=/usr/local/txt2pho/data/
# Path to voice files
INVPATH=/usr/local/txt2pho/data/
# Path to temporary and log files (default: /tmp/)
TEMPPATH=/tmp/
#
# --------------------------------------
#
# DEFAULT variables
#
# Default voice
INVENTORY=female
# Debuglevel
DEBUGLEVEL=0
#
# --------------------------------------
#
# PROSODY variables
#
# Name of prosody generation tree
NEWTREE=newtree
# Reduction level
REDUCTION=1
# Prominence computation by rule or CART tree
PROMCOMP=1
# Default speech rate
SPEECHRATE=1.1
# Duration computation
USENET=3
#
# --------------------------------------
#
Nachdem Sie txt2pho korrekt eingerichtet haben, können Sie einen ersten Test
der Sprachausgabe vornehmen. Geben Sie dazu ein:
bash$ echo "Hallo Welt" | txt2pho > test.pho
Dies müsste nun eine Datei namens test.pho erzeugen, die ungefähr
so aussieht:
_ 10 0 161
h 83 23 163 47 165 71 167 95 170
a 89 18 173 40 176 63 180 85 182
l 41 17 185 66 187
o: 84 7 189 31 190 55 190 79 160
v 63 3 158 35 157 67 156 98 155
E 96 20 154 41 152 61 151 82 150
l 69 4 149 33 148 62 147 91 146
t 80 12 144 38 144
_ 483 3 160 7 160 11 160 15 160 19 160 24 160 28 160 32 160 36 160 40 160
Wenn hierbei ein Fehler auftritt, dann ist Ihr txt2pho nicht korrekt
konfiguriert. Prüfen Sie in diesem Falle die Konfigurationsdatei
~/.txt2phorc auf Tippfehler, korrekte Pfade und ausreichende
Leserechte. Vergessen Sie nicht, dass in der Datei jeder Pfad mit einem
Schrägstrich enden muss!
Haben Sie die Phonemdatei erzeugt, können Sie diese dann an mbrola
verfüttern:
bash$ mbrola /usr/local/mbrola/de1/de1 test.pho test.wav
Die Stimme (de1) können Sie natürlich je nach Geschmack auswählen
und den Pfad müssen Sie ggf. Ihrer lokalen Installation anpassen.
Spielen Sie nun die hoffentlich korrekt erzeugte Audio-Datei ab:
bash$ play test.wav
Wenn Sie nun eine Stimme hören, die die Worte "Hallo Welt" spricht, dann
funktioniert Ihr TTS-System bereits.
Sie können die oben stehenden Befehle später dann auch wie folgt
zusammenfassen:
bash$ echo "Hallo Welt" | txt2pho | mbrola /usr/local/mbrola/de1/de1 - test.wav
bash$ play test.wav
Das Beispielskript speak nimmt Text von der Standardeingabe und
erzeugt daraus direkt eine Sprachausgabe auf die Soundkarte.
Das Skript können Sie hier herunterladen.
Im Wesentlichen handelt es sich um ein Consolen-Frontend für die verschiedenen
Programme, die zur Synthese benötigt werden. Zuerst wird der eingelesene Text auf
Wunsch durch das Programm pipefilt geschickt (Option -p), dann
durch den Preprocessor (Option -a) und zum Schluss durch numfilt
(Option: -n). Danach wird daraus eine Phonemdatei erzeugt, diese an
mbrola übergeben und der Klang dann über einen Play-Befehl abgespielt.
Verwendungsbeispiel:
bash$ speak -p -a -n < mailcopy.txt
Liest die Mail aus der Datei mailcopy.txt vor.
Eine Bemerkung am Rande: Das Skript speak ist mit dem Skript
mkulawmsg aus der vbox3-Anleitung identisch! Je nachdem, wie sie
es aufrufen, entscheidet sich seine Funktion. Haben Sie mkulawmsg
also bereits heruntergeladen, genügt ein:
bash# ln -s mkulawmsg speak
Als Player kommen im Prinzip alle Audioplayer in Frage, die entsprechend
kodierte (raw, 16bit, little endian, sample rate je nach mbrola-Voice) Audiodaten
von der Standardeingabe einlesen können. Passende Vorlagen für den
ALSA-Player
aplay und das sox-Frontend play sind vorhanden und müssen
nur passend ein- bzw. auskommentiert werden.
Man kann das Skript speak auch benutzen, um sich eine automatische
Begrüssung generieren zu lassen, sobald man sich auf dem Rechner einloggt.
Folgender Befehl erzeugt eine solche Begrüssung auf meinem Rechner:
speak -a -n -p -l 60 <<EOF
Hallo, Malte.
Willkommen auf dem Rechner `hostname`.
Heute ist `date +'%A, der %d. %B %Y, %H Uhr %M'`.
Der Spruch des Tages lautet: `fortune`
EOF
Damit dies beim Einloggen automatisch gesprochen wird, müssen Sie es in
der für das Login zuständigen Datei eintragen. Für Logins auf Textconsolen
wäre dies bei der Bash z.B. die ~/.profile. Bei grafischen Logins
die ~/.xinitrc oder ~/.xsession. Wenn Sie KDE verwenden,
können Sie es auch als ausführbares Skript im Autostart-Ordner speichern.
Eine weitere Anwendung, die recht praktisch ist, ist die automatische
Mailbenachrichtigung. Sie können das Skript mailnotify.sh, welches
Sie hier herunterladen können, benutzen,
um mithilfe von fetchmail die Anzahl der neuen Mails auf dem Server zu
ermitteln und eine entsprechende Sprachausgabe zu machen.
Eine solche wäre dann z.B. "Sie haben fünf neue Nachrichten".
Das Skript erfordert eine korrekte, auf Ihren E-Mail-Account konfigurierte
~/.fetchmailrc und funktioniert nur so gut, wie fetchmail selbst.
Denn laut dessen Manpage soll die Zählung nur bei IMAP sicher und bei POP3
einigermassen zuverlässig laufen.
Um es regelmässig im Hintergrund laufen zu lassen, können Sie es als
Cronjob einrichten. Bei mir lasse ich das Programm gkrellm die Mailprüfung machen und habe das Skript
mailnotify.sh nur als Benachrichtigungsprogramm eingetragen.
Die neue Version 0.0.2 kommt nun auch damit klar, wenn fetchmail mehrere
Postfächer oder IMAP-Ordner überprüft und gibt in diesem Falle die Gesamtsumme
aller neuen Mails an.
Für die TTS-Systeme festival und rsynth gibt es den
speechd, der ein Gerät
namens /dev/speech implemeniert. Alles, was an plain text dorthin
geschrieben wird, wird laut ausgesprochen.
Der speechd funktioniert leider nicht mit mbrola, aber es ist überhaupt
kein Problem, das mit einfachen Shell-Hilfsmitteln nachzubilden.
Als "Gerätedatei" verwenden wir eine sogenannte Named Pipe. Die Rechte
der Datei legen fest, wer sie nutzen darf; in meinem Beispiel sind dies
root und alle User der Gruppe 'audio'.
bash# cd /dev
bash# mknod speech p
bash# chown root.audio speech
bash# chmod 0660 speech
Lässt man nun ein:
bash# speak -a -n -p < /dev/speech
laufen, so wartet dies, bis etwas in die Datei geschrieben wird, liest es
dann vor und beendet sich.
bash$ echo "Hallo Welt" > /dev/speech
Damit man die Named Pipe mehr als einmal benutzen kann, muss man also
nichts weiter machen, als eine Endlosschleife um das Skript herum zu packen.
bash# while speak -a -n -p < /dev/speech; do echo -n "."; done
Nun kann man beliebig oft Ausgaben nach /dev/speech umleiten, ohne
jedesmal das speak-Skript neu starten zu müssen. Der echo-Befehl schreibt für
jede Benutzung einen Punkt auf das Terminal, wer das nicht mag, kann statt
dessen einfach true aufrufen.
In der oben beschriebenen Form bricht die Schleife ab, falls speak einen
Fehler produziert. Dies kann gewünscht sein, da es auf Probleme hinweist.
Möchte man aber, dass speak unabhängig von eventuellen Fehlern neu gestartet
wird, lautet der Aufruf:
bash# while true; do speak -a -n -p < /dev/speech; done;
Für den alltäglichen Gebrauch kann man diesen Aufruf dann z.B. in ein
Runlevelskript packen oder aber einfach aus der inittab heraus aufrufen.
Nun kann man einfach und jederzeit beliebige Texte nach /dev/speech
schreiben und sie sich so vorlesen lassen, genau wie der speechd es machen
würde.
Ich habe ein Shellskript namens speakd
vorbereitet, welches man dazu benutzen kann. Es ist sozusagen unser
speechd-Ersatz.
Ein Runlevel-Skript hierzu können Sie sich einfach selbst erstellen, die
meisten Distributionen bringen eine Vorlage hierfür mit, die meistens
/etc/init.d/skeleton heisst.
Die Alternative, ein Eintrag in der /etc/inittab, würde in
etwa so aussehen:
# start speakd to allow speech synthesis using /dev/speech
sp:2345:respawn:/usr/local/sbin/speakd
Ein abschliessendes:
bash# init q
aktiviert den Dämon.
Update: Dass speakd normalerweise nicht zeilenweise von
/dev/speech einliest, sondern so lange wartet, bis der schreibende
Prozess mit seiner Eingabe fertig ist und die Pipe wieder geschlossen hat,
ist Absicht.
Will man nämlich einen längeren Text dorthin ausgeben, so ist ja
beispielsweise die Verwendung des pipefilt-Präprozessor sinnvoll. Damit
werden dann die linefeeds entfernt, so dass mbrola nicht an jedem
Zeilenende eine Kunstpause einlegt. Logischerweise kann man das nur
machen, wenn man mehrere Zeilen auf einmal einliest, denn andernfalls hat
man für jede Zeile einen eigenen speak-Aufruf, was eine solche Kunstpause
unvermeidbar macht.
Es gibt aber Anwendungsfälle, wo dies suboptimal ist. Leitet man beispielsweise
die Ausgabe eines Skripts nach /dev/speech um, so hört man den Text
erst dann, wenn das Skript komplett durchgelaufen ist. Besonders bei interaktiven
Anwendung ist das natürlich doof. Ich habe daher speakd etwas erweitert, unter
anderem um eine Kommandozeilenoption -n, mit der man ihn dazu bringt, eben doch
zeilenweise zu lesen. Natürlich muss man dann auf oben genannten Filterkomfort
verzichten.
Troubleshooting
mbrola produziert eine SIGSEGV
Falls mbrola bei Ihnen nicht funktioniert und dabei folgendes Fehlerbild auftritt:
bash$ cd /pfad/zu/mbrola
bash$ ./mbrola-linux-i386 /pfad/zu/voice text.pho output.wav
Segmentation fault.
ist es wahrscheinlich, dass es ein Problem mit Ihrer libc gibt. Bei mir war
dieses Problem vor einigen Monaten auch vorhanden, hat sich beim nächsten
Upgrade meines Debians aber selbst gelöst. Als Alternative können Sie versuchen,
eine andere libc per LD_PRELOAD vor mbrola zu hängen. Die
uclibc bietet sich
hier an, da sie gerade mal 200k groß ist und trotzdem alles bietet, was
mbrola braucht.
|