Jak syntetyzować mowę z tekstu

Dokumentacja referencyjna | Package (NuGet) | Dodatkowe przykłady w usłudze GitHub

W tym przewodniku z instrukcjami poznasz typowe wzorce projektowe służące do wykonywania syntezy mowy w tekście.

Aby uzyskać więcej informacji na temat następujących obszarów, zobacz Co to jest zamiana tekstu na mowę?

  • Uzyskiwanie odpowiedzi jako strumieni w pamięci.
  • Dostosowywanie szybkości próbkowania danych wyjściowych i szybkości bitów.
  • Przesyłanie żądań syntezy przy użyciu języka znaczników syntezy mowy (SSML).
  • Korzystanie z głosów neuronowych.
  • Subskrybowanie zdarzeń i działanie na podstawie wyników.

Wybieranie języka syntezy i głosu

Funkcja zamiany tekstu na mowę w usłudze Mowa obsługuje ponad 400 głosów i ponad 140 języków i wariantów. Pełną listę możesz uzyskać lub wypróbować w galerii głosów.

Określ język lub głos, SpeechConfig aby dopasować tekst wejściowy i użyć określonego głosu. Poniższy fragment kodu pokazuje, jak działa ta technika:

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

Wszystkie neuronowe głosy są wielojęzyczne i płynne we własnym języku i języku angielskim. Jeśli na przykład tekst wejściowy w języku angielskim to "Jestem podekscytowany, aby spróbować zamiany tekstu na mowę", a następnie wybierzesz es-ES-ElviraNeuraltekst mówiony w języku angielskim z hiszpańskim akcentem.

Jeśli głos nie mówi w języku tekstu wejściowego, usługa rozpoznawania mowy nie tworzy syntetyzowanego dźwięku. Aby uzyskać pełną listę obsługiwanych głosów neuronowych, zobacz Obsługa języka i głosu dla usługi Mowa.

Uwaga

Domyślny głos to pierwszy głos zwracany na ustawienia regionalne z interfejsu API listy głosowej.

Głos, który mówi, jest określany w kolejności priorytetu w następujący sposób:

  • Jeśli nie ustawisz SpeechSynthesisVoiceName lub SpeechSynthesisLanguage, domyślny głos mówi en-US .
  • Jeśli ustawisz SpeechSynthesisLanguagetylko , domyślny głos dla określonych ustawień regionalnych mówi.
  • Jeśli ustawienia i SpeechSynthesisVoiceNameSpeechSynthesisLanguage są ustawione, SpeechSynthesisLanguage ustawienie jest ignorowane. Głos, który określisz przy użyciu SpeechSynthesisVoiceName głosu.
  • Jeśli element głosowy jest ustawiony przy użyciu języka znaczników syntezy mowy (SSML),SpeechSynthesisVoiceName ustawienia i SpeechSynthesisLanguage są ignorowane.

Syntetyzowanie mowy do pliku

Utwórz obiekt SpeechSynthesizer. Ten obiekt pokazany w poniższych fragmentach kodu uruchamia tekst konwersji mowy i danych wyjściowych do głośników, plików lub innych strumieni wyjściowych. SpeechSynthesizer akceptuje jako parametry:

  1. AudioConfig Utwórz wystąpienie, aby automatycznie zapisywać dane wyjściowe w pliku .wav przy użyciu FromWavFileOutput() funkcji . Utwórz wystąpienie za pomocą instrukcji using .

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

    Instrukcja using w tym kontekście automatycznie usuwa niezarządzane zasoby i powoduje, że obiekt wykracza poza zakres po usunięciu.

  2. Utwórz wystąpienie wystąpienia za pomocą innej using instrukcjiSpeechSynthesizer. speechConfig Przekaż obiekt i audioConfig obiekt jako parametry. Aby syntetyzować mowę i zapisywać w pliku, uruchom polecenie SpeakTextAsync() z ciągiem tekstu.

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

Po uruchomieniu programu program tworzy syntetyzowany plik .wav , który jest zapisywany w określonej lokalizacji. Ten wynik jest dobrym przykładem najbardziej podstawowego użycia. Następnie możesz dostosować dane wyjściowe i obsłużyć odpowiedź wyjściową jako strumień w pamięci na potrzeby pracy ze scenariuszami niestandardowymi.

Syntetyzowanie do danych wyjściowych osoby mówiącej

Aby uzyskać syntetyzowany mowę do bieżącego aktywnego urządzenia wyjściowego, takiego jak głośnik, pomiń AudioConfig parametr podczas tworzenia SpeechSynthesizer wystąpienia. Oto przykład:

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

Uzyskiwanie wyniku jako strumienia w pamięci

Możesz użyć wynikowych danych dźwiękowych jako strumienia w pamięci, a nie bezpośredniego zapisywania w pliku. Za pomocą strumienia w pamięci można tworzyć niestandardowe zachowanie:

  • Abstrakcja wynikowej tablicy bajtów jako strumienia możliwego do wyszukiwania dla niestandardowych usług podrzędnych.
  • Zintegruj wynik z innymi interfejsami API lub usługami.
  • Zmodyfikuj dane audio, zapisz niestandardowe nagłówki .wav i wykonaj powiązane zadania.

Tę zmianę można wprowadzić w poprzednim przykładzie. Najpierw usuń AudioConfig blok, ponieważ ręcznie zarządzasz zachowaniem danych wyjściowych z tego punktu w celu zwiększenia kontroli. Przekaż null element AudioConfig w konstruktorze SpeechSynthesizer .

Uwaga

Przekazywanie null dla elementu AudioConfig, a nie pomijanie go tak jak w poprzednim przykładzie danych wyjściowych osoby mówiącej, nie odtwarza dźwięku domyślnie na bieżącym aktywnym urządzeniu wyjściowym.

Zapisz wynik w zmiennej SpeechSynthesisResult . Właściwość AudioData zawiera byte [] wystąpienie danych wyjściowych. Możesz pracować z tym byte [] wystąpieniem ręcznie lub użyć klasy AudioDataStream do zarządzania strumieniem w pamięci.

W tym przykładzie użyjesz funkcji statycznej AudioDataStream.FromResult() , aby pobrać strumień z wyniku:

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

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

W tym momencie można zaimplementować dowolne zachowanie niestandardowe przy użyciu wynikowego stream obiektu.

Dostosowywanie formatu audio

Możesz dostosować atrybuty danych wyjściowych dźwięku, w tym:

  • Typ pliku audio
  • Częstotliwość próbkowania
  • Głębokość bitu

Aby zmienić format dźwięku, należy użyć SetSpeechSynthesisOutputFormat() funkcji w SpeechConfig obiekcie . Ta funkcja oczekuje enum wystąpienia typu SpeechSynthesisOutputFormat. Użyj polecenia , enum aby wybrać format danych wyjściowych. Aby uzyskać dostępne formaty, zobacz listę formatów audio.

Istnieją różne opcje dla różnych typów plików, w zależności od wymagań. Z definicji nieprzetworzone formaty, takie jak Raw24Khz16BitMonoPcm nie zawierają nagłówków dźwięku. Używaj formatów pierwotnych tylko w jednej z następujących sytuacji:

  • Wiesz, że implementacja podrzędna może dekodować nieprzetworzone strumienie bitowe.
  • Planujesz ręcznie tworzyć nagłówki na podstawie czynników, takich jak głębokość bitów, częstotliwość próbkowania i liczba kanałów.

W tym przykładzie określono format Riff24Khz16BitMonoPcm RIFF o wysokiej wierności, ustawiając SpeechSynthesisOutputFormat dla SpeechConfig obiektu. Podobnie jak w przykładzie w poprzedniej sekcji, użyj audioDataStream, aby uzyskać strumień w pamięci wyniku, a następnie zapisać go w pliku.

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

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

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

Po uruchomieniu programu zapisuje plik .wav do określonej ścieżki.

Dostosowywanie cech mowy przy użyciu języka SSML

Za pomocą języka SSML można dostroić wysokość, wymowę, szybkość mówienia, głośność i inne aspekty w danych wyjściowych zamiany tekstu na mowę, przesyłając żądania ze schematu XML. W tej sekcji przedstawiono przykład zmiany głosu. Aby uzyskać więcej informacji, zobacz Omówienie języka znaczników syntezy mowy.

Aby rozpocząć korzystanie z języka SSML do dostosowywania, należy wprowadzić niewielką zmianę, która przełącza głos.

  1. Utwórz nowy plik XML dla konfiguracji SSML w katalogu głównym projektu.

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

    W tym przykładzie plik jest ssml.xml. Element główny to zawsze <speak>. Zawijanie tekstu w elemecie <voice> umożliwia zmianę głosu przy użyciu parametru name . Aby uzyskać pełną listę obsługiwanych głosów neuronowych, zobacz Obsługiwane języki.

  2. Zmień żądanie syntezy mowy, aby odwołać się do pliku XML. Żądanie jest w większości takie samo, ale zamiast używać SpeakTextAsync() funkcji , należy użyć polecenia SpeakSsmlAsync(). Ta funkcja oczekuje ciągu XML. Najpierw załaduj konfigurację SSML jako ciąg przy użyciu polecenia File.ReadAllText(). Od tego momentu obiekt wynikowy jest dokładnie taki sam jak w poprzednich przykładach.

    Uwaga

    Jeśli używasz programu Visual Studio, konfiguracja kompilacji prawdopodobnie nie znajdzie pliku XML domyślnie. Kliknij prawym przyciskiem myszy plik XML i wybierz polecenie Właściwości. Zmień akcję kompilacji na Zawartość. Zmień wartość Kopiuj na Katalog wyjściowy, aby zawsze kopiować.

    public static async Task SynthesizeAudioAsync()
    {
        var speechConfig = SpeechConfig.FromSubscription("YourSpeechKey", "YourSpeechRegion");
        using var speechSynthesizer = new SpeechSynthesizer(speechConfig, null);
    
        var ssml = File.ReadAllText("./ssml.xml");
        var result = await speechSynthesizer.SpeakSsmlAsync(ssml);
    
        using var stream = AudioDataStream.FromResult(result);
        await stream.SaveToWaveFileAsync("path/to/write/file.wav");
    }
    

Uwaga

Aby zmienić głos bez użycia języka SSML, możesz ustawić właściwość przy SpeechConfig użyciu polecenia SpeechConfig.SpeechSynthesisVoiceName = "en-US-AvaMultilingualNeural";.

Subskrybowanie zdarzeń syntezatora

Możesz chcieć uzyskać więcej szczegółowych informacji na temat przetwarzania i wyników zamiany tekstu na mowę. Na przykład możesz chcieć wiedzieć, kiedy syntetyzator uruchamia się i zatrzymuje, lub możesz chcieć wiedzieć o innych zdarzeniach napotkanych podczas syntezy.

Używając narzędzia SpeechSynthesizer do zamiany tekstu na mowę, możesz subskrybować zdarzenia w tej tabeli:

Wydarzenie opis Przypadek użycia
BookmarkReached Sygnały, że osiągnięto zakładkę. Aby wyzwolić zdarzenie osiągnięto zakładkę bookmark , element jest wymagany w języku SSML. To zdarzenie zgłasza czas, jaki upłynął w danych wyjściowych audio między rozpoczęciem syntezy a elementem bookmark . Właściwość zdarzenia Text to wartość ciągu ustawiona w atrybucie zakładki mark . bookmark Elementy nie są mówione. Możesz użyć bookmark elementu , aby wstawić niestandardowe znaczniki w języku SSML, aby uzyskać przesunięcie każdego znacznika w strumieniu audio. Element bookmark może służyć do odwoływania się do określonej lokalizacji w sekwencji tekstu lub tagu.
SynthesisCanceled Sygnały, że synteza mowy została anulowana. Możesz potwierdzić, kiedy synteza zostanie anulowana.
SynthesisCompleted Sygnały, że synteza mowy jest kompletna. Po zakończeniu syntezy można potwierdzić.
SynthesisStarted Sygnały, że rozpoczęła się synteza mowy. Możesz potwierdzić, kiedy rozpoczęto syntezę.
Synthesizing Sygnały, że synteza mowy jest w toku. To zdarzenie jest uruchamiane za każdym razem, gdy zestaw SDK otrzymuje fragment dźwięku z usługi Mowa. Możesz potwierdzić, kiedy synteza jest w toku.
VisemeReceived Sygnały, że odebrano zdarzenie viseme. Visemes są często używane do reprezentowania kluczowych pozy w obserwowanej mowie. Kluczowe pozy obejmują położenie ust, szczęki i języka w produkcji konkretnej fonemy. Możesz użyć visemes, aby animować twarz postaci jako dźwięk mowy odtwarzane.
WordBoundary Sygnały, że odebrano granicę słowa. To zdarzenie jest wywoływane na początku każdego nowego słowa mówionego, interpunkcyjnego i zdania. Zdarzenie zgłasza przesunięcie czasu bieżącego wyrazu w znacznikach od początku dźwięku wyjściowego. To zdarzenie zgłasza również położenie znaku w tekście wejściowym lub SSML bezpośrednio przed wyrazem, który ma być wypowiadany. To zdarzenie jest często używane do pobierania względnych pozycji tekstu i odpowiadającego mu dźwięku. Możesz chcieć wiedzieć o nowym słowie, a następnie podjąć działania na podstawie chronometrażu. Możesz na przykład uzyskać informacje, które mogą pomóc w podjęciu decyzji o tym, kiedy i jak długo będą wyróżniać wyrazy podczas ich wypowiadania.

Uwaga

Zdarzenia są zgłaszane, gdy dane wyjściowe audio staną się dostępne, co jest szybsze niż odtwarzanie na urządzeniu wyjściowym. Obiekt wywołujący musi odpowiednio synchronizować przesyłanie strumieniowe i w czasie rzeczywistym.

Oto przykład pokazujący sposób subskrybowania zdarzeń na potrzeby syntezy mowy. Postępuj zgodnie z instrukcjami w przewodniku Szybki start, ale zastąp zawartość tego pliku Program.cs następującym kodem języka C#:

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-AvaMultilingualNeural";  
        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();
    }
}

Więcej przykładów zamiany tekstu na mowę można znaleźć w witrynie GitHub.

Używanie niestandardowego punktu końcowego

Niestandardowy punkt końcowy jest funkcjonalnie identyczny ze standardowym punktem końcowym używanym do obsługi żądań zamiany tekstu na mowę.

Jedną z różnic jest to, że należy określić, EndpointId aby używać niestandardowego głosu za pośrednictwem zestawu SPEECH SDK. Możesz rozpocząć od tekstu w przewodniku Szybki start do mowy, a następnie zaktualizować kod za pomocą elementu EndpointId i SpeechSynthesisVoiceName.

var speechConfig = SpeechConfig.FromSubscription(speechKey, speechRegion);     
speechConfig.SpeechSynthesisVoiceName = "YourCustomVoiceName";
speechConfig.EndpointId = "YourEndpointId";

Aby użyć głosu niestandardowego za pomocą języka SSML (Speech Synthesis Markup Language), określ nazwę modelu jako nazwę głosu. W tym przykładzie użyto YourCustomVoiceName głosu.

<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="en-US">
    <voice name="YourCustomVoiceName">
        This is the text that is spoken. 
    </voice>
</speak>

Uruchamianie i używanie kontenera

Kontenery mowy udostępniają internetowe interfejsy API punktów końcowych zapytań oparte na protokole Websocket, które są dostępne za pośrednictwem zestawu SPEECH SDK i interfejsu wiersza polecenia usługi Mowa. Domyślnie zestaw SDK usługi Mowa i interfejs wiersza polecenia usługi Mowa używają publicznej usługi rozpoznawania mowy. Aby użyć kontenera, należy zmienić metodę inicjowania. Użyj adresu URL hosta kontenera zamiast klucza i regionu.

Aby uzyskać więcej informacji na temat kontenerów, zobacz Instalowanie i uruchamianie kontenerów usługi Mowa za pomocą platformy Docker.

Dokumentacja referencyjna | Package (NuGet) | Dodatkowe przykłady w usłudze GitHub

W tym przewodniku z instrukcjami poznasz typowe wzorce projektowe służące do wykonywania syntezy mowy w tekście.

Aby uzyskać więcej informacji na temat następujących obszarów, zobacz Co to jest zamiana tekstu na mowę?

  • Uzyskiwanie odpowiedzi jako strumieni w pamięci.
  • Dostosowywanie szybkości próbkowania danych wyjściowych i szybkości bitów.
  • Przesyłanie żądań syntezy przy użyciu języka znaczników syntezy mowy (SSML).
  • Korzystanie z głosów neuronowych.
  • Subskrybowanie zdarzeń i działanie na podstawie wyników.

Wybieranie języka syntezy i głosu

Funkcja zamiany tekstu na mowę w usłudze Mowa obsługuje ponad 400 głosów i ponad 140 języków i wariantów. Zapoznaj się z pełną listą obsługiwanych ustawień regionalnych zamiany tekstu na mowę lub wypróbuj je w galerii głosów.

Określ język lub głos klasy SpeechConfig , aby dopasować tekst wejściowy i użyć określonego głosu. Poniższy fragment kodu pokazuje, jak działa ta technika:

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

Wszystkie neuronowe głosy są wielojęzyczne i płynne we własnym języku i języku angielskim. Jeśli na przykład tekst wejściowy w języku angielskim to "Jestem podekscytowany, aby spróbować zamiany tekstu na mowę", a następnie wybierzesz es-ES-ElviraNeuraltekst mówiony w języku angielskim z hiszpańskim akcentem.

Jeśli głos nie mówi w języku tekstu wejściowego, usługa rozpoznawania mowy nie tworzy syntetyzowanego dźwięku. Aby uzyskać pełną listę obsługiwanych głosów neuronowych, zobacz Obsługa języka i głosu dla usługi Mowa.

Uwaga

Domyślny głos to pierwszy głos zwracany na ustawienia regionalne z interfejsu API listy głosowej.

Głos, który mówi, jest określany w kolejności priorytetu w następujący sposób:

  • Jeśli nie ustawisz SpeechSynthesisVoiceName lub SpeechSynthesisLanguage, domyślny głos mówi en-US .
  • Jeśli ustawisz SpeechSynthesisLanguagetylko , domyślny głos dla określonych ustawień regionalnych mówi.
  • Jeśli ustawienia i SpeechSynthesisVoiceNameSpeechSynthesisLanguage są ustawione, SpeechSynthesisLanguage ustawienie jest ignorowane. Głos, który określisz przy użyciu SpeechSynthesisVoiceName głosu.
  • Jeśli element głosowy jest ustawiony przy użyciu języka znaczników syntezy mowy (SSML),SpeechSynthesisVoiceName ustawienia i SpeechSynthesisLanguage są ignorowane.

Syntetyzowanie mowy do pliku

Utwórz obiekt SpeechSynthesizer. Ten obiekt pokazany w poniższych fragmentach kodu uruchamia tekst konwersji mowy i danych wyjściowych do głośników, plików lub innych strumieni wyjściowych. SpeechSynthesizer akceptuje jako parametry:

  1. AudioConfig Utwórz wystąpienie, aby automatycznie zapisywać dane wyjściowe w pliku .wav przy użyciu FromWavFileOutput() funkcji :

    void synthesizeSpeech()
    {
        auto speechConfig = SpeechConfig::FromSubscription("YourSpeechKey", "YourSpeechRegion");
        auto audioConfig = AudioConfig::FromWavFileOutput("path/to/write/file.wav");
    }
    
  2. Utwórz wystąpienie SpeechSynthesizer wystąpienia. speechConfig Przekaż obiekt i audioConfig obiekt jako parametry. Aby syntetyzować mowę i zapisywać w pliku, uruchom polecenie SpeakTextAsync() z ciągiem tekstu.

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

Po uruchomieniu programu program tworzy syntetyzowany plik .wav , który jest zapisywany w określonej lokalizacji. Ten wynik jest dobrym przykładem najbardziej podstawowego użycia. Następnie możesz dostosować dane wyjściowe i obsłużyć odpowiedź wyjściową jako strumień w pamięci na potrzeby pracy ze scenariuszami niestandardowymi.

Syntetyzowanie do danych wyjściowych osoby mówiącej

Aby uzyskać syntetyzowany mowę do bieżącego aktywnego urządzenia wyjściowego, takiego jak głośnik, pomiń AudioConfig parametr podczas tworzenia SpeechSynthesizer wystąpienia. Oto przykład:

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

Uzyskiwanie wyniku jako strumienia w pamięci

Możesz użyć wynikowych danych dźwiękowych jako strumienia w pamięci, a nie bezpośredniego zapisywania w pliku. Za pomocą strumienia w pamięci można tworzyć niestandardowe zachowanie:

  • Abstrakcja wynikowej tablicy bajtów jako strumienia możliwego do wyszukiwania dla niestandardowych usług podrzędnych.
  • Zintegruj wynik z innymi interfejsami API lub usługami.
  • Zmodyfikuj dane audio, zapisz niestandardowe nagłówki .wav i wykonaj powiązane zadania.

Tę zmianę można wprowadzić w poprzednim przykładzie. Najpierw usuń AudioConfig blok, ponieważ ręcznie zarządzasz zachowaniem danych wyjściowych z tego punktu w celu zwiększenia kontroli. Przekaż NULL element AudioConfig w konstruktorze SpeechSynthesizer .

Uwaga

Przekazywanie NULL dla elementu AudioConfig, a nie pomijanie go tak jak w poprzednim przykładzie danych wyjściowych osoby mówiącej, nie odtwarza dźwięku domyślnie na bieżącym aktywnym urządzeniu wyjściowym.

Zapisz wynik w zmiennej SpeechSynthesisResult . Funkcja GetAudioData getter zwraca byte [] wystąpienie danych wyjściowych. Możesz pracować z tym byte [] wystąpieniem ręcznie lub użyć klasy AudioDataStream do zarządzania strumieniem w pamięci.

W tym przykładzie użyj funkcji statycznej AudioDataStream.FromResult() , aby pobrać strumień z wyniku:

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

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

W tym momencie można zaimplementować dowolne zachowanie niestandardowe przy użyciu wynikowego stream obiektu.

Dostosowywanie formatu audio

Możesz dostosować atrybuty danych wyjściowych dźwięku, w tym:

  • Typ pliku audio
  • Częstotliwość próbkowania
  • Głębokość bitu

Aby zmienić format dźwięku, użyj SetSpeechSynthesisOutputFormat() funkcji w SpeechConfig obiekcie . Ta funkcja oczekuje enum wystąpienia typu SpeechSynthesisOutputFormat. Użyj polecenia , enum aby wybrać format danych wyjściowych. Aby uzyskać dostępne formaty, zobacz listę formatów audio.

Istnieją różne opcje dla różnych typów plików, w zależności od wymagań. Z definicji nieprzetworzone formaty, takie jak Raw24Khz16BitMonoPcm nie zawierają nagłówków dźwięku. Używaj formatów pierwotnych tylko w jednej z następujących sytuacji:

  • Wiesz, że implementacja podrzędna może dekodować nieprzetworzone strumienie bitowe.
  • Planujesz ręcznie tworzyć nagłówki na podstawie czynników, takich jak głębokość bitów, częstotliwość próbkowania i liczba kanałów.

W tym przykładzie określono format Riff24Khz16BitMonoPcm RIFF o wysokiej wierności, ustawiając SpeechSynthesisOutputFormat dla SpeechConfig obiektu. Podobnie jak w przykładzie w poprzedniej sekcji, użyj AudioDataStream polecenia , aby uzyskać strumień w pamięci wyniku, a następnie zapisać go w pliku.

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

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

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

Po uruchomieniu programu zapisuje plik .wav do określonej ścieżki.

Dostosowywanie cech mowy przy użyciu języka SSML

Za pomocą języka SSML można dostroić wysokość, wymowę, szybkość mówienia, głośność i inne aspekty w danych wyjściowych zamiany tekstu na mowę, przesyłając żądania ze schematu XML. W tej sekcji przedstawiono przykład zmiany głosu. Aby uzyskać więcej informacji, zobacz Omówienie języka znaczników syntezy mowy.

Aby rozpocząć korzystanie z języka SSML do dostosowywania, wprowadź niewielką zmianę, która przełącza głos.

  1. Utwórz nowy plik XML dla konfiguracji SSML w katalogu głównym projektu.

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

    W tym przykładzie plik jest ssml.xml. Element główny to zawsze <speak>. Zawijanie tekstu w elemecie <voice> umożliwia zmianę głosu przy użyciu parametru name . Aby uzyskać pełną listę obsługiwanych głosów neuronowych, zobacz Obsługiwane języki.

  2. Zmień żądanie syntezy mowy, aby odwołać się do pliku XML. Żądanie jest w większości takie samo. Zamiast używać funkcji, należy użyć SpeakTextAsync() polecenia SpeakSsmlAsync(). Ta funkcja oczekuje ciągu XML. Najpierw załaduj konfigurację SSML jako ciąg. Od tego momentu obiekt wynikowy jest dokładnie taki sam jak w poprzednich przykładach.

    void synthesizeSpeech()
    {
        auto speechConfig = SpeechConfig::FromSubscription("YourSpeechKey", "YourSpeechRegion");
        auto speechSynthesizer = 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 = speechSynthesizer->SpeakSsmlAsync(ssml).get();
    
        auto stream = AudioDataStream::FromResult(result);
        stream->SaveToWavFileAsync("path/to/write/file.wav").get();
    }
    

Uwaga

Aby zmienić głos bez użycia języka SSML, możesz ustawić właściwość przy SpeechConfig użyciu polecenia SpeechConfig.SetSpeechSynthesisVoiceName("en-US-AndrewMultilingualNeural").

Subskrybowanie zdarzeń syntezatora

Możesz chcieć uzyskać więcej szczegółowych informacji na temat przetwarzania i wyników zamiany tekstu na mowę. Na przykład możesz chcieć wiedzieć, kiedy syntetyzator uruchamia się i zatrzymuje, lub możesz chcieć wiedzieć o innych zdarzeniach napotkanych podczas syntezy.

Używając narzędzia SpeechSynthesizer do zamiany tekstu na mowę, możesz subskrybować zdarzenia w tej tabeli:

Wydarzenie opis Przypadek użycia
BookmarkReached Sygnały, że osiągnięto zakładkę. Aby wyzwolić zdarzenie osiągnięto zakładkę bookmark , element jest wymagany w języku SSML. To zdarzenie zgłasza czas, jaki upłynął w danych wyjściowych audio między rozpoczęciem syntezy a elementem bookmark . Właściwość zdarzenia Text to wartość ciągu ustawiona w atrybucie zakładki mark . bookmark Elementy nie są mówione. Możesz użyć bookmark elementu , aby wstawić niestandardowe znaczniki w języku SSML, aby uzyskać przesunięcie każdego znacznika w strumieniu audio. Element bookmark może służyć do odwoływania się do określonej lokalizacji w sekwencji tekstu lub tagu.
SynthesisCanceled Sygnały, że synteza mowy została anulowana. Możesz potwierdzić, kiedy synteza zostanie anulowana.
SynthesisCompleted Sygnały, że synteza mowy jest kompletna. Po zakończeniu syntezy można potwierdzić.
SynthesisStarted Sygnały, że rozpoczęła się synteza mowy. Możesz potwierdzić, kiedy rozpoczęto syntezę.
Synthesizing Sygnały, że synteza mowy jest w toku. To zdarzenie jest uruchamiane za każdym razem, gdy zestaw SDK otrzymuje fragment dźwięku z usługi Mowa. Możesz potwierdzić, kiedy synteza jest w toku.
VisemeReceived Sygnały, że odebrano zdarzenie viseme. Visemes są często używane do reprezentowania kluczowych pozy w obserwowanej mowie. Kluczowe pozy obejmują położenie ust, szczęki i języka w produkcji konkretnej fonemy. Możesz użyć visemes, aby animować twarz postaci jako dźwięk mowy odtwarzane.
WordBoundary Sygnały, że odebrano granicę słowa. To zdarzenie jest wywoływane na początku każdego nowego słowa mówionego, interpunkcyjnego i zdania. Zdarzenie zgłasza przesunięcie czasu bieżącego wyrazu w znacznikach od początku dźwięku wyjściowego. To zdarzenie zgłasza również położenie znaku w tekście wejściowym lub SSML bezpośrednio przed wyrazem, który ma być wypowiadany. To zdarzenie jest często używane do pobierania względnych pozycji tekstu i odpowiadającego mu dźwięku. Możesz chcieć wiedzieć o nowym słowie, a następnie podjąć działania na podstawie chronometrażu. Możesz na przykład uzyskać informacje, które mogą pomóc w podjęciu decyzji o tym, kiedy i jak długo będą wyróżniać wyrazy podczas ich wypowiadania.

Uwaga

Zdarzenia są zgłaszane, gdy dane wyjściowe audio staną się dostępne, co jest szybsze niż odtwarzanie na urządzeniu wyjściowym. Obiekt wywołujący musi odpowiednio synchronizować przesyłanie strumieniowe i w czasie rzeczywistym.

Oto przykład pokazujący sposób subskrybowania zdarzeń na potrzeby syntezy mowy. Postępuj zgodnie z instrukcjami w przewodniku Szybki start, ale zastąp zawartość tego pliku main.cpp następującym kodem:

#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-AvaMultilingualNeural'>
            <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
}

Więcej przykładów zamiany tekstu na mowę można znaleźć w witrynie GitHub.

Używanie niestandardowego punktu końcowego

Niestandardowy punkt końcowy jest funkcjonalnie identyczny ze standardowym punktem końcowym używanym do obsługi żądań zamiany tekstu na mowę.

Jedną z różnic jest to, że należy określić, EndpointId aby używać niestandardowego głosu za pośrednictwem zestawu SPEECH SDK. Możesz rozpocząć od tekstu w przewodniku Szybki start do mowy, a następnie zaktualizować kod za pomocą elementu EndpointId i SpeechSynthesisVoiceName.

auto speechConfig = SpeechConfig::FromSubscription(speechKey, speechRegion);
speechConfig->SetSpeechSynthesisVoiceName("YourCustomVoiceName");
speechConfig->SetEndpointId("YourEndpointId");

Aby użyć głosu niestandardowego za pomocą języka SSML (Speech Synthesis Markup Language), określ nazwę modelu jako nazwę głosu. W tym przykładzie użyto YourCustomVoiceName głosu.

<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="en-US">
    <voice name="YourCustomVoiceName">
        This is the text that is spoken. 
    </voice>
</speak>

Uruchamianie i używanie kontenera

Kontenery mowy udostępniają internetowe interfejsy API punktów końcowych zapytań oparte na protokole Websocket, które są dostępne za pośrednictwem zestawu SPEECH SDK i interfejsu wiersza polecenia usługi Mowa. Domyślnie zestaw SDK usługi Mowa i interfejs wiersza polecenia usługi Mowa używają publicznej usługi rozpoznawania mowy. Aby użyć kontenera, należy zmienić metodę inicjowania. Użyj adresu URL hosta kontenera zamiast klucza i regionu.

Aby uzyskać więcej informacji na temat kontenerów, zobacz Instalowanie i uruchamianie kontenerów usługi Mowa za pomocą platformy Docker.

Dokumentacja referencyjna Package (Go)Additional Samples on GitHub (Dodatkowe przykłady w witrynie GitHub) | |

W tym przewodniku z instrukcjami poznasz typowe wzorce projektowe służące do wykonywania syntezy mowy w tekście.

Aby uzyskać więcej informacji na temat następujących obszarów, zobacz Co to jest zamiana tekstu na mowę?

  • Uzyskiwanie odpowiedzi jako strumieni w pamięci.
  • Dostosowywanie szybkości próbkowania danych wyjściowych i szybkości bitów.
  • Przesyłanie żądań syntezy przy użyciu języka znaczników syntezy mowy (SSML).
  • Korzystanie z głosów neuronowych.
  • Subskrybowanie zdarzeń i działanie na podstawie wyników.

Wymagania wstępne

  • Subskrypcja platformy Azure — utwórz jedną bezpłatnie.
  • Utwórz zasób usługi Mowa w witrynie Azure Portal.
  • Klucz zasobu usługi Mowa i region. Po wdrożeniu zasobu usługi Mowa wybierz pozycję Przejdź do zasobu , aby wyświetlić klucze i zarządzać nimi. Aby uzyskać więcej informacji na temat zasobów usług Azure AI, zobacz Pobieranie kluczy dla zasobu.

Instalowanie zestawu SDK usługi Mowa

Przed wykonaniem niczego należy zainstalować zestaw SPEECH SDK dla języka Go.

Zamiana tekstu na mowę na prelegenta

Użyj poniższego przykładu kodu, aby uruchomić syntezę mowy na domyślnym urządzeniu wyjściowym audio. Zastąp zmienne subscription i region kluczem mowy i lokalizacją/regionem. Uruchomienie skryptu mówi tekst wejściowy do domyślnego głośnika.

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)
            }
        }
    }
}

Uruchom następujące polecenia, aby utworzyć plik go.mod , który łączy się ze składnikami hostowanymi w usłudze GitHub:

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

Teraz skompiluj i uruchom kod:

go build
go run quickstart

Aby uzyskać szczegółowe informacje o klasach, zobacz dokumentację i SpeechSynthesizer dokumentacjęSpeechConfig.

Zamiana tekstu na mowę do strumienia w pamięci

Możesz użyć wynikowych danych dźwiękowych jako strumienia w pamięci, a nie bezpośredniego zapisywania w pliku. Za pomocą strumienia w pamięci można tworzyć niestandardowe zachowanie:

  • Abstrakcja wynikowej tablicy bajtów jako strumienia możliwego do wyszukiwania dla niestandardowych usług podrzędnych.
  • Zintegruj wynik z innymi interfejsami API lub usługami.
  • Zmodyfikuj dane audio, zapisz niestandardowe nagłówki .wav i wykonaj powiązane zadania.

Tę zmianę można wprowadzić w poprzednim przykładzie. AudioConfig Usuń blok, ponieważ ręcznie zarządzasz zachowaniem danych wyjściowych z tego punktu w celu zwiększenia kontroli. Następnie przekaż nil element AudioConfig w konstruktorze SpeechSynthesizer .

Uwaga

Przekazywanie nil dla elementu AudioConfig, a nie pomijanie go tak jak w poprzednim przykładzie danych wyjściowych osoby mówiącej, nie będzie odtwarzać dźwięku domyślnie na bieżącym aktywnym urządzeniu wyjściowym.

Zapisz wynik w zmiennej SpeechSynthesisResult . Właściwość AudioData zwraca []byte wystąpienie danych wyjściowych. Możesz pracować z tym []byte wystąpieniem ręcznie lub użyć AudioDataStream klasy do zarządzania strumieniem w pamięci. W tym przykładzie użyjesz funkcji statycznej NewAudioDataStreamFromSpeechSynthesisResult() , aby pobrać strumień z wyniku.

Zastąp zmienne subscription i region kluczem mowy i lokalizacją/regionem:

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))
    }
}

Uruchom następujące polecenia, aby utworzyć plik go.mod , który łączy się ze składnikami hostowanymi w usłudze GitHub:

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

Teraz skompiluj i uruchom kod:

go build
go run quickstart

Aby uzyskać szczegółowe informacje o klasach, zobacz dokumentację i SpeechSynthesizer dokumentacjęSpeechConfig.

Wybieranie języka syntezy i głosu

Funkcja zamiany tekstu na mowę w usłudze Mowa obsługuje ponad 400 głosów i ponad 140 języków i wariantów. Pełną listę możesz uzyskać lub wypróbować w galerii głosów.

Określ język lub głos, SpeechConfig aby dopasować tekst wejściowy i użyć określonego głosu:

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-AvaMultilingualNeural")

Wszystkie neuronowe głosy są wielojęzyczne i płynne we własnym języku i języku angielskim. Jeśli na przykład tekst wejściowy w języku angielskim to "Jestem podekscytowany, aby spróbować zamiany tekstu na mowę", a następnie wybierzesz es-ES-ElviraNeuraltekst mówiony w języku angielskim z hiszpańskim akcentem.

Jeśli głos nie mówi w języku tekstu wejściowego, usługa rozpoznawania mowy nie tworzy syntetyzowanego dźwięku. Aby uzyskać pełną listę obsługiwanych głosów neuronowych, zobacz Obsługa języka i głosu dla usługi Mowa.

Uwaga

Domyślny głos to pierwszy głos zwracany na ustawienia regionalne z interfejsu API listy głosowej.

Głos, który mówi, jest określany w kolejności priorytetu w następujący sposób:

  • Jeśli nie ustawisz SpeechSynthesisVoiceName lub SpeechSynthesisLanguage, domyślny głos mówi en-US .
  • Jeśli ustawisz SpeechSynthesisLanguagetylko , domyślny głos dla określonych ustawień regionalnych mówi.
  • Jeśli ustawienia i SpeechSynthesisVoiceNameSpeechSynthesisLanguage są ustawione, SpeechSynthesisLanguage ustawienie jest ignorowane. Głos, który określisz przy użyciu SpeechSynthesisVoiceName głosu.
  • Jeśli element głosowy jest ustawiony przy użyciu języka znaczników syntezy mowy (SSML),SpeechSynthesisVoiceName ustawienia i SpeechSynthesisLanguage są ignorowane.

Dostosowywanie cech mowy przy użyciu języka SSML

Możesz użyć języka znaczników syntezy mowy (SSML) w celu dostosowania wysokości, wymowy, szybkości mówienia, głośności i nie tylko w tekście do danych wyjściowych mowy, przesyłając żądania ze schematu XML. W tej sekcji przedstawiono przykład zmiany głosu. Aby uzyskać więcej informacji, zobacz Omówienie języka znaczników syntezy mowy.

Aby rozpocząć korzystanie z języka SSML do dostosowywania, należy wprowadzić niewielką zmianę, która przełącza głos.

Najpierw utwórz nowy plik XML konfiguracji SSML w katalogu głównym projektu. W tym przykładzie jest to ssml.xml. Element główny to zawsze <speak>. Zawijanie tekstu w elemecie <voice> umożliwia zmianę głosu przy użyciu parametru name . Aby uzyskać pełną listę obsługiwanych głosów neuronowych, zobacz Obsługiwane języki.

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

Następnie należy zmienić żądanie syntezy mowy, aby odwołać się do pliku XML. Żądanie jest w większości takie samo, ale zamiast używać SpeakTextAsync() funkcji , należy użyć polecenia SpeakSsmlAsync(). Ta funkcja oczekuje ciągu XML, więc najpierw załadujesz konfigurację SSML jako ciąg. Od tego momentu obiekt wynikowy jest dokładnie taki sam jak w poprzednich przykładach.

Uwaga

Aby ustawić głos bez użycia języka SSML, możesz ustawić właściwość przy SpeechConfig użyciu polecenia speechConfig.SetSpeechSynthesisVoiceName("en-US-AvaMultilingualNeural").

Subskrybowanie zdarzeń syntezatora

Możesz chcieć uzyskać więcej szczegółowych informacji na temat przetwarzania i wyników zamiany tekstu na mowę. Na przykład możesz chcieć wiedzieć, kiedy syntetyzator uruchamia się i zatrzymuje, lub możesz chcieć wiedzieć o innych zdarzeniach napotkanych podczas syntezy.

Używając narzędzia SpeechSynthesizer do zamiany tekstu na mowę, możesz subskrybować zdarzenia w tej tabeli:

Wydarzenie opis Przypadek użycia
BookmarkReached Sygnały, że osiągnięto zakładkę. Aby wyzwolić zdarzenie osiągnięto zakładkę bookmark , element jest wymagany w języku SSML. To zdarzenie zgłasza czas, jaki upłynął w danych wyjściowych audio między rozpoczęciem syntezy a elementem bookmark . Właściwość zdarzenia Text to wartość ciągu ustawiona w atrybucie zakładki mark . bookmark Elementy nie są mówione. Możesz użyć bookmark elementu , aby wstawić niestandardowe znaczniki w języku SSML, aby uzyskać przesunięcie każdego znacznika w strumieniu audio. Element bookmark może służyć do odwoływania się do określonej lokalizacji w sekwencji tekstu lub tagu.
SynthesisCanceled Sygnały, że synteza mowy została anulowana. Możesz potwierdzić, kiedy synteza zostanie anulowana.
SynthesisCompleted Sygnały, że synteza mowy jest kompletna. Po zakończeniu syntezy można potwierdzić.
SynthesisStarted Sygnały, że rozpoczęła się synteza mowy. Możesz potwierdzić, kiedy rozpoczęto syntezę.
Synthesizing Sygnały, że synteza mowy jest w toku. To zdarzenie jest uruchamiane za każdym razem, gdy zestaw SDK otrzymuje fragment dźwięku z usługi Mowa. Możesz potwierdzić, kiedy synteza jest w toku.
VisemeReceived Sygnały, że odebrano zdarzenie viseme. Visemes są często używane do reprezentowania kluczowych pozy w obserwowanej mowie. Kluczowe pozy obejmują położenie ust, szczęki i języka w produkcji konkretnej fonemy. Możesz użyć visemes, aby animować twarz postaci jako dźwięk mowy odtwarzane.
WordBoundary Sygnały, że odebrano granicę słowa. To zdarzenie jest wywoływane na początku każdego nowego słowa mówionego, interpunkcyjnego i zdania. Zdarzenie zgłasza przesunięcie czasu bieżącego wyrazu w znacznikach od początku dźwięku wyjściowego. To zdarzenie zgłasza również położenie znaku w tekście wejściowym lub SSML bezpośrednio przed wyrazem, który ma być wypowiadany. To zdarzenie jest często używane do pobierania względnych pozycji tekstu i odpowiadającego mu dźwięku. Możesz chcieć wiedzieć o nowym słowie, a następnie podjąć działania na podstawie chronometrażu. Możesz na przykład uzyskać informacje, które mogą pomóc w podjęciu decyzji o tym, kiedy i jak długo będą wyróżniać wyrazy podczas ich wypowiadania.

Uwaga

Zdarzenia są zgłaszane, gdy dane wyjściowe audio staną się dostępne, co jest szybsze niż odtwarzanie na urządzeniu wyjściowym. Obiekt wywołujący musi odpowiednio synchronizować przesyłanie strumieniowe i w czasie rzeczywistym.

Oto przykład pokazujący sposób subskrybowania zdarzeń na potrzeby syntezy mowy. Możesz postępować zgodnie z instrukcjami w przewodniku Szybki start, ale zastąp zawartość tego speech-synthesis.go pliku następującym kodem Języka Go:

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-AvaMultilingualNeural"

    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)
        }
    }
}

Więcej przykładów zamiany tekstu na mowę można znaleźć w witrynie GitHub.

Uruchamianie i używanie kontenera

Kontenery mowy udostępniają internetowe interfejsy API punktów końcowych zapytań oparte na protokole Websocket, które są dostępne za pośrednictwem zestawu SPEECH SDK i interfejsu wiersza polecenia usługi Mowa. Domyślnie zestaw SDK usługi Mowa i interfejs wiersza polecenia usługi Mowa używają publicznej usługi rozpoznawania mowy. Aby użyć kontenera, należy zmienić metodę inicjowania. Użyj adresu URL hosta kontenera zamiast klucza i regionu.

Aby uzyskać więcej informacji na temat kontenerów, zobacz Instalowanie i uruchamianie kontenerów usługi Mowa za pomocą platformy Docker.

| Dokumentacja referencyjna — dodatkowe przykłady w usłudze GitHub

W tym przewodniku z instrukcjami poznasz typowe wzorce projektowe służące do wykonywania syntezy mowy w tekście.

Aby uzyskać więcej informacji na temat następujących obszarów, zobacz Co to jest zamiana tekstu na mowę?

  • Uzyskiwanie odpowiedzi jako strumieni w pamięci.
  • Dostosowywanie szybkości próbkowania danych wyjściowych i szybkości bitów.
  • Przesyłanie żądań syntezy przy użyciu języka znaczników syntezy mowy (SSML).
  • Korzystanie z głosów neuronowych.
  • Subskrybowanie zdarzeń i działanie na podstawie wyników.

Wybieranie języka syntezy i głosu

Funkcja zamiany tekstu na mowę w usłudze Mowa obsługuje ponad 400 głosów i ponad 140 języków i wariantów. Pełną listę możesz uzyskać lub wypróbować w galerii głosów.

Określ język lub głos funkcji SpeechConfig , aby dopasować tekst wejściowy i użyć określonego głosu. Poniższy fragment kodu pokazuje, jak działa ta technika:

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-AvaMultilingualNeural");
}

Wszystkie neuronowe głosy są wielojęzyczne i płynne we własnym języku i języku angielskim. Jeśli na przykład tekst wejściowy w języku angielskim to "Jestem podekscytowany, aby spróbować zamiany tekstu na mowę", a następnie wybierzesz es-ES-ElviraNeuraltekst mówiony w języku angielskim z hiszpańskim akcentem.

Jeśli głos nie mówi w języku tekstu wejściowego, usługa rozpoznawania mowy nie tworzy syntetyzowanego dźwięku. Aby uzyskać pełną listę obsługiwanych głosów neuronowych, zobacz Obsługa języka i głosu dla usługi Mowa.

Uwaga

Domyślny głos to pierwszy głos zwracany na ustawienia regionalne z interfejsu API listy głosowej.

Głos, który mówi, jest określany w kolejności priorytetu w następujący sposób:

  • Jeśli nie ustawisz SpeechSynthesisVoiceName lub SpeechSynthesisLanguage, domyślny głos mówi en-US .
  • Jeśli ustawisz SpeechSynthesisLanguagetylko , domyślny głos dla określonych ustawień regionalnych mówi.
  • Jeśli ustawienia i SpeechSynthesisVoiceNameSpeechSynthesisLanguage są ustawione, SpeechSynthesisLanguage ustawienie jest ignorowane. Głos określony przy użyciu SpeechSynthesisVoiceName głosu.
  • Jeśli element głosowy jest ustawiony przy użyciu języka znaczników syntezy mowy (SSML),SpeechSynthesisVoiceName ustawienia i SpeechSynthesisLanguage są ignorowane.

Syntetyzowanie mowy do pliku

Utwórz SpeechSynthesizer obiekt. Ten obiekt uruchamia konwersje mowy na mowę i dane wyjściowe do osób mówiących, plików lub innych strumieni wyjściowych. SpeechSynthesizer akceptuje jako parametry:

  • SpeechConfig Obiekt utworzony w poprzednim kroku.
  • AudioConfig Obiekt określający sposób obsługi wyników wyjściowych.
  1. AudioConfig Utwórz wystąpienie, aby automatycznie zapisywać dane wyjściowe w pliku .wav przy użyciu funkcji statycznejfromWavFileOutput():

    public static void main(String[] args) {
        SpeechConfig speechConfig = SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
        AudioConfig audioConfig = AudioConfig.fromWavFileOutput("path/to/write/file.wav");
    }
    
  2. Utwórz wystąpienie SpeechSynthesizer wystąpienia. speechConfig Przekaż obiekt i audioConfig obiekt jako parametry. Aby syntetyzować mowę i zapisywać w pliku, uruchom polecenie SpeakText() z ciągiem tekstu.

    public static void main(String[] args) {
        SpeechConfig speechConfig = SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
        AudioConfig audioConfig = AudioConfig.fromWavFileOutput("path/to/write/file.wav");
    
        SpeechSynthesizer speechSynthesizer = new SpeechSynthesizer(speechConfig, audioConfig);
        speechSynthesizer.SpeakText("I'm excited to try text to speech");
    }
    

Po uruchomieniu programu program tworzy syntetyzowany plik .wav , który jest zapisywany w określonej lokalizacji. Ten wynik jest dobrym przykładem najbardziej podstawowego użycia. Następnie możesz dostosować dane wyjściowe i obsłużyć odpowiedź wyjściową jako strumień w pamięci na potrzeby pracy ze scenariuszami niestandardowymi.

Syntetyzowanie do danych wyjściowych osoby mówiącej

Możesz chcieć uzyskać więcej szczegółowych informacji na temat przetwarzania i wyników zamiany tekstu na mowę. Na przykład możesz chcieć wiedzieć, kiedy syntetyzator uruchamia się i zatrzymuje, lub możesz chcieć wiedzieć o innych zdarzeniach napotkanych podczas syntezy.

Aby uzyskać syntetyzację mowy do bieżącego aktywnego urządzenia wyjściowego, takiego jak głośnik, utwórz wystąpienie AudioConfig przy użyciu funkcji statycznej fromDefaultSpeakerOutput() . Oto przykład:

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

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

Uzyskiwanie wyniku jako strumienia w pamięci

Możesz użyć wynikowych danych dźwiękowych jako strumienia w pamięci, a nie bezpośredniego zapisywania w pliku. Za pomocą strumienia w pamięci można tworzyć niestandardowe zachowanie:

  • Abstrakcja wynikowej tablicy bajtów jako strumienia możliwego do wyszukiwania dla niestandardowych usług podrzędnych.
  • Zintegruj wynik z innymi interfejsami API lub usługami.
  • Zmodyfikuj dane audio, zapisz niestandardowe nagłówki .wav i wykonaj powiązane zadania.

Tę zmianę można wprowadzić w poprzednim przykładzie. Najpierw usuń AudioConfig blok, ponieważ ręcznie zarządzasz zachowaniem danych wyjściowych z tego punktu w celu zwiększenia kontroli. Następnie przekaż null element AudioConfig w konstruktorze SpeechSynthesizer .

Uwaga

Przekazywanie null dla elementu AudioConfig, a nie pomijanie go tak jak w poprzednim przykładzie danych wyjściowych osoby mówiącej, nie odtwarza dźwięku domyślnie na bieżącym aktywnym urządzeniu wyjściowym.

Zapisz wynik w zmiennej SpeechSynthesisResult . Funkcja SpeechSynthesisResult.getAudioData() zwraca byte [] wystąpienie danych wyjściowych. Możesz pracować z tym byte [] wystąpieniem ręcznie lub użyć AudioDataStream klasy do zarządzania strumieniem w pamięci.

W tym przykładzie użyj funkcji statycznej AudioDataStream.fromResult() , aby pobrać strumień z wyniku:

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

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

W tym momencie można zaimplementować dowolne zachowanie niestandardowe przy użyciu wynikowego stream obiektu.

Dostosowywanie formatu audio

Możesz dostosować atrybuty danych wyjściowych dźwięku, w tym:

  • Typ pliku audio
  • Częstotliwość próbkowania
  • Głębokość bitu

Aby zmienić format dźwięku, należy użyć setSpeechSynthesisOutputFormat() funkcji w SpeechConfig obiekcie . Ta funkcja oczekuje enum wystąpienia typu SpeechSynthesisOutputFormat. Użyj polecenia , enum aby wybrać format danych wyjściowych. Aby uzyskać dostępne formaty, zobacz listę formatów audio.

Istnieją różne opcje dla różnych typów plików, w zależności od wymagań. Z definicji nieprzetworzone formaty, takie jak Raw24Khz16BitMonoPcm nie zawierają nagłówków dźwięku. Używaj formatów pierwotnych tylko w jednej z następujących sytuacji:

  • Wiesz, że implementacja podrzędna może dekodować nieprzetworzone strumienie bitowe.
  • Planujesz ręcznie tworzyć nagłówki na podstawie czynników, takich jak głębokość bitów, częstotliwość próbkowania i liczba kanałów.

W tym przykładzie określono format Riff24Khz16BitMonoPcm RIFF o wysokiej wierności, ustawiając SpeechSynthesisOutputFormat dla SpeechConfig obiektu. Podobnie jak w przykładzie w poprzedniej sekcji, użyj AudioDataStream polecenia , aby uzyskać strumień w pamięci wyniku, a następnie zapisać go w pliku.

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

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

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

Po uruchomieniu programu zapisuje plik .wav do określonej ścieżki.

Dostosowywanie cech mowy przy użyciu języka SSML

Za pomocą języka SSML można dostroić wysokość, wymowę, szybkość mówienia, głośność i inne aspekty w danych wyjściowych zamiany tekstu na mowę, przesyłając żądania ze schematu XML. W tej sekcji przedstawiono przykład zmiany głosu. Aby uzyskać więcej informacji, zobacz artykuł z instrukcjami dotyczącymi języka SSML.

Aby rozpocząć korzystanie z języka SSML do dostosowywania, należy wprowadzić niewielką zmianę, która przełącza głos.

  1. Utwórz nowy plik XML dla konfiguracji SSML w katalogu głównym projektu.

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

    W tym przykładzie plik jest ssml.xml. Element główny to zawsze <speak>. Zawijanie tekstu w elemecie <voice> umożliwia zmianę głosu przy użyciu parametru name . Aby uzyskać pełną listę obsługiwanych głosów neuronowych, zobacz Obsługiwane języki.

  2. Zmień żądanie syntezy mowy, aby odwołać się do pliku XML. Żądanie jest w większości takie samo. Zamiast używać funkcji, należy użyć SpeakText() polecenia SpeakSsml(). Ta funkcja oczekuje ciągu XML, więc najpierw utwórz funkcję, aby załadować plik XML i zwrócić go jako ciąg:

    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.";
        }
    }
    

    W tym momencie obiekt wynikowy jest dokładnie taki sam jak w poprzednich przykładach:

    public static void main(String[] args) {
        SpeechConfig speechConfig = SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
        SpeechSynthesizer speechSynthesizer = new SpeechSynthesizer(speechConfig, null);
    
        String ssml = xmlToString("ssml.xml");
        SpeechSynthesisResult result = speechSynthesizer.SpeakSsml(ssml);
        AudioDataStream stream = AudioDataStream.fromResult(result);
        stream.saveToWavFile("path/to/write/file.wav");
    }
    

Uwaga

Aby zmienić głos bez użycia języka SSML, ustaw właściwość przy SpeechConfig użyciu polecenia SpeechConfig.setSpeechSynthesisVoiceName("en-US-AvaMultilingualNeural");.

Subskrybowanie zdarzeń syntezatora

Możesz chcieć uzyskać więcej szczegółowych informacji na temat przetwarzania i wyników zamiany tekstu na mowę. Na przykład możesz chcieć wiedzieć, kiedy syntetyzator uruchamia się i zatrzymuje, lub możesz chcieć wiedzieć o innych zdarzeniach napotkanych podczas syntezy.

Używając narzędzia SpeechSynthesizer do zamiany tekstu na mowę, możesz subskrybować zdarzenia w tej tabeli:

Wydarzenie opis Przypadek użycia
BookmarkReached Sygnały, że osiągnięto zakładkę. Aby wyzwolić zdarzenie osiągnięto zakładkę bookmark , element jest wymagany w języku SSML. To zdarzenie zgłasza czas, jaki upłynął w danych wyjściowych audio między rozpoczęciem syntezy a elementem bookmark . Właściwość zdarzenia Text to wartość ciągu ustawiona w atrybucie zakładki mark . bookmark Elementy nie są mówione. Możesz użyć bookmark elementu , aby wstawić niestandardowe znaczniki w języku SSML, aby uzyskać przesunięcie każdego znacznika w strumieniu audio. Element bookmark może służyć do odwoływania się do określonej lokalizacji w sekwencji tekstu lub tagu.
SynthesisCanceled Sygnały, że synteza mowy została anulowana. Możesz potwierdzić, kiedy synteza zostanie anulowana.
SynthesisCompleted Sygnały, że synteza mowy jest kompletna. Po zakończeniu syntezy można potwierdzić.
SynthesisStarted Sygnały, że rozpoczęła się synteza mowy. Możesz potwierdzić, kiedy rozpoczęto syntezę.
Synthesizing Sygnały, że synteza mowy jest w toku. To zdarzenie jest uruchamiane za każdym razem, gdy zestaw SDK otrzymuje fragment dźwięku z usługi Mowa. Możesz potwierdzić, kiedy synteza jest w toku.
VisemeReceived Sygnały, że odebrano zdarzenie viseme. Visemes są często używane do reprezentowania kluczowych pozy w obserwowanej mowie. Kluczowe pozy obejmują położenie ust, szczęki i języka w produkcji konkretnej fonemy. Możesz użyć visemes, aby animować twarz postaci jako dźwięk mowy odtwarzane.
WordBoundary Sygnały, że odebrano granicę słowa. To zdarzenie jest wywoływane na początku każdego nowego słowa mówionego, interpunkcyjnego i zdania. Zdarzenie zgłasza przesunięcie czasu bieżącego wyrazu w znacznikach od początku dźwięku wyjściowego. To zdarzenie zgłasza również położenie znaku w tekście wejściowym lub SSML bezpośrednio przed wyrazem, który ma być wypowiadany. To zdarzenie jest często używane do pobierania względnych pozycji tekstu i odpowiadającego mu dźwięku. Możesz chcieć wiedzieć o nowym słowie, a następnie podjąć działania na podstawie chronometrażu. Możesz na przykład uzyskać informacje, które mogą pomóc w podjęciu decyzji o tym, kiedy i jak długo będą wyróżniać wyrazy podczas ich wypowiadania.

Uwaga

Zdarzenia są zgłaszane, gdy dane wyjściowe audio staną się dostępne, co jest szybsze niż odtwarzanie na urządzeniu wyjściowym. Obiekt wywołujący musi odpowiednio synchronizować przesyłanie strumieniowe i w czasie rzeczywistym.

Oto przykład pokazujący sposób subskrybowania zdarzeń na potrzeby syntezy mowy. Postępuj zgodnie z instrukcjami w przewodniku Szybki start, ale zastąp zawartość tego pliku SpeechSynthesis.java następującym kodem Java:

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-AvaMultilingualNeural"; 
        
        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);
    }
}

Więcej przykładów zamiany tekstu na mowę można znaleźć w witrynie GitHub.

Używanie niestandardowego punktu końcowego

Niestandardowy punkt końcowy jest funkcjonalnie identyczny ze standardowym punktem końcowym używanym do obsługi żądań zamiany tekstu na mowę.

Jedną z różnic jest to, że należy określić, EndpointId aby używać niestandardowego głosu za pośrednictwem zestawu SPEECH SDK. Możesz rozpocząć od tekstu w przewodniku Szybki start do mowy, a następnie zaktualizować kod za pomocą elementu EndpointId i SpeechSynthesisVoiceName.

SpeechConfig speechConfig = SpeechConfig.fromSubscription(speechKey, speechRegion);
speechConfig.setSpeechSynthesisVoiceName("YourCustomVoiceName");
speechConfig.setEndpointId("YourEndpointId");

Aby użyć głosu niestandardowego za pomocą języka SSML (Speech Synthesis Markup Language), określ nazwę modelu jako nazwę głosu. W tym przykładzie użyto YourCustomVoiceName głosu.

<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="en-US">
    <voice name="YourCustomVoiceName">
        This is the text that is spoken. 
    </voice>
</speak>

Uruchamianie i używanie kontenera

Kontenery mowy udostępniają internetowe interfejsy API punktów końcowych zapytań oparte na protokole Websocket, które są dostępne za pośrednictwem zestawu SPEECH SDK i interfejsu wiersza polecenia usługi Mowa. Domyślnie zestaw SDK usługi Mowa i interfejs wiersza polecenia usługi Mowa używają publicznej usługi rozpoznawania mowy. Aby użyć kontenera, należy zmienić metodę inicjowania. Użyj adresu URL hosta kontenera zamiast klucza i regionu.

Aby uzyskać więcej informacji na temat kontenerów, zobacz Instalowanie i uruchamianie kontenerów usługi Mowa za pomocą platformy Docker.

Dokumentacja referencyjna | Package (npm)Additional Samples on GitHub Library source code (Dodatkowe przykłady w kodzie źródłowym biblioteki GitHub) | |

W tym przewodniku z instrukcjami poznasz typowe wzorce projektowe służące do wykonywania syntezy mowy w tekście.

Aby uzyskać więcej informacji na temat następujących obszarów, zobacz Co to jest zamiana tekstu na mowę?

  • Uzyskiwanie odpowiedzi jako strumieni w pamięci.
  • Dostosowywanie szybkości próbkowania danych wyjściowych i szybkości bitów.
  • Przesyłanie żądań syntezy przy użyciu języka znaczników syntezy mowy (SSML).
  • Korzystanie z głosów neuronowych.
  • Subskrybowanie zdarzeń i działanie na podstawie wyników.

Wybieranie języka syntezy i głosu

Funkcja zamiany tekstu na mowę w usłudze Mowa obsługuje ponad 400 głosów i ponad 140 języków i wariantów. Pełną listę możesz uzyskać lub wypróbować w galerii głosów.

Określ język lub głos, SpeechConfig aby dopasować tekst wejściowy i użyć określonego głosu:

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

synthesizeSpeech();

Wszystkie neuronowe głosy są wielojęzyczne i płynne we własnym języku i języku angielskim. Jeśli na przykład tekst wejściowy w języku angielskim to "Jestem podekscytowany, aby spróbować zamiany tekstu na mowę", a następnie wybierzesz es-ES-ElviraNeuraltekst mówiony w języku angielskim z hiszpańskim akcentem.

Jeśli głos nie mówi w języku tekstu wejściowego, usługa rozpoznawania mowy nie tworzy syntetyzowanego dźwięku. Aby uzyskać pełną listę obsługiwanych głosów neuronowych, zobacz Obsługa języka i głosu dla usługi Mowa.

Uwaga

Domyślny głos to pierwszy głos zwracany na ustawienia regionalne z interfejsu API listy głosowej.

Głos, który mówi, jest określany w kolejności priorytetu w następujący sposób:

  • Jeśli nie ustawisz SpeechSynthesisVoiceName lub SpeechSynthesisLanguage, domyślny głos mówi en-US .
  • Jeśli ustawisz SpeechSynthesisLanguagetylko , domyślny głos dla określonych ustawień regionalnych mówi.
  • Jeśli ustawienia i SpeechSynthesisVoiceNameSpeechSynthesisLanguage są ustawione, SpeechSynthesisLanguage ustawienie jest ignorowane. Głos, który określisz przy użyciu SpeechSynthesisVoiceName głosu.
  • Jeśli element głosowy jest ustawiony przy użyciu języka znaczników syntezy mowy (SSML),SpeechSynthesisVoiceName ustawienia i SpeechSynthesisLanguage są ignorowane.

Syntetyzowanie tekstu na mowę

Aby uzyskać syntetyzację mowy do bieżącego aktywnego urządzenia wyjściowego, takiego jak głośnik, utwórz wystąpienie AudioConfig przy użyciu funkcji statycznej fromDefaultSpeakerOutput() . Oto przykład:

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

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

Po uruchomieniu programu syntetyzowany dźwięk jest odtwarzany z głośnika. Ten wynik jest dobrym przykładem najbardziej podstawowego użycia. Następnie możesz dostosować dane wyjściowe i obsłużyć odpowiedź wyjściową jako strumień w pamięci na potrzeby pracy ze scenariuszami niestandardowymi.

Uzyskiwanie wyniku jako strumienia w pamięci

Możesz użyć wynikowych danych dźwiękowych jako strumienia w pamięci, a nie bezpośredniego zapisywania w pliku. Za pomocą strumienia w pamięci można tworzyć niestandardowe zachowanie:

  • Abstrakcja wynikowej tablicy bajtów jako strumienia możliwego do wyszukiwania dla niestandardowych usług podrzędnych.
  • Zintegruj wynik z innymi interfejsami API lub usługami.
  • Zmodyfikuj dane audio, napisz nagłówki niestandardowe .wav i wykonaj powiązane zadania.

Tę zmianę można wprowadzić w poprzednim przykładzie. AudioConfig Usuń blok, ponieważ ręcznie zarządzasz zachowaniem danych wyjściowych z tego punktu w celu zwiększenia kontroli. Następnie przekaż null element AudioConfig w konstruktorze SpeechSynthesizer .

Uwaga

Przekazywanie null dla elementu AudioConfig, a nie pomijanie go tak jak w poprzednim przykładzie danych wyjściowych osoby mówiącej, nie odtwarza dźwięku domyślnie na bieżącym aktywnym urządzeniu wyjściowym.

Zapisz wynik w zmiennej SpeechSynthesisResult . Właściwość SpeechSynthesisResult.audioData zwraca ArrayBuffer wartość danych wyjściowych— domyślny typ strumienia przeglądarki. W przypadku kodu po stronie serwera przekonwertuj ArrayBuffer na strumień buforu.

Następujący kod działa po stronie klienta:

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

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

Dowolne zachowanie niestandardowe można zaimplementować przy użyciu wynikowego ArrayBuffer obiektu. ArrayBuffer jest typowym typem odbierania w przeglądarce i odtwarzania z tego formatu.

W przypadku dowolnego kodu opartego na serwerze, jeśli musisz pracować z danymi jako strumieniem, musisz przekonwertować ArrayBuffer obiekt na strumień:

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

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

            speechSynthesizer.close();

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

Dostosowywanie formatu audio

Możesz dostosować atrybuty danych wyjściowych dźwięku, w tym:

  • Typ pliku audio
  • Częstotliwość próbkowania
  • Głębokość bitu

Aby zmienić format audio, użyj speechSynthesisOutputFormat właściwości w SpeechConfig obiekcie . Ta właściwość oczekuje enum wystąpienia typu SpeechSynthesisOutputFormat. Użyj polecenia , enum aby wybrać format danych wyjściowych. Aby uzyskać dostępne formaty, zobacz listę formatów audio.

Istnieją różne opcje dla różnych typów plików, w zależności od wymagań. Z definicji nieprzetworzone formaty, takie jak Raw24Khz16BitMonoPcm nie zawierają nagłówków dźwięku. Używaj formatów pierwotnych tylko w jednej z następujących sytuacji:

  • Wiesz, że implementacja podrzędna może dekodować nieprzetworzone strumienie bitowe.
  • Planujesz ręcznie tworzyć nagłówki na podstawie czynników, takich jak głębokość bitów, częstotliwość próbkowania i liczba kanałów.

W tym przykładzie określono format Riff24Khz16BitMonoPcm RIFF o wysokiej wierności, ustawiając speechSynthesisOutputFormat dla SpeechConfig obiektu. Podobnie jak w przykładzie w poprzedniej sekcji, pobierz dane audio ArrayBuffer i wchodzenie z nim w interakcje.

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

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

    const speechSynthesizer = new sdk.SpeechSynthesizer(speechConfig, null);
    speechSynthesizer.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}.`)

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

Dostosowywanie cech mowy przy użyciu języka SSML

Za pomocą języka SSML można dostroić wysokość, wymowę, szybkość mówienia, głośność i inne aspekty w danych wyjściowych zamiany tekstu na mowę, przesyłając żądania ze schematu XML. W tej sekcji przedstawiono przykład zmiany głosu. Aby uzyskać więcej informacji, zobacz Omówienie języka znaczników syntezy mowy.

Aby rozpocząć korzystanie z języka SSML do dostosowywania, należy wprowadzić niewielką zmianę, która przełącza głos.

  1. Utwórz nowy plik XML dla konfiguracji SSML w katalogu głównym projektu.

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

    W tym przykładzie jest to ssml.xml. Element główny to zawsze <speak>. Zawijanie tekstu w elemecie <voice> umożliwia zmianę głosu przy użyciu parametru name . Aby uzyskać pełną listę obsługiwanych głosów neuronowych, zobacz Obsługiwane języki.

  2. Zmień żądanie syntezy mowy, aby odwołać się do pliku XML. Żądanie jest w większości takie samo, ale zamiast używać speakTextAsync() funkcji , należy użyć polecenia speakSsmlAsync(). Ta funkcja oczekuje ciągu XML. Utwórz funkcję, aby załadować plik XML i zwrócić go jako ciąg:

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

    Aby uzyskać więcej informacji na temat readFileSyncprogramu , zobacz Node.js system plików.

    Obiekt wynikowy jest dokładnie taki sam jak w poprzednich przykładach:

    function synthesizeSpeech() {
        const speechConfig = sdk.SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
        const speechSynthesizer = new sdk.SpeechSynthesizer(speechConfig, null);
    
        const ssml = xmlToString("ssml.xml");
        speechSynthesizer.speakSsmlAsync(
            ssml,
            result => {
                if (result.errorDetails) {
                    console.error(result.errorDetails);
                } else {
                    console.log(JSON.stringify(result));
                }
    
                speechSynthesizer.close();
            },
            error => {
                console.log(error);
                speechSynthesizer.close();
            });
    }
    

Uwaga

Aby zmienić głos bez użycia języka SSML, możesz ustawić właściwość przy SpeechConfig użyciu polecenia SpeechConfig.speechSynthesisVoiceName = "en-US-AvaMultilingualNeural";.

Subskrybowanie zdarzeń syntezatora

Możesz chcieć uzyskać więcej szczegółowych informacji na temat przetwarzania i wyników zamiany tekstu na mowę. Na przykład możesz chcieć wiedzieć, kiedy syntetyzator uruchamia się i zatrzymuje, lub możesz chcieć wiedzieć o innych zdarzeniach napotkanych podczas syntezy.

Używając narzędzia SpeechSynthesizer do zamiany tekstu na mowę, możesz subskrybować zdarzenia w tej tabeli:

Wydarzenie opis Przypadek użycia
BookmarkReached Sygnały, że osiągnięto zakładkę. Aby wyzwolić zdarzenie osiągnięto zakładkę bookmark , element jest wymagany w języku SSML. To zdarzenie zgłasza czas, jaki upłynął w danych wyjściowych audio między rozpoczęciem syntezy a elementem bookmark . Właściwość zdarzenia Text to wartość ciągu ustawiona w atrybucie zakładki mark . bookmark Elementy nie są mówione. Możesz użyć bookmark elementu , aby wstawić niestandardowe znaczniki w języku SSML, aby uzyskać przesunięcie każdego znacznika w strumieniu audio. Element bookmark może służyć do odwoływania się do określonej lokalizacji w sekwencji tekstu lub tagu.
SynthesisCanceled Sygnały, że synteza mowy została anulowana. Możesz potwierdzić, kiedy synteza zostanie anulowana.
SynthesisCompleted Sygnały, że synteza mowy jest kompletna. Po zakończeniu syntezy można potwierdzić.
SynthesisStarted Sygnały, że rozpoczęła się synteza mowy. Możesz potwierdzić, kiedy rozpoczęto syntezę.
Synthesizing Sygnały, że synteza mowy jest w toku. To zdarzenie jest uruchamiane za każdym razem, gdy zestaw SDK otrzymuje fragment dźwięku z usługi Mowa. Możesz potwierdzić, kiedy synteza jest w toku.
VisemeReceived Sygnały, że odebrano zdarzenie viseme. Visemes są często używane do reprezentowania kluczowych pozy w obserwowanej mowie. Kluczowe pozy obejmują położenie ust, szczęki i języka w produkcji konkretnej fonemy. Możesz użyć visemes, aby animować twarz postaci jako dźwięk mowy odtwarzane.
WordBoundary Sygnały, że odebrano granicę słowa. To zdarzenie jest wywoływane na początku każdego nowego słowa mówionego, interpunkcyjnego i zdania. Zdarzenie zgłasza przesunięcie czasu bieżącego wyrazu w znacznikach od początku dźwięku wyjściowego. To zdarzenie zgłasza również położenie znaku w tekście wejściowym lub SSML bezpośrednio przed wyrazem, który ma być wypowiadany. To zdarzenie jest często używane do pobierania względnych pozycji tekstu i odpowiadającego mu dźwięku. Możesz chcieć wiedzieć o nowym słowie, a następnie podjąć działania na podstawie chronometrażu. Możesz na przykład uzyskać informacje, które mogą pomóc w podjęciu decyzji o tym, kiedy i jak długo będą wyróżniać wyrazy podczas ich wypowiadania.

Uwaga

Zdarzenia są zgłaszane, gdy dane wyjściowe audio staną się dostępne, co jest szybsze niż odtwarzanie na urządzeniu wyjściowym. Obiekt wywołujący musi odpowiednio synchronizować przesyłanie strumieniowe i w czasie rzeczywistym.

Oto przykład pokazujący sposób subskrybowania zdarzeń na potrzeby syntezy mowy. Możesz postępować zgodnie z instrukcjami w przewodniku Szybki start, ale zastąp zawartość tego pliku SpeechSynthesis.js następującym kodem JavaScript.

(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-AvaMultilingualNeural";  
    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;
    });
}());

Więcej przykładów zamiany tekstu na mowę można znaleźć w witrynie GitHub.

Uruchamianie i używanie kontenera

Kontenery mowy udostępniają internetowe interfejsy API punktów końcowych zapytań oparte na protokole Websocket, które są dostępne za pośrednictwem zestawu SPEECH SDK i interfejsu wiersza polecenia usługi Mowa. Domyślnie zestaw SDK usługi Mowa i interfejs wiersza polecenia usługi Mowa używają publicznej usługi rozpoznawania mowy. Aby użyć kontenera, należy zmienić metodę inicjowania. Użyj adresu URL hosta kontenera zamiast klucza i regionu.

Aby uzyskać więcej informacji na temat kontenerów, zobacz Instalowanie i uruchamianie kontenerów usługi Mowa za pomocą platformy Docker.

Dokumentacja referencyjna Pakietu (Pobierz) | Dodatkowe przykłady w usłudze GitHub |

W tym przewodniku z instrukcjami poznasz typowe wzorce projektowe służące do wykonywania syntezy mowy w tekście.

Aby uzyskać więcej informacji na temat następujących obszarów, zobacz Co to jest zamiana tekstu na mowę?

  • Uzyskiwanie odpowiedzi jako strumieni w pamięci.
  • Dostosowywanie szybkości próbkowania danych wyjściowych i szybkości bitów.
  • Przesyłanie żądań syntezy przy użyciu języka znaczników syntezy mowy (SSML).
  • Korzystanie z głosów neuronowych.
  • Subskrybowanie zdarzeń i działanie na podstawie wyników.

Wymagania wstępne

  • Subskrypcja platformy Azure — utwórz jedną bezpłatnie.
  • Utwórz zasób usługi Mowa w witrynie Azure Portal.
  • Klucz zasobu usługi Mowa i region. Po wdrożeniu zasobu usługi Mowa wybierz pozycję Przejdź do zasobu , aby wyświetlić klucze i zarządzać nimi. Aby uzyskać więcej informacji na temat zasobów usług Azure AI, zobacz Pobieranie kluczy dla zasobu.

Instalowanie zestawu SPEECH SDK i przykładów

Repozytorium Azure-Samples/cognitive-services-speech-sdk zawiera przykłady napisane w języku Objective-C dla systemów iOS i Mac. Wybierz link, aby wyświetlić instrukcje instalacji dla każdego przykładu:

Używanie niestandardowego punktu końcowego

Niestandardowy punkt końcowy jest funkcjonalnie identyczny ze standardowym punktem końcowym używanym do obsługi żądań zamiany tekstu na mowę.

Jedną z różnic jest to, że należy określić, EndpointId aby używać niestandardowego głosu za pośrednictwem zestawu SPEECH SDK. Możesz rozpocząć od tekstu w przewodniku Szybki start do mowy, a następnie zaktualizować kod za pomocą elementu EndpointId i SpeechSynthesisVoiceName.

SPXSpeechConfiguration *speechConfig = [[SPXSpeechConfiguration alloc] initWithSubscription:speechKey region:speechRegion];
speechConfig.speechSynthesisVoiceName = @"YourCustomVoiceName";
speechConfig.EndpointId = @"YourEndpointId";

Aby użyć głosu niestandardowego za pomocą języka SSML (Speech Synthesis Markup Language), określ nazwę modelu jako nazwę głosu. W tym przykładzie użyto YourCustomVoiceName głosu.

<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="en-US">
    <voice name="YourCustomVoiceName">
        This is the text that is spoken. 
    </voice>
</speak>

Uruchamianie i używanie kontenera

Kontenery mowy udostępniają internetowe interfejsy API punktów końcowych zapytań oparte na protokole Websocket, które są dostępne za pośrednictwem zestawu SPEECH SDK i interfejsu wiersza polecenia usługi Mowa. Domyślnie zestaw SDK usługi Mowa i interfejs wiersza polecenia usługi Mowa używają publicznej usługi rozpoznawania mowy. Aby użyć kontenera, należy zmienić metodę inicjowania. Użyj adresu URL hosta kontenera zamiast klucza i regionu.

Aby uzyskać więcej informacji na temat kontenerów, zobacz Instalowanie i uruchamianie kontenerów usługi Mowa za pomocą platformy Docker.

Dokumentacja referencyjna Pakietu (Pobierz) | Dodatkowe przykłady w usłudze GitHub |

W tym przewodniku z instrukcjami poznasz typowe wzorce projektowe służące do wykonywania syntezy mowy w tekście.

Aby uzyskać więcej informacji na temat następujących obszarów, zobacz Co to jest zamiana tekstu na mowę?

  • Uzyskiwanie odpowiedzi jako strumieni w pamięci.
  • Dostosowywanie szybkości próbkowania danych wyjściowych i szybkości bitów.
  • Przesyłanie żądań syntezy przy użyciu języka znaczników syntezy mowy (SSML).
  • Korzystanie z głosów neuronowych.
  • Subskrybowanie zdarzeń i działanie na podstawie wyników.

Wymagania wstępne

  • Subskrypcja platformy Azure — utwórz jedną bezpłatnie.
  • Utwórz zasób usługi Mowa w witrynie Azure Portal.
  • Klucz zasobu usługi Mowa i region. Po wdrożeniu zasobu usługi Mowa wybierz pozycję Przejdź do zasobu , aby wyświetlić klucze i zarządzać nimi. Aby uzyskać więcej informacji na temat zasobów usług Azure AI, zobacz Pobieranie kluczy dla zasobu.

Instalowanie zestawu SPEECH SDK i przykładów

Repozytorium Azure-Samples/cognitive-services-speech-sdk zawiera przykłady napisane w języku Swift dla systemów iOS i Mac. Wybierz link, aby wyświetlić instrukcje instalacji dla każdego przykładu:

Uruchamianie i używanie kontenera

Kontenery mowy udostępniają internetowe interfejsy API punktów końcowych zapytań oparte na protokole Websocket, które są dostępne za pośrednictwem zestawu SPEECH SDK i interfejsu wiersza polecenia usługi Mowa. Domyślnie zestaw SDK usługi Mowa i interfejs wiersza polecenia usługi Mowa używają publicznej usługi rozpoznawania mowy. Aby użyć kontenera, należy zmienić metodę inicjowania. Użyj adresu URL hosta kontenera zamiast klucza i regionu.

Aby uzyskać więcej informacji na temat kontenerów, zobacz Instalowanie i uruchamianie kontenerów usługi Mowa za pomocą platformy Docker.

Dokumentacja referencyjna | Package (PyPi) | Dodatkowe przykłady w witrynie GitHub

W tym przewodniku z instrukcjami poznasz typowe wzorce projektowe służące do wykonywania syntezy mowy w tekście.

Aby uzyskać więcej informacji na temat następujących obszarów, zobacz Co to jest zamiana tekstu na mowę?

  • Uzyskiwanie odpowiedzi jako strumieni w pamięci.
  • Dostosowywanie szybkości próbkowania danych wyjściowych i szybkości bitów.
  • Przesyłanie żądań syntezy przy użyciu języka znaczników syntezy mowy (SSML).
  • Korzystanie z głosów neuronowych.
  • Subskrybowanie zdarzeń i działanie na podstawie wyników.

Wybieranie języka syntezy i głosu

Funkcja zamiany tekstu na mowę w usłudze Mowa obsługuje ponad 400 głosów i ponad 140 języków i wariantów. Pełną listę możesz uzyskać lub wypróbować w galerii głosów.

Określ język lub głos, SpeechConfig aby dopasować tekst wejściowy i użyć określonego głosu:

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

Wszystkie neuronowe głosy są wielojęzyczne i płynne we własnym języku i języku angielskim. Jeśli na przykład tekst wejściowy w języku angielskim to "Jestem podekscytowany, aby spróbować zamiany tekstu na mowę", a następnie wybierzesz es-ES-ElviraNeuraltekst mówiony w języku angielskim z hiszpańskim akcentem.

Jeśli głos nie mówi w języku tekstu wejściowego, usługa rozpoznawania mowy nie tworzy syntetyzowanego dźwięku. Aby uzyskać pełną listę obsługiwanych głosów neuronowych, zobacz Obsługa języka i głosu dla usługi Mowa.

Uwaga

Domyślny głos to pierwszy głos zwracany na ustawienia regionalne z interfejsu API listy głosowej.

Głos, który mówi, jest określany w kolejności priorytetu w następujący sposób:

  • Jeśli nie ustawisz SpeechSynthesisVoiceName lub SpeechSynthesisLanguage, domyślny głos mówi en-US .
  • Jeśli ustawisz SpeechSynthesisLanguagetylko , domyślny głos dla określonych ustawień regionalnych mówi.
  • Jeśli ustawienia i SpeechSynthesisVoiceNameSpeechSynthesisLanguage są ustawione, SpeechSynthesisLanguage ustawienie jest ignorowane. Głos, który określisz przy użyciu SpeechSynthesisVoiceName głosu.
  • Jeśli element głosowy jest ustawiony przy użyciu języka znaczników syntezy mowy (SSML),SpeechSynthesisVoiceName ustawienia i SpeechSynthesisLanguage są ignorowane.

Syntetyzowanie mowy do pliku

Utwórz obiekt SpeechSynthesizer. Ten obiekt uruchamia konwersje mowy na mowę i dane wyjściowe do osób mówiących, plików lub innych strumieni wyjściowych. SpeechSynthesizer akceptuje jako parametry:

  1. AudioOutputConfig Utwórz wystąpienie, aby automatycznie zapisywać dane wyjściowe w pliku .wav przy użyciu parametru konstruktorafilename:

    audio_config = speechsdk.audio.AudioOutputConfig(filename="path/to/write/file.wav")
    
  2. SpeechSynthesizer Utwórz wystąpienie, przekazując speech_config obiekt i audio_config obiekt jako parametry. Aby syntetyzować mowę i zapisywać w pliku, uruchom polecenie speak_text_async() z ciągiem tekstu.

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

Po uruchomieniu programu program tworzy syntetyzowany plik .wav , który jest zapisywany w określonej lokalizacji. Ten wynik jest dobrym przykładem najbardziej podstawowego użycia. Następnie możesz dostosować dane wyjściowe i obsłużyć odpowiedź wyjściową jako strumień w pamięci na potrzeby pracy ze scenariuszami niestandardowymi.

Syntetyzowanie do danych wyjściowych osoby mówiącej

Aby uzyskać syntetyzowany mowę do bieżącego aktywnego urządzenia wyjściowego, takiego jak głośnik, ustaw use_default_speaker parametr podczas tworzenia AudioOutputConfig wystąpienia. Oto przykład:

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

Uzyskiwanie wyniku jako strumienia w pamięci

Możesz użyć wynikowych danych dźwiękowych jako strumienia w pamięci, a nie bezpośredniego zapisywania w pliku. Za pomocą strumienia w pamięci można tworzyć niestandardowe zachowanie:

  • Abstrakcja wynikowej tablicy bajtów jako strumienia możliwego do wyszukiwania dla niestandardowych usług podrzędnych.
  • Zintegruj wynik z innymi interfejsami API lub usługami.
  • Zmodyfikuj dane audio, zapisz niestandardowe nagłówki .wav i wykonaj powiązane zadania.

Tę zmianę można wprowadzić w poprzednim przykładzie. Najpierw usuń AudioConfigelement , ponieważ ręcznie zarządzasz zachowaniem danych wyjściowych z tego punktu w celu zwiększenia kontroli. Przekaż None element AudioConfig w konstruktorze SpeechSynthesizer .

Uwaga

Przekazywanie None dla elementu AudioConfig, a nie pomijanie go tak jak w poprzednim przykładzie danych wyjściowych osoby mówiącej, nie odtwarza dźwięku domyślnie na bieżącym aktywnym urządzeniu wyjściowym.

Zapisz wynik w zmiennej SpeechSynthesisResult . Właściwość audio_data zawiera bytes obiekt danych wyjściowych. Możesz pracować z tym obiektem ręcznie lub użyć AudioDataStream klasy do zarządzania strumieniem w pamięci.

W tym przykładzie użyj konstruktora AudioDataStream , aby pobrać strumień z wyniku:

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

W tym momencie można zaimplementować dowolne zachowanie niestandardowe przy użyciu wynikowego stream obiektu.

Dostosowywanie formatu audio

Możesz dostosować atrybuty danych wyjściowych dźwięku, w tym:

  • Typ pliku audio
  • Częstotliwość próbkowania
  • Głębokość bitu

Aby zmienić format dźwięku, użyj set_speech_synthesis_output_format() funkcji w SpeechConfig obiekcie . Ta funkcja oczekuje enum wystąpienia typu SpeechSynthesisOutputFormat. Użyj polecenia , enum aby wybrać format danych wyjściowych. Aby uzyskać dostępne formaty, zobacz listę formatów audio.

Istnieją różne opcje dla różnych typów plików, w zależności od wymagań. Z definicji nieprzetworzone formaty, takie jak Raw24Khz16BitMonoPcm nie zawierają nagłówków dźwięku. Używaj formatów pierwotnych tylko w jednej z następujących sytuacji:

  • Wiesz, że implementacja podrzędna może dekodować nieprzetworzone strumienie bitowe.
  • Planujesz ręcznie tworzyć nagłówki na podstawie czynników, takich jak głębokość bitów, częstotliwość próbkowania i liczba kanałów.

W tym przykładzie określono format Riff24Khz16BitMonoPcm RIFF o wysokiej wierności, ustawiając SpeechSynthesisOutputFormat dla SpeechConfig obiektu. Podobnie jak w przykładzie w poprzedniej sekcji, użyj AudioDataStream polecenia , aby uzyskać strumień w pamięci wyniku, a następnie zapisać go w pliku.

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

result = speech_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")

Po uruchomieniu programu zapisuje plik .wav do określonej ścieżki.

Dostosowywanie cech mowy przy użyciu języka SSML

Za pomocą języka SSML można dostroić wysokość, wymowę, szybkość mówienia, głośność i inne aspekty w danych wyjściowych zamiany tekstu na mowę, przesyłając żądania ze schematu XML. W tej sekcji przedstawiono przykład zmiany głosu. Aby uzyskać więcej informacji, zobacz Omówienie języka znaczników syntezy mowy.

Aby rozpocząć korzystanie z języka SSML do dostosowywania, wprowadź niewielką zmianę, która przełącza głos.

  1. Utwórz nowy plik XML dla konfiguracji SSML w katalogu głównym projektu.

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

    W tym przykładzie plik jest ssml.xml. Element główny to zawsze <speak>. Zawijanie tekstu w elemecie <voice> umożliwia zmianę głosu przy użyciu parametru name . Aby uzyskać pełną listę obsługiwanych głosów neuronowych, zobacz Obsługiwane języki.

  2. Zmień żądanie syntezy mowy, aby odwołać się do pliku XML. Żądanie jest w większości takie samo. Zamiast używać speak_text_async() funkcji, użyj polecenia speak_ssml_async(). Ta funkcja oczekuje ciągu XML. Najpierw odczytaj konfigurację SSML jako ciąg. Od tego momentu obiekt wynikowy jest dokładnie taki sam jak w poprzednich przykładach.

    Uwaga

    Jeśli element ssml_string zawiera  na początku ciągu, musisz usunąć format BOM lub usługa zwróci błąd. W tym celu należy ustawić encoding parametr w następujący sposób: open("ssml.xml", "r", encoding="utf-8-sig").

    speech_synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config, audio_config=None)
    
    ssml_string = open("ssml.xml", "r").read()
    result = speech_synthesizer.speak_ssml_async(ssml_string).get()
    
    stream = speechsdk.AudioDataStream(result)
    stream.save_to_wav_file("path/to/write/file.wav")
    

Uwaga

Aby zmienić głos bez użycia języka SSML, możesz ustawić właściwość przy SpeechConfig użyciu polecenia speech_config.speech_synthesis_voice_name = "en-US-AvaMultilingualNeural".

Subskrybowanie zdarzeń syntezatora

Możesz chcieć uzyskać więcej szczegółowych informacji na temat przetwarzania i wyników zamiany tekstu na mowę. Na przykład możesz chcieć wiedzieć, kiedy syntetyzator uruchamia się i zatrzymuje, lub możesz chcieć wiedzieć o innych zdarzeniach napotkanych podczas syntezy.

Używając narzędzia SpeechSynthesizer do zamiany tekstu na mowę, możesz subskrybować zdarzenia w tej tabeli:

Wydarzenie opis Przypadek użycia
BookmarkReached Sygnały, że osiągnięto zakładkę. Aby wyzwolić zdarzenie osiągnięto zakładkę bookmark , element jest wymagany w języku SSML. To zdarzenie zgłasza czas, jaki upłynął w danych wyjściowych audio między rozpoczęciem syntezy a elementem bookmark . Właściwość zdarzenia Text to wartość ciągu ustawiona w atrybucie zakładki mark . bookmark Elementy nie są mówione. Możesz użyć bookmark elementu , aby wstawić niestandardowe znaczniki w języku SSML, aby uzyskać przesunięcie każdego znacznika w strumieniu audio. Element bookmark może służyć do odwoływania się do określonej lokalizacji w sekwencji tekstu lub tagu.
SynthesisCanceled Sygnały, że synteza mowy została anulowana. Możesz potwierdzić, kiedy synteza zostanie anulowana.
SynthesisCompleted Sygnały, że synteza mowy jest kompletna. Po zakończeniu syntezy można potwierdzić.
SynthesisStarted Sygnały, że rozpoczęła się synteza mowy. Możesz potwierdzić, kiedy rozpoczęto syntezę.
Synthesizing Sygnały, że synteza mowy jest w toku. To zdarzenie jest uruchamiane za każdym razem, gdy zestaw SDK otrzymuje fragment dźwięku z usługi Mowa. Możesz potwierdzić, kiedy synteza jest w toku.
VisemeReceived Sygnały, że odebrano zdarzenie viseme. Visemes są często używane do reprezentowania kluczowych pozy w obserwowanej mowie. Kluczowe pozy obejmują położenie ust, szczęki i języka w produkcji konkretnej fonemy. Możesz użyć visemes, aby animować twarz postaci jako dźwięk mowy odtwarzane.
WordBoundary Sygnały, że odebrano granicę słowa. To zdarzenie jest wywoływane na początku każdego nowego słowa mówionego, interpunkcyjnego i zdania. Zdarzenie zgłasza przesunięcie czasu bieżącego wyrazu w znacznikach od początku dźwięku wyjściowego. To zdarzenie zgłasza również położenie znaku w tekście wejściowym lub SSML bezpośrednio przed wyrazem, który ma być wypowiadany. To zdarzenie jest często używane do pobierania względnych pozycji tekstu i odpowiadającego mu dźwięku. Możesz chcieć wiedzieć o nowym słowie, a następnie podjąć działania na podstawie chronometrażu. Możesz na przykład uzyskać informacje, które mogą pomóc w podjęciu decyzji o tym, kiedy i jak długo będą wyróżniać wyrazy podczas ich wypowiadania.

Uwaga

Zdarzenia są zgłaszane, gdy dane wyjściowe audio staną się dostępne, co jest szybsze niż odtwarzanie na urządzeniu wyjściowym. Obiekt wywołujący musi odpowiednio synchronizować przesyłanie strumieniowe i w czasie rzeczywistym.

Oto przykład pokazujący sposób subskrybowania zdarzeń na potrzeby syntezy mowy. Postępuj zgodnie z instrukcjami w przewodniku Szybki start, ale zastąp zawartość tego pliku speech-synthesis.py następującym kodem w języku Python:

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-AvaMultilingualNeural'

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?")

Więcej przykładów zamiany tekstu na mowę można znaleźć w witrynie GitHub.

Używanie niestandardowego punktu końcowego

Niestandardowy punkt końcowy jest funkcjonalnie identyczny ze standardowym punktem końcowym używanym do obsługi żądań zamiany tekstu na mowę.

Jedną z różnic jest to, że należy określić, endpoint_id aby używać niestandardowego głosu za pośrednictwem zestawu SPEECH SDK. Możesz rozpocząć od tekstu w przewodniku Szybki start do mowy, a następnie zaktualizować kod za pomocą elementu endpoint_id i speech_synthesis_voice_name.

speech_config = speechsdk.SpeechConfig(subscription=os.environ.get('SPEECH_KEY'), region=os.environ.get('SPEECH_REGION'))
speech_config.endpoint_id = "YourEndpointId"
speech_config.speech_synthesis_voice_name = "YourCustomVoiceName"

Aby użyć głosu niestandardowego za pomocą języka SSML (Speech Synthesis Markup Language), określ nazwę modelu jako nazwę głosu. W tym przykładzie użyto YourCustomVoiceName głosu.

<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="en-US">
    <voice name="YourCustomVoiceName">
        This is the text that is spoken. 
    </voice>
</speak>

Uruchamianie i używanie kontenera

Kontenery mowy udostępniają internetowe interfejsy API punktów końcowych zapytań oparte na protokole Websocket, które są dostępne za pośrednictwem zestawu SPEECH SDK i interfejsu wiersza polecenia usługi Mowa. Domyślnie zestaw SDK usługi Mowa i interfejs wiersza polecenia usługi Mowa używają publicznej usługi rozpoznawania mowy. Aby użyć kontenera, należy zmienić metodę inicjowania. Użyj adresu URL hosta kontenera zamiast klucza i regionu.

Aby uzyskać więcej informacji na temat kontenerów, zobacz Instalowanie i uruchamianie kontenerów usługi Mowa za pomocą platformy Docker.

Interfejs API REST zamiany mowy na tekst — dokumentacja | interfejsu API REST zamiany mowy na tekst w celu uzyskania krótkiej dokumentacji | audio — dodatkowe przykłady w usłudze GitHub

W tym przewodniku z instrukcjami poznasz typowe wzorce projektowe służące do wykonywania syntezy mowy w tekście.

Aby uzyskać więcej informacji na temat następujących obszarów, zobacz Co to jest zamiana tekstu na mowę?

  • Uzyskiwanie odpowiedzi jako strumieni w pamięci.
  • Dostosowywanie szybkości próbkowania danych wyjściowych i szybkości bitów.
  • Przesyłanie żądań syntezy przy użyciu języka znaczników syntezy mowy (SSML).
  • Korzystanie z głosów neuronowych.
  • Subskrybowanie zdarzeń i działanie na podstawie wyników.

Wymagania wstępne

  • Subskrypcja platformy Azure — utwórz jedną bezpłatnie.
  • Utwórz zasób usługi Mowa w witrynie Azure Portal.
  • Klucz zasobu usługi Mowa i region. Po wdrożeniu zasobu usługi Mowa wybierz pozycję Przejdź do zasobu , aby wyświetlić klucze i zarządzać nimi. Aby uzyskać więcej informacji na temat zasobów usług Azure AI, zobacz Pobieranie kluczy dla zasobu.

Konwertowanie tekstu na mowę

W wierszu polecenia uruchom następujące polecenie. Wstaw następujące wartości do polecenia :

  • Klucz zasobu usługi Mowa
  • Region zasobu usługi Mowa

Możesz również zmienić następujące wartości:

  • Wartość nagłówka X-Microsoft-OutputFormat , która kontroluje format danych wyjściowych dźwięku. Listę obsługiwanych formatów danych wyjściowych audio można znaleźć w dokumentacji interfejsu API REST zamiany tekstu na mowę.
  • Głos wyjściowy. Aby uzyskać listę głosów dostępnych dla punktu końcowego usługi Mowa, zobacz interfejs API listy głosów.
  • Plik wyjściowy. W tym przykładzie kierujemy odpowiedź z serwera do pliku o nazwie output.mp3.
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 name='\''en-US-AvaMultilingualNeural'\''>
        I am excited to try text to speech
    </voice>
</speak>' > output.mp3

W tym przewodniku z instrukcjami poznasz typowe wzorce projektowe służące do wykonywania syntezy mowy w tekście.

Aby uzyskać więcej informacji na temat następujących obszarów, zobacz Co to jest zamiana tekstu na mowę?

  • Uzyskiwanie odpowiedzi jako strumieni w pamięci.
  • Dostosowywanie szybkości próbkowania danych wyjściowych i szybkości bitów.
  • Przesyłanie żądań syntezy przy użyciu języka znaczników syntezy mowy (SSML).
  • Korzystanie z głosów neuronowych.
  • Subskrybowanie zdarzeń i działanie na podstawie wyników.

Wymagania wstępne

  • Subskrypcja platformy Azure — utwórz jedną bezpłatnie.
  • Utwórz zasób usługi Mowa w witrynie Azure Portal.
  • Klucz zasobu usługi Mowa i region. Po wdrożeniu zasobu usługi Mowa wybierz pozycję Przejdź do zasobu , aby wyświetlić klucze i zarządzać nimi. Aby uzyskać więcej informacji na temat zasobów usług Azure AI, zobacz Pobieranie kluczy dla zasobu.

Pobierz i zainstaluj

Wykonaj następujące kroki i zapoznaj się z przewodnikiem Szybki start interfejsu wiersza polecenia usługi Mowa, aby uzyskać inne wymagania dotyczące platformy.

  1. Uruchom następujące polecenie interfejsu wiersza polecenia platformy .NET, aby zainstalować interfejs wiersza polecenia usługi Mowa:

    dotnet tool install --global Microsoft.CognitiveServices.Speech.CLI
    
  2. Uruchom następujące polecenia, aby skonfigurować klucz zasobu usługi Mowa i region. Zastąp SUBSCRIPTION-KEY ciąg kluczem zasobu usługi Mowa i zastąp REGION element regionem zasobu usługi Mowa.

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

Syntetyzowanie mowy przy użyciu głośnika

Teraz możesz uruchomić interfejs wiersza polecenia usługi Mowa, aby syntetyzować mowę z tekstu.

  • W oknie konsoli przejdź do katalogu zawierającego plik binarny interfejsu wiersza polecenia usługi Mowa. Uruchom następujące polecenie:

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

Interfejs wiersza polecenia usługi Mowa tworzy język naturalny w języku angielskim za pośrednictwem osoby mówiącej na komputerze.

Syntetyzowanie mowy do pliku

  • Uruchom następujące polecenie, aby zmienić dane wyjściowe z głośnika na plik .wav :

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

Interfejs wiersza polecenia usługi Mowa tworzy język naturalny w języku angielskim do pliku audio greetings.wav .

Uruchamianie i używanie kontenera

Kontenery mowy udostępniają internetowe interfejsy API punktów końcowych zapytań oparte na protokole Websocket, które są dostępne za pośrednictwem zestawu SPEECH SDK i interfejsu wiersza polecenia usługi Mowa. Domyślnie zestaw SDK usługi Mowa i interfejs wiersza polecenia usługi Mowa używają publicznej usługi rozpoznawania mowy. Aby użyć kontenera, należy zmienić metodę inicjowania. Użyj adresu URL hosta kontenera zamiast klucza i regionu.

Aby uzyskać więcej informacji na temat kontenerów, zobacz Instalowanie i uruchamianie kontenerów usługi Mowa za pomocą platformy Docker.

Następne kroki