Mein erstes mittelhochdeutsches Hörbuch – Teil 3

Dies ist der dritte Teil des Tutorials. Der Beginn findet sich hier.

Der Blick ins Lexikon hilft!

Wir wollen, dass Hedda uns einen mittelhochdeutschen Text flüssig vorliest und das in möglichst korrekter Aussprache. Um beiden Anforderungen gerecht zu werden,  blieb uns nichts anderes übrig, als den gesamten Text in Lautschrift zu übersetzen und dann im Ganzen an Hedda zur Aussprache zu übergeben. Denn als wir versuchten, den Text in Einzelpassagen zu zerlegen, die wir Hedda in unterschiedlichem Format übergaben, war die Unterbrechung und der Neuansatz bei jeder Einheit deutlich und störend zu hören. Dabei könnte es doch so einfach sein: Hedda ist für die Ausgabe moderner deutscher Texte optimiert und bei diesen hat sie keine Schwierigkeiten, sie relativ unfallfrei und sogar mit so etwas wie einer angemessenen Betonung in flüssigem Vortrag vorlesen. Trifft sie dabei auf ihr unbekannte Wörter, liest sie ohne Unterbrechung so, wie es der üblichen Aussprache deutscher Buchstaben entspricht. Da sich jedoch das Mittelhochdeutsche nicht in jeder Hinsicht vom modernen Hochdeutsch unterscheidet, könnten wir häufig ihre Voreinstellungen übernehmen und müssten nur in Einzelfällen eingreifen.  Wir bräuchten dafür nur eine Möglichkeit, Hedda einen Text im Ganzen zum Lesen vorzulegen, in dem Passagen in Lautschrift auf solche in Buchstabenschrift folgen und umgekehrt.

Tatsächlich ist das möglich. Als Prompt wird in der englischsprachigen Terminologie der speech.dll eine sprachliche Äußerung verstanden und mit der Klasse Promptbuilder gibt es die Möglichkeit, eine solche Äußerung aus elementaren und heterogenen Bestandteilen zusammenzusetzen. Probieren wir es gleich aus:

        static void Main(string[] args)
        {
            
            SpeechSynthesizer synth = new SpeechSynthesizer();
            
            PromptBuilder pb = new PromptBuilder();
            pb.AppendText("Swêr");
            pb.AppendSsmlMarkup(@"<phoneme alphabet=""ups"" ph=""S1 R EH C . T Y lng"">rehtiu</phoneme>");
            pb.AppendText("wort gemerken kan,");

            synth.Speak(pb);
          
        }

 

 

Heureka! Mit dieser Technik können wir uns viel Arbeit ersparen. Eine zusätzliche Ersparnis ergibt sich durch die Verwendung eines Lexikons. In diesem vermerken wir die Sonderfälle der Aussprache für Hedda. Diese müssen wir dann nur einmal angeben und nicht bei jedem Vorkommen im Text. Wir müssen Hedda nur mitteilen, dass sie von nun an für jedes Wort im Text überprüfen soll, ob es zu diesem einen Eintrag im Lexikon der Sonderfälle gibt:

 

        static void Main(string[] args)
        {

            SpeechSynthesizer synth = new SpeechSynthesizer(); 
            PromptBuilder pb = new PromptBuilder();

            // Ein Lexion zur Aufnahme der abweichend auszusprechenden Wortformen:
            Dictionary<string, string> Lexikon = new Dictionary<string, string>
            {
                ["rehtiu"] = "S1 R EH C . T Y lng"
            };

            // unser Beispieltext:
            string Text = "Swêr rehtiu wort gemerken kan,";

            /* Los geht's Hedda!
             * Lies Wort für Wort.
             * Überprüfe, ob das Wort im Lexikon vermerkt wurde.
             * Wenn ja, dann folge der dort in Lautschrift notierten Aussprache.
             * Wenn nicht ... mach's wie immer, sprich so, wie es da "geschrieben" steht.*/

            foreach (string Wort in Text.Split(' '))
            {
                if (Lexikon.Keys.Contains(Wort))
                {
                    //Sonderfall:
                    pb.AppendSsmlMarkup(@"<phoneme alphabet=""ups"" ph=""" +Lexikon[Wort]+@""">"// Die Lautschriftvariante
                                        +Wort+"</phoneme>");//  gefolgt von der Graphie
                }
                else
                {
                    pb.AppendText(Wort); // Normalfall: Hochdeutsche Aussprache.
                }
            }       

            synth.Speak(pb);  
        }
    }

 

An Heddas Vortrag hat sich nichts geändert, nur an der Art und Weise, wie er zustande kam. Deshalb sollen die Details noch einmal genauer betrachtet werden. Wir haben es diesmal Hedda, bzw. dem von uns geschriebenen Computerprogramm überlassen, den vorzulesenden Text in Wörter zu zerlegen. Wir tun das durch die Anweisung Split(' '), die der alten computerlinguistischen Faustregel folgt, dass als Wort jede Abfolge von Zeichen zwischen zwei Leerzeichen angesehen wird. Das ist selbstverständlich eine grobe Vereinfachung, die aber für unsere Zwecke erst einmal genügt. Wort für Wort schlägt das Programm dann unter den Schlüsselbegriffen mit Lexikon.Keys.Contains(Wort) im Lexikon nach und hängt gegebenenfalls den dort vorgefundenen Eintrag an das Prompt der Aussage an. Gibt es keinen solchen Eintrag, dann wird das Wort selber an Hedda zur späteren Verarbeitung weitergereicht.

Nun ist unser Lexikon mit exakt einem Eintrag nicht gerade umfangreich. Aber wir haben uns ja auch nicht die Aufgabe gestellt, nur eine einzige Verszeile in gesprochene Sprache umzuwandeln, sondern wollten uns ein ganzes Buch vorlesen lassen. Oder zumindest die ersten 50 Verse davon. Doch bevor wir daran gehen, werden wir ein wenig „aufräumen“.

Für unsere bisherigen Experimente haben wir nur ein paar Zeilen Programmiercode gebraucht, die wir in der statischen Methode Main untergebracht haben. Wir wollen jetzt aber zu komplexeren Arbeitsschritten übergehen, die Hedda erledigen soll. Und deshalb werden wir nun als nächstes eine eigene Klasse für diese Aufgaben anlegen und unserem Projekt hinzufügen. Der geben wir den Namen Hedda.cs. Dann können wir auch weiter, und jetzt mit deutlich mehr Berechtigung davon sprechen, dass wir Hedda einen Befehl geben, oder Hedda etwas im Lexikon nachschlägt:

Die automatisch generierte Klasse Hedda.cs ändern wir ab, so dass sie nun so aussieht:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Speech.Synthesis;

namespace Mittelhochdeutsches_Hörbuch1
{
    class Hedda
    {
        // Ein Lexion zur Aufnahme der abweichend auszusprechenden Wortformen:
        private Dictionary<string, string> Lexikon = new Dictionary<string, string>
        {
            ["rehtiu"] = "S1 R EH C . T Y lng"
        };

        public  void LeseZeile (string Zeile, PromptBuilder pb)
        {

            /* Los geht's Hedda!
             * Lies Wort für Wort.
             * Überprüfe, ob das Wort im Lexikon vermerkt wurde.
             * Wenn ja, dann folge der dort in Lautschrift notierten Aussprache.
             * Wenn nicht ... mach's wie immer, sprich so, wie es da "geschrieben" steht.*/

            foreach (string Wort in Zeile.Split(' '))
            {
                if (Lexikon.Keys.Contains(Wort))
                {
                    //Sonderfall:
                    pb.AppendSsmlMarkup(@"<phoneme alphabet=""ups"" ph=""" + Lexikon[Wort] + @""">"// Die Lautschriftvariante
                                        + Wort + "</phoneme>");//  gefolgt von der Graphie
                }
                else
                {
                    pb.AppendText(Wort); // Normalfall: Hochdeutsche Aussprache.
                }
            }
        }
    }
}

 

Problemlos dürften sich die Elemente wiedererkennen lassen, die wir aus der Methode Main in Program.cs übernommen haben: Das Lexikon, die Schleife, in der wir Hedda die Worte der Zeile lesen lassen … Nur, dass wir diese jetzt in eine Methode der Klasse Hedda.cs, einen Befehl an Hedda, verpackt haben. Wichtig ist es übrigens, nicht die Änderung an den using – Anweisungen zu übersehen: Damit Hedda ihren Dienst tun kann, braucht auch sie die Speech.dll. „Unsere“ Methode Main müssen wir auch noch ändern, sie sieht jetzt so aus:

        static void Main(string[] args)
        {


            SpeechSynthesizer synth = new SpeechSynthesizer(); 
            PromptBuilder pb = new PromptBuilder();
            Hedda Hedda = new Hedda();

            //Unsere Textdatei: 
             
            StreamReader Textdatei = new StreamReader("D:/Lanzelet 1 - 49.txt");

            string Zeile;

            /* Schleife:
             * Solange bis das Ende der Textdatei erreicht ist (der Befehl ReadLine() null ergibt)
             * Lies die nächste Zeile ein
             * Und übergib sie an Hedda zum Vorlesen.
             */
            while(( Zeile = Textdatei.ReadLine())!=null)
            {
                Hedda.LeseZeile(Zeile, pb);
            }
            
            synth.Speak(pb);  
        }
[/csharp]

&nbsp;

<em><strong><span style="color: #ff0000;">ACHTUNG!</span></strong> Ich habe die Textdatei, die wir verwenden, auf meinem Rechner im Hauptverzeichnis von Laufwerk D: abgespeichert. Wenn sie auf einem anderen Laufwerk oder Verzeichnis gespeichert wurde, muss die Pfadangabe natürlich entsprechend angepasst werden.</em>

Und auch in <code><span style="font-family: courier new,courier,monospace;">Program.cs</span></code> müssen wir noch eine <code><span style="font-family: courier new,courier,monospace;">using</span></code>-Zeile einfügen, damit <code><span style="font-family: courier new,courier,monospace;">Main</span></code> die Datei einlesen kann:

[code language="csharp"]using System.IO;

Dann können wir uns entspannt zurücklehnen und unser erstes Hörbuch genießen …

Na?

Zufrieden?

Wie …? Wirklich?    … gar nicht?

Es ist wohl nicht zu leugnen: Wir haben noch etwas Arbeit vor uns!!!

Wir mögen damit zurechtkommen, wenn Hedda beim Vortrag einer einzelnen Verszeile, deren Text wir am Bildschirm mitlesen können, ein einziges Wort als völlig unverständliche Lautfolge umsetzt. Wenn wir sie jedoch eine längere Passage lesen lassen, ist es kaum noch möglich ihr zu folgen. Wir sollten uns jedoch vom ziemlich katastrophalen ersten Höreindruck nicht enttäuschen lassen. Schließlich enthält unser Lexikon ja bisher nur einen Eintrag! So kann es kaum eine Hilfe darstellen. Füllen wir es doch mit ein paar Einträgen und ändern die Klasse Hedda.cs entsprechend ab:

        // Ein Lexion zur Aufnahme der abweichend auszusprechenden Wortformen:
        private Dictionary<string, string> Lexikon = new Dictionary<string, string>
        {
            ["rehtiu"] = "S1 R EH C . T Y lng",
            ["gemerken"]="G EX . S1 M EH R . K EX N",
            ["gedenke"]="G EX . S1 D EH N . K EX",
            ["wie"] = "S1 V I lng + EX",
            ["ein"] = "E + I N",
            ["wîze"] = "S1 V I lng . Z EX",
            ["hie"] = "S1 H I lng + EX",
            ["bî"] = "S1 B I lng",
            ["zîten"]= "S1 TS I lng . T EX N",
            ["sît"] = "S1 S I lng T",
            ["diu"] = "D Y lng",
            ["dûhte"] = "S1 D U lng X . T EX",
            ["niht"] = "N IH C T",
            ["gemuot"] = "G EH . S1 M U lng + O T"

        };

 

Die ersten fünf Verszeilen sind nach der kleinen Änderung jetzt deutlich besser zu verstehen:

… und wenn wir uns konzentrieren, begegnen uns auch im weiteren Text einige der neuen Einträge unseres Lexikons wieder und machen diesen damit vereinzelt verständlicher.

Versuchen wir es positiv zu sehen: Wir sind auf dem richtigen Weg!

Ein Weg, der allerdings noch recht lang zu werden verspricht, wie diejenigen sicher bestätigen werden, die sich die Mühe gemacht haben, die Lexikoneinträge per Hand in Hedda.cs einzutragen und sie nicht einfach per copy & paste übernommen haben. Diesen fleißigen Tippern wird dabei jedoch vermutlich auch aufgefallen sein, dass die Umsetzung der Grapheme in Phoneme sehr regelhaft erfolgt. Als UPS-Notation der Aussprache für ein î haben wir zum Beispiel in wîze, bî, zîten und sît jeweils I lng ermittelt (IPA-Notierung: [i:]). Nach unserer bisherigen Erfahrung gilt anscheinend:

Bestimmten Buchstaben (-folgen) entsprechen stets und immer wieder bestimmte (Abfolgen von) Lautzeichen.

Wir werden versuchen aus dieser Beobachtung Nutzen zu ziehen, um uns weitere (unnötige) Tipparbeit zu ersparen. Und damit beginnen wir umgehend …

… im vierten Teil unseres Projektes.

Mein erstes mittelhochdeutsches Hörbuch – Teil 2

Dies ist der zweite Teil des Tutorials (daher heißt es auch Teil 2 im Titel). Der erste Teil findet sich hier.

Hedda spricht (eine Zeile) Mittelhochdeutsch!

Wir legen los und in Visual Studio ein neues Projekt an:

Aus dem Auswahlmenü wählen wir die Konsolen-App (Net-Framework), der wir einen sprechenden Namen geben. Wie wäre es mit „Mittelhochdeutsches Hörbuch1“? Unter welchem Namen auch immer, das Projekt wird erzeugt und uns die Datei Program.cs präsentiert:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Mittelhochdeutsches_Hörbuch1
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}

Bevor wir unseren Computer zum Sprechen bringen können, müssen wir noch die zur Spracherzeugung benötigte Bibliothek einbinden. Dazu öffnen wir den Reiter „Projekt/Verweis hinzufügen“.

In den Assemblys aktivieren wir „System.Speech“ mit einem Häkchen:

Dann ändern wir die Ausgangsdatei (per copy & paste oder abtippen) folgendermaßen ab und starten mit F5 unser erstes Experiment:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Speech.Synthesis;

namespace Mittelhochdeutsches_Hörbuch1
{
    class Program
    {
        static void Main(string[] args)
        {            
            SpeechSynthesizer synth = new SpeechSynthesizer();
            synth.Speak("Swêr rehtiu wort gemerken kan,");            }
        }
    }
}

 

Jetzt sollten wir eine Stimme hören, die mit der erwarteten falschen Aussprache unseren Text spricht. Es ist gut möglich, dass diese Stimme uns unbekannt ist und nicht derjenigen entspricht, die wir von der Windows-Sprachausgabe gewohnt sind. Auf meinem Rechner ist es jedenfalls eine weibliche Stimme und damit definitiv nicht Stefan, die ich höre. Der Grund hierfür ist, dass Stefan dafür vorgesehen ist, Deutsch mit mir zu sprechen und anscheinend nur dazu in der Lage ist. Ihm fehlt die Möglichkeit, sich an ein anderes Idiom anzupassen. Etwas technischer formuliert: Das Sprachprofil, das mit dem Namen Stefan verbunden wird, bietet nicht alle Möglichkeiten, die durch die Programmierschnittstelle System.Speech.dll vorgesehen sind, und steht uns damit nicht zur Verfügung. Oder vielmehr: mir, zum Zeitpunkt, an dem ich dies schreibe. Denn selbstverständlich kann sich das mit dem nächsten Windows-Update ändern oder mit der nächsten Generation der Speech-Schnittstelle.

Wir können uns, wenn wir wollen, beim nächsten Durchlauf unseres kurzen Programms die uns zur Verfügung stehenden Stimmen vorstellen lassen, indem wir unsere statische Methode Main leicht verändern:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Speech.Synthesis;

namespace Mittelhochdeutsches_Hörbuch1
{
    class Program
    {
        static void Main(string[] args)
        {
            
            SpeechSynthesizer synth = new SpeechSynthesizer();

            foreach (var voice in synth.GetInstalledVoices())
            {
                synth.SelectVoice(voice.VoiceInfo.Name);
                synth.Speak(voice.VoiceInfo.Description);
                synth.Speak("Swêr rehtiu wort gemerken kan,");            }
            }
        }
     }
}

 

Mir stehen eine weibliche Stimme mit dem Namen Hedda zur Verfügung, die deutsch spricht, und eine Amerikanerin namens Sira. Ob es sich bei der um eine Verwandte von Apples ureigener Siri handelt? Und wer hat der „Deutschen“ den so typisch deutschen Namen Hedda verpasst? Die Auswahl der Stimmen ist sehr begrenzt, aber zumindest durch die Namensgebung für einen kleinen nerdigen Lacher gut.  Wer wie ich mit Hedda leben muss (Nein, Sira kann ich mir nicht als Vorleserin der Aventiure vorstellen), mag vielleicht mit der Option käuflicher Stimmenprofile liebäugeln, aber eigentlich reicht ja eine Stimme für unser Vorhaben.

Sofern wir sie dazu bringen können, phonetisch korrektes Mittelhochdeutsch von sich zu geben.

Hedda sollte also eine Lautschrift verstehen, beziehungsweise in der Lage sein, einen in dieser transkribierten Text angemessen wiederzugeben. Genau das verspricht uns die Speech.dll, wenn sie Hedda unter den installierten – und der Norm gerechten –  Stimmen aufführt. Und genau das werden wir jetzt austesten. Wenn wir es (vorerst) nicht ganz so kritisch sehen wollen, gibt es in dieser ersten Zeile unseres Textes ja nur ein Wort, das wirklich so falsch klingt, dass wir handeln müssen: rehtiu. Die anderen Wörter sind in ihrer hochdeutschen Aussprache nicht perfekt, aber, wenn wir ein paar Augen zudrücken, halbwegs akzeptabel. Konzentrieren wir uns auf rehtiu und versuchen Hedda beizubringen, das etwas besser zu artikulieren:

 

        static void Main(string[] args)
        {
            
            SpeechSynthesizer synth = new SpeechSynthesizer();
            string ssmlRehtiu =  @"<speak version=""1.0"" xml:lang=""de-DE"">"
                                + @<phoneme alphabet=""ups"" ph=""S1 R EH C . T YH lng"">"
                                + "Rehtiu</Phoneme></speak>";
            synth.SpeakSsml(ssmlRehtiu);
        }

 

 

Das klingt doch schon besser, oder? Was wir hier benutzen, ist der SSML-Standard, ein XML-Codierungsschema zur Steuerung von Sprachausgaben (Speech Synthesis Markup Language). Wenn wir eine dafür passendere Formatierung wählen sieht das ungefähr so aus:

   <speak version="1.0" xml:lang="de-DE">
       <phoneme Alphabet="ups" ph="S1 R EH C . T YH lng"&>rehtiu</Phoneme>
   </speak>

 

Das <speak>-Tag klammert eine Sprachausgabe ein. Innerhalb des <phoneme>-Tags finden wir unseren Ausgabetext wieder, so wie wir ihn kennen („kennen“ heißt, in der Buchstabendarstellung). Die Lautschriftfassung findet sich im Attribut ph = „S1 R EH C . T YH lng“. Es handelt sich um das Lautschriftsystem UPS, eine Microsoft-Eigenkreation. Dass wir dieses Kodierungssystem verwenden, müssen wir natürlich auch angeben: alphabet = „ups“. Im <speak>-Tag vermerken wir noch (verpflichtend!) die Version des Sprachstandards auf die wir uns beziehen und die Sprache, an der sich unsere Hedda orientieren soll. „de-DE“ steht selbstverständlich für das in Deutschland gesprochene Deutsch (im Gegensatz zum Schweizerischen beispielsweise).

Soweit so gut. Hedda ist in der Lage Text in einer Lautschrift zu verstehen. Tatsächlich sind es sogar drei Lautschriften, allen voran das internationale phonetische Alphabet (IPA). Dieses besteht bekanntlich in seinem Kern aus den lateinischen Buchstaben, die um einige Graphien ergänzt wurden, die besonders Altphilologen gut vertraut sind und normalerweise in der Sprache, der sie entnommen wurden, Laute repräsentieren, die es im Lateinischen nicht gab. Viele dieser Zeichen finden sich nicht auf der Standardtastatur und nicht im Standard-ASCII-Zeichensatz. Beispielsweise der ⁠ʃ⁠-Laut in hübsch: [‚hyp⁠ʃ⁠]). Aus diesem Grund gibt es die beiden anderen Varianten der Lautkodierung, die Hedda versteht. Für Computerprogramme leicht zu verarbeiten ist die SAPI-ID (SAPI = Speech API), ein System, das jedem der IPA-Zeichen einen Zahlenwert zuweist: hübsch wird als [02C8 0068 028F 0283] erfasst. Uns kommt das weniger entgegen und deshalb haben wir uns für UPS entschieden, um mit Hedda zu kommunizieren.

UPS nutzt nur Zeichen, die auf der Tastatur (und im ASCII-Code) vorkommen. Häufig, aber nicht immer, entsprechen auch hier einzelne Buchstaben den lateinischen Lautwerten (wenn auch eher in der englischen Aussprache). Komplexere oder (vom englisch getönten Latein her betrachtet) ungewöhnlichere Laute werden durch Buchstabenkombinationen (EH AX etc.) wiedergegeben, die jeweils eine Einheit der Lautzeichenkette repräsentieren. Um die Segmente deutlich voneinander zu trennen muss ein Leerzeichen zwischen ihnen eingefügt werden.

ACHTUNG! Hedda, bzw. die Speech.dll, ist in dieser Hinsicht ausgesprochen pingelig! Fehlt das Leerzeichen, und lässt sich kein einzelner Lautwert finden, der einer Buchstabenfolge zugeordnet werden kann, bricht die Sprachausgabe ab!

In unserem Beispiel findet sich unter anderem auch die Kodierung lng. Sie gibt keinen Lautwert wieder, sondern zeigt an, dass der vorangehende Laut lang gesprochen werden soll (IPA verwendet den Doppeltpunkt [:] zur Bezeichnung der Länge). Auch solche Signale müssen durch Leerzeichen von ihren Nachbarn getrennt werden. Die weitere Erläuterung der Symbole der Lautschrift erspare ich uns vorerst. Sie findet sich schließlich ausführlich auf den Supportseiten von Microsoft dokumentiert.

Machen wir erst einmal weiter: Wir lassen Hedda den Beginn der Zeile sprechen und akzeptieren ihr modernes Hochdeutsch als Mittelhochdeutsch, fügen dann das problematische rehtiu in Lautschrift ein, und setzten danach den Text fort – jetzt wieder Neuhochdeutsch-Pseudomittelhochdeutsch:

 

        static void Main(string[] args)
        {
            
            SpeechSynthesizer synth = new SpeechSynthesizer();
            string ssmlRehtiu =  @""
                                + @""
                                + "rehtiu";
            synth.Speak("Swêr");
            synth.SpeakSsml(ssmlRehtiu);
            synth.Speak("wort gemerken kan,");
        }

 

Das
hört sich
jetzt
sehr
abgehackt an. Vielleicht sollten wir doch gleich die ganze Zeile in phonetischer Schreibweise erfassen. Dann brauchen wir auch nicht so viele faule Kompromisse einzugehen:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Speech.Synthesis;

namespace Mittelhochdeutsches_Hörbuch1
{
    class Program
    {
        static void Main(string[] args)
        {
            
            SpeechSynthesizer synth = new SpeechSynthesizer();

            foreach (var voice in synth.GetInstalledVoices())
            {
                synth.Speak(voice.VoiceInfo.Description);
                string phoneme = " S1 S V EH lng R . "
                                +"S1 R EH C . T YH lng . "
                                +"S1 V AOX T . "
                                +"G EH . S1 M EX R . K EX N . "
                                +"S1 K A N _,";

                string grapheme = "Swêr rehtiu wort gemerken kan,";
                synth.SpeakSsml(@""
                                +grapheme+"");
            }
        }
    }
}

Wenn wir also unseren Text einfach Zeile für Zeile in Lautschrift umsetzen und diese dann zu einer sehr, sehr, seeeehr lange Zeichenkette zusammensetzen … die wir dann natürlich noch zwischen die SSML-tags quetschen …

Nein. Das ergibt selbst dann kaum entzifferbare Bandwurmkonstruktionen, wenn  wir Hedda eine Verschnaufpause am Ende jeder Zeile zugestehen, wo es nicht so auffällt. Und überhaupt wäre es letztlich deutlich einfacher, den Text direkt selber einzusprechen. Wir müssen und werden einen Weg finden, der mit weniger Aufwand zum Ziel führt.

… im dritten Teil des Projektes.

Mein erstes mittelhochdeutsches Hörbuch – Teil 1

Einleitung: Stefan liest

Nicht jede Lesung, nicht jede musikalische Interpretation eines mittelhochdeutschen Gedichts, die sich auf YouTube finden lässt, genügt wissenschaftlichen germanistischen Ansprüchen, aber wenn es nur darum geht, einmal einen Eindruck vom Klang der mittelhochdeutschen Sprache zu erhalten, dann wird man dort schnell fündig. Wer allerdings auf das Hören als Ersatz für das Sehen angewiesen ist, oder einfach nur den Wunsch verspürt, einen längeren mittelhochdeutschen Text anzuhören, anstatt ihn zu lesen, wird nicht nur auf den einschlägigen Plattformen vergeblich nach „Material“ suchen.

Das im folgenden Artikel vorgestellte Projekt versucht ein wenig Abhilfe zu schaffen. Es soll selbstverständlich nicht darum gehen, Hilfestellung bei der Einrichtung eines eigenen Tonstudios oder bei der Aufnahme eigener Lesungen zu geben. Nein, wir beabsichtigen, unseren Computer dazu zu bringen, uns einen mittelhochdeutschen Text vorzulesen und zwar so, dass wir ihn gut verstehen und seine Aussprache auch Fachleuten für das Mittelhochdeutsche keine Schmerzen verursacht. Die Ausgabe leiten wir dann in eine Audio-Datei, damit wir unser Hörbuch auf jedem uns genehmen Gerät abspielen können.

Das scheint auf den ersten Blick gar nicht so schwer zu bewerkstelligen: Schließlich lässt sich jedes Handy und jeder übliche Browser dazu bewegen, Texte vorzulesen. Dazu muss man allerdings teilweise eine zusätzliche App oder ein Add-On installieren. Das Betriebssystem eines Laptop- oder Desktop-Computer lässt sich natürlich ebenfalls um die Fähigkeit zur Sprachsynthese erweitern, wenn es diese nicht bereits von Haus aus mitbringt. Wer diesen Text beispielsweise auf einem Windows Rechner vor sich sieht, muss nur die  Strg-, die Windows– und die Enter-Taste gemeinsam betätigen, um die automatische Sprachausgabe zu aktivieren. Die auf meinem Rechner zu hörende Stimme von Windows10-Stefan klingt zwar manchmal etwas blechern, aber doch im Ganzen gut verständlich:

Ein ritter sô gelêret was,
daz er an den buochen las,
swaz er dar an geschriben vant:
der was Hartman genant,
dienstman was er zOuwe.

Nun ja, ein paar Worte hören sich etwas exotisch an  – ab und zu scheint Stefan bei fremdartigen Schreibungen zu vermuten, dass sie wohl englisch ausgesprochen werden müssen. Andere Wörter hingegen klingen viel zu vertraut. Kein Wunder! Stefan spricht und liest modernes Hochdeutsch und ahnt ja nicht, dass er in „dienstman“ einen Diphthong von sich geben soll. Probieren wir es gleich mit einem anderen Text als dem Armen Heinrich (Natürlich erkannt, oder?). Wie wäre es beispielsweise mit der Einleitung des Lanzelet des Ulrich von Zatzikhoven, eines ungefähren Zeitgenossen des gelehrten Ritters Hartmann von Aue?

Swer rehtiu wort gemerken kan,
der gedenke wie ein wîse man
hie vor bî alten zîten sprach,
dem sît diu welt der volge jach.

Das … klingt, zumindest von Stefan gelesen, schon weit weniger akzeptabel für mich. Jemand müsste Stefan ein paar Lektionen in der Aussprache mittelhochdeutscher Worte erteilen, bevor ich bereit wäre mir von ihm die fast 9500 Verse der an sich recht spannenden (und actionreichen!) Erzählung vom Artushof vorlesen zu lassen.

Dieser Gedanke soll der Ausgangspunkt für das heutige Projekt sein. Es gibt neben kommerziellen Angeboten zahlreiche Open-Source-Ansätze zur Spracherzeugung und -ausgabe, die Schnittstellen zur individuellen Anpassung und Programmierung bieten. Aber wir bleiben vorerst in der Microsoft-Umgebung und werden unsere Lösung in C# im Visual-Studio umsetzen. Größere Programmierkenntnisse brauchen wir dafür nicht und das ist der Hauptgrund für unsere Wahl. Zudem können wir uns in diesem Fall darauf verlassen, dass die Technologie stabil und fehlerfrei auf allen Rechnern läuft, auf denen Windows stabil und fehlerfr … Naja … auf denen halt …

Wer noch nie mit Visual-Studio oder C# gearbeitet hat, findet bei Verständnisfragen in reichem Maße Hilfe auf den Supportseiten von Microsoft. Dort kann er auch die (für private Zwecke) kostenlose Community-Version der Entwicklungsumgebung herunterladen:

Zum Download von Visual-Studio 2017

Als Übungstext verwenden wir nicht den gesamten Lanzelet-Roman, sondern beschränken uns vorerst bescheiden auf die ersten 49 Zeilen, die wir per copy & paste der Textfassung der Bibliotheca Augustana entnommen haben:

Lanzelet Verse 1 – 49

In Windows 10 per Rechtsklick das Kontextmenü öffnen und „Ziel speichern“ wählen, um den Text auf den eigenen Computer herunter zu laden und dort zu speichern. Jetzt ist alles vorbereitet. Wir können loslegen …

… und zwar im Teil 2.

Wer allerdings jetzt schon wissen will, was auf ihn zukommen wird, kann jetzt auch erst einen Blick auf den Tutorial-Überblick werfen:

Mein erstes mittelhochdeutsches Hörbuch – Teil 1 weiterlesen