Synthetisieren von Sprache aus Text

ReferenzdokumentationPaket (NuGet)Zusätzliche Beispiele auf GitHub

In dieser Schrittanleitung werden gängige Entwurfsmuster für die Sprachsynthese vorgestellt.

Unter Was ist Text-zu-Sprache? finden Sie weitere Informationen zu folgenden Themen:

  • Abrufen von Antworten als In-Memory-Datenströme
  • Anpassen der Abtast- und Bitrate der Ausgabe
  • Übermitteln von Syntheseanforderungen mithilfe der Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML)
  • Verwenden neuronaler Stimmen
  • Abonnieren von Ereignissen und ergebnisbezogenes Handeln

Auswählen von Synthesesprache und Stimme

Das Feature für die Sprachsynthese im Azure Speech-Dienst unterstützt mehr als 270 Stimmen und über 110 Sprachen und Varianten. Sie können die vollständige Liste abrufen oder sie im Stimmkatalog ausprobieren.

Geben Sie die Sprache oder Stimme von SpeechConfig für Ihren Eingabetext an, und verwenden Sie die gewünschte Stimme:

static async Task SynthesizeAudioAsync()
{
    var speechConfig = SpeechConfig.FromSubscription("YourSpeechKey", "YourSpeechRegion");
    // Set either the `SpeechSynthesisVoiceName` or `SpeechSynthesisLanguage`.
    speechConfig.SpeechSynthesisLanguage = "en-US"; 
    speechConfig.SpeechSynthesisVoiceName = "en-US-JennyNeural";
}

Alle neuronalen Stimmen sind mehrsprachig und können in ihrer eigenen Sprache und in englischer Sprache sprechen. Wenn der Eingabetext auf Englisch beispielsweise „I'm excited to try text to speech“ lautet und Sie es-ES-ElviraNeural festlegen, wird der Text in englischer Sprache mit einem spanischen Akzent gesprochen. Wenn die Stimme nicht die Sprache des Eingabetexts spricht, erfolgt keine synthetisierte Audioausgabe seitens des Speech-Diensts. Sehen Sie sich die gesamte Liste mit den unterstützten neuronalen Stimmen an.

Hinweis

Die Standardstimme ist die erste Stimme, die pro Gebietsschema über die Stimmlisten-API zurückgegeben wird.

Die Stimme, die spricht, wird wie folgt nach ihrer Priorität bestimmt:

  • Wenn Sie weder SpeechSynthesisLanguage noch en-US festlegen, spricht die Standardstimme für SpeechSynthesisVoiceName.
  • Wenn Sie nur SpeechSynthesisLanguage festlegen, spricht die Standardstimme für das angegebene Gebietsschema.
  • Wenn sowohl SpeechSynthesisVoiceName als auch SpeechSynthesisLanguage festgelegt sind, wird die Einstellung SpeechSynthesisLanguage ignoriert. Es spricht die Stimme, die Sie über SpeechSynthesisVoiceName angegeben haben.
  • Wenn das Stimmelement über Speech Synthesis Markup Language (SSML) festgelegt wird, werden die Einstellungen SpeechSynthesisVoiceName und SpeechSynthesisLanguage ignoriert.

Synthetisieren von Sprache in eine Datei

Als Nächstes erstellen Sie ein SpeechSynthesizer-Objekt. Dieses Objekt führt die Konvertierungen von Text in Sprache und Ausgaben an Lautsprecher, in Dateien oder andere Ausgabestreams aus. SpeechSynthesizer akzeptiert folgende Parameter:

  • Das SpeechConfig-Objekt, das Sie im vorherigen Schritt erstellt haben
  • Ein AudioConfig-Objekt, das angibt, wie Ausgabeergebnisse behandelt werden sollen

Erstellen Sie zunächst eine AudioConfig-Instanz, um die Ausgabe mithilfe der Funktion FromWavFileOutput() automatisch in eine WAV-Datei zu schreiben. Instanziieren Sie sie mit einer using-Anweisung. Eine using-Anweisung in diesem Kontext gibt automatisch nicht verwaltete Ressourcen frei und führt dazu, dass das Objekt nach der Freigabe nicht mehr zum Geltungsbereich gehört.

static async Task SynthesizeAudioAsync()
{
    var speechConfig = SpeechConfig.FromSubscription("YourSpeechKey", "YourSpeechRegion");
    using var audioConfig = AudioConfig.FromWavFileOutput("path/to/write/file.wav");
}

Instanziieren Sie als Nächstes mit einer weiteren using-Anweisung eine SpeechSynthesizer-Instanz. Übergeben Sie die speechConfig- und audioConfig-Objekte als Parameter. Das Prozess zum Ausführen der Sprachsynthese und Schreiben der Daten in eine Datei ist so einfach wie das Ausführen von SpeakTextAsync() mit einer Textzeichenfolge.

static async Task SynthesizeAudioAsync()
{
    var speechConfig = SpeechConfig.FromSubscription("YourSpeechKey", "YourSpeechRegion");
    using var audioConfig = AudioConfig.FromWavFileOutput("path/to/write/file.wav");
    using var synthesizer = new SpeechSynthesizer(speechConfig, audioConfig);
    await synthesizer.SpeakTextAsync("I'm excited to try text-to-speech");
}

Führen Sie das Programm aus. Eine synthetisierte WAV-Datei wird an den von Ihnen angegebenen Speicherort geschrieben. Dies ist ein gutes Beispiel für die einfachste Verwendung. Als Nächstes befassen Sie sich mit dem Anpassen der Ausgabe und dem Verarbeiten der Ausgabeantwort als In-Memory-Datenstrom für benutzerdefinierte Szenarien.

Synthetisieren der Lautsprecherausgabe

Zum Ausgeben von synthetisierter Sprache auf dem aktuell aktiven Ausgabegerät wie einem Lautsprecher lassen Sie den Parameter AudioConfig weg, wenn Sie die SpeechSynthesizer-Instanz erstellen. Hier sehen Sie ein Beispiel:

static async Task SynthesizeAudioAsync()
{
    var speechConfig = SpeechConfig.FromSubscription("YourSpeechKey", "YourSpeechRegion");
    using var synthesizer = new SpeechSynthesizer(speechConfig);
    await synthesizer.SpeakTextAsync("I'm excited to try text to speech");
}

Abrufen eines Ergebnisses als In-Memory-Datenstrom

Sie können die resultierenden Audiodaten als einen In-Memory-Datenstrom verwenden, statt sie direkt in eine Datei zu schreiben. Mit einem In-Memory-Datenstrom können Sie benutzerdefiniertes Verhalten erstellen, wie etwa:

  • Abstrahieren des resultierenden Bytearrays als durchsuchbaren Datenstrom für benutzerdefinierte Downstreamdienste
  • Integrieren des Ergebnisses in andere APIs oder Dienste
  • Ändern der Audiodaten, Schreiben benutzerdefinierter WAV-Header und Ausführen zugehöriger Aufgaben

Diese Änderung lässt sich einfach am vorherigen Beispiel vornehmen. Entfernen Sie zunächst den AudioConfig-Block, weil Sie das Ausgabeverhalten ab jetzt manuell verwalten, um eine bessere Steuerung zu erzielen. Übergeben Sie anschließend im SpeechSynthesizer-Konstruktor null für AudioConfig.

Hinweis

Wenn Sie null für AudioConfig übergeben, anstatt den Parameter wie im obigen Beispiel für die Lautsprecherausgabe wegzulassen, werden die Audiodaten nicht standardmäßig auf dem derzeit aktiven Ausgabegerät wiedergegeben.

Dieses Mal speichern Sie das Ergebnis in einer SpeechSynthesisResult-Variable. Die AudioData-Eigenschaft enthält eine byte []-Instanz für die Ausgabedaten. Sie können diese byte []-Instanz manuell nutzen oder die AudioDataStream-Klasse verwenden, um den In-Memory-Datenstrom zu verwalten. In diesem Beispiel verwenden Sie die statische Funktion AudioDataStream.FromResult(), um einen Datenstrom aus dem Ergebnis abzurufen:

static async Task SynthesizeAudioAsync()
{
    var speechConfig = SpeechConfig.FromSubscription("YourSpeechKey", "YourSpeechRegion");
    using var synthesizer = new SpeechSynthesizer(speechConfig, null);

    var result = await synthesizer.SpeakTextAsync("I'm excited to try text-to-speech");
    using var stream = AudioDataStream.FromResult(result);
}

Nun können Sie mit dem resultierenden stream-Objekt ein beliebiges benutzerdefiniertes Verhalten implementieren.

Anpassen des Audioformats

Sie können die Attribute der Audioausgabe anpassen, z. B.:

  • Audiodateityp
  • Samplingrate
  • Bittiefe

Zum Ändern des Audioformats wenden Sie die Funktion SetSpeechSynthesisOutputFormat() auf das Objekt SpeechConfig an. Diese Funktion erwartet eine enum-Instanz vom Typ SpeechSynthesisOutputFormat, die Sie zum Auswählen des Ausgabeformats verwenden. Sehen Sie sich die Liste der verfügbaren Audioformate an.

Abhängig von Ihren Anforderungen stehen Ihnen verschiedene Optionen für unterschiedliche Dateitypen zur Verfügung. Rohformate wie Raw24Khz16BitMonoPcm enthalten gemäß Definition keine Audioheader. Verwenden Sie Rohformate nur in den folgenden Situationen:

  • Sie wissen, dass Ihre Downstreamimplementierung einen unformatierten Bitstream decodieren kann.
  • Sie planen, Header basierend auf Faktoren wie Bittiefe, Abtastrate und Anzahl von Kanälen manuell zu erstellen.

In diesem Beispiel geben Sie das High-Fidelity-RIFF-Format Riff24Khz16BitMonoPcm an, indem Sie SpeechSynthesisOutputFormat für das SpeechConfig-Objekt festlegen. Ähnlich wie im Beispiel im vorherigen Abschnitt nutzen Sie AudioDataStream, um einen InMemory-Datenstrom des Ergebnisses zu erhalten, das Sie anschließend in eine Datei schreiben.

static async Task SynthesizeAudioAsync()
{
    var speechConfig = SpeechConfig.FromSubscription("YourSpeechKey", "YourSpeechRegion");
    speechConfig.SetSpeechSynthesisOutputFormat(SpeechSynthesisOutputFormat.Riff24Khz16BitMonoPcm);

    using var synthesizer = new SpeechSynthesizer(speechConfig, null);
    var result = await synthesizer.SpeakTextAsync("I'm excited to try text-to-speech");

    using var stream = AudioDataStream.FromResult(result);
    await stream.SaveToWaveFileAsync("path/to/write/file.wav");
}

Beim erneuten Ausführen Ihres Programms wird eine WAV-Datei in den angegebenen Pfad geschrieben.

Verwenden von SSML zum Anpassen von Sprachmerkmalen

Mit SSML können Sie die Tonhöhe, Aussprache, Sprechgeschwindigkeit, Lautstärke und weitere Aspekte der Ausgabe der Sprachsynthese optimieren, indem Sie Ihre Anforderungen per XML-Schema übermitteln. Dieser Abschnitt enthält ein Beispiel für das Ändern der Stimme. Eine ausführlichere Anleitung finden Sie im Artikel Verbessern der Synthese mit Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML).

Wenn Sie SSML für die Anpassung nutzen möchten, nehmen Sie eine einfache Änderung vor, um die Stimme zu wechseln.

Erstellen Sie zuerst im Stammverzeichnis des Projekts eine neue XML-Datei für die SSML-Konfiguration. In diesem Beispiel lautet er ssml.xml. Das Stammelement ist immer <speak>. Indem Sie den Text in einem <voice>-Element umschließen, können Sie die Stimme mit dem name-Parameter ändern. Sehen Sie sich die gesamte Liste mit den unterstützten neuronalen Stimmen an.

<speak version="1.0" xmlns="https://www.w3.org/2001/10/synthesis" xml:lang="en-US">
  <voice name="en-US-JennyNeural">
    When you're on the freeway, it's a good idea to use a GPS.
  </voice>
</speak>

Als Nächstes müssen Sie die Anforderung der Sprachsynthese so ändern, dass darin auf Ihre XML-Datei verwiesen wird. Die Anforderung bleibt größtenteils unverändert, aber Sie verwenden nun SpeakSsmlAsync() anstelle von SpeakTextAsync(). Diese Funktion erwartet eine XML-Zeichenfolge. Daher laden Sie zunächst mithilfe von File.ReadAllText() Ihre SSML-Konfiguration als Zeichenfolge. Ab diesem Punkt stimmt das sich ergebende Objekt genau mit den Objekten in den vorherigen Beispielen überein.

Hinweis

Wenn Sie Visual Studio verwenden, findet Ihre Buildkonfiguration die XML-Datei wahrscheinlich nicht standardmäßig. Um dies zu erreichen, klicken Sie mit der rechten Maustaste auf die XML-Datei, und wählen Sie Eigenschaften aus. Ändern Sie Buildaktion in Inhalt und In Ausgabeverzeichnis kopieren in Immer kopieren.

public static async Task SynthesizeAudioAsync()
{
    var speechConfig = SpeechConfig.FromSubscription("YourSpeechKey", "YourSpeechRegion");
    using var synthesizer = new SpeechSynthesizer(speechConfig, null);

    var ssml = File.ReadAllText("./ssml.xml");
    var result = await synthesizer.SpeakSsmlAsync(ssml);

    using var stream = AudioDataStream.FromResult(result);
    await stream.SaveToWaveFileAsync("path/to/write/file.wav");
}

Hinweis

Wenn Sie die Stimme ohne SSML ändern möchten, können Sie die Eigenschaft für SpeechConfig mithilfe von SpeechConfig.SpeechSynthesisVoiceName = "en-US-JennyNeural"; festlegen.

Abonnieren von Synthesizerereignissen

Es kann sinnvoll sein, sich genauere Erkenntnisse zur Sprachsyntheseverarbeitung und den Ergebnissen zu verschaffen. Beispielsweise möchten Sie vielleicht wissen, wann der Synthesizer beginnt und anhält, oder Sie möchten wissen, welche anderen Ereignisse während der Synthese auftreten.

Während Sie den SpeechSynthesizer für die Sprachsynthese verwenden, können Sie die Ereignisse in dieser Tabelle abonnieren:

Ereignis BESCHREIBUNG Anwendungsfall
BookmarkReached Signalisiert, dass eine Textmarke erreicht wurde. Zum Auslösen eines Textmarke-erreicht-Ereignisses ist im SSML ein bookmark-Element erforderlich. Dieses Ereignis meldet die verstrichene Audioausgabezeit zwischen dem Beginn der Synthese und dem bookmark-Element. Die Eigenschaft Text des Ereignisses ist der Zeichenfolgenwert, den Sie im Attribut mark der Textmarke festlegen. Die bookmark-Elemente werden nicht ausgesprochen. Sie können das bookmark-Element verwenden, um benutzerdefinierte Marker in SSML einzufügen, um den Offset der einzelnen Marker im Audiostream abzurufen. Das bookmark-Element kann verwendet werden, um auf eine bestimmte Position in der Text- oder Tagsequenz zu verweisen.
SynthesisCanceled Zeigt an, dass die Sprachsynthese abgebrochen wurde. Sie können bestätigen, wenn die Synthese abgebrochen wurde.
SynthesisCompleted Zeigt an, dass die Sprachsynthese abgeschlossen wurde. Sie können bestätigen, wenn die Synthese abgeschlossen wurde.
SynthesisStarted Zeigt an, dass die Sprachsynthese begonnen wurde. Sie können bestätigen, wenn die Synthese begonnen hat.
Synthesizing Zeigt an, dass die Sprachsynthese fortgesetzt wird. Dieses Ereignis wird jedes Mal ausgelöst, wenn das SDK einen Audioabschnitt vom Speech-Dienst empfängt. Sie können bestätigen, wenn die Synthese aktuell ausgeführt wird.
VisemeReceived Zeigt an, dass ein Visemereignis empfangen wurde. Viseme (Mundbilder) werden häufig verwendet, um die wichtigsten Gesichtsausdrücke beim Sprechen darzustellen. Sie umfassen u. a. die Position der Lippen, des Kiefers und der Zunge beim Erzeugen eines bestimmten Phonems. Sie können Viseme (Mundbilder) anwenden, um das Gesicht einer Figur zu animieren, wenn die Audiodatei abgespielt wird.
WordBoundary Zeigt an, dass eine Wortgrenze empfangen wurde. Dieses Ereignis wird am Anfang jedes neuen gesprochenen Worts, beim Erreichen von Satzzeichen und am Satzanfang ausgelöst. Das Ereignis meldet den Zeitoffset des aktuellen Worts (in Ticks) vom Anfang der Audioausgabe. Dieses Ereignis meldet außerdem die Zeichenposition im Eingabetext (oder SSML) unmittelbar vor dem Wort, das als Nächstes gesprochen wird. Dieses Ereignis wird häufig verwendet, um die relativen Positionen von Text und den entsprechenden Audiodaten abzurufen. Es kann sinnvoll sein, Informationen zu einem neuen Wort zu empfangen und dann auf der Grundlage des Timings Aktionen auszuführen. Sie können z. B. Informationen abrufen, die Sie bei der Entscheidung unterstützen, wann und wie lange Wörter beim Sprechen hervorgehoben werden sollen.

Hinweis

Es werden Ereignisse ausgelöst, wenn die ausgegebenen Audiodaten verfügbar werden, was schneller erfolgt als die Wiedergabe über ein Ausgabegerät. Der Aufrufer muss das Streaming ordnungsgemäß und in Echtzeit synchronisieren.

Dieses Beispiel zeigt, wie Ereignisse für die Sprachsynthese abonniert werden. Sie können die Anweisungen in der Schnellstartanleitung befolgen, aber den Inhalt dieser Program.cs-Datei durch den folgenden C#-Code ersetzen.

using Microsoft.CognitiveServices.Speech;

class Program 
{
    // This example requires environment variables named "SPEECH_KEY" and "SPEECH_REGION"
    static string speechKey = Environment.GetEnvironmentVariable("SPEECH_KEY");
    static string speechRegion = Environment.GetEnvironmentVariable("SPEECH_REGION");

    async static Task Main(string[] args)
    {
        var speechConfig = SpeechConfig.FromSubscription(speechKey, speechRegion);
         
        var speechSynthesisVoiceName  = "en-US-JennyNeural";  
        var ssml = @$"<speak version='1.0' xml:lang='en-US' xmlns='http://www.w3.org/2001/10/synthesis' xmlns:mstts='http://www.w3.org/2001/mstts'>
            <voice name='{speechSynthesisVoiceName}'>
                <mstts:viseme type='redlips_front'/>
                The rainbow has seven colors: <bookmark mark='colors_list_begin'/>Red, orange, yellow, green, blue, indigo, and violet.<bookmark mark='colors_list_end'/>.
            </voice>
        </speak>";

        // Required for sentence-level WordBoundary events
        speechConfig.SetProperty(PropertyId.SpeechServiceResponse_RequestSentenceBoundary, "true");

        using (var speechSynthesizer = new SpeechSynthesizer(speechConfig))
        {
            // Subscribe to events

            speechSynthesizer.BookmarkReached += (s, e) =>
            {
                Console.WriteLine($"BookmarkReached event:" +
                    $"\r\n\tAudioOffset: {(e.AudioOffset + 5000) / 10000}ms" +
                    $"\r\n\tText: \"{e.Text}\".");
            };

            speechSynthesizer.SynthesisCanceled += (s, e) =>
            {
                Console.WriteLine("SynthesisCanceled event");
            };

            speechSynthesizer.SynthesisCompleted += (s, e) =>
            {                
                Console.WriteLine($"SynthesisCompleted event:" +
                    $"\r\n\tAudioData: {e.Result.AudioData.Length} bytes" +
                    $"\r\n\tAudioDuration: {e.Result.AudioDuration}");
            };

            speechSynthesizer.SynthesisStarted += (s, e) =>
            {
                Console.WriteLine("SynthesisStarted event");
            };

            speechSynthesizer.Synthesizing += (s, e) =>
            {
                Console.WriteLine($"Synthesizing event:" +
                    $"\r\n\tAudioData: {e.Result.AudioData.Length} bytes");
            };

            speechSynthesizer.VisemeReceived += (s, e) =>
            {
                Console.WriteLine($"VisemeReceived event:" +
                    $"\r\n\tAudioOffset: {(e.AudioOffset + 5000) / 10000}ms" +
                    $"\r\n\tVisemeId: {e.VisemeId}");
            };

            speechSynthesizer.WordBoundary += (s, e) =>
            {
                Console.WriteLine($"WordBoundary event:" +
                    // Word, Punctuation, or Sentence
                    $"\r\n\tBoundaryType: {e.BoundaryType}" +
                    $"\r\n\tAudioOffset: {(e.AudioOffset + 5000) / 10000}ms" +
                    $"\r\n\tDuration: {e.Duration}" +
                    $"\r\n\tText: \"{e.Text}\"" +
                    $"\r\n\tTextOffset: {e.TextOffset}" +
                    $"\r\n\tWordLength: {e.WordLength}");
            };

            // Synthesize the SSML
            Console.WriteLine($"SSML to synthesize: \r\n{ssml}");
            var speechSynthesisResult = await speechSynthesizer.SpeakSsmlAsync(ssml);

            // Output the results
            switch (speechSynthesisResult.Reason)
            {
                case ResultReason.SynthesizingAudioCompleted:
                    Console.WriteLine("SynthesizingAudioCompleted result");
                    break;
                case ResultReason.Canceled:
                    var cancellation = SpeechSynthesisCancellationDetails.FromResult(speechSynthesisResult);
                    Console.WriteLine($"CANCELED: Reason={cancellation.Reason}");

                    if (cancellation.Reason == CancellationReason.Error)
                    {
                        Console.WriteLine($"CANCELED: ErrorCode={cancellation.ErrorCode}");
                        Console.WriteLine($"CANCELED: ErrorDetails=[{cancellation.ErrorDetails}]");
                        Console.WriteLine($"CANCELED: Did you set the speech resource key and region values?");
                    }
                    break;
                default:
                    break;
            }
        }

        Console.WriteLine("Press any key to exit...");
        Console.ReadKey();
    }
}

Weitere Beispiele zur Sprachsynthese finden Sie auf GitHub.

ReferenzdokumentationPaket (NuGet)Zusätzliche Beispiele auf GitHub

In dieser Schrittanleitung werden gängige Entwurfsmuster für die Sprachsynthese vorgestellt.

Unter Was ist Text-zu-Sprache? finden Sie weitere Informationen zu folgenden Themen:

  • Abrufen von Antworten als In-Memory-Datenströme
  • Anpassen der Abtast- und Bitrate der Ausgabe
  • Übermitteln von Syntheseanforderungen mithilfe der Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML)
  • Verwenden neuronaler Stimmen
  • Abonnieren von Ereignissen und ergebnisbezogenes Handeln

Auswählen von Synthesesprache und Stimme

Das Feature für die Sprachsynthese im Azure Speech-Dienst unterstützt mehr als 270 Stimmen und über 110 Sprachen und Varianten. Weitere Informationen finden Sie in der vollständigen Liste der unterstützten Gebietsschemas für Sprachsynthese, oder probieren Sie sie im Stimmkatalog aus.

Geben Sie die Sprache oder Stimme von SpeechConfig für Ihren Eingabetext an, und verwenden Sie die gewünschte Stimme:

void synthesizeSpeech()
{
    auto speechConfig = SpeechConfig::FromSubscription("YourSpeechKey", "YourSpeechRegion");
    // Set either the `SpeechSynthesisVoiceName` or `SpeechSynthesisLanguage`.
    speechConfig->SetSpeechSynthesisLanguage("en-US"); 
    speechConfig->SetSpeechSynthesisVoiceName("en-US-JennyNeural");
}

Alle neuronalen Stimmen sind mehrsprachig und können in ihrer eigenen Sprache und in englischer Sprache sprechen. Wenn der Eingabetext auf Englisch beispielsweise „I'm excited to try text to speech“ lautet und Sie es-ES-ElviraNeural festlegen, wird der Text in englischer Sprache mit einem spanischen Akzent gesprochen. Wenn die Stimme nicht die Sprache des Eingabetexts spricht, erfolgt keine synthetisierte Audioausgabe seitens des Speech-Diensts. Sehen Sie sich die gesamte Liste mit den unterstützten neuronalen Stimmen an.

Hinweis

Die Standardstimme ist die erste Stimme, die pro Gebietsschema über die Stimmlisten-API zurückgegeben wird.

Die Stimme, die spricht, wird wie folgt nach ihrer Priorität bestimmt:

  • Wenn Sie weder SpeechSynthesisLanguage noch en-US festlegen, spricht die Standardstimme für SpeechSynthesisVoiceName.
  • Wenn Sie nur SpeechSynthesisLanguage festlegen, spricht die Standardstimme für das angegebene Gebietsschema.
  • Wenn sowohl SpeechSynthesisVoiceName als auch SpeechSynthesisLanguage festgelegt sind, wird die Einstellung SpeechSynthesisLanguage ignoriert. Es spricht die Stimme, die Sie über SpeechSynthesisVoiceName angegeben haben.
  • Wenn das Stimmelement über Speech Synthesis Markup Language (SSML) festgelegt wird, werden die Einstellungen SpeechSynthesisVoiceName und SpeechSynthesisLanguage ignoriert.

Synthetisieren von Sprache in eine Datei

Als Nächstes erstellen Sie ein SpeechSynthesizer-Objekt. Dieses Objekt führt die Konvertierungen von Text in Sprache und Ausgaben an Lautsprecher, in Dateien oder andere Ausgabestreams aus. SpeechSynthesizer akzeptiert folgende Parameter:

  • Das SpeechConfig-Objekt, das Sie im vorherigen Schritt erstellt haben
  • Ein AudioConfig-Objekt, das angibt, wie Ausgabeergebnisse behandelt werden sollen

Erstellen Sie zunächst eine AudioConfig-Instanz, um die Ausgabe mithilfe der Funktion FromWavFileOutput() automatisch in eine WAV-Datei zu schreiben:

void synthesizeSpeech()
{
    auto speechConfig = SpeechConfig::FromSubscription("YourSpeechKey", "YourSpeechRegion");
    auto audioConfig = AudioConfig::FromWavFileOutput("path/to/write/file.wav");
}

Instanziieren Sie als Nächstes eine SpeechSynthesizer-Instanz. Übergeben Sie die speechConfig- und audioConfig-Objekte als Parameter. Das Prozess zum Ausführen der Sprachsynthese und Schreiben der Daten in eine Datei ist so einfach wie das Ausführen von SpeakTextAsync() mit einer Textzeichenfolge.

void synthesizeSpeech()
{
    auto speechConfig = SpeechConfig::FromSubscription("YourSpeechKey", "YourSpeechRegion");
    auto audioConfig = AudioConfig::FromWavFileOutput("path/to/write/file.wav");
    auto synthesizer = SpeechSynthesizer::FromConfig(speechConfig, audioConfig);
    auto result = synthesizer->SpeakTextAsync("A simple test to write to a file.").get();
}

Führen Sie das Programm aus. Eine synthetisierte WAV-Datei wird an den von Ihnen angegebenen Speicherort geschrieben. Dies ist ein gutes Beispiel für die einfachste Verwendung. Als Nächstes befassen Sie sich mit dem Anpassen der Ausgabe und dem Verarbeiten der Ausgabeantwort als In-Memory-Datenstrom für benutzerdefinierte Szenarien.

Synthetisieren der Lautsprecherausgabe

Zum Ausgeben von synthetisierter Sprache auf dem aktuell aktiven Ausgabegerät wie einem Lautsprecher lassen Sie den Parameter AudioConfig weg, wenn Sie die SpeechSynthesizer-Instanz erstellen. Hier sehen Sie ein Beispiel:

void synthesizeSpeech()
{
    auto speechConfig = SpeechConfig::FromSubscription("YourSpeechKey", "YourSpeechRegion");
    auto synthesizer = SpeechSynthesizer::FromConfig(speechConfig);
    auto result = synthesizer->SpeakTextAsync("I'm excited to try text to speech").get();
}

Abrufen eines Ergebnisses als In-Memory-Datenstrom

Sie können die resultierenden Audiodaten als einen In-Memory-Datenstrom verwenden, statt sie direkt in eine Datei zu schreiben. Mit einem In-Memory-Datenstrom können Sie benutzerdefiniertes Verhalten erstellen, wie etwa:

  • Abstrahieren des resultierenden Bytearrays als durchsuchbaren Datenstrom für benutzerdefinierte Downstreamdienste
  • Integrieren des Ergebnisses in andere APIs oder Dienste
  • Ändern der Audiodaten, Schreiben benutzerdefinierter WAV-Header und Ausführen zugehöriger Aufgaben

Diese Änderung lässt sich einfach am vorherigen Beispiel vornehmen. Entfernen Sie zunächst den AudioConfig-Block, weil Sie das Ausgabeverhalten ab jetzt manuell verwalten, um eine bessere Steuerung zu erzielen. Übergeben Sie anschließend im SpeechSynthesizer-Konstruktor NULL für AudioConfig.

Hinweis

Wenn Sie NULL für AudioConfig übergeben, anstatt den Parameter wie im obigen Beispiel für die Lautsprecherausgabe wegzulassen, werden die Audiodaten nicht standardmäßig auf dem derzeit aktiven Ausgabegerät wiedergegeben.

Dieses Mal speichern Sie das Ergebnis in einer SpeechSynthesisResult-Variable. Der GetAudioData-Getter gibt eine byte []-Instanz für die Ausgabedaten zurück. Sie können diese byte []-Instanz manuell nutzen oder die AudioDataStream-Klasse verwenden, um den In-Memory-Datenstrom zu verwalten. In diesem Beispiel verwenden Sie die statische Funktion AudioDataStream.FromResult(), um einen Datenstrom aus dem Ergebnis abzurufen:

void synthesizeSpeech()
{
    auto speechConfig = SpeechConfig::FromSubscription("YourSpeechKey", "YourSpeechRegion");
    auto synthesizer = SpeechSynthesizer::FromConfig(speechConfig);

    auto result = synthesizer->SpeakTextAsync("Getting the response as an in-memory stream.").get();
    auto stream = AudioDataStream::FromResult(result);
}

Nun können Sie mit dem resultierenden stream-Objekt ein beliebiges benutzerdefiniertes Verhalten implementieren.

Anpassen des Audioformats

Sie können die Attribute der Audioausgabe anpassen, z. B.:

  • Audiodateityp
  • Samplingrate
  • Bittiefe

Zum Ändern des Audioformats wenden Sie die Funktion SetSpeechSynthesisOutputFormat() auf das Objekt SpeechConfig an. Diese Funktion erwartet eine enum-Instanz vom Typ SpeechSynthesisOutputFormat, die Sie zum Auswählen des Ausgabeformats verwenden. Sehen Sie sich die Liste der verfügbaren Audioformate an.

Abhängig von Ihren Anforderungen stehen Ihnen verschiedene Optionen für unterschiedliche Dateitypen zur Verfügung. Rohformate wie Raw24Khz16BitMonoPcm enthalten gemäß Definition keine Audioheader. Verwenden Sie Rohformate nur in den folgenden Situationen:

  • Sie wissen, dass Ihre Downstreamimplementierung einen unformatierten Bitstream decodieren kann.
  • Sie planen, Header basierend auf Faktoren wie Bittiefe, Abtastrate und Anzahl von Kanälen manuell zu erstellen.

In diesem Beispiel geben Sie das High-Fidelity-RIFF-Format Riff24Khz16BitMonoPcm an, indem Sie SpeechSynthesisOutputFormat für das SpeechConfig-Objekt festlegen. Ähnlich wie im Beispiel im vorherigen Abschnitt nutzen Sie AudioDataStream, um einen InMemory-Datenstrom des Ergebnisses zu erhalten, das Sie anschließend in eine Datei schreiben.

void synthesizeSpeech()
{
    auto speechConfig = SpeechConfig::FromSubscription("YourSpeechKey", "YourSpeechRegion");
    speechConfig->SetSpeechSynthesisOutputFormat(SpeechSynthesisOutputFormat::Riff24Khz16BitMonoPcm);

    auto synthesizer = SpeechSynthesizer::FromConfig(speechConfig);
    auto result = synthesizer->SpeakTextAsync("A simple test to write to a file.").get();

    auto stream = AudioDataStream::FromResult(result);
    stream->SaveToWavFileAsync("path/to/write/file.wav").get();
}

Beim erneuten Ausführen Ihres Programms wird eine WAV-Datei in den angegebenen Pfad geschrieben.

Verwenden von SSML zum Anpassen von Sprachmerkmalen

Mit SSML können Sie die Tonhöhe, Aussprache, Sprechgeschwindigkeit, Lautstärke und weitere Aspekte der Ausgabe der Sprachsynthese optimieren, indem Sie Ihre Anforderungen per XML-Schema übermitteln. Dieser Abschnitt enthält ein Beispiel für das Ändern der Stimme. Eine ausführlichere Anleitung finden Sie im Artikel Verbessern der Synthese mit Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML).

Wenn Sie SSML für die Anpassung nutzen möchten, nehmen Sie eine einfache Änderung vor, um die Stimme zu wechseln.

Erstellen Sie zuerst im Stammverzeichnis des Projekts eine neue XML-Datei für die SSML-Konfiguration. In diesem Beispiel lautet er ssml.xml. Das Stammelement ist immer <speak>. Indem Sie den Text in einem <voice>-Element umschließen, können Sie die Stimme mit dem name-Parameter ändern. Sehen Sie sich die gesamte Liste mit den unterstützten neuronalen Stimmen an.

<speak version="1.0" xmlns="https://www.w3.org/2001/10/synthesis" xml:lang="en-US">
  <voice name="en-US-JennyNeural">
    When you're on the freeway, it's a good idea to use a GPS.
  </voice>
</speak>

Als Nächstes müssen Sie die Anforderung der Sprachsynthese so ändern, dass darin auf Ihre XML-Datei verwiesen wird. Die Anforderung bleibt größtenteils unverändert, aber Sie verwenden nun SpeakSsmlAsync() anstelle von SpeakTextAsync(). Diese Funktion erwartet eine XML-Zeichenfolge. Daher laden Sie zunächst Ihre SSML-Konfiguration als Zeichenfolge. Ab diesem Punkt stimmt das sich ergebende Objekt genau mit den Objekten in den vorherigen Beispielen überein.

void synthesizeSpeech()
{
    auto speechConfig = SpeechConfig::FromSubscription("YourSpeechKey", "YourSpeechRegion");
    auto synthesizer = SpeechSynthesizer::FromConfig(speechConfig);

    std::ifstream file("./ssml.xml");
    std::string ssml, line;
    while (std::getline(file, line))
    {
        ssml += line;
        ssml.push_back('\n');
    }
    auto result = synthesizer->SpeakSsmlAsync(ssml).get();

    auto stream = AudioDataStream::FromResult(result);
    stream->SaveToWavFileAsync("path/to/write/file.wav").get();
}

Hinweis

Wenn Sie die Stimme ohne SSML ändern möchten, können Sie die Eigenschaft für SpeechConfig mithilfe von SpeechConfig.SetSpeechSynthesisVoiceName("en-US-ChristopherNeural") festlegen.

Abonnieren von Synthesizerereignissen

Es kann sinnvoll sein, sich genauere Erkenntnisse zur Sprachsyntheseverarbeitung und den Ergebnissen zu verschaffen. Beispielsweise möchten Sie vielleicht wissen, wann der Synthesizer beginnt und anhält, oder Sie möchten wissen, welche anderen Ereignisse während der Synthese auftreten.

Während Sie den SpeechSynthesizer für die Sprachsynthese verwenden, können Sie die Ereignisse in dieser Tabelle abonnieren:

Ereignis BESCHREIBUNG Anwendungsfall
BookmarkReached Signalisiert, dass eine Textmarke erreicht wurde. Zum Auslösen eines Textmarke-erreicht-Ereignisses ist im SSML ein bookmark-Element erforderlich. Dieses Ereignis meldet die verstrichene Audioausgabezeit zwischen dem Beginn der Synthese und dem bookmark-Element. Die Eigenschaft Text des Ereignisses ist der Zeichenfolgenwert, den Sie im Attribut mark der Textmarke festlegen. Die bookmark-Elemente werden nicht ausgesprochen. Sie können das bookmark-Element verwenden, um benutzerdefinierte Marker in SSML einzufügen, um den Offset der einzelnen Marker im Audiostream abzurufen. Das bookmark-Element kann verwendet werden, um auf eine bestimmte Position in der Text- oder Tagsequenz zu verweisen.
SynthesisCanceled Zeigt an, dass die Sprachsynthese abgebrochen wurde. Sie können bestätigen, wenn die Synthese abgebrochen wurde.
SynthesisCompleted Zeigt an, dass die Sprachsynthese abgeschlossen wurde. Sie können bestätigen, wenn die Synthese abgeschlossen wurde.
SynthesisStarted Zeigt an, dass die Sprachsynthese begonnen wurde. Sie können bestätigen, wenn die Synthese begonnen hat.
Synthesizing Zeigt an, dass die Sprachsynthese fortgesetzt wird. Dieses Ereignis wird jedes Mal ausgelöst, wenn das SDK einen Audioabschnitt vom Speech-Dienst empfängt. Sie können bestätigen, wenn die Synthese aktuell ausgeführt wird.
VisemeReceived Zeigt an, dass ein Visemereignis empfangen wurde. Viseme (Mundbilder) werden häufig verwendet, um die wichtigsten Gesichtsausdrücke beim Sprechen darzustellen. Sie umfassen u. a. die Position der Lippen, des Kiefers und der Zunge beim Erzeugen eines bestimmten Phonems. Sie können Viseme (Mundbilder) anwenden, um das Gesicht einer Figur zu animieren, wenn die Audiodatei abgespielt wird.
WordBoundary Zeigt an, dass eine Wortgrenze empfangen wurde. Dieses Ereignis wird am Anfang jedes neuen gesprochenen Worts, beim Erreichen von Satzzeichen und am Satzanfang ausgelöst. Das Ereignis meldet den Zeitoffset des aktuellen Worts (in Ticks) vom Anfang der Audioausgabe. Dieses Ereignis meldet außerdem die Zeichenposition im Eingabetext (oder SSML) unmittelbar vor dem Wort, das als Nächstes gesprochen wird. Dieses Ereignis wird häufig verwendet, um die relativen Positionen von Text und den entsprechenden Audiodaten abzurufen. Es kann sinnvoll sein, Informationen zu einem neuen Wort zu empfangen und dann auf der Grundlage des Timings Aktionen auszuführen. Sie können z. B. Informationen abrufen, die Sie bei der Entscheidung unterstützen, wann und wie lange Wörter beim Sprechen hervorgehoben werden sollen.

Hinweis

Es werden Ereignisse ausgelöst, wenn die ausgegebenen Audiodaten verfügbar werden, was schneller erfolgt als die Wiedergabe über ein Ausgabegerät. Der Aufrufer muss das Streaming ordnungsgemäß und in Echtzeit synchronisieren.

Dieses Beispiel zeigt, wie Ereignisse für die Sprachsynthese abonniert werden. Sie können die Anweisungen in der Schnellstartanleitung befolgen, aber den Inhalt dieser main.cpp-Datei durch den folgenden C++-Code ersetzen.

#include <iostream> 
#include <stdlib.h>
#include <speechapi_cxx.h>

using namespace Microsoft::CognitiveServices::Speech;
using namespace Microsoft::CognitiveServices::Speech::Audio;

std::string getEnvironmentVariable(const char* name);

int main()
{
    // This example requires environment variables named "SPEECH_KEY" and "SPEECH_REGION"
    auto speechKey = getEnvironmentVariable("SPEECH_KEY");
    auto speechRegion = getEnvironmentVariable("SPEECH_REGION");

    if ((size(speechKey) == 0) || (size(speechRegion) == 0)) {
        std::cout << "Please set both SPEECH_KEY and SPEECH_REGION environment variables." << std::endl;
        return -1;
    }

    auto speechConfig = SpeechConfig::FromSubscription(speechKey, speechRegion);

    // Required for WordBoundary event sentences.
    speechConfig->SetProperty(PropertyId::SpeechServiceResponse_RequestSentenceBoundary, "true");

    const auto ssml = R"(<speak version='1.0' xml:lang='en-US' xmlns='http://www.w3.org/2001/10/synthesis' xmlns:mstts='http://www.w3.org/2001/mstts'>
        <voice name = 'en-US-JennyNeural'>
            <mstts:viseme type = 'redlips_front' />
            The rainbow has seven colors : <bookmark mark = 'colors_list_begin' />Red, orange, yellow, green, blue, indigo, and violet.<bookmark mark = 'colors_list_end' />.
        </voice>
        </speak>)";

    auto speechSynthesizer = SpeechSynthesizer::FromConfig(speechConfig);

    // Subscribe to events

    speechSynthesizer->BookmarkReached += [](const SpeechSynthesisBookmarkEventArgs& e)
    {
        std::cout << "Bookmark reached. "
            << "\r\n\tAudioOffset: " << round(e.AudioOffset / 10000) << "ms"
            << "\r\n\tText: " << e.Text << std::endl;
    };

    speechSynthesizer->SynthesisCanceled += [](const SpeechSynthesisEventArgs& e)
    {
        std::cout << "SynthesisCanceled event" << std::endl;
    };

    speechSynthesizer->SynthesisCompleted += [](const SpeechSynthesisEventArgs& e)
    {
        auto audioDuration = std::chrono::duration_cast<std::chrono::milliseconds>(e.Result->AudioDuration).count();

        std::cout << "SynthesisCompleted event:"
            << "\r\n\tAudioData: " << e.Result->GetAudioData()->size() << "bytes"
            << "\r\n\tAudioDuration: " << audioDuration << std::endl;
    };

    speechSynthesizer->SynthesisStarted += [](const SpeechSynthesisEventArgs& e)
    {
        std::cout << "SynthesisStarted event" << std::endl;
    };

    speechSynthesizer->Synthesizing += [](const SpeechSynthesisEventArgs& e)
    {
        std::cout << "Synthesizing event:"
            << "\r\n\tAudioData: " << e.Result->GetAudioData()->size() << "bytes" << std::endl;
    };

    speechSynthesizer->VisemeReceived += [](const SpeechSynthesisVisemeEventArgs& e)
    {
        std::cout << "VisemeReceived event:"
            << "\r\n\tAudioOffset: " << round(e.AudioOffset / 10000) << "ms"
            << "\r\n\tVisemeId: " << e.VisemeId << std::endl;
    };

    speechSynthesizer->WordBoundary += [](const SpeechSynthesisWordBoundaryEventArgs& e)
    {
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(e.Duration).count();
        
        auto boundaryType = "";
        switch (e.BoundaryType) {
        case SpeechSynthesisBoundaryType::Punctuation:
            boundaryType = "Punctuation";
            break;
        case SpeechSynthesisBoundaryType::Sentence:
            boundaryType = "Sentence";
            break;
        case SpeechSynthesisBoundaryType::Word:
            boundaryType = "Word";
            break;
        }

        std::cout << "WordBoundary event:"
            // Word, Punctuation, or Sentence
            << "\r\n\tBoundaryType: " << boundaryType
            << "\r\n\tAudioOffset: " << round(e.AudioOffset / 10000) << "ms"
            << "\r\n\tDuration: " << duration
            << "\r\n\tText: \"" << e.Text << "\""
            << "\r\n\tTextOffset: " << e.TextOffset
            << "\r\n\tWordLength: " << e.WordLength << std::endl;
    };

    auto result = speechSynthesizer->SpeakSsmlAsync(ssml).get();

    // Checks result.
    if (result->Reason == ResultReason::SynthesizingAudioCompleted)
    {
        std::cout << "SynthesizingAudioCompleted result" << std::endl;
    }
    else if (result->Reason == ResultReason::Canceled)
    {
        auto cancellation = SpeechSynthesisCancellationDetails::FromResult(result);
        std::cout << "CANCELED: Reason=" << (int)cancellation->Reason << std::endl;

        if (cancellation->Reason == CancellationReason::Error)
        {
            std::cout << "CANCELED: ErrorCode=" << (int)cancellation->ErrorCode << std::endl;
            std::cout << "CANCELED: ErrorDetails=[" << cancellation->ErrorDetails << "]" << std::endl;
            std::cout << "CANCELED: Did you set the speech resource key and region values?" << std::endl;
        }
    }

    std::cout << "Press enter to exit..." << std::endl;
    std::cin.get();
}

std::string getEnvironmentVariable(const char* name)
{
#if defined(_MSC_VER)
    size_t requiredSize = 0;
    (void)getenv_s(&requiredSize, nullptr, 0, name);
    if (requiredSize == 0)
    {
        return "";
    }
    auto buffer = std::make_unique<char[]>(requiredSize);
    (void)getenv_s(&requiredSize, buffer.get(), requiredSize, name);
    return buffer.get();
#else
    auto value = getenv(name);
    return value ? value : "";
#endif
}

Weitere Beispiele zur Sprachsynthese finden Sie auf GitHub.

ReferenzdokumentationPaket (Go)Zusätzliche Beispiele auf GitHub

In dieser Schrittanleitung werden gängige Entwurfsmuster für die Sprachsynthese vorgestellt.

Unter Was ist Text-zu-Sprache? finden Sie weitere Informationen zu folgenden Themen:

  • Abrufen von Antworten als In-Memory-Datenströme
  • Anpassen der Abtast- und Bitrate der Ausgabe
  • Übermitteln von Syntheseanforderungen mithilfe der Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML)
  • Verwenden neuronaler Stimmen
  • Abonnieren von Ereignissen und ergebnisbezogenes Handeln

Voraussetzungen

Installieren des Speech SDK

Zuallererst müssen Sie das Speech SDK für Go installieren.

Text-zu-Sprache über Lautsprecher

Verwenden Sie das folgende Codebeispiel, um die Sprachsynthese über Ihr standardmäßiges Audioausgabegerät durchzuführen. Ersetzen Sie die Variablen subscription und region durch Ihren Schlüssel für die Spracheingabe und durch Ihren Standort/Ihre Region. Wenn Sie das Skript ausführen, wird Ihr Eingabetext über den Standardlautsprecher gesprochen.

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/Microsoft/cognitive-services-speech-sdk-go/audio"
	"github.com/Microsoft/cognitive-services-speech-sdk-go/common"
	"github.com/Microsoft/cognitive-services-speech-sdk-go/speech"
)

func synthesizeStartedHandler(event speech.SpeechSynthesisEventArgs) {
	defer event.Close()
	fmt.Println("Synthesis started.")
}

func synthesizingHandler(event speech.SpeechSynthesisEventArgs) {
	defer event.Close()
	fmt.Printf("Synthesizing, audio chunk size %d.\n", len(event.Result.AudioData))
}

func synthesizedHandler(event speech.SpeechSynthesisEventArgs) {
	defer event.Close()
	fmt.Printf("Synthesized, audio length %d.\n", len(event.Result.AudioData))
}

func cancelledHandler(event speech.SpeechSynthesisEventArgs) {
	defer event.Close()
	fmt.Println("Received a cancellation.")
}

func main() {
    subscription := "YourSpeechKey"
    region := "YourSpeechRegion"

	audioConfig, err := audio.NewAudioConfigFromDefaultSpeakerOutput()
	if err != nil {
		fmt.Println("Got an error: ", err)
		return
	}
	defer audioConfig.Close()
	speechConfig, err := speech.NewSpeechConfigFromSubscription(subscription, region)
	if err != nil {
		fmt.Println("Got an error: ", err)
		return
	}
	defer speechConfig.Close()
	speechSynthesizer, err := speech.NewSpeechSynthesizerFromConfig(speechConfig, audioConfig)
	if err != nil {
		fmt.Println("Got an error: ", err)
		return
	}
	defer speechSynthesizer.Close()

	speechSynthesizer.SynthesisStarted(synthesizeStartedHandler)
	speechSynthesizer.Synthesizing(synthesizingHandler)
	speechSynthesizer.SynthesisCompleted(synthesizedHandler)
	speechSynthesizer.SynthesisCanceled(cancelledHandler)

	for {
		fmt.Printf("Enter some text that you want to speak, or enter empty text to exit.\n> ")
		text, _ := bufio.NewReader(os.Stdin).ReadString('\n')
		text = strings.TrimSuffix(text, "\n")
		if len(text) == 0 {
			break
		}

		task := speechSynthesizer.SpeakTextAsync(text)
		var outcome speech.SpeechSynthesisOutcome
		select {
		case outcome = <-task:
		case <-time.After(60 * time.Second):
			fmt.Println("Timed out")
			return
		}
		defer outcome.Close()
		if outcome.Error != nil {
			fmt.Println("Got an error: ", outcome.Error)
			return
		}

		if outcome.Result.Reason == common.SynthesizingAudioCompleted {
			fmt.Printf("Speech synthesized to speaker for text [%s].\n", text)
		} else {
			cancellation, _ := speech.NewCancellationDetailsFromSpeechSynthesisResult(outcome.Result)
			fmt.Printf("CANCELED: Reason=%d.\n", cancellation.Reason)

			if cancellation.Reason == common.Error {
				fmt.Printf("CANCELED: ErrorCode=%d\nCANCELED: ErrorDetails=[%s]\nCANCELED: Did you set the speech resource key and region values?\n",
					cancellation.ErrorCode,
					cancellation.ErrorDetails)
			}
		}
	}
}

Führen Sie die folgenden Befehle aus, um eine Datei namens go.mod zu erstellen, die mit auf GitHub gehosteten Komponenten verknüpft ist:

go mod init quickstart
go get github.com/Microsoft/cognitive-services-speech-sdk-go

Erstellen Sie nun den Code, und führen Sie ihn aus:

go build
go run quickstart

Ausführliche Informationen zu den Klassen finden Sie in der Referenzdokumentation zu SpeechConfig und SpeechSynthesizer.

Text-zu-Sprache über In-Memory-Datenstrom

Sie können die resultierenden Audiodaten als einen In-Memory-Datenstrom verwenden, statt sie direkt in eine Datei zu schreiben. Mit einem In-Memory-Datenstrom können Sie benutzerdefiniertes Verhalten erstellen, wie etwa:

  • Abstrahieren des resultierenden Bytearrays als durchsuchbaren Datenstrom für benutzerdefinierte Downstreamdienste
  • Integrieren des Ergebnisses in andere APIs oder Dienste
  • Ändern der Audiodaten, Schreiben benutzerdefinierter WAV-Header und Ausführen zugehöriger Aufgaben

Diese Änderung lässt sich einfach am vorherigen Beispiel vornehmen. Entfernen Sie zunächst den AudioConfig-Block, weil Sie das Ausgabeverhalten ab jetzt manuell verwalten, um eine bessere Steuerung zu erzielen. Übergeben Sie anschließend im SpeechSynthesizer-Konstruktor nil für AudioConfig.

Hinweis

Wenn Sie NULL für AudioConfig übergeben, anstatt den Parameter wie im obigen Beispiel für die Lautsprecherausgabe wegzulassen, werden die Audiodaten nicht standardmäßig auf dem derzeit aktiven Ausgabegerät wiedergegeben.

Dieses Mal speichern Sie das Ergebnis in einer SpeechSynthesisResult-Variable. Die AudioData-Eigenschaft gibt eine []byte-Instanz für die Ausgabedaten zurück. Sie können diese []byte-Instanz manuell nutzen oder die AudioDataStream-Klasse verwenden, um den In-Memory-Datenstrom zu verwalten. In diesem Beispiel verwenden Sie die statische Funktion NewAudioDataStreamFromSpeechSynthesisResult(), um einen Datenstrom aus dem Ergebnis abzurufen.

Ersetzen Sie die Variablen subscription und region durch Ihren Schlüssel für die Spracheingabe und durch Ihren Standort bzw. Ihre Region:

package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
	"time"

	"github.com/Microsoft/cognitive-services-speech-sdk-go/speech"
)

func synthesizeStartedHandler(event speech.SpeechSynthesisEventArgs) {
	defer event.Close()
	fmt.Println("Synthesis started.")
}

func synthesizingHandler(event speech.SpeechSynthesisEventArgs) {
	defer event.Close()
	fmt.Printf("Synthesizing, audio chunk size %d.\n", len(event.Result.AudioData))
}

func synthesizedHandler(event speech.SpeechSynthesisEventArgs) {
	defer event.Close()
	fmt.Printf("Synthesized, audio length %d.\n", len(event.Result.AudioData))
}

func cancelledHandler(event speech.SpeechSynthesisEventArgs) {
	defer event.Close()
	fmt.Println("Received a cancellation.")
}

func main() {
	subscription := "YourSpeechKey"
	region := "YourSpeechRegion"

	speechConfig, err := speech.NewSpeechConfigFromSubscription(subscription, region)
	if err != nil {
		fmt.Println("Got an error: ", err)
		return
	}
	defer speechConfig.Close()
	speechSynthesizer, err := speech.NewSpeechSynthesizerFromConfig(speechConfig, nil)
	if err != nil {
		fmt.Println("Got an error: ", err)
		return
	}
	defer speechSynthesizer.Close()

	speechSynthesizer.SynthesisStarted(synthesizeStartedHandler)
	speechSynthesizer.Synthesizing(synthesizingHandler)
	speechSynthesizer.SynthesisCompleted(synthesizedHandler)
	speechSynthesizer.SynthesisCanceled(cancelledHandler)

	for {
		fmt.Printf("Enter some text that you want to speak, or enter empty text to exit.\n> ")
		text, _ := bufio.NewReader(os.Stdin).ReadString('\n')
		text = strings.TrimSuffix(text, "\n")
		if len(text) == 0 {
			break
		}

		// StartSpeakingTextAsync sends the result to channel when the synthesis starts.
		task := speechSynthesizer.StartSpeakingTextAsync(text)
		var outcome speech.SpeechSynthesisOutcome
		select {
		case outcome = <-task:
		case <-time.After(60 * time.Second):
			fmt.Println("Timed out")
			return
		}
		defer outcome.Close()
		if outcome.Error != nil {
			fmt.Println("Got an error: ", outcome.Error)
			return
		}

		// In most cases, we want to streaming receive the audio to lower the latency.
		// We can use AudioDataStream to do so.
		stream, err := speech.NewAudioDataStreamFromSpeechSynthesisResult(outcome.Result)
		defer stream.Close()
		if err != nil {
			fmt.Println("Got an error: ", err)
			return
		}

		var all_audio []byte
		audio_chunk := make([]byte, 2048)
		for {
			n, err := stream.Read(audio_chunk)

			if err == io.EOF {
				break
			}

			all_audio = append(all_audio, audio_chunk[:n]...)
		}

		fmt.Printf("Read [%d] bytes from audio data stream.\n", len(all_audio))
	}
}

Führen Sie die folgenden Befehle aus, um eine Datei namens go.mod zu erstellen, die mit auf GitHub gehosteten Komponenten verknüpft ist:

go mod init quickstart
go get github.com/Microsoft/cognitive-services-speech-sdk-go

Erstellen Sie nun den Code, und führen Sie ihn aus:

go build
go run quickstart

Ausführliche Informationen zu den Klassen finden Sie in der Referenzdokumentation zu SpeechConfig und SpeechSynthesizer.

Auswählen von Synthesesprache und Stimme

Das Feature für die Sprachsynthese im Azure Speech-Dienst unterstützt mehr als 270 Stimmen und über 110 Sprachen und Varianten. Sie können die vollständige Liste abrufen oder sie im Stimmkatalog ausprobieren.

Geben Sie die Sprache oder Stimme von SpeechConfig für Ihren Eingabetext an, und verwenden Sie die gewünschte Stimme:

speechConfig, err := speech.NewSpeechConfigFromSubscription(key, region)
if err != nil {
	fmt.Println("Got an error: ", err)
	return
}
defer speechConfig.Close()

speechConfig.SetSpeechSynthesisLanguage("en-US")
speechConfig.SetSpeechSynthesisVoiceName("en-US-JennyNeural")

Alle neuronalen Stimmen sind mehrsprachig und können in ihrer eigenen Sprache und in englischer Sprache sprechen. Wenn der Eingabetext auf Englisch beispielsweise „I'm excited to try text to speech“ lautet und Sie es-ES-ElviraNeural festlegen, wird der Text in englischer Sprache mit einem spanischen Akzent gesprochen. Wenn die Stimme nicht die Sprache des Eingabetexts spricht, erfolgt keine synthetisierte Audioausgabe seitens des Speech-Diensts. Sehen Sie sich die gesamte Liste mit den unterstützten neuronalen Stimmen an.

Hinweis

Die Standardstimme ist die erste Stimme, die pro Gebietsschema über die Stimmlisten-API zurückgegeben wird.

Die Stimme, die spricht, wird wie folgt nach ihrer Priorität bestimmt:

  • Wenn Sie weder SpeechSynthesisLanguage noch en-US festlegen, spricht die Standardstimme für SpeechSynthesisVoiceName.
  • Wenn Sie nur SpeechSynthesisLanguage festlegen, spricht die Standardstimme für das angegebene Gebietsschema.
  • Wenn sowohl SpeechSynthesisVoiceName als auch SpeechSynthesisLanguage festgelegt sind, wird die Einstellung SpeechSynthesisLanguage ignoriert. Es spricht die Stimme, die Sie über SpeechSynthesisVoiceName angegeben haben.
  • Wenn das Stimmelement über Speech Synthesis Markup Language (SSML) festgelegt wird, werden die Einstellungen SpeechSynthesisVoiceName und SpeechSynthesisLanguage ignoriert.

Verwenden von SSML zum Anpassen von Sprachmerkmalen

Mit der Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML) können Sie die Tonhöhe, Aussprache, Sprechgeschwindigkeit, Lautstärke und weitere Aspekte der Ausgabe der Sprachsynthese optimieren, indem Sie Ihre Anforderungen per XML-Schema übermitteln. Dieser Abschnitt enthält ein Beispiel für das Ändern der Stimme. Eine ausführlichere Anleitung finden Sie im Artikel Verbessern der Synthese mit Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML).

Wenn Sie SSML für die Anpassung nutzen möchten, nehmen Sie eine einfache Änderung vor, um die Stimme zu wechseln.

Erstellen Sie zuerst im Stammverzeichnis des Projekts eine neue XML-Datei für die SSML-Konfiguration. In diesem Beispiel lautet er ssml.xml. Das Stammelement ist immer <speak>. Indem Sie den Text in einem <voice>-Element umschließen, können Sie die Stimme mit dem name-Parameter ändern. Sehen Sie sich die gesamte Liste mit den unterstützten neuronalen Stimmen an.

<speak version="1.0" xmlns="https://www.w3.org/2001/10/synthesis" xml:lang="en-US">
  <voice name="en-US-JennyNeural">
    When you're on the freeway, it's a good idea to use a GPS.
  </voice>
</speak>

Als Nächstes müssen Sie die Anforderung der Sprachsynthese so ändern, dass darin auf Ihre XML-Datei verwiesen wird. Die Anforderung bleibt größtenteils unverändert, aber Sie verwenden nun SpeakSsmlAsync() anstelle von SpeakTextAsync(). Diese Funktion erwartet eine XML-Zeichenfolge. Daher laden Sie zunächst Ihre SSML-Konfiguration als Zeichenfolge. Ab diesem Punkt stimmt das sich ergebende Objekt genau mit den Objekten in den vorherigen Beispielen überein.

Hinweis

Wenn Sie die Stimme ohne SSML festlegen möchten, können Sie die Eigenschaft für SpeechConfig mithilfe von speechConfig.SetSpeechSynthesisVoiceName("en-US-JennyNeural") festlegen.

Abonnieren von Synthesizerereignissen

Es kann sinnvoll sein, sich genauere Erkenntnisse zur Sprachsyntheseverarbeitung und den Ergebnissen zu verschaffen. Beispielsweise möchten Sie vielleicht wissen, wann der Synthesizer beginnt und anhält, oder Sie möchten wissen, welche anderen Ereignisse während der Synthese auftreten.

Während Sie den SpeechSynthesizer für die Sprachsynthese verwenden, können Sie die Ereignisse in dieser Tabelle abonnieren:

Ereignis BESCHREIBUNG Anwendungsfall
BookmarkReached Signalisiert, dass eine Textmarke erreicht wurde. Zum Auslösen eines Textmarke-erreicht-Ereignisses ist im SSML ein bookmark-Element erforderlich. Dieses Ereignis meldet die verstrichene Audioausgabezeit zwischen dem Beginn der Synthese und dem bookmark-Element. Die Eigenschaft Text des Ereignisses ist der Zeichenfolgenwert, den Sie im Attribut mark der Textmarke festlegen. Die bookmark-Elemente werden nicht ausgesprochen. Sie können das bookmark-Element verwenden, um benutzerdefinierte Marker in SSML einzufügen, um den Offset der einzelnen Marker im Audiostream abzurufen. Das bookmark-Element kann verwendet werden, um auf eine bestimmte Position in der Text- oder Tagsequenz zu verweisen.
SynthesisCanceled Zeigt an, dass die Sprachsynthese abgebrochen wurde. Sie können bestätigen, wenn die Synthese abgebrochen wurde.
SynthesisCompleted Zeigt an, dass die Sprachsynthese abgeschlossen wurde. Sie können bestätigen, wenn die Synthese abgeschlossen wurde.
SynthesisStarted Zeigt an, dass die Sprachsynthese begonnen wurde. Sie können bestätigen, wenn die Synthese begonnen hat.
Synthesizing Zeigt an, dass die Sprachsynthese fortgesetzt wird. Dieses Ereignis wird jedes Mal ausgelöst, wenn das SDK einen Audioabschnitt vom Speech-Dienst empfängt. Sie können bestätigen, wenn die Synthese aktuell ausgeführt wird.
VisemeReceived Zeigt an, dass ein Visemereignis empfangen wurde. Viseme (Mundbilder) werden häufig verwendet, um die wichtigsten Gesichtsausdrücke beim Sprechen darzustellen. Sie umfassen u. a. die Position der Lippen, des Kiefers und der Zunge beim Erzeugen eines bestimmten Phonems. Sie können Viseme (Mundbilder) anwenden, um das Gesicht einer Figur zu animieren, wenn die Audiodatei abgespielt wird.
WordBoundary Zeigt an, dass eine Wortgrenze empfangen wurde. Dieses Ereignis wird am Anfang jedes neuen gesprochenen Worts, beim Erreichen von Satzzeichen und am Satzanfang ausgelöst. Das Ereignis meldet den Zeitoffset des aktuellen Worts (in Ticks) vom Anfang der Audioausgabe. Dieses Ereignis meldet außerdem die Zeichenposition im Eingabetext (oder SSML) unmittelbar vor dem Wort, das als Nächstes gesprochen wird. Dieses Ereignis wird häufig verwendet, um die relativen Positionen von Text und den entsprechenden Audiodaten abzurufen. Es kann sinnvoll sein, Informationen zu einem neuen Wort zu empfangen und dann auf der Grundlage des Timings Aktionen auszuführen. Sie können z. B. Informationen abrufen, die Sie bei der Entscheidung unterstützen, wann und wie lange Wörter beim Sprechen hervorgehoben werden sollen.

Hinweis

Es werden Ereignisse ausgelöst, wenn die ausgegebenen Audiodaten verfügbar werden, was schneller erfolgt als die Wiedergabe über ein Ausgabegerät. Der Aufrufer muss das Streaming ordnungsgemäß und in Echtzeit synchronisieren.

Dieses Beispiel zeigt, wie Ereignisse für die Sprachsynthese abonniert werden. Sie können die Anweisungen in der Schnellstartanleitung befolgen, aber den Inhalt dieser speech-synthesis.go-Datei durch den folgenden Go-Code ersetzen.

package main

import (
	"fmt"
	"os"
	"time"

	"github.com/Microsoft/cognitive-services-speech-sdk-go/audio"
	"github.com/Microsoft/cognitive-services-speech-sdk-go/common"
	"github.com/Microsoft/cognitive-services-speech-sdk-go/speech"
)

func bookmarkReachedHandler(event speech.SpeechSynthesisBookmarkEventArgs) {
	defer event.Close()
	fmt.Println("BookmarkReached event")
}

func synthesisCanceledHandler(event speech.SpeechSynthesisEventArgs) {
	defer event.Close()
	fmt.Println("SynthesisCanceled event")
}

func synthesisCompletedHandler(event speech.SpeechSynthesisEventArgs) {
	defer event.Close()
	fmt.Println("SynthesisCompleted event")
	fmt.Printf("\tAudioData: %d bytes\n", len(event.Result.AudioData))
	fmt.Printf("\tAudioDuration: %d\n", event.Result.AudioDuration)
}

func synthesisStartedHandler(event speech.SpeechSynthesisEventArgs) {
	defer event.Close()
	fmt.Println("SynthesisStarted event")
}

func synthesizingHandler(event speech.SpeechSynthesisEventArgs) {
	defer event.Close()
	fmt.Println("Synthesizing event")
	fmt.Printf("\tAudioData %d bytes\n", len(event.Result.AudioData))
}

func visemeReceivedHandler(event speech.SpeechSynthesisVisemeEventArgs) {
	defer event.Close()
	fmt.Println("VisemeReceived event")
	fmt.Printf("\tAudioOffset: %dms\n", (event.AudioOffset+5000)/10000)
	fmt.Printf("\tVisemeID %d\n", event.VisemeID)
}

func wordBoundaryHandler(event speech.SpeechSynthesisWordBoundaryEventArgs) {
	defer event.Close()
	boundaryType := ""
	switch event.BoundaryType {
	case 0:
		boundaryType = "Word"
	case 1:
		boundaryType = "Punctuation"
	case 2:
		boundaryType = "Sentence"
	}
	fmt.Println("WordBoundary event")
	fmt.Printf("\tBoundaryType %v\n", boundaryType)
	fmt.Printf("\tAudioOffset: %dms\n", (event.AudioOffset+5000)/10000)
	fmt.Printf("\tDuration %d\n", event.Duration)
	fmt.Printf("\tText %s\n", event.Text)
	fmt.Printf("\tTextOffset %d\n", event.TextOffset)
	fmt.Printf("\tWordLength %d\n", event.WordLength)
}

func main() {
    // This example requires environment variables named "SPEECH_KEY" and "SPEECH_REGION"
	speechKey := os.Getenv("SPEECH_KEY")
	speechRegion := os.Getenv("SPEECH_REGION")

	audioConfig, err := audio.NewAudioConfigFromDefaultSpeakerOutput()
	if err != nil {
		fmt.Println("Got an error: ", err)
		return
	}
	defer audioConfig.Close()
	speechConfig, err := speech.NewSpeechConfigFromSubscription(speechKey, speechRegion)
	if err != nil {
		fmt.Println("Got an error: ", err)
		return
	}
	defer speechConfig.Close()

	// Required for WordBoundary event sentences.
	speechConfig.SetProperty(common.SpeechServiceResponseRequestSentenceBoundary, "true")

	speechSynthesizer, err := speech.NewSpeechSynthesizerFromConfig(speechConfig, audioConfig)
	if err != nil {
		fmt.Println("Got an error: ", err)
		return
	}
	defer speechSynthesizer.Close()

	speechSynthesizer.BookmarkReached(bookmarkReachedHandler)
	speechSynthesizer.SynthesisCanceled(synthesisCanceledHandler)
	speechSynthesizer.SynthesisCompleted(synthesisCompletedHandler)
	speechSynthesizer.SynthesisStarted(synthesisStartedHandler)
	speechSynthesizer.Synthesizing(synthesizingHandler)
	speechSynthesizer.VisemeReceived(visemeReceivedHandler)
	speechSynthesizer.WordBoundary(wordBoundaryHandler)

	speechSynthesisVoiceName := "en-US-JennyNeural"

	ssml := fmt.Sprintf(`<speak version='1.0' xml:lang='en-US' xmlns='http://www.w3.org/2001/10/synthesis' xmlns:mstts='http://www.w3.org/2001/mstts'>
            <voice name='%s'>
                <mstts:viseme type='redlips_front'/>
                The rainbow has seven colors: <bookmark mark='colors_list_begin'/>Red, orange, yellow, green, blue, indigo, and violet.<bookmark mark='colors_list_end'/>.
            </voice>
        </speak>`, speechSynthesisVoiceName)

	// Synthesize the SSML
	fmt.Printf("SSML to synthesize: \n\t%s\n", ssml)
	task := speechSynthesizer.SpeakSsmlAsync(ssml)

	var outcome speech.SpeechSynthesisOutcome
	select {
	case outcome = <-task:
	case <-time.After(60 * time.Second):
		fmt.Println("Timed out")
		return
	}
	defer outcome.Close()
	if outcome.Error != nil {
		fmt.Println("Got an error: ", outcome.Error)
		return
	}

	if outcome.Result.Reason == common.SynthesizingAudioCompleted {
		fmt.Println("SynthesizingAudioCompleted result")
	} else {
		cancellation, _ := speech.NewCancellationDetailsFromSpeechSynthesisResult(outcome.Result)
		fmt.Printf("CANCELED: Reason=%d.\n", cancellation.Reason)

		if cancellation.Reason == common.Error {
			fmt.Printf("CANCELED: ErrorCode=%d\nCANCELED: ErrorDetails=[%s]\nCANCELED: Did you set the speech resource key and region values?\n",
				cancellation.ErrorCode,
				cancellation.ErrorDetails)
		}
	}
}

Weitere Beispiele zur Sprachsynthese finden Sie auf GitHub.

Referenzdokumentation | Zusätzliche Beispiele auf GitHub

In dieser Schrittanleitung werden gängige Entwurfsmuster für die Sprachsynthese vorgestellt.

Unter Was ist Text-zu-Sprache? finden Sie weitere Informationen zu folgenden Themen:

  • Abrufen von Antworten als In-Memory-Datenströme
  • Anpassen der Abtast- und Bitrate der Ausgabe
  • Übermitteln von Syntheseanforderungen mithilfe der Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML)
  • Verwenden neuronaler Stimmen
  • Abonnieren von Ereignissen und ergebnisbezogenes Handeln

Auswählen von Synthesesprache und Stimme

Das Feature für die Sprachsynthese im Azure Speech-Dienst unterstützt mehr als 270 Stimmen und über 110 Sprachen und Varianten. Sie können die vollständige Liste abrufen oder sie im Stimmkatalog ausprobieren.

Geben Sie die Sprache oder Stimme von SpeechConfig für Ihren Eingabetext an, und verwenden Sie die gewünschte Stimme:

public static void main(String[] args) {
    SpeechConfig speechConfig = SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
    // Set either the `SpeechSynthesisVoiceName` or `SpeechSynthesisLanguage`.
    speechConfig.setSpeechSynthesisLanguage("en-US"); 
    speechConfig.setSpeechSynthesisVoiceName("en-US-JennyNeural");
}

Alle neuronalen Stimmen sind mehrsprachig und können in ihrer eigenen Sprache und in englischer Sprache sprechen. Wenn der Eingabetext auf Englisch beispielsweise „I'm excited to try text to speech“ lautet und Sie es-ES-ElviraNeural festlegen, wird der Text in englischer Sprache mit einem spanischen Akzent gesprochen. Wenn die Stimme nicht die Sprache des Eingabetexts spricht, erfolgt keine synthetisierte Audioausgabe seitens des Speech-Diensts. Sehen Sie sich die gesamte Liste mit den unterstützten neuronalen Stimmen an.

Hinweis

Die Standardstimme ist die erste Stimme, die pro Gebietsschema über die Stimmlisten-API zurückgegeben wird.

Die Stimme, die spricht, wird wie folgt nach ihrer Priorität bestimmt:

  • Wenn Sie weder SpeechSynthesisLanguage noch en-US festlegen, spricht die Standardstimme für SpeechSynthesisVoiceName.
  • Wenn Sie nur SpeechSynthesisLanguage festlegen, spricht die Standardstimme für das angegebene Gebietsschema.
  • Wenn sowohl SpeechSynthesisVoiceName als auch SpeechSynthesisLanguage festgelegt sind, wird die Einstellung SpeechSynthesisLanguage ignoriert. Es spricht die Stimme, die Sie über SpeechSynthesisVoiceName angegeben haben.
  • Wenn das Stimmelement über Speech Synthesis Markup Language (SSML) festgelegt wird, werden die Einstellungen SpeechSynthesisVoiceName und SpeechSynthesisLanguage ignoriert.

Synthetisieren von Sprache in eine Datei

Als Nächstes erstellen Sie ein SpeechSynthesizer-Objekt. Dieses Objekt führt die Konvertierungen von Text in Sprache und Ausgaben an Lautsprecher, in Dateien oder andere Ausgabestreams aus. SpeechSynthesizer akzeptiert folgende Parameter:

  • Das SpeechConfig-Objekt, das Sie im vorherigen Schritt erstellt haben
  • Ein AudioConfig-Objekt, das angibt, wie Ausgabeergebnisse behandelt werden sollen

Erstellen Sie zunächst eine AudioConfig-Instanz, um die Ausgabe mithilfe der statischen Funktion fromWavFileOutput() automatisch in eine WAV-Datei zu schreiben:

public static void main(String[] args) {
    SpeechConfig speechConfig = SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
    AudioConfig audioConfig = AudioConfig.fromWavFileOutput("path/to/write/file.wav");
}

Instanziieren Sie als Nächstes eine SpeechSynthesizer-Instanz. Übergeben Sie die speechConfig- und audioConfig-Objekte als Parameter. Das Ausführen der Sprachsynthese und Schreiben der Daten in eine Datei ist so einfach wie das Ausführen von SpeakText() mit einer Textzeichenfolge.

public static void main(String[] args) {
    SpeechConfig speechConfig = SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
    AudioConfig audioConfig = AudioConfig.fromWavFileOutput("path/to/write/file.wav");

    SpeechSynthesizer synthesizer = new SpeechSynthesizer(speechConfig, audioConfig);
    synthesizer.SpeakText("I'm excited to try text-to-speech");
}

Führen Sie das Programm aus. Eine synthetisierte WAV-Datei wird an den von Ihnen angegebenen Speicherort geschrieben. Dies ist ein gutes Beispiel für die einfachste Verwendung. Als Nächstes befassen Sie sich mit dem Anpassen der Ausgabe und dem Verarbeiten der Ausgabeantwort als In-Memory-Datenstrom für benutzerdefinierte Szenarien.

Synthetisieren der Lautsprecherausgabe

Es kann sinnvoll sein, sich genauere Erkenntnisse zur Sprachsyntheseverarbeitung und den Ergebnissen zu verschaffen. Beispielsweise möchten Sie vielleicht wissen, wann der Synthesizer beginnt und anhält, oder Sie möchten wissen, welche anderen Ereignisse während der Synthese auftreten.

Zum Ausgeben von synthetisierter Sprache an das aktuell aktive Ausgabegerät wie etwa einen Lautsprecher instanziieren Sie AudioConfig mithilfe der statischen Funktion fromDefaultSpeakerOutput(). Hier sehen Sie ein Beispiel:

public static void main(String[] args) {
    SpeechConfig speechConfig = SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
    AudioConfig audioConfig = AudioConfig.fromDefaultSpeakerOutput();

    SpeechSynthesizer synthesizer = new SpeechSynthesizer(speechConfig, audioConfig);
    synthesizer.SpeakText("I'm excited to try text to speech");
}

Abrufen eines Ergebnisses als In-Memory-Datenstrom

Sie können die resultierenden Audiodaten als einen In-Memory-Datenstrom verwenden, statt sie direkt in eine Datei zu schreiben. Mit einem In-Memory-Datenstrom können Sie benutzerdefiniertes Verhalten erstellen, wie etwa:

  • Abstrahieren des resultierenden Bytearrays als durchsuchbaren Datenstrom für benutzerdefinierte Downstreamdienste
  • Integrieren des Ergebnisses in andere APIs oder Dienste
  • Ändern der Audiodaten, Schreiben benutzerdefinierter WAV-Header und Ausführen zugehöriger Aufgaben

Diese Änderung lässt sich einfach am vorherigen Beispiel vornehmen. Entfernen Sie zunächst den AudioConfig-Block, weil Sie das Ausgabeverhalten ab jetzt manuell verwalten, um eine bessere Steuerung zu erzielen. Übergeben Sie anschließend im SpeechSynthesizer-Konstruktor null für AudioConfig.

Hinweis

Wenn Sie null für AudioConfig übergeben, anstatt den Parameter wie im obigen Beispiel für die Lautsprecherausgabe wegzulassen, werden die Audiodaten nicht standardmäßig auf dem derzeit aktiven Ausgabegerät wiedergegeben.

Hierbei speichern Sie das Ergebnis nun in einer Variablen vom Typ SpeechSynthesisResult. Die Funktion SpeechSynthesisResult.getAudioData() gibt eine byte []-Instanz der Ausgabedaten zurück. Sie können diese byte []-Instanz manuell nutzen oder die AudioDataStream-Klasse verwenden, um den In-Memory-Datenstrom zu verwalten. In diesem Beispiel verwenden Sie die statische Funktion AudioDataStream.fromResult(), um einen Datenstrom aus dem Ergebnis abzurufen:

public static void main(String[] args) {
    SpeechConfig speechConfig = SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
    SpeechSynthesizer synthesizer = new SpeechSynthesizer(speechConfig, null);

    SpeechSynthesisResult result = synthesizer.SpeakText("I'm excited to try text-to-speech");
    AudioDataStream stream = AudioDataStream.fromResult(result);
    System.out.print(stream.getStatus());
}

Nun können Sie mit dem resultierenden stream-Objekt ein beliebiges benutzerdefiniertes Verhalten implementieren.

Anpassen des Audioformats

Sie können die Attribute der Audioausgabe anpassen, z. B.:

  • Audiodateityp
  • Samplingrate
  • Bittiefe

Zum Ändern des Audioformats wenden Sie die Funktion setSpeechSynthesisOutputFormat() auf das Objekt SpeechConfig an. Diese Funktion erwartet eine enum-Instanz vom Typ SpeechSynthesisOutputFormat, die Sie zum Auswählen des Ausgabeformats verwenden. Sehen Sie sich die Liste der verfügbaren Audioformate an.

Abhängig von Ihren Anforderungen stehen Ihnen verschiedene Optionen für unterschiedliche Dateitypen zur Verfügung. Rohformate wie Raw24Khz16BitMonoPcm enthalten gemäß Definition keine Audioheader. Verwenden Sie Rohformate nur in den folgenden Situationen:

  • Sie wissen, dass Ihre Downstreamimplementierung einen unformatierten Bitstream decodieren kann.
  • Sie planen, Header basierend auf Faktoren wie Bittiefe, Abtastrate und Anzahl von Kanälen manuell zu erstellen.

In diesem Beispiel geben Sie das High-Fidelity-RIFF-Format Riff24Khz16BitMonoPcm an, indem Sie SpeechSynthesisOutputFormat für das SpeechConfig-Objekt festlegen. Ähnlich wie im Beispiel im vorherigen Abschnitt nutzen Sie AudioDataStream, um einen InMemory-Datenstrom des Ergebnisses zu erhalten, das Sie anschließend in eine Datei schreiben.

public static void main(String[] args) {
    SpeechConfig speechConfig = SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");

    // set the output format
    speechConfig.setSpeechSynthesisOutputFormat(SpeechSynthesisOutputFormat.Riff24Khz16BitMonoPcm);

    SpeechSynthesizer synthesizer = new SpeechSynthesizer(speechConfig, null);
    SpeechSynthesisResult result = synthesizer.SpeakText("I'm excited to try text-to-speech");
    AudioDataStream stream = AudioDataStream.fromResult(result);
    stream.saveToWavFile("path/to/write/file.wav");
}

Beim erneuten Ausführen Ihres Programms wird eine WAV-Datei in den angegebenen Pfad geschrieben.

Verwenden von SSML zum Anpassen von Sprachmerkmalen

Mit SSML können Sie die Tonhöhe, Aussprache, Sprechgeschwindigkeit, Lautstärke und weitere Aspekte der Ausgabe der Sprachsynthese optimieren, indem Sie Ihre Anforderungen per XML-Schema übermitteln. Dieser Abschnitt enthält ein Beispiel für das Ändern der Stimme. Eine ausführlichere Anleitung finden Sie im Artikel Verbessern der Synthese mit Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML).

Wenn Sie SSML für die Anpassung nutzen möchten, nehmen Sie eine einfache Änderung vor, um die Stimme zu wechseln.

Erstellen Sie zuerst im Stammverzeichnis des Projekts eine neue XML-Datei für die SSML-Konfiguration. In diesem Beispiel lautet er ssml.xml. Das Stammelement ist immer <speak>. Indem Sie den Text in einem <voice>-Element umschließen, können Sie die Stimme mit dem name-Parameter ändern. Sehen Sie sich die gesamte Liste mit den unterstützten neuronalen Stimmen an.

<speak version="1.0" xmlns="https://www.w3.org/2001/10/synthesis" xml:lang="en-US">
  <voice name="en-US-JennyNeural">
    When you're on the freeway, it's a good idea to use a GPS.
  </voice>
</speak>

Als Nächstes müssen Sie die Anforderung der Sprachsynthese so ändern, dass darin auf Ihre XML-Datei verwiesen wird. Die Anforderung bleibt größtenteils unverändert, aber Sie verwenden nun SpeakSsml() anstelle von SpeakText(). Diese Funktion erwartet eine XML-Zeichenfolge. Daher erstellen Sie zunächst eine Funktion, um eine XML-Datei zu laden und als Zeichenfolge zurückzugeben:

private static String xmlToString(String filePath) {
    File file = new File(filePath);
    StringBuilder fileContents = new StringBuilder((int)file.length());

    try (Scanner scanner = new Scanner(file)) {
        while(scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine() + System.lineSeparator());
        }
        return fileContents.toString().trim();
    } catch (FileNotFoundException ex) {
        return "File not found.";
    }
}

Ab hier ist das Ergebnisobjekt mit den vorhergehenden Beispielen identisch:

public static void main(String[] args) {
    SpeechConfig speechConfig = SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
    SpeechSynthesizer synthesizer = new SpeechSynthesizer(speechConfig, null);

    String ssml = xmlToString("ssml.xml");
    SpeechSynthesisResult result = synthesizer.SpeakSsml(ssml);
    AudioDataStream stream = AudioDataStream.fromResult(result);
    stream.saveToWavFile("path/to/write/file.wav");
}

Hinweis

Wenn Sie die Stimme ohne SSML ändern möchten, können Sie die Eigenschaft für SpeechConfig mithilfe von SpeechConfig.setSpeechSynthesisVoiceName("en-US-JennyNeural"); festlegen.

Abonnieren von Synthesizerereignissen

Es kann sinnvoll sein, sich genauere Erkenntnisse zur Sprachsyntheseverarbeitung und den Ergebnissen zu verschaffen. Beispielsweise möchten Sie vielleicht wissen, wann der Synthesizer beginnt und anhält, oder Sie möchten wissen, welche anderen Ereignisse während der Synthese auftreten.

Während Sie den SpeechSynthesizer für die Sprachsynthese verwenden, können Sie die Ereignisse in dieser Tabelle abonnieren:

Ereignis BESCHREIBUNG Anwendungsfall
BookmarkReached Signalisiert, dass eine Textmarke erreicht wurde. Zum Auslösen eines Textmarke-erreicht-Ereignisses ist im SSML ein bookmark-Element erforderlich. Dieses Ereignis meldet die verstrichene Audioausgabezeit zwischen dem Beginn der Synthese und dem bookmark-Element. Die Eigenschaft Text des Ereignisses ist der Zeichenfolgenwert, den Sie im Attribut mark der Textmarke festlegen. Die bookmark-Elemente werden nicht ausgesprochen. Sie können das bookmark-Element verwenden, um benutzerdefinierte Marker in SSML einzufügen, um den Offset der einzelnen Marker im Audiostream abzurufen. Das bookmark-Element kann verwendet werden, um auf eine bestimmte Position in der Text- oder Tagsequenz zu verweisen.
SynthesisCanceled Zeigt an, dass die Sprachsynthese abgebrochen wurde. Sie können bestätigen, wenn die Synthese abgebrochen wurde.
SynthesisCompleted Zeigt an, dass die Sprachsynthese abgeschlossen wurde. Sie können bestätigen, wenn die Synthese abgeschlossen wurde.
SynthesisStarted Zeigt an, dass die Sprachsynthese begonnen wurde. Sie können bestätigen, wenn die Synthese begonnen hat.
Synthesizing Zeigt an, dass die Sprachsynthese fortgesetzt wird. Dieses Ereignis wird jedes Mal ausgelöst, wenn das SDK einen Audioabschnitt vom Speech-Dienst empfängt. Sie können bestätigen, wenn die Synthese aktuell ausgeführt wird.
VisemeReceived Zeigt an, dass ein Visemereignis empfangen wurde. Viseme (Mundbilder) werden häufig verwendet, um die wichtigsten Gesichtsausdrücke beim Sprechen darzustellen. Sie umfassen u. a. die Position der Lippen, des Kiefers und der Zunge beim Erzeugen eines bestimmten Phonems. Sie können Viseme (Mundbilder) anwenden, um das Gesicht einer Figur zu animieren, wenn die Audiodatei abgespielt wird.
WordBoundary Zeigt an, dass eine Wortgrenze empfangen wurde. Dieses Ereignis wird am Anfang jedes neuen gesprochenen Worts, beim Erreichen von Satzzeichen und am Satzanfang ausgelöst. Das Ereignis meldet den Zeitoffset des aktuellen Worts (in Ticks) vom Anfang der Audioausgabe. Dieses Ereignis meldet außerdem die Zeichenposition im Eingabetext (oder SSML) unmittelbar vor dem Wort, das als Nächstes gesprochen wird. Dieses Ereignis wird häufig verwendet, um die relativen Positionen von Text und den entsprechenden Audiodaten abzurufen. Es kann sinnvoll sein, Informationen zu einem neuen Wort zu empfangen und dann auf der Grundlage des Timings Aktionen auszuführen. Sie können z. B. Informationen abrufen, die Sie bei der Entscheidung unterstützen, wann und wie lange Wörter beim Sprechen hervorgehoben werden sollen.

Hinweis

Es werden Ereignisse ausgelöst, wenn die ausgegebenen Audiodaten verfügbar werden, was schneller erfolgt als die Wiedergabe über ein Ausgabegerät. Der Aufrufer muss das Streaming ordnungsgemäß und in Echtzeit synchronisieren.

Dieses Beispiel zeigt, wie Ereignisse für die Sprachsynthese abonniert werden. Sie können die Anweisungen in der Schnellstartanleitung befolgen, aber den Inhalt dieser SpeechSynthesis.java-Datei durch den folgenden Java-Code ersetzen.

import com.microsoft.cognitiveservices.speech.*;
import com.microsoft.cognitiveservices.speech.audio.*;

import java.util.Scanner;
import java.util.concurrent.ExecutionException;

public class SpeechSynthesis {
    // This example requires environment variables named "SPEECH_KEY" and "SPEECH_REGION"
    private static String speechKey = System.getenv("SPEECH_KEY");
    private static String speechRegion = System.getenv("SPEECH_REGION");

    public static void main(String[] args) throws InterruptedException, ExecutionException {

        SpeechConfig speechConfig = SpeechConfig.fromSubscription(speechKey, speechRegion);
        
        // Required for WordBoundary event sentences.
        speechConfig.setProperty(PropertyId.SpeechServiceResponse_RequestSentenceBoundary, "true");

        String speechSynthesisVoiceName = "en-US-JennyNeural"; 
        
        String ssml = String.format("<speak version='1.0' xml:lang='en-US' xmlns='http://www.w3.org/2001/10/synthesis' xmlns:mstts='http://www.w3.org/2001/mstts'>"
            .concat(String.format("<voice name='%s'>", speechSynthesisVoiceName))
            .concat("<mstts:viseme type='redlips_front'/>")
            .concat("The rainbow has seven colors: <bookmark mark='colors_list_begin'/>Red, orange, yellow, green, blue, indigo, and violet.<bookmark mark='colors_list_end'/>.")
            .concat("</voice>")
            .concat("</speak>"));

        SpeechSynthesizer speechSynthesizer = new SpeechSynthesizer(speechConfig);
        {
            // Subscribe to events

            speechSynthesizer.BookmarkReached.addEventListener((o, e) -> {
                System.out.println("BookmarkReached event:");
                System.out.println("\tAudioOffset: " + ((e.getAudioOffset() + 5000) / 10000) + "ms");
                System.out.println("\tText: " + e.getText());
            });

            speechSynthesizer.SynthesisCanceled.addEventListener((o, e) -> {
                System.out.println("SynthesisCanceled event");
            });

            speechSynthesizer.SynthesisCompleted.addEventListener((o, e) -> {
                SpeechSynthesisResult result = e.getResult();                
                byte[] audioData = result.getAudioData();
                System.out.println("SynthesisCompleted event:");
                System.out.println("\tAudioData: " + audioData.length + " bytes");
                System.out.println("\tAudioDuration: " + result.getAudioDuration());
                result.close();
            });
            
            speechSynthesizer.SynthesisStarted.addEventListener((o, e) -> {
                System.out.println("SynthesisStarted event");
            });

            speechSynthesizer.Synthesizing.addEventListener((o, e) -> {
                SpeechSynthesisResult result = e.getResult();
                byte[] audioData = result.getAudioData();
                System.out.println("Synthesizing event:");
                System.out.println("\tAudioData: " + audioData.length + " bytes");
                result.close();
            });

            speechSynthesizer.VisemeReceived.addEventListener((o, e) -> {
                System.out.println("VisemeReceived event:");
                System.out.println("\tAudioOffset: " + ((e.getAudioOffset() + 5000) / 10000) + "ms");
                System.out.println("\tVisemeId: " + e.getVisemeId());
            });

            speechSynthesizer.WordBoundary.addEventListener((o, e) -> {
                System.out.println("WordBoundary event:");
                System.out.println("\tBoundaryType: " + e.getBoundaryType());
                System.out.println("\tAudioOffset: " + ((e.getAudioOffset() + 5000) / 10000) + "ms");
                System.out.println("\tDuration: " + e.getDuration());
                System.out.println("\tText: " + e.getText());
                System.out.println("\tTextOffset: " + e.getTextOffset());
                System.out.println("\tWordLength: " + e.getWordLength());
            });

            // Synthesize the SSML
            System.out.println("SSML to synthesize:");
            System.out.println(ssml);
            SpeechSynthesisResult speechSynthesisResult = speechSynthesizer.SpeakSsmlAsync(ssml).get();

            if (speechSynthesisResult.getReason() == ResultReason.SynthesizingAudioCompleted) {
                System.out.println("SynthesizingAudioCompleted result");
            }
            else if (speechSynthesisResult.getReason() == ResultReason.Canceled) {
                SpeechSynthesisCancellationDetails cancellation = SpeechSynthesisCancellationDetails.fromResult(speechSynthesisResult);
                System.out.println("CANCELED: Reason=" + cancellation.getReason());

                if (cancellation.getReason() == CancellationReason.Error) {
                    System.out.println("CANCELED: ErrorCode=" + cancellation.getErrorCode());
                    System.out.println("CANCELED: ErrorDetails=" + cancellation.getErrorDetails());
                    System.out.println("CANCELED: Did you set the speech resource key and region values?");
                }
            }
        }
        speechSynthesizer.close();

        System.exit(0);
    }
}

Weitere Beispiele zur Sprachsynthese finden Sie auf GitHub.

ReferenzdokumentationPaket (npm)Zusätzliche Beispiele auf GitHubQuellcode der Bibliothek

In dieser Schrittanleitung werden gängige Entwurfsmuster für die Sprachsynthese vorgestellt.

Unter Was ist Text-zu-Sprache? finden Sie weitere Informationen zu folgenden Themen:

  • Abrufen von Antworten als In-Memory-Datenströme
  • Anpassen der Abtast- und Bitrate der Ausgabe
  • Übermitteln von Syntheseanforderungen mithilfe der Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML)
  • Verwenden neuronaler Stimmen
  • Abonnieren von Ereignissen und ergebnisbezogenes Handeln

Auswählen von Synthesesprache und Stimme

Das Feature für die Sprachsynthese im Azure Speech-Dienst unterstützt mehr als 270 Stimmen und über 110 Sprachen und Varianten. Sie können die vollständige Liste abrufen oder sie im Stimmkatalog ausprobieren.

Geben Sie die Sprache oder Stimme von SpeechConfig für Ihren Eingabetext an, und verwenden Sie die gewünschte Stimme:

function synthesizeSpeech() {
    const speechConfig = sdk.SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
    // Set either the `SpeechSynthesisVoiceName` or `SpeechSynthesisLanguage`.
    speechConfig.speechSynthesisLanguage = "en-US"; 
    speechConfig.speechSynthesisVoiceName = "en-US-JennyNeural";
}

synthesizeSpeech();

Alle neuronalen Stimmen sind mehrsprachig und können in ihrer eigenen Sprache und in englischer Sprache sprechen. Wenn der Eingabetext auf Englisch beispielsweise „I'm excited to try text to speech“ lautet und Sie es-ES-ElviraNeural festlegen, wird der Text in englischer Sprache mit einem spanischen Akzent gesprochen. Wenn die Stimme nicht die Sprache des Eingabetexts spricht, erfolgt keine synthetisierte Audioausgabe seitens des Speech-Diensts. Sehen Sie sich die gesamte Liste mit den unterstützten neuronalen Stimmen an.

Hinweis

Die Standardstimme ist die erste Stimme, die pro Gebietsschema über die Stimmlisten-API zurückgegeben wird.

Die Stimme, die spricht, wird wie folgt nach ihrer Priorität bestimmt:

  • Wenn Sie weder SpeechSynthesisLanguage noch en-US festlegen, spricht die Standardstimme für SpeechSynthesisVoiceName.
  • Wenn Sie nur SpeechSynthesisLanguage festlegen, spricht die Standardstimme für das angegebene Gebietsschema.
  • Wenn sowohl SpeechSynthesisVoiceName als auch SpeechSynthesisLanguage festgelegt sind, wird die Einstellung SpeechSynthesisLanguage ignoriert. Es spricht die Stimme, die Sie über SpeechSynthesisVoiceName angegeben haben.
  • Wenn das Stimmelement über Speech Synthesis Markup Language (SSML) festgelegt wird, werden die Einstellungen SpeechSynthesisVoiceName und SpeechSynthesisLanguage ignoriert.

Synthetisieren von Text in Sprache

Zum Ausgeben von synthetisierter Sprache an das aktuell aktive Ausgabegerät wie etwa einen Lautsprecher instanziieren Sie AudioConfig mithilfe der statischen Funktion fromDefaultSpeakerOutput(). Hier sehen Sie ein Beispiel:

function synthesizeSpeech() {
    const speechConfig = sdk.SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
    const audioConfig = sdk.AudioConfig.fromDefaultSpeakerOutput();

    const synthesizer = new SpeechSynthesizer(speechConfig, audioConfig);
    synthesizer.speakTextAsync(
        "I'm excited to try text to speech",
        result => {
            if (result) {
                synthesizer.close();
                return result.audioData;
            }
        },
        error => {
            console.log(error);
            synthesizer.close();
        });
}

Führen Sie das Programm aus. Synthetisierte Audiodaten werden über den Lautsprecher wiedergegeben. Dies ist ein gutes Beispiel für die einfachste Verwendung. Als Nächstes befassen Sie sich mit dem Anpassen der Ausgabe und dem Verarbeiten der Ausgabeantwort als In-Memory-Datenstrom für benutzerdefinierte Szenarien.

Abrufen eines Ergebnisses als In-Memory-Datenstrom

Sie können die resultierenden Audiodaten als einen In-Memory-Datenstrom verwenden, statt sie direkt in eine Datei zu schreiben. Mit einem In-Memory-Datenstrom können Sie benutzerdefiniertes Verhalten erstellen, wie etwa:

  • Abstrahieren des resultierenden Bytearrays als durchsuchbaren Datenstrom für benutzerdefinierte Downstreamdienste
  • Integrieren des Ergebnisses in andere APIs oder Dienste
  • Ändern der Audiodaten, Schreiben benutzerdefinierter .wav-Header und Ausführen zugehöriger Aufgaben

Diese Änderung lässt sich einfach am vorherigen Beispiel vornehmen. Entfernen Sie zunächst den AudioConfig-Block, weil Sie das Ausgabeverhalten ab jetzt manuell verwalten, um eine bessere Steuerung zu erzielen. Übergeben Sie anschließend im SpeechSynthesizer-Konstruktor null für AudioConfig.

Hinweis

Wenn Sie null für AudioConfig übergeben, anstatt den Parameter wie im obigen Beispiel für die Lautsprecherausgabe wegzulassen, werden die Audiodaten nicht standardmäßig auf dem derzeit aktiven Ausgabegerät wiedergegeben.

Hierbei speichern Sie das Ergebnis nun in einer Variablen vom Typ SpeechSynthesisResult. Die SpeechSynthesisResult.audioData-Eigenschaft gibt einen ArrayBuffer-Wert der Ausgabedaten zurück, den Standard-Browserstreamtyp. Konvertieren Sie ArrayBuffer für serverseitigen Code in einen Pufferstream.

Der folgende Code funktioniert für die Clientseite:

function synthesizeSpeech() {
    const speechConfig = sdk.SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
    const synthesizer = new sdk.SpeechSynthesizer(speechConfig);

    synthesizer.speakTextAsync(
        "I'm excited to try text-to-speech",
        result => {
            synthesizer.close();
            return result.audioData;
        },
        error => {
            console.log(error);
            synthesizer.close();
        });
}

Nun können Sie mit dem resultierenden ArrayBuffer-Objekt ein beliebiges benutzerdefiniertes Verhalten implementieren. ArrayBuffer ist ein gängiger Typ, der in einem Browser empfangen und in diesem Format wiedergegeben wird.

Wenn Sie in serverbasiertem Code mit den Daten als Stream arbeiten müssen, müssen Sie das ArrayBuffer-Objekt in einen Stream konvertieren:

function synthesizeSpeech() {
    const speechConfig = sdk.SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
    const synthesizer = new sdk.SpeechSynthesizer(speechConfig);

    synthesizer.speakTextAsync(
        "I'm excited to try text-to-speech",
        result => {
            const { audioData } = result;

            synthesizer.close();

            // convert arrayBuffer to stream
            // return stream
            const bufferStream = new PassThrough();
            bufferStream.end(Buffer.from(audioData));
            return bufferStream;
        },
        error => {
            console.log(error);
            synthesizer.close();
        });
}

Anpassen des Audioformats

Sie können die Attribute der Audioausgabe anpassen, z. B.:

  • Audiodateityp
  • Samplingrate
  • Bittiefe

Zum Ändern des Audioformats wenden Sie die Eigenschaft speechSynthesisOutputFormat auf das Objekt SpeechConfig an. Diese Eigenschaft erwartet eine enum-Instanz vom Typ SpeechSynthesisOutputFormat, die Sie zum Auswählen des Ausgabeformats verwenden. Sehen Sie sich die Liste der verfügbaren Audioformate an.

Abhängig von Ihren Anforderungen stehen Ihnen verschiedene Optionen für unterschiedliche Dateitypen zur Verfügung. Rohformate wie Raw24Khz16BitMonoPcm enthalten gemäß Definition keine Audioheader. Verwenden Sie Rohformate nur in den folgenden Situationen:

  • Sie wissen, dass Ihre Downstreamimplementierung einen unformatierten Bitstream decodieren kann.
  • Sie planen, Header basierend auf Faktoren wie Bittiefe, Abtastrate und Anzahl von Kanälen manuell zu erstellen.

In diesem Beispiel geben Sie das High-Fidelity-RIFF-Format Riff24Khz16BitMonoPcm an, indem Sie speechSynthesisOutputFormat für das SpeechConfig-Objekt festlegen. Rufen Sie die ArrayBuffer-Audiodaten ähnlich wie im Beispiel im vorherigen Abschnitt ab, und interagieren Sie damit.

function synthesizeSpeech() {
    const speechConfig = SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");

    // Set the output format
    speechConfig.speechSynthesisOutputFormat = sdk.SpeechSynthesisOutputFormat.Riff24Khz16BitMonoPcm;

    const synthesizer = new sdk.SpeechSynthesizer(speechConfig, null);
    synthesizer.speakTextAsync(
        "I'm excited to try text-to-speech",
        result => {
            // Interact with the audio ArrayBuffer data
            const audioData = result.audioData;
            console.log(`Audio data byte size: ${audioData.byteLength}.`)

            synthesizer.close();
        },
        error => {
            console.log(error);
            synthesizer.close();
        });
}

Verwenden von SSML zum Anpassen von Sprachmerkmalen

Mit SSML können Sie die Tonhöhe, Aussprache, Sprechgeschwindigkeit, Lautstärke und weitere Aspekte der Ausgabe der Sprachsynthese optimieren, indem Sie Ihre Anforderungen per XML-Schema übermitteln. Dieser Abschnitt enthält ein Beispiel für das Ändern der Stimme. Eine ausführlichere Anleitung finden Sie im Artikel Verbessern der Synthese mit Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML).

Wenn Sie SSML für die Anpassung nutzen möchten, nehmen Sie eine einfache Änderung vor, um die Stimme zu wechseln.

Erstellen Sie zuerst im Stammverzeichnis des Projekts eine neue XML-Datei für die SSML-Konfiguration. In diesem Beispiel lautet er ssml.xml. Das Stammelement ist immer <speak>. Indem Sie den Text in einem <voice>-Element umschließen, können Sie die Stimme mit dem name-Parameter ändern. Sehen Sie sich die gesamte Liste mit den unterstützten neuronalen Stimmen an.

<speak version="1.0" xmlns="https://www.w3.org/2001/10/synthesis" xml:lang="en-US">
  <voice name="en-US-JennyNeural">
    When you're on the freeway, it's a good idea to use a GPS.
  </voice>
</speak>

Als Nächstes müssen Sie die Anforderung der Sprachsynthese so ändern, dass darin auf Ihre XML-Datei verwiesen wird. Die Anforderung bleibt größtenteils unverändert, aber Sie verwenden nun speakSsmlAsync() anstelle von speakTextAsync(). Diese Funktion erwartet eine XML-Zeichenfolge. Daher erstellen Sie zuerst eine Funktion, um eine XML-Datei zu laden und als Zeichenfolge zurückzugeben:

function xmlToString(filePath) {
    const xml = readFileSync(filePath, "utf8");
    return xml;
}

Weitere Informationen zu readFileSync finden Sie unter Node.js-Dateisystem. Ab hier ist das Ergebnisobjekt mit den vorhergehenden Beispielen identisch:

function synthesizeSpeech() {
    const speechConfig = sdk.SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
    const synthesizer = new sdk.SpeechSynthesizer(speechConfig, null);

    const ssml = xmlToString("ssml.xml");
    synthesizer.speakSsmlAsync(
        ssml,
        result => {
            if (result.errorDetails) {
                console.error(result.errorDetails);
            } else {
                console.log(JSON.stringify(result));
            }

            synthesizer.close();
        },
        error => {
            console.log(error);
            synthesizer.close();
        });
}

Hinweis

Wenn Sie die Stimme ohne SSML ändern möchten, können Sie die Eigenschaft für SpeechConfig mithilfe von SpeechConfig.speechSynthesisVoiceName = "en-US-JennyNeural"; festlegen.

Abonnieren von Synthesizerereignissen

Es kann sinnvoll sein, sich genauere Erkenntnisse zur Sprachsyntheseverarbeitung und den Ergebnissen zu verschaffen. Beispielsweise möchten Sie vielleicht wissen, wann der Synthesizer beginnt und anhält, oder Sie möchten wissen, welche anderen Ereignisse während der Synthese auftreten.

Während Sie den SpeechSynthesizer für die Sprachsynthese verwenden, können Sie die Ereignisse in dieser Tabelle abonnieren:

Ereignis BESCHREIBUNG Anwendungsfall
BookmarkReached Signalisiert, dass eine Textmarke erreicht wurde. Zum Auslösen eines Textmarke-erreicht-Ereignisses ist im SSML ein bookmark-Element erforderlich. Dieses Ereignis meldet die verstrichene Audioausgabezeit zwischen dem Beginn der Synthese und dem bookmark-Element. Die Eigenschaft Text des Ereignisses ist der Zeichenfolgenwert, den Sie im Attribut mark der Textmarke festlegen. Die bookmark-Elemente werden nicht ausgesprochen. Sie können das bookmark-Element verwenden, um benutzerdefinierte Marker in SSML einzufügen, um den Offset der einzelnen Marker im Audiostream abzurufen. Das bookmark-Element kann verwendet werden, um auf eine bestimmte Position in der Text- oder Tagsequenz zu verweisen.
SynthesisCanceled Zeigt an, dass die Sprachsynthese abgebrochen wurde. Sie können bestätigen, wenn die Synthese abgebrochen wurde.
SynthesisCompleted Zeigt an, dass die Sprachsynthese abgeschlossen wurde. Sie können bestätigen, wenn die Synthese abgeschlossen wurde.
SynthesisStarted Zeigt an, dass die Sprachsynthese begonnen wurde. Sie können bestätigen, wenn die Synthese begonnen hat.
Synthesizing Zeigt an, dass die Sprachsynthese fortgesetzt wird. Dieses Ereignis wird jedes Mal ausgelöst, wenn das SDK einen Audioabschnitt vom Speech-Dienst empfängt. Sie können bestätigen, wenn die Synthese aktuell ausgeführt wird.
VisemeReceived Zeigt an, dass ein Visemereignis empfangen wurde. Viseme (Mundbilder) werden häufig verwendet, um die wichtigsten Gesichtsausdrücke beim Sprechen darzustellen. Sie umfassen u. a. die Position der Lippen, des Kiefers und der Zunge beim Erzeugen eines bestimmten Phonems. Sie können Viseme (Mundbilder) anwenden, um das Gesicht einer Figur zu animieren, wenn die Audiodatei abgespielt wird.
WordBoundary Zeigt an, dass eine Wortgrenze empfangen wurde. Dieses Ereignis wird am Anfang jedes neuen gesprochenen Worts, beim Erreichen von Satzzeichen und am Satzanfang ausgelöst. Das Ereignis meldet den Zeitoffset des aktuellen Worts (in Ticks) vom Anfang der Audioausgabe. Dieses Ereignis meldet außerdem die Zeichenposition im Eingabetext (oder SSML) unmittelbar vor dem Wort, das als Nächstes gesprochen wird. Dieses Ereignis wird häufig verwendet, um die relativen Positionen von Text und den entsprechenden Audiodaten abzurufen. Es kann sinnvoll sein, Informationen zu einem neuen Wort zu empfangen und dann auf der Grundlage des Timings Aktionen auszuführen. Sie können z. B. Informationen abrufen, die Sie bei der Entscheidung unterstützen, wann und wie lange Wörter beim Sprechen hervorgehoben werden sollen.

Hinweis

Es werden Ereignisse ausgelöst, wenn die ausgegebenen Audiodaten verfügbar werden, was schneller erfolgt als die Wiedergabe über ein Ausgabegerät. Der Aufrufer muss das Streaming ordnungsgemäß und in Echtzeit synchronisieren.

Dieses Beispiel zeigt, wie Ereignisse für die Sprachsynthese abonniert werden. Sie können die Anweisungen in der Schnellstartanleitung befolgen, aber den Inhalt dieser SpeechSynthesis.js-Datei durch den folgenden JavaScript-Code ersetzen.

(function() {

    "use strict";

    var sdk = require("microsoft-cognitiveservices-speech-sdk");

    var audioFile = "YourAudioFile.wav";
    // This example requires environment variables named "SPEECH_KEY" and "SPEECH_REGION"
    const speechConfig = sdk.SpeechConfig.fromSubscription(process.env.SPEECH_KEY, process.env.SPEECH_REGION);
    const audioConfig = sdk.AudioConfig.fromAudioFileOutput(audioFile);

    var speechSynthesisVoiceName  = "en-US-JennyNeural";  
    var ssml = `<speak version='1.0' xml:lang='en-US' xmlns='http://www.w3.org/2001/10/synthesis' xmlns:mstts='http://www.w3.org/2001/mstts'> \r\n \
        <voice name='${speechSynthesisVoiceName}'> \r\n \
            <mstts:viseme type='redlips_front'/> \r\n \
            The rainbow has seven colors: <bookmark mark='colors_list_begin'/>Red, orange, yellow, green, blue, indigo, and violet.<bookmark mark='colors_list_end'/>. \r\n \
        </voice> \r\n \
    </speak>`;
    
    // Required for WordBoundary event sentences.
    speechConfig.setProperty(sdk.PropertyId.SpeechServiceResponse_RequestSentenceBoundary, "true");

    // Create the speech speechSynthesizer.
    var speechSynthesizer = new sdk.SpeechSynthesizer(speechConfig, audioConfig);

    speechSynthesizer.bookmarkReached = function (s, e) {
        var str = `BookmarkReached event: \
            \r\n\tAudioOffset: ${(e.audioOffset + 5000) / 10000}ms \
            \r\n\tText: \"${e.text}\".`;
        console.log(str);
    };

    speechSynthesizer.synthesisCanceled = function (s, e) {
        console.log("SynthesisCanceled event");
    };
    
    speechSynthesizer.synthesisCompleted = function (s, e) {
        var str = `SynthesisCompleted event: \
                    \r\n\tAudioData: ${e.result.audioData.byteLength} bytes \
                    \r\n\tAudioDuration: ${e.result.audioDuration}`;
        console.log(str);
    };

    speechSynthesizer.synthesisStarted = function (s, e) {
        console.log("SynthesisStarted event");
    };

    speechSynthesizer.synthesizing = function (s, e) {
        var str = `Synthesizing event: \
            \r\n\tAudioData: ${e.result.audioData.byteLength} bytes`;
        console.log(str);
    };
    
    speechSynthesizer.visemeReceived = function(s, e) {
        var str = `VisemeReceived event: \
            \r\n\tAudioOffset: ${(e.audioOffset + 5000) / 10000}ms \
            \r\n\tVisemeId: ${e.visemeId}`;
        console.log(str);
    };

    speechSynthesizer.wordBoundary = function (s, e) {
        // Word, Punctuation, or Sentence
        var str = `WordBoundary event: \
            \r\n\tBoundaryType: ${e.boundaryType} \
            \r\n\tAudioOffset: ${(e.audioOffset + 5000) / 10000}ms \
            \r\n\tDuration: ${e.duration} \
            \r\n\tText: \"${e.text}\" \
            \r\n\tTextOffset: ${e.textOffset} \
            \r\n\tWordLength: ${e.wordLength}`;
        console.log(str);
    };

    // Synthesize the SSML
    console.log(`SSML to synthesize: \r\n ${ssml}`)
    console.log(`Synthesize to: ${audioFile}`);
    speechSynthesizer.speakSsmlAsync(ssml,
        function (result) {
      if (result.reason === sdk.ResultReason.SynthesizingAudioCompleted) {
        console.log("SynthesizingAudioCompleted result");
      } else {
        console.error("Speech synthesis canceled, " + result.errorDetails +
            "\nDid you set the speech resource key and region values?");
      }
      speechSynthesizer.close();
      speechSynthesizer = null;
    },
        function (err) {
      console.trace("err - " + err);
      speechSynthesizer.close();
      speechSynthesizer = null;
    });
}());

Weitere Beispiele zur Sprachsynthese finden Sie auf GitHub.

ReferenzdokumentationPaket (Download)Zusätzliche Beispiele auf GitHub

In dieser Schrittanleitung werden gängige Entwurfsmuster für die Sprachsynthese vorgestellt.

Unter Was ist Text-zu-Sprache? finden Sie weitere Informationen zu folgenden Themen:

  • Abrufen von Antworten als In-Memory-Datenströme
  • Anpassen der Abtast- und Bitrate der Ausgabe
  • Übermitteln von Syntheseanforderungen mithilfe der Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML)
  • Verwenden neuronaler Stimmen
  • Abonnieren von Ereignissen und ergebnisbezogenes Handeln

Voraussetzungen

Installieren des Speech SDK und der Beispiele

Das Repository Azure-Samples/cognitive-services-speech-sdk enthält Beispiele in Objective-C für iOS und Mac. Wählen Sie einen Link aus, um Installationsanweisungen für die einzelnen Beispiele anzuzeigen:

ReferenzdokumentationPaket (Download)Zusätzliche Beispiele auf GitHub

In dieser Schrittanleitung werden gängige Entwurfsmuster für die Sprachsynthese vorgestellt.

Unter Was ist Text-zu-Sprache? finden Sie weitere Informationen zu folgenden Themen:

  • Abrufen von Antworten als In-Memory-Datenströme
  • Anpassen der Abtast- und Bitrate der Ausgabe
  • Übermitteln von Syntheseanforderungen mithilfe der Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML)
  • Verwenden neuronaler Stimmen
  • Abonnieren von Ereignissen und ergebnisbezogenes Handeln

Voraussetzungen

Installieren des Speech SDK und der Beispiele

Das Repository Azure-Samples/cognitive-services-speech-sdk enthält Beispiele in Swift für iOS und Mac. Wählen Sie einen Link aus, um Installationsanweisungen für die einzelnen Beispiele anzuzeigen:

ReferenzdokumentationPaket (PyPi)Zusätzliche Beispiele auf GitHub

In dieser Schrittanleitung werden gängige Entwurfsmuster für die Sprachsynthese vorgestellt.

Unter Was ist Text-zu-Sprache? finden Sie weitere Informationen zu folgenden Themen:

  • Abrufen von Antworten als In-Memory-Datenströme
  • Anpassen der Abtast- und Bitrate der Ausgabe
  • Übermitteln von Syntheseanforderungen mithilfe der Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML)
  • Verwenden neuronaler Stimmen
  • Abonnieren von Ereignissen und ergebnisbezogenes Handeln

Auswählen von Synthesesprache und Stimme

Das Feature für die Sprachsynthese im Azure Speech-Dienst unterstützt mehr als 270 Stimmen und über 110 Sprachen und Varianten. Sie können die vollständige Liste abrufen oder sie im Stimmkatalog ausprobieren.

Geben Sie die Sprache oder Stimme von SpeechConfig für Ihren Eingabetext an, und verwenden Sie die gewünschte Stimme:

# Set either the `SpeechSynthesisVoiceName` or `SpeechSynthesisLanguage`.
speech_config.speech_synthesis_language = "en-US" 
speech_config.speech_synthesis_voice_name ="en-US-JennyNeural"

Alle neuronalen Stimmen sind mehrsprachig und können in ihrer eigenen Sprache und in englischer Sprache sprechen. Wenn der Eingabetext auf Englisch beispielsweise „I'm excited to try text to speech“ lautet und Sie es-ES-ElviraNeural festlegen, wird der Text in englischer Sprache mit einem spanischen Akzent gesprochen. Wenn die Stimme nicht die Sprache des Eingabetexts spricht, erfolgt keine synthetisierte Audioausgabe seitens des Speech-Diensts. Sehen Sie sich die gesamte Liste mit den unterstützten neuronalen Stimmen an.

Hinweis

Die Standardstimme ist die erste Stimme, die pro Gebietsschema über die Stimmlisten-API zurückgegeben wird.

Die Stimme, die spricht, wird wie folgt nach ihrer Priorität bestimmt:

  • Wenn Sie weder SpeechSynthesisLanguage noch en-US festlegen, spricht die Standardstimme für SpeechSynthesisVoiceName.
  • Wenn Sie nur SpeechSynthesisLanguage festlegen, spricht die Standardstimme für das angegebene Gebietsschema.
  • Wenn sowohl SpeechSynthesisVoiceName als auch SpeechSynthesisLanguage festgelegt sind, wird die Einstellung SpeechSynthesisLanguage ignoriert. Es spricht die Stimme, die Sie über SpeechSynthesisVoiceName angegeben haben.
  • Wenn das Stimmelement über Speech Synthesis Markup Language (SSML) festgelegt wird, werden die Einstellungen SpeechSynthesisVoiceName und SpeechSynthesisLanguage ignoriert.

Synthetisieren von Sprache in eine Datei

Als Nächstes erstellen Sie ein SpeechSynthesizer-Objekt. Dieses Objekt führt die Konvertierungen von Text in Sprache und Ausgaben an Lautsprecher, in Dateien oder andere Ausgabestreams aus. SpeechSynthesizer akzeptiert folgende Parameter:

  • Das SpeechConfig-Objekt, das Sie im vorherigen Schritt erstellt haben
  • Ein AudioOutputConfig-Objekt, das angibt, wie Ausgabeergebnisse behandelt werden sollen

Erstellen Sie zunächst eine AudioOutputConfig-Instanz, um die Ausgabe mithilfe des Konstruktorparameters filename automatisch in eine WAV-Datei zu schreiben:

audio_config = speechsdk.audio.AudioOutputConfig(filename="path/to/write/file.wav")

Instanziieren Sie als Nächstes SpeechSynthesizer, indem Sie die speech_config- und audio_config-Objekte als Parameter übergeben. Das Ausführen der Sprachsynthese und Schreiben der Daten in eine Datei ist so einfach wie das Ausführen von speak_text_async() mit einer Textzeichenfolge.

synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config, audio_config=audio_config)
synthesizer.speak_text_async("I'm excited to try text-to-speech")

Führen Sie das Programm aus. Eine synthetisierte WAV-Datei wird an den von Ihnen angegebenen Speicherort geschrieben. Dies ist ein gutes Beispiel für die einfachste Verwendung. Als Nächstes befassen Sie sich mit dem Anpassen der Ausgabe und dem Verarbeiten der Ausgabeantwort als In-Memory-Datenstrom für benutzerdefinierte Szenarien.

Synthetisieren der Lautsprecherausgabe

Zum Ausgeben von synthetisierter Sprache auf dem aktuell aktiven Ausgabegerät wie einem Lautsprecher legen Sie den Parameter use_default_speaker fest, wenn Sie die AudioOutputConfig-Instanz erstellen. Hier sehen Sie ein Beispiel:

audio_config = speechsdk.audio.AudioOutputConfig(use_default_speaker=True)

Abrufen eines Ergebnisses als In-Memory-Datenstrom

Sie können die resultierenden Audiodaten als einen In-Memory-Datenstrom verwenden, statt sie direkt in eine Datei zu schreiben. Mit einem In-Memory-Datenstrom können Sie benutzerdefiniertes Verhalten erstellen, wie etwa:

  • Abstrahieren des resultierenden Bytearrays als durchsuchbaren Datenstrom für benutzerdefinierte Downstreamdienste
  • Integrieren des Ergebnisses in andere APIs oder Dienste
  • Ändern der Audiodaten, Schreiben benutzerdefinierter WAV-Header und Ausführen zugehöriger Aufgaben

Diese Änderung lässt sich einfach am vorherigen Beispiel vornehmen. Entfernen Sie zunächst AudioConfig, weil Sie das Ausgabeverhalten ab jetzt manuell verwalten, um eine bessere Steuerung zu erzielen. Übergeben Sie anschließend im SpeechSynthesizer-Konstruktor None für AudioConfig.

Hinweis

Wenn Sie None für AudioConfig übergeben, anstatt den Parameter wie im obigen Beispiel für die Lautsprecherausgabe wegzulassen, werden die Audiodaten nicht standardmäßig auf dem derzeit aktiven Ausgabegerät wiedergegeben.

Dieses Mal speichern Sie das Ergebnis in einer Variablen des Typs SpeechSynthesisResult. Die audio_data-Eigenschaft enthält ein bytes-Objekt der Ausgabedaten. Sie können dieses Objekt manuell nutzen oder die AudioDataStream-Klasse verwenden, um den InMemory-Datenstrom zu verwalten. In diesem Beispiel verwenden Sie den AudioDataStream-Konstruktor, um einen Datenstrom aus dem Ergebnis abzurufen:

synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config, audio_config=None)
result = synthesizer.speak_text_async("I'm excited to try text-to-speech").get()
stream = AudioDataStream(result)

Nun können Sie mit dem resultierenden stream-Objekt ein beliebiges benutzerdefiniertes Verhalten implementieren.

Anpassen des Audioformats

Sie können die Attribute der Audioausgabe anpassen, z. B.:

  • Audiodateityp
  • Samplingrate
  • Bittiefe

Zum Ändern des Audioformats wenden Sie die Funktion set_speech_synthesis_output_format() auf das Objekt SpeechConfig an. Diese Funktion erwartet eine enum-Instanz vom Typ SpeechSynthesisOutputFormat, die Sie zum Auswählen des Ausgabeformats verwenden. Sehen Sie sich die Liste der verfügbaren Audioformate an.

Abhängig von Ihren Anforderungen stehen Ihnen verschiedene Optionen für unterschiedliche Dateitypen zur Verfügung. Rohformate wie Raw24Khz16BitMonoPcm enthalten gemäß Definition keine Audioheader. Verwenden Sie Rohformate nur in den folgenden Situationen:

  • Sie wissen, dass Ihre Downstreamimplementierung einen unformatierten Bitstream decodieren kann.
  • Sie planen, Header basierend auf Faktoren wie Bittiefe, Abtastrate und Anzahl von Kanälen manuell zu erstellen.

In diesem Beispiel geben Sie das High-Fidelity-RIFF-Format Riff24Khz16BitMonoPcm an, indem Sie SpeechSynthesisOutputFormat für das SpeechConfig-Objekt festlegen. Ähnlich wie im Beispiel im vorherigen Abschnitt nutzen Sie AudioDataStream, um einen InMemory-Datenstrom des Ergebnisses zu erhalten, das Sie anschließend in eine Datei schreiben.

speech_config.set_speech_synthesis_output_format(speechsdk.SpeechSynthesisOutputFormat.Riff24Khz16BitMonoPcm)
synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config, audio_config=None)

result = synthesizer.speak_text_async("I'm excited to try text-to-speech").get()
stream = speechsdk.AudioDataStream(result)
stream.save_to_wav_file("path/to/write/file.wav")

Beim erneuten Ausführen Ihres Programms wird eine benutzerdefinierte WAV-Datei in den angegebenen Pfad geschrieben.

Verwenden von SSML zum Anpassen von Sprachmerkmalen

Mit SSML können Sie die Tonhöhe, Aussprache, Sprechgeschwindigkeit, Lautstärke und weitere Aspekte der Ausgabe der Sprachsynthese optimieren, indem Sie Ihre Anforderungen per XML-Schema übermitteln. Dieser Abschnitt enthält ein Beispiel für das Ändern der Stimme. Eine ausführlichere Anleitung finden Sie im Artikel Verbessern der Synthese mit Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML).

Wenn Sie SSML für die Anpassung nutzen möchten, nehmen Sie eine einfache Änderung vor, um die Stimme zu wechseln.

Erstellen Sie zuerst im Stammverzeichnis des Projekts eine neue XML-Datei für die SSML-Konfiguration. In diesem Beispiel lautet er ssml.xml. Das Stammelement ist immer <speak>. Indem Sie den Text in einem <voice>-Element umschließen, können Sie die Stimme mit dem name-Parameter ändern. Sehen Sie sich die gesamte Liste mit den unterstützten neuronalen Stimmen an.

<speak version="1.0" xmlns="https://www.w3.org/2001/10/synthesis" xml:lang="en-US">
  <voice name="en-US-JennyNeural">
    When you're on the freeway, it's a good idea to use a GPS.
  </voice>
</speak>

Als Nächstes müssen Sie die Anforderung der Sprachsynthese so ändern, dass darin auf Ihre XML-Datei verwiesen wird. Die Anforderung bleibt größtenteils unverändert, aber Sie verwenden nun speak_ssml_async() anstelle von speak_text_async(). Diese Funktion erwartet eine XML-Zeichenfolge. Daher lesen Sie zunächst Ihre SSML-Konfiguration als Zeichenfolge ein. Ab diesem Punkt stimmt das sich ergebende Objekt genau mit den Objekten in den vorherigen Beispielen überein.

Hinweis

Wenn ssml_string am Anfang der Zeichenfolge  enthält, müssen Sie das BOM-Format entfernen, andernfalls gibt der Dienst einen Fehler zurück. Hierzu müssen Sie den Parameter encoding wie folgt festlegen: open("ssml.xml", "r", encoding="utf-8-sig").

synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config, audio_config=None)

ssml_string = open("ssml.xml", "r").read()
result = synthesizer.speak_ssml_async(ssml_string).get()

stream = speechsdk.AudioDataStream(result)
stream.save_to_wav_file("path/to/write/file.wav")

Hinweis

Wenn Sie die Stimme ohne SSML ändern möchten, können Sie die Eigenschaft für SpeechConfig mithilfe von speech_config.speech_synthesis_voice_name = "en-US-JennyNeural" festlegen.

Abonnieren von Synthesizerereignissen

Es kann sinnvoll sein, sich genauere Erkenntnisse zur Sprachsyntheseverarbeitung und den Ergebnissen zu verschaffen. Beispielsweise möchten Sie vielleicht wissen, wann der Synthesizer beginnt und anhält, oder Sie möchten wissen, welche anderen Ereignisse während der Synthese auftreten.

Während Sie den SpeechSynthesizer für die Sprachsynthese verwenden, können Sie die Ereignisse in dieser Tabelle abonnieren:

Ereignis BESCHREIBUNG Anwendungsfall
BookmarkReached Signalisiert, dass eine Textmarke erreicht wurde. Zum Auslösen eines Textmarke-erreicht-Ereignisses ist im SSML ein bookmark-Element erforderlich. Dieses Ereignis meldet die verstrichene Audioausgabezeit zwischen dem Beginn der Synthese und dem bookmark-Element. Die Eigenschaft Text des Ereignisses ist der Zeichenfolgenwert, den Sie im Attribut mark der Textmarke festlegen. Die bookmark-Elemente werden nicht ausgesprochen. Sie können das bookmark-Element verwenden, um benutzerdefinierte Marker in SSML einzufügen, um den Offset der einzelnen Marker im Audiostream abzurufen. Das bookmark-Element kann verwendet werden, um auf eine bestimmte Position in der Text- oder Tagsequenz zu verweisen.
SynthesisCanceled Zeigt an, dass die Sprachsynthese abgebrochen wurde. Sie können bestätigen, wenn die Synthese abgebrochen wurde.
SynthesisCompleted Zeigt an, dass die Sprachsynthese abgeschlossen wurde. Sie können bestätigen, wenn die Synthese abgeschlossen wurde.
SynthesisStarted Zeigt an, dass die Sprachsynthese begonnen wurde. Sie können bestätigen, wenn die Synthese begonnen hat.
Synthesizing Zeigt an, dass die Sprachsynthese fortgesetzt wird. Dieses Ereignis wird jedes Mal ausgelöst, wenn das SDK einen Audioabschnitt vom Speech-Dienst empfängt. Sie können bestätigen, wenn die Synthese aktuell ausgeführt wird.
VisemeReceived Zeigt an, dass ein Visemereignis empfangen wurde. Viseme (Mundbilder) werden häufig verwendet, um die wichtigsten Gesichtsausdrücke beim Sprechen darzustellen. Sie umfassen u. a. die Position der Lippen, des Kiefers und der Zunge beim Erzeugen eines bestimmten Phonems. Sie können Viseme (Mundbilder) anwenden, um das Gesicht einer Figur zu animieren, wenn die Audiodatei abgespielt wird.
WordBoundary Zeigt an, dass eine Wortgrenze empfangen wurde. Dieses Ereignis wird am Anfang jedes neuen gesprochenen Worts, beim Erreichen von Satzzeichen und am Satzanfang ausgelöst. Das Ereignis meldet den Zeitoffset des aktuellen Worts (in Ticks) vom Anfang der Audioausgabe. Dieses Ereignis meldet außerdem die Zeichenposition im Eingabetext (oder SSML) unmittelbar vor dem Wort, das als Nächstes gesprochen wird. Dieses Ereignis wird häufig verwendet, um die relativen Positionen von Text und den entsprechenden Audiodaten abzurufen. Es kann sinnvoll sein, Informationen zu einem neuen Wort zu empfangen und dann auf der Grundlage des Timings Aktionen auszuführen. Sie können z. B. Informationen abrufen, die Sie bei der Entscheidung unterstützen, wann und wie lange Wörter beim Sprechen hervorgehoben werden sollen.

Hinweis

Es werden Ereignisse ausgelöst, wenn die ausgegebenen Audiodaten verfügbar werden, was schneller erfolgt als die Wiedergabe über ein Ausgabegerät. Der Aufrufer muss das Streaming ordnungsgemäß und in Echtzeit synchronisieren.

Dieses Beispiel zeigt, wie Ereignisse für die Sprachsynthese abonniert werden. Sie können die Anweisungen in der Schnellstartanleitung befolgen, aber den Inhalt dieser speech-synthesis.py-Datei durch den folgenden Python-Code ersetzen.

import os
import azure.cognitiveservices.speech as speechsdk

def speech_synthesizer_bookmark_reached_cb(evt: speechsdk.SessionEventArgs):
    print('BookmarkReached event:')
    print('\tAudioOffset: {}ms'.format((evt.audio_offset + 5000) / 10000))
    print('\tText: {}'.format(evt.text))

def speech_synthesizer_synthesis_canceled_cb(evt: speechsdk.SessionEventArgs):
    print('SynthesisCanceled event')

def speech_synthesizer_synthesis_completed_cb(evt: speechsdk.SessionEventArgs):
    print('SynthesisCompleted event:')
    print('\tAudioData: {} bytes'.format(len(evt.result.audio_data)))
    print('\tAudioDuration: {}'.format(evt.result.audio_duration))

def speech_synthesizer_synthesis_started_cb(evt: speechsdk.SessionEventArgs):
    print('SynthesisStarted event')

def speech_synthesizer_synthesizing_cb(evt: speechsdk.SessionEventArgs):
    print('Synthesizing event:')
    print('\tAudioData: {} bytes'.format(len(evt.result.audio_data)))

def speech_synthesizer_viseme_received_cb(evt: speechsdk.SessionEventArgs):
    print('VisemeReceived event:')
    print('\tAudioOffset: {}ms'.format((evt.audio_offset + 5000) / 10000))
    print('\tVisemeId: {}'.format(evt.viseme_id))

def speech_synthesizer_word_boundary_cb(evt: speechsdk.SessionEventArgs):
    print('WordBoundary event:')
    print('\tBoundaryType: {}'.format(evt.boundary_type))
    print('\tAudioOffset: {}ms'.format((evt.audio_offset + 5000) / 10000))
    print('\tDuration: {}'.format(evt.duration))
    print('\tText: {}'.format(evt.text))
    print('\tTextOffset: {}'.format(evt.text_offset))
    print('\tWordLength: {}'.format(evt.word_length))

# This example requires environment variables named "SPEECH_KEY" and "SPEECH_REGION"
speech_config = speechsdk.SpeechConfig(subscription=os.environ.get('SPEECH_KEY'), region=os.environ.get('SPEECH_REGION'))

# Required for WordBoundary event sentences.
speech_config.set_property(property_id=speechsdk.PropertyId.SpeechServiceResponse_RequestSentenceBoundary, value='true')

audio_config = speechsdk.audio.AudioOutputConfig(use_default_speaker=True)
speech_synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config, audio_config=audio_config)

# Subscribe to events
speech_synthesizer.bookmark_reached.connect(speech_synthesizer_bookmark_reached_cb)
speech_synthesizer.synthesis_canceled.connect(speech_synthesizer_synthesis_canceled_cb)
speech_synthesizer.synthesis_completed.connect(speech_synthesizer_synthesis_completed_cb)
speech_synthesizer.synthesis_started.connect(speech_synthesizer_synthesis_started_cb)
speech_synthesizer.synthesizing.connect(speech_synthesizer_synthesizing_cb)
speech_synthesizer.viseme_received.connect(speech_synthesizer_viseme_received_cb)
speech_synthesizer.synthesis_word_boundary.connect(speech_synthesizer_word_boundary_cb)

# The language of the voice that speaks.
speech_synthesis_voice_name='en-US-JennyNeural'

ssml = """<speak version='1.0' xml:lang='en-US' xmlns='http://www.w3.org/2001/10/synthesis' xmlns:mstts='http://www.w3.org/2001/mstts'>
    <voice name='{}'>
        <mstts:viseme type='redlips_front'/>
        The rainbow has seven colors: <bookmark mark='colors_list_begin'/>Red, orange, yellow, green, blue, indigo, and violet.<bookmark mark='colors_list_end'/>.
    </voice>
</speak>""".format(speech_synthesis_voice_name)

# Synthesize the SSML
print("SSML to synthesize: \r\n{}".format(ssml))
speech_synthesis_result = speech_synthesizer.speak_ssml_async(ssml).get()

if speech_synthesis_result.reason == speechsdk.ResultReason.SynthesizingAudioCompleted:
    print("SynthesizingAudioCompleted result")
elif speech_synthesis_result.reason == speechsdk.ResultReason.Canceled:
    cancellation_details = speech_synthesis_result.cancellation_details
    print("Speech synthesis canceled: {}".format(cancellation_details.reason))
    if cancellation_details.reason == speechsdk.CancellationReason.Error:
        if cancellation_details.error_details:
            print("Error details: {}".format(cancellation_details.error_details))
            print("Did you set the speech resource key and region values?")

Weitere Beispiele zur Sprachsynthese finden Sie auf GitHub.

Referenz zur Spracherkennungs-REST-API | Referenz zur Spracherkennungs-REST-API für kurze Audiodaten | Zusätzliche Beispiele auf GitHub

In dieser Schrittanleitung werden gängige Entwurfsmuster für die Sprachsynthese vorgestellt.

Unter Was ist Text-zu-Sprache? finden Sie weitere Informationen zu folgenden Themen:

  • Abrufen von Antworten als In-Memory-Datenströme
  • Anpassen der Abtast- und Bitrate der Ausgabe
  • Übermitteln von Syntheseanforderungen mithilfe der Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML)
  • Verwenden neuronaler Stimmen
  • Abonnieren von Ereignissen und ergebnisbezogenes Handeln

Voraussetzungen

Konvertieren von Text in Sprache

Führen Sie an der Eingabeaufforderung den folgenden Befehl aus. Fügen Sie diese Werte in den Befehl ein:

  • Ihr Speech-Ressourcenschlüssel
  • Ihre Speech-Ressourcenregion

Sie können ggf. auch die folgenden Werte ändern:

  • Headerwert X-Microsoft-OutputFormat, mit dem das Format der Audioausgabe gesteuert wird. Eine Liste mit den unterstützten Formaten für die Audioausgabe finden Sie in der Referenz zur Text-to-Speech-REST-API.
  • Die Stimme für die Ausgabe. Informationen zum Abrufen einer Liste der für Ihren Speech-Dienstendpunkt verfügbaren Stimmen finden Sie bei der Voice List-API.
  • Die Ausgabedatei. In diesem Beispiel leiten wir die Antwort des Servers an eine Datei mit dem Namen output.mp3 weiter.
curl --location --request POST 'https://YOUR_RESOURCE_REGION.tts.speech.microsoft.com/cognitiveservices/v1' \
--header 'Ocp-Apim-Subscription-Key: YOUR_RESOURCE_KEY' \
--header 'Content-Type: application/ssml+xml' \
--header 'X-Microsoft-OutputFormat: audio-16khz-128kbitrate-mono-mp3' \
--header 'User-Agent: curl' \
--data-raw '<speak version='\''1.0'\'' xml:lang='\''en-US'\''>
    <voice xml:lang='\''en-US'\'' xml:gender='\''Female'\'' name='\''en-US-JennyNeural'\''>
        I am excited to try text to speech
    </voice>
</speak>' > output.mp3

In dieser Schrittanleitung werden gängige Entwurfsmuster für die Sprachsynthese vorgestellt.

Unter Was ist Text-zu-Sprache? finden Sie weitere Informationen zu folgenden Themen:

  • Abrufen von Antworten als In-Memory-Datenströme
  • Anpassen der Abtast- und Bitrate der Ausgabe
  • Übermitteln von Syntheseanforderungen mithilfe der Markupsprache für Sprachsynthese (Speech Synthesis Markup Language, SSML)
  • Verwenden neuronaler Stimmen
  • Abonnieren von Ereignissen und ergebnisbezogenes Handeln

Voraussetzungen

Herunterladen und Installieren

Befolgen Sie diese Schritte, und lesen Sie den Schnellstart zur Speech-CLI, um weitere Anforderungen für Ihre Plattform zu erfahren.

  1. Installieren Sie die Speech-CLI mithilfe der .NET-CLI durch Eingabe des folgenden Befehls:

    dotnet tool install --global Microsoft.CognitiveServices.Speech.CLI
    
  2. Konfigurieren Sie den Schlüssel und die Region Ihrer Speech-Ressource, indem Sie die folgenden Befehle ausführen. Ersetzen Sie SUBSCRIPTION-KEY durch den Schlüssel Ihrer Speech-Ressource und REGION durch die Region Ihrer Speech-Ressource:

    spx config @key --set SUBSCRIPTION-KEY
    spx config @region --set REGION
    

Synthetisieren von Sprache über einen Lautsprecher

Sie sind jetzt bereit, die Speech-Befehlszeilenschnittstelle auszuführen, um aus Text Sprache zu synthetisieren. Wechseln Sie an der Befehlszeile in das Verzeichnis, das die Binärdatei der Speech-Befehlszeilenschnittstelle enthält. Führen Sie dann den folgenden Befehl aus:

spx synthesize --text "I'm excited to try text-to-speech"

Die Speech-Befehlszeilenschnittstelle gibt natürlichsprachliches Englisch über den Lautsprecher des Computers aus.

Synthetisieren von Sprache in eine Datei

Führen Sie den folgenden Befehl aus, um die Ausgabe über den Lautsprecher in eine WAV-Datei zu ändern:

spx synthesize --text "I'm excited to try text-to-speech" --audio output greetings.wav

Die Speech-Befehlszeilenschnittstelle gibt natürlichsprachliches Englisch in die Audiodatei greetings.wav aus.

Nächste Schritte