Homepage Logo

Letzte Änderung dieses Dokuments: 20.03.2013, 22:00:41.

Text-To-Speech

1. Inhalt

   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


2. Einleitung

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.


3. Einführung

3.1. Allgemeines

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:

Schematische Darstellung eines TTS-Systems

3.2. Wo gibt's was?

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.


4. Installation

4.1. mbrola Binaries

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

4.2. txt2pho

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.


5. Konfiguration

5.1. mbrola

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.

5.2. txt2pho

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

#
# --------------------------------------
#

5.3. Erster Test: "Hallo Welt"

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

6. Verwendungsbeispiele

6.1. Das Skript speak

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.

6.2. Begrüssung bei Login

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.

6.3. Mailbenachrichtigung

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.

6.4. /dev/speech - speechd oder Named Pipe mit speakd

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.

[05.05.2008] Neuer PGP-Schlüssel
Ich habe einen neuen PGP/GPG-Schlüssel erzeugt. Der alte ist nach wie vor gültig und kann auch noch benutzt werden.

[02.04.2008] Umzug
Die Domain malte-wetz.de wird jetzt bei einem anderen Anbieter gehostet. Es sollte keine Probleme mehr mit der Umleitung geben und Werbepopups oder -frames gehören der Vergangenheit an.

[02.04.2008] Gästebuch offline
Das Gästebuch bleibt erst einmal offline. Es wurde dort zu viel Werbemüll hinein geschrieben. Sorry.

[09.01.2006] Diverses
Kleinere Korrekturen und Ergänzungen an den Texten, IP-Filter im Gästebuch stark erweitert (Lateinamerika, Spanien, Asien, Italien).

[28.07.2005] vbox3-Anleitung
Kleinere Ergänzungen/Korrekturen im Abschnitt 4.1.1

[23.04.2005] gDesklets aktualisiert
Da meine gDesklets offenbar von gdesklets.gnomedesktop.org gelöscht wurden, habe ich die aktuellsten Fassungen hier abgelegt.

[25.01.2005] Kleinere Reparaturen
Links auf BSI-Seite und OE-FAQ angepasst und Gästebuch repariert.