Síntesis de voz a partir de texto

Documentación de referencia | Paquete (NuGet) | Ejemplos adicionales en GitHub

En esta guía paso a paso aprenderá modelos de diseño comunes para realizar la síntesis de texto a voz.

Para obtener más información sobre las siguientes áreas, consulte ¿Qué es el texto a voz?

  • Obtención de respuestas como secuencias en memoria
  • Personalización de la frecuencia de muestreo y la velocidad de bits de salida
  • Envío de solicitudes de síntesis mediante el lenguaje de marcado de síntesis de voz (SSML)
  • Uso de voces neuronales
  • Suscripción a eventos y actuación sobre los resultados.

Selección del idioma y la voz de síntesis

La característica de texto a voz en el servicio de Voz admite más de 400 voces y más de 140 idiomas y variantes. Puede obtener la lista completa o probarlos en la Galería de voces.

Especifique el idioma o la voz de SpeechConfig para que coincida con el texto de entrada y usar la voz especificada. El siguiente fragmento de código muestra cómo funciona esta técnica:

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

Todas las voces neuronales son multilingües y fluidas en su propio idioma y en inglés. Por ejemplo, si el texto de entrada en inglés es "I'm excited to try text to speech" (estoy encantado de probar texto a voz) y selecciona es-ES-ElviraNeural, el texto se hablará en inglés con acento español.

Si la voz no habla el idioma del texto de entrada, el servicio de Voz no crea audio sintetizado. Para obtener una lista completa de las voces neuronales admitidas, consulte Compatibilidad de idioma y voz con el servicio voz.

Nota:

La voz predeterminada es la primera voz devuelta por la configuración regional desde la API de lista de voz.

La voz que habla se determina en orden de prioridad de la siguiente manera:

  • Si no establece SpeechSynthesisVoiceName o SpeechSynthesisLanguage, habla la voz predeterminada para en-US.
  • Si solo establece SpeechSynthesisLanguage, habla la voz predeterminada para la configuración regional especificada.
  • Si se establecen SpeechSynthesisVoiceName y SpeechSynthesisLanguage, se omitirá la configuración SpeechSynthesisLanguage. Habla la voz que especifique mediante SpeechSynthesisVoiceName.
  • Si el elemento de voz se establece a través del lenguaje de marcado de síntesis de voz (SSML), se omiten los valores SpeechSynthesisVoiceName y SpeechSynthesisLanguage.

Síntesis de voz en un archivo

Cree un objeto SpeechSynthesizer. Este objeto, que se muestra en los siguientes fragmentos, ejecuta conversiones de texto a voz y envía la salida a altavoces, archivos u otras secuencias de salida. SpeechSynthesizer acepta como parámetros:

  • El objeto SpeechConfig que creó en el paso anterior.
  • Un objeto AudioConfig que especifica cómo se deben manejar los resultados de la salida.
  1. Cree una instancia de AudioConfig para escribir automáticamente la salida en un archivo .wav mediante la función FromWavFileOutput(). Cree una instancia de ella con una instrucción using.

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

    En este contexto, una instrucción using desecha automáticamente los recursos no administrados y hace que el objeto deje de estar dentro del ámbito después de la eliminación.

  2. Cree una instancia de SpeechSynthesizercon otra instrucción using. Pase el objeto speechConfig y el objeto audioConfig como parámetros. Para sintetizar la voz y escribir en un archivo, ejecute SpeakTextAsync() con una cadena de texto.

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

Al ejecutar el programa, crea un archivo .wav sintetizado, que se escribe en la ubicación especificada. Este resultado es un buen ejemplo del uso más básico. A continuación, puede personalizar la salida y controlar la respuesta de la salida como una secuencia en memoria para trabajar con escenarios personalizados.

Síntesis a la salida de altavoz

Para generar voz sintetizada en el dispositivo de salida activo actual, como un altavoz, omita el parámetro AudioConfig al crear la instancia SpeechSynthesizer. Este es un ejemplo:

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

Obtención de un resultado en forma de secuencia en memoria

Puede usar los datos de audio resultantes como una transmisión en memoria en vez de escribirlos directamente en un archivo. Con la transmisión en memoria, puede crear comportamientos personalizados:

  • Abstraer la matriz de bytes resultante como una secuencia que permita la búsqueda para los servicios de bajada personalizados
  • Integrar el resultado con otros servicios o API
  • Modificar los datos de audio, escribir encabezados .wav personalizados y hacer tareas relacionadas.

Puede realizar este cambio en el ejemplo anterior. En primer lugar, quite el bloqueo de AudioConfig, porque a partir de este momento administra el comportamiento de la salida de forma manual, ya que así obtiene mayor control. Pase null para AudioConfig en el constructor SpeechSynthesizer.

Nota:

Al usar null para AudioConfig, en lugar de omitirlo como lo hizo en el ejemplo de salida del altavoz anterior, el audio no se reproduce de manera predeterminada en el dispositivo de salida activo actual.

Guarde el resultado en una variable SpeechSynthesisResult. La propiedad AudioData contiene una instancia de byte [] para los datos de salida. Puede trabajar manualmente con esta instancia de byte [], o bien puede usar la clase AudioDataStream para administrar la secuencia en memoria.

En este ejemplo, se usa la función estática AudioDataStream.FromResult() para obtener una secuencia del resultado:

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

A partir de aquí, se puede implementar cualquier comportamiento personalizado mediante el objeto stream resultante.

Personalización del formato de audio

Puede personalizar los atributos de salida de audio, incluidos:

  • Tipo de archivo de audio
  • Frecuencia de muestreo
  • Profundidad en bits

Para cambiar el formato de audio se usa la función SetSpeechSynthesisOutputFormat() en el objeto SpeechConfig. Esta función espera una instancia enum de tipo SpeechSynthesisOutputFormat. Use el enum para seleccionar el formato de salida. Para ver los formatos disponibles, consulte la lista de formatos de audio.

Hay varias opciones para los distintos tipos de archivo, por lo que puede elegir la que cumpla con sus requisitos. Por definición, los formatos sin procesar, como Raw24Khz16BitMonoPcm, no incluyen encabezados de audio. Use formatos sin procesar solo en una de estas situaciones:

  • Sabe que la implementación de bajada puede descodificar una secuencia de bits sin procesar.
  • Tiene previsto compilar manualmente encabezados en función de factores como la profundidad de bits, la frecuencia de muestreo y el número de canales.

En este ejemplo, se especifica el formato RIFF de alta fidelidad Riff24Khz16BitMonoPcm, para lo que se establece SpeechSynthesisOutputFormat en el objeto SpeechConfig. Al igual que en el ejemplo de la sección anterior, se usa AudioDataStream para obtener una secuencia en memoria del resultado y, después, escribirla en un archivo.

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

Al ejecutar el programa, escribe un archivo .wav en la ruta de acceso especificada.

Uso de SSML para personalizar las características de la voz

Puede usar SSML para ajustar el tono, la pronunciación, la velocidad del habla, el volumen y otros aspectos de la salida de texto a voz mediante el envío de solicitudes desde un lenguaje de definición de esquema XML. En esta sección, se muestra un ejemplo de cómo cambiar la voz. Para obtener más información, consulte Información general del Lenguaje de marcado de síntesis de voz.

Para empezar a usar SSML para la personalización, realice un cambio mínimo que cambie la voz.

  1. Cree un archivo XML para la configuración de SSML en el directorio raíz del proyecto.

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

    En este ejemplo, el archivo es ssml.xml. El elemento raíz siempre es <speak>. Ajustar el texto en un elemento <voice> permite cambiar la voz mediante el parámetro name. Hay una lista completa de voces neuronales admitidas, consulte Idiomas admitidos.

  2. Cambiar la solicitud de síntesis de voz para que haga referencia al archivo XML. La solicitud es básicamente la misma, pero en lugar de usar la función SpeakTextAsync(), se usa SpeakSsmlAsync(). Esta función espera una cadena XML. En primer lugar, cargue su configuración SSML como una cadena mediante File.ReadAllText(). Desde aquí, el objeto del resultado es exactamente el mismo que el de los ejemplos anteriores.

    Nota:

    Si usa Visual Studio, es probable que la configuración de compilación no encuentre el archivo XML de manera predeterminada. Haga clic con el botón derecho en el archivo XML y seleccione Propiedades. Cambie Acción de compilación a Contenido. Cambie Copiar en el directorio de salida a Copiar siempre.

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

Nota:

Para cambiar la voz sin usar SSML, puede establecer la propiedad en SpeechConfig mediante SpeechConfig.SpeechSynthesisVoiceName = "en-US-AvaMultilingualNeural";.

Suscripción a eventos del sintetizador

Es posible que quiera obtener más información sobre el procesamiento de texto a voz y los resultados. Por ejemplo, puede que quiera saber cuándo se inicia y detiene el sintetizador, o que desee conocer otros eventos que se han encontrado durante la síntesis.

Al usar SpeechSynthesizer para texto a voz, puede suscribirse a los eventos de esta tabla:

Evento Descripción Caso de uso
BookmarkReached Indica que se alcanzó un marcador. Para desencadenar un evento de marcador alcanzado, se requiere un elemento bookmark en SSML. Este evento informa del tiempo transcurrido del audio de salida entre el inicio de la síntesis y el elemento bookmark. La propiedad del evento Text es el valor de cadena que estableció en el atributo mark del marcador. Los elementos bookmark no se hablan. Puede usar el elemento bookmark para insertar marcadores personalizados en SSML para obtener el desplazamiento de cada marcador en la secuencia de audio. El elemento bookmark se puede usar para hacer referencia a una ubicación específica en el texto o la secuencia de etiquetas.
SynthesisCanceled Indica que se canceló la síntesis de voz. Puede confirmar cuándo se ha cancelado la síntesis.
SynthesisCompleted Indica que la síntesis de voz se ha completado. Puede confirmar cuándo se ha completado la síntesis.
SynthesisStarted Indica que se ha iniciado la síntesis de voz. Puede confirmar cuándo se ha iniciado la síntesis.
Synthesizing Indica que la síntesis de voz está en curso. Este evento se desencadena cada vez que el SDK recibe un fragmento de audio del servicio Voz. Puede confirmar cuándo está la síntesis en curso.
VisemeReceived Indica que se recibió un evento de visema. Los visemas se suelen usar para representar los principales planteamientos de la voz observada. Entre los planteamientos clave se incluye la posición de los labios, la mandíbula y la lengua al generar un fonema determinado. Puede usar los visemas para animar la cara de un personaje mientras se reproduce el audio de voz.
WordBoundary Indica que se recibió un límite de palabras. Este evento se genera al principio de cada palabra hablada, puntuación y frases nuevas. El evento informa del desplazamiento de tiempo de la palabra actual, en tics, desde el principio del audio de salida. Este evento notifica la posición de un carácter en la cadena de entrada o SSML inmediatamente antes de la palabra que se va a pronunciar. Este evento se suele usar para obtener posiciones relativas del texto y el audio correspondiente. Es posible que quiera conocer una palabra nueva y, después, tomar medidas en función del tiempo. Por ejemplo, puede obtener información que pueda ayudarle a decidir cuándo y durante cuánto tiempo se resaltan las palabras mientras se dicen.

Nota:

Los eventos se generan cuando los datos de audio de salida están disponibles, lo que es más rápido que la reproducción en un dispositivo de salida. El autor de la llamada debe sincronizar correctamente el streaming y el tiempo real.

Este es un ejemplo que muestra cómo suscribirse a eventos para la síntesis de voz. Puede seguir las instrucciones del inicio rápido, pero reemplace el contenido de ese archivo Program.cs por el siguiente código de 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();
    }
}

Puede encontrar más muestras de texto a voz en GitHub.

Uso de un punto de conexión personalizado

El punto de conexión personalizado es funcionalmente idéntico al punto de conexión estándar que se usa en las solicitudes de texto a voz.

Una diferencia es que EndpointId debe especificarse para usar la voz personalizada a través del SDK de Voz. Puede empezar con el inicio rápido de texto a voz y, a continuación, actualizar el código con EndpointId y SpeechSynthesisVoiceName.

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

Para usar una voz personalizada mediante el lenguaje de marcado de síntesis de voz (SSML), especifique el nombre del modelo como nombre de voz. En este ejemplo se usa la voz YourCustomVoiceName.

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

Ejecutar y usar un contenedor

Los contenedores de voz proporcionan API de punto de conexión de consulta basadas en websocket a las que se accede a través del SDK de Voz y la CLI de Voz. De forma predeterminada, el SDK de Voz y la CLI de Voz usan el servicio de Voz público. Para usar el contenedor, deberá cambiar el método de inicialización. Use una dirección URL de host de contenedor en lugar de la clave y la región.

Para obtener más información sobre los contenedores, consulta Instalar y ejecutar contenedores de voz con Docker.

Documentación de referencia | Paquete (NuGet) | Ejemplos adicionales en GitHub

En esta guía paso a paso aprenderá modelos de diseño comunes para realizar la síntesis de texto a voz.

Para obtener más información sobre las siguientes áreas, consulte ¿Qué es el texto a voz?

  • Obtención de respuestas como secuencias en memoria
  • Personalización de la frecuencia de muestreo y la velocidad de bits de salida
  • Envío de solicitudes de síntesis mediante el lenguaje de marcado de síntesis de voz (SSML)
  • Uso de voces neuronales
  • Suscripción a eventos y actuación sobre los resultados.

Selección del idioma y la voz de síntesis

La característica de texto a voz en el servicio de Voz admite más de 400 voces y más de 140 idiomas y variantes. Consulte la lista completa de configuraciones regionales de texto a voz admitidas o pruébelas en la Galería de voces.

Especifique el idioma o la voz de la clase SpeechConfig para que coincida con el texto de entrada y usar la voz especificada. El siguiente fragmento de código muestra cómo funciona esta técnica:

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

Todas las voces neuronales son multilingües y fluidas en su propio idioma y en inglés. Por ejemplo, si el texto de entrada en inglés es «I'm excited to try text to speech» (estoy encantado de probar texto a voz) y establece es-ES-ElviraNeural, el texto se hablará en inglés con acento español.

Si la voz no habla el idioma del texto de entrada, el servicio de Voz no crea audio sintetizado. Para obtener una lista completa de las voces neuronales admitidas, consulte Compatibilidad de idioma y voz con el servicio voz.

Nota:

La voz predeterminada es la primera voz devuelta por la configuración regional desde la API de lista de voz.

La voz que habla se determina en orden de prioridad de la siguiente manera:

  • Si no establece SpeechSynthesisVoiceName o SpeechSynthesisLanguage, habla la voz predeterminada para en-US.
  • Si solo establece SpeechSynthesisLanguage, habla la voz predeterminada para la configuración regional especificada.
  • Si se establecen SpeechSynthesisVoiceName y SpeechSynthesisLanguage, se omitirá la configuración SpeechSynthesisLanguage. Habla la voz que especifique mediante SpeechSynthesisVoiceName.
  • Si el elemento de voz se establece a través del lenguaje de marcado de síntesis de voz (SSML), se omiten los valores SpeechSynthesisVoiceName y SpeechSynthesisLanguage.

Síntesis de voz en un archivo

Cree un objeto SpeechSynthesizer. Este objeto, que se muestra en los siguientes fragmentos, ejecuta conversiones de texto a voz y envía la salida a altavoces, archivos u otras secuencias de salida. SpeechSynthesizer acepta como parámetros:

  • El objeto SpeechConfig que creó en el paso anterior.
  • Un objeto AudioConfig que especifica cómo se deben manejar los resultados de la salida.
  1. Cree una instancia de AudioConfig para escribir automáticamente la salida en un archivo .wav mediante la función FromWavFileOutput():

    void synthesizeSpeech()
    {
        auto speechConfig = SpeechConfig::FromSubscription("YourSpeechKey", "YourSpeechRegion");
        auto audioConfig = AudioConfig::FromWavFileOutput("path/to/write/file.wav");
    }
    
  2. Cree una instancia SpeechSynthesizer. Pase el objeto speechConfig y el objeto audioConfig como parámetros. Para sintetizar la voz y escribir en un archivo, ejecute SpeakTextAsync() con una cadena de texto.

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

Al ejecutar el programa, crea un archivo .wav sintetizado, que se escribe en la ubicación especificada. Este resultado es un buen ejemplo del uso más básico. A continuación, puede personalizar la salida y controlar la respuesta de la salida como una secuencia en memoria para trabajar con escenarios personalizados.

Síntesis a la salida de altavoz

Para generar voz sintetizada en el dispositivo de salida activo actual, como un altavoz, omita el parámetro AudioConfig al crear la instancia SpeechSynthesizer. Este es un ejemplo:

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

Obtención de un resultado en forma de secuencia en memoria

Puede usar los datos de audio resultantes como una transmisión en memoria en vez de escribirlos directamente en un archivo. Con la transmisión en memoria, puede crear comportamientos personalizados:

  • Abstraer la matriz de bytes resultante como una secuencia que permita la búsqueda para los servicios de bajada personalizados
  • Integrar el resultado con otros servicios o API
  • Modificar los datos de audio, escribir encabezados .wav personalizados y hacer tareas relacionadas.

Puede realizar este cambio en el ejemplo anterior. En primer lugar, quite el bloqueo de AudioConfig, porque a partir de este momento administra el comportamiento de la salida de forma manual, ya que así obtiene mayor control. Pase NULL para AudioConfig en el constructor SpeechSynthesizer.

Nota:

Al usar NULL para AudioConfig, en lugar de omitirlo como lo hizo en el ejemplo de salida del altavoz anterior, el audio no se reproduce de manera predeterminada en el dispositivo de salida activo actual.

Guarde el resultado en una variable SpeechSynthesisResult. El captador GetAudioData devuelve una instancia de byte [] para los datos de salida. Puede trabajar manualmente con esta instancia de byte [], o bien puede usar la clase AudioDataStream para administrar la secuencia en memoria.

En este ejemplo, se usa la función estática AudioDataStream.FromResult() para obtener una secuencia del resultado:

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

A partir de aquí, se puede implementar cualquier comportamiento personalizado mediante el objeto stream resultante.

Personalización del formato de audio

Puede personalizar los atributos de salida de audio, incluidos:

  • Tipo de archivo de audio
  • Frecuencia de muestreo
  • Profundidad en bits

Para cambiar el formato de audio se usa la función SetSpeechSynthesisOutputFormat() en el objeto SpeechConfig. Esta función espera una instancia enum de tipo SpeechSynthesisOutputFormat. Use el enum para seleccionar el formato de salida. Para ver los formatos disponibles, consulte la lista de formatos de audio.

Hay varias opciones para los distintos tipos de archivo, por lo que puede elegir la que cumpla con sus requisitos. Por definición, los formatos sin procesar, como Raw24Khz16BitMonoPcm, no incluyen encabezados de audio. Use formatos sin procesar solo en una de estas situaciones:

  • Sabe que la implementación de bajada puede descodificar una secuencia de bits sin procesar.
  • Tiene previsto compilar manualmente encabezados en función de factores como la profundidad de bits, la frecuencia de muestreo y el número de canales.

En este ejemplo, se especifica el formato RIFF de alta fidelidad Riff24Khz16BitMonoPcm, para lo que se establece SpeechSynthesisOutputFormat en el objeto SpeechConfig. Al igual que en el ejemplo de la sección anterior, se usa AudioDataStream para obtener una secuencia en memoria del resultado y, después, escribirla en un archivo.

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

Al ejecutar el programa, escribe un archivo .wav en la ruta de acceso especificada.

Uso de SSML para personalizar las características de la voz

Puede usar SSML para ajustar el tono, la pronunciación, la velocidad del habla, el volumen y otros aspectos de la salida de texto a voz mediante el envío de solicitudes desde un lenguaje de definición de esquema XML. En esta sección, se muestra un ejemplo de cómo cambiar la voz. Para obtener más información, consulte Información general del Lenguaje de marcado de síntesis de voz.

Para empezar a usar SSML para la personalización, realice un cambio mínimo que cambie la voz.

  1. Cree un archivo XML para la configuración de SSML en el directorio raíz del proyecto.

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

    En este ejemplo, el archivo es ssml.xml. El elemento raíz siempre es <speak>. Ajustar el texto en un elemento <voice> permite cambiar la voz mediante el parámetro name. Hay una lista completa de voces neuronales admitidas, consulte Idiomas admitidos.

  2. Cambiar la solicitud de síntesis de voz para que haga referencia al archivo XML. La solicitud es principalmente la misma. En lugar de usar la función SpeakTextAsync(), se usa SpeakSsmlAsync(). Esta función espera una cadena XML. En primer lugar, cargue su configuración SSML como una cadena. Desde aquí, el objeto del resultado es exactamente el mismo que el de los ejemplos anteriores.

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

Nota:

Para cambiar la voz sin usar SSML, puede establecer la propiedad en SpeechConfig mediante SpeechConfig.SetSpeechSynthesisVoiceName("en-US-AndrewMultilingualNeural").

Suscripción a eventos del sintetizador

Es posible que quiera obtener más información sobre el procesamiento de texto a voz y los resultados. Por ejemplo, puede que quiera saber cuándo se inicia y detiene el sintetizador, o que desee conocer otros eventos que se han encontrado durante la síntesis.

Al usar SpeechSynthesizer para texto a voz, puede suscribirse a los eventos de esta tabla:

Evento Descripción Caso de uso
BookmarkReached Indica que se alcanzó un marcador. Para desencadenar un evento de marcador alcanzado, se requiere un elemento bookmark en SSML. Este evento informa del tiempo transcurrido del audio de salida entre el inicio de la síntesis y el elemento bookmark. La propiedad del evento Text es el valor de cadena que estableció en el atributo mark del marcador. Los elementos bookmark no se hablan. Puede usar el elemento bookmark para insertar marcadores personalizados en SSML para obtener el desplazamiento de cada marcador en la secuencia de audio. El elemento bookmark se puede usar para hacer referencia a una ubicación específica en el texto o la secuencia de etiquetas.
SynthesisCanceled Indica que se canceló la síntesis de voz. Puede confirmar cuándo se ha cancelado la síntesis.
SynthesisCompleted Indica que la síntesis de voz se ha completado. Puede confirmar cuándo se ha completado la síntesis.
SynthesisStarted Indica que se ha iniciado la síntesis de voz. Puede confirmar cuándo se ha iniciado la síntesis.
Synthesizing Indica que la síntesis de voz está en curso. Este evento se desencadena cada vez que el SDK recibe un fragmento de audio del servicio Voz. Puede confirmar cuándo está la síntesis en curso.
VisemeReceived Indica que se recibió un evento de visema. Los visemas se suelen usar para representar los principales planteamientos de la voz observada. Entre los planteamientos clave se incluye la posición de los labios, la mandíbula y la lengua al generar un fonema determinado. Puede usar los visemas para animar la cara de un personaje mientras se reproduce el audio de voz.
WordBoundary Indica que se recibió un límite de palabras. Este evento se genera al principio de cada palabra hablada, puntuación y frases nuevas. El evento informa del desplazamiento de tiempo de la palabra actual, en tics, desde el principio del audio de salida. Este evento notifica la posición de un carácter en la cadena de entrada o SSML inmediatamente antes de la palabra que se va a pronunciar. Este evento se suele usar para obtener posiciones relativas del texto y el audio correspondiente. Es posible que quiera conocer una palabra nueva y, después, tomar medidas en función del tiempo. Por ejemplo, puede obtener información que pueda ayudarle a decidir cuándo y durante cuánto tiempo se resaltan las palabras mientras se dicen.

Nota:

Los eventos se generan cuando los datos de audio de salida están disponibles, lo que es más rápido que la reproducción en un dispositivo de salida. El autor de la llamada debe sincronizar correctamente el streaming y el tiempo real.

Este es un ejemplo que muestra cómo suscribirse a eventos para la síntesis de voz. Puede seguir las instrucciones del inicio rápido, pero reemplace el contenido de ese archivo main.cpp por el siguiente código:

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

Puede encontrar más muestras de texto a voz en GitHub.

Uso de un punto de conexión personalizado

El punto de conexión personalizado es técnicamente idéntico al punto de conexión estándar que se usa en las solicitudes de texto a voz.

Una diferencia es que EndpointId debe especificarse para usar la voz personalizada a través del SDK de Voz. Puede empezar con el inicio rápido de texto a voz y, a continuación, actualizar el código con EndpointId y SpeechSynthesisVoiceName.

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

Para usar una voz personalizada mediante el lenguaje de marcado de síntesis de voz (SSML), especifique el nombre del modelo como nombre de voz. En este ejemplo se usa la voz YourCustomVoiceName.

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

Ejecutar y usar un contenedor

Los contenedores de voz proporcionan API de punto de conexión de consulta basadas en websocket a las que se accede a través del SDK de Voz y la CLI de Voz. De forma predeterminada, el SDK de Voz y la CLI de Voz usan el servicio de Voz público. Para usar el contenedor, deberá cambiar el método de inicialización. Use una dirección URL de host de contenedor en lugar de la clave y la región.

Para obtener más información sobre los contenedores, consulta Instalar y ejecutar contenedores de voz con Docker.

Documentación de referencia | Paquete (Go) | Ejemplos adicionales en GitHub

En esta guía paso a paso aprenderá modelos de diseño comunes para realizar la síntesis de texto a voz.

Para obtener más información sobre las siguientes áreas, consulte ¿Qué es el texto a voz?

  • Obtención de respuestas como secuencias en memoria
  • Personalización de la frecuencia de muestreo y la velocidad de bits de salida
  • Envío de solicitudes de síntesis mediante el lenguaje de marcado de síntesis de voz (SSML)
  • Uso de voces neuronales
  • Suscripción a eventos y actuación sobre los resultados.

Requisitos previos

Instalación de Speech SDK

En primer lugar, debe instalar el SDK de Voz para Go.

Texto a voz para altavoz

Use el siguiente ejemplo de código para ejecutar la síntesis de voz para el dispositivo de salida de audio predeterminado. Reemplace las variables subscription y region por la clave de voz y la suscripción o región. La ejecución del script genera el texto de entrada hablado para el altavoz predeterminado.

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

Ejecute los comandos siguientes para crear un archivo go.mod que vincule a los componentes hospedados en GitHub:

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

Compile y ejecute ahora el código:

go build
go run quickstart

Para información detallada sobre las clases, consulte los documentos de referencia SpeechConfig y SpeechSynthesizer.

Texto a voz para emisión en memoria

Puede usar los datos de audio resultantes como una transmisión en memoria en vez de escribirlos directamente en un archivo. Con la transmisión en memoria, puede crear comportamientos personalizados:

  • Abstraer la matriz de bytes resultante como una secuencia que permita la búsqueda para los servicios de bajada personalizados
  • Integrar el resultado con otros servicios o API
  • Modificar los datos de audio, escribir encabezados .wav personalizados y hacer tareas relacionadas.

Puede realizar este cambio en el ejemplo anterior. Quite el bloqueo de AudioConfig, porque a partir de este momento administrará el comportamiento de la salida de forma manual, ya que así obtiene mayor control. Luego, pase nil para AudioConfig en el constructor SpeechSynthesizer.

Nota:

Al usar nil para AudioConfig, en lugar de omitirlo como lo hizo en el ejemplo de salida del altavoz anterior, el audio no se reproducirá de manera predeterminada en el dispositivo de salida activo actual.

Guarde el resultado en una variable SpeechSynthesisResult. La propiedad AudioData devuelve una instancia de []byte para los datos de salida. Puede trabajar manualmente con esta instancia de []byte, o bien puede usar la clase AudioDataStream para administrar la secuencia en memoria. En este ejemplo, se usa la función estática NewAudioDataStreamFromSpeechSynthesisResult() para obtener una secuencia del resultado.

Reemplace las variables subscription y region por la clave de voz y la ubicación o región:

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

Ejecute los comandos siguientes para crear un archivo go.mod que vincule a los componentes hospedados en GitHub:

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

Compile y ejecute ahora el código:

go build
go run quickstart

Para información detallada sobre las clases, consulte los documentos de referencia SpeechConfig y SpeechSynthesizer.

Selección del idioma y la voz de síntesis

La característica de texto a voz en el servicio de Voz admite más de 400 voces y más de 140 idiomas y variantes. Puede obtener la lista completa o probarlos en la Galería de voces.

Especifique el idioma o la voz de SpeechConfig para que coincida con el texto de entrada y usar la voz que prefiera:

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

Todas las voces neuronales son multilingües y fluidas en su propio idioma y en inglés. Por ejemplo, si el texto de entrada en inglés es «I'm excited to try text to speech» (estoy encantado de probar texto a voz) y establece es-ES-ElviraNeural, el texto se hablará en inglés con acento español.

Si la voz no habla el idioma del texto de entrada, el servicio de Voz no crea audio sintetizado. Para obtener una lista completa de las voces neuronales admitidas, consulte Compatibilidad de idioma y voz con el servicio voz.

Nota:

La voz predeterminada es la primera voz devuelta por la configuración regional desde la API de lista de voz.

La voz que habla se determina en orden de prioridad de la siguiente manera:

  • Si no establece SpeechSynthesisVoiceName o SpeechSynthesisLanguage, habla la voz predeterminada para en-US.
  • Si solo establece SpeechSynthesisLanguage, habla la voz predeterminada para la configuración regional especificada.
  • Si se establecen SpeechSynthesisVoiceName y SpeechSynthesisLanguage, se omitirá la configuración SpeechSynthesisLanguage. Habla la voz que especifique mediante SpeechSynthesisVoiceName.
  • Si el elemento de voz se establece a través del lenguaje de marcado de síntesis de voz (SSML), se omiten los valores SpeechSynthesisVoiceName y SpeechSynthesisLanguage.

Uso de SSML para personalizar las características de la voz

Puede usar el lenguaje de marcado de síntesis de voz (SSML) para ajustar el tono, la pronunciación, la velocidad del habla, el volumen, etc. de la salida de texto a voz mediante el envío de solicitudes desde un lenguaje de definición de esquema XML. En esta sección, se muestra un ejemplo de cómo cambiar la voz. Para obtener más información, consulte Información general del Lenguaje de marcado de síntesis de voz.

Para empezar a usar SSML para la personalización, realice un cambio mínimo que cambie la voz.

En primer lugar, cree un archivo XML para la configuración de SSML en el directorio raíz del proyecto. En este ejemplo, es ssml.xml. El elemento raíz siempre es <speak>. Ajustar el texto en un elemento <voice> permite cambiar la voz mediante el parámetro name. Hay una lista completa de voces neuronales admitidas, consulte Idiomas admitidos.

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

A continuación, debe cambiar la solicitud de síntesis de voz para que haga referencia al archivo XML. La solicitud es básicamente la misma, pero en lugar de usar la función SpeakTextAsync(), se usa SpeakSsmlAsync(). Esta función espera una cadena XML, por lo que lo primero que se debe hacer es cargar la configuración de SSML como una cadena. Desde aquí, el objeto del resultado es exactamente el mismo que el de los ejemplos anteriores.

Nota:

Para cambiar la voz sin usar SSML, puede establecer la propiedad en SpeechConfig mediante speechConfig.SetSpeechSynthesisVoiceName("en-US-AvaMultilingualNeural").

Suscripción a eventos del sintetizador

Es posible que quiera obtener más información sobre el procesamiento de texto a voz y los resultados. Por ejemplo, puede que quiera saber cuándo se inicia y detiene el sintetizador, o que desee conocer otros eventos que se han encontrado durante la síntesis.

Al usar SpeechSynthesizer para texto a voz, puede suscribirse a los eventos de esta tabla:

Evento Descripción Caso de uso
BookmarkReached Indica que se alcanzó un marcador. Para desencadenar un evento de marcador alcanzado, se requiere un elemento bookmark en SSML. Este evento informa del tiempo transcurrido del audio de salida entre el inicio de la síntesis y el elemento bookmark. La propiedad del evento Text es el valor de cadena que estableció en el atributo mark del marcador. Los elementos bookmark no se hablan. Puede usar el elemento bookmark para insertar marcadores personalizados en SSML para obtener el desplazamiento de cada marcador en la secuencia de audio. El elemento bookmark se puede usar para hacer referencia a una ubicación específica en el texto o la secuencia de etiquetas.
SynthesisCanceled Indica que se canceló la síntesis de voz. Puede confirmar cuándo se ha cancelado la síntesis.
SynthesisCompleted Indica que la síntesis de voz se ha completado. Puede confirmar cuándo se ha completado la síntesis.
SynthesisStarted Indica que se ha iniciado la síntesis de voz. Puede confirmar cuándo se ha iniciado la síntesis.
Synthesizing Indica que la síntesis de voz está en curso. Este evento se desencadena cada vez que el SDK recibe un fragmento de audio del servicio Voz. Puede confirmar cuándo está la síntesis en curso.
VisemeReceived Indica que se recibió un evento de visema. Los visemas se suelen usar para representar los principales planteamientos de la voz observada. Entre los planteamientos clave se incluye la posición de los labios, la mandíbula y la lengua al generar un fonema determinado. Puede usar los visemas para animar la cara de un personaje mientras se reproduce el audio de voz.
WordBoundary Indica que se recibió un límite de palabras. Este evento se genera al principio de cada palabra hablada, puntuación y frases nuevas. El evento informa del desplazamiento de tiempo de la palabra actual, en tics, desde el principio del audio de salida. Este evento notifica la posición de un carácter en la cadena de entrada o SSML inmediatamente antes de la palabra que se va a pronunciar. Este evento se suele usar para obtener posiciones relativas del texto y el audio correspondiente. Es posible que quiera conocer una palabra nueva y, después, tomar medidas en función del tiempo. Por ejemplo, puede obtener información que pueda ayudarle a decidir cuándo y durante cuánto tiempo se resaltan las palabras mientras se dicen.

Nota:

Los eventos se generan cuando los datos de audio de salida están disponibles, lo que es más rápido que la reproducción en un dispositivo de salida. El autor de la llamada debe sincronizar correctamente el streaming y el tiempo real.

Este es un ejemplo que muestra cómo suscribirse a eventos para la síntesis de voz. Puede seguir las instrucciones del inicio rápido, pero reemplace el contenido de ese archivo speech-synthesis.go por el siguiente código de 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)
        }
    }
}

Puede encontrar más muestras de texto a voz en GitHub.

Ejecutar y usar un contenedor

Los contenedores de voz proporcionan API de punto de conexión de consulta basadas en websocket a las que se accede a través del SDK de Voz y la CLI de Voz. De forma predeterminada, el SDK de Voz y la CLI de Voz usan el servicio de Voz público. Para usar el contenedor, deberá cambiar el método de inicialización. Use una dirección URL de host de contenedor en lugar de la clave y la región.

Para obtener más información sobre los contenedores, consulta Instalar y ejecutar contenedores de voz con Docker.

Documentación de referencia | Ejemplos adicionales en GitHub

En esta guía paso a paso aprenderá modelos de diseño comunes para realizar la síntesis de texto a voz.

Para obtener más información sobre las siguientes áreas, consulte ¿Qué es el texto a voz?

  • Obtención de respuestas como secuencias en memoria
  • Personalización de la frecuencia de muestreo y la velocidad de bits de salida
  • Envío de solicitudes de síntesis mediante el lenguaje de marcado de síntesis de voz (SSML)
  • Uso de voces neuronales
  • Suscripción a eventos y actuación sobre los resultados.

Selección del idioma y la voz de síntesis

La característica de texto a voz en el servicio de Voz admite más de 400 voces y más de 140 idiomas y variantes. Puede obtener la lista completa o probarlos en la Galería de voces.

Especifique el idioma o la voz de SpeechConfig para que coincida con el texto de entrada y usar la voz especificada. El siguiente fragmento de código muestra cómo funciona esta técnica:

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

Todas las voces neuronales son multilingües y fluidas en su propio idioma y en inglés. Por ejemplo, si el texto de entrada en inglés es «I'm excited to try text to speech» (estoy encantado de probar texto a voz) y establece es-ES-ElviraNeural, el texto se hablará en inglés con acento español.

Si la voz no habla el idioma del texto de entrada, el servicio de Voz no crea audio sintetizado. Para obtener una lista completa de las voces neuronales admitidas, consulte Compatibilidad de idioma y voz con el servicio voz.

Nota:

La voz predeterminada es la primera voz devuelta por la configuración regional desde la API de lista de voz.

La voz que habla se determina en orden de prioridad de la siguiente manera:

  • Si no establece SpeechSynthesisVoiceName o SpeechSynthesisLanguage, habla la voz predeterminada para en-US.
  • Si solo establece SpeechSynthesisLanguage, habla la voz predeterminada para la configuración regional especificada.
  • Si se establecen SpeechSynthesisVoiceName y SpeechSynthesisLanguage, se omitirá la configuración SpeechSynthesisLanguage. Habla la voz que haya especificado mediante SpeechSynthesisVoiceName.
  • Si el elemento de voz se establece a través del lenguaje de marcado de síntesis de voz (SSML), se omiten los valores SpeechSynthesisVoiceName y SpeechSynthesisLanguage.

Síntesis de voz en un archivo

Crear un objeto SpeechSynthesizer. Este objeto ejecuta conversiones de texto a voz y envía la salida a altavoces, archivos u otras secuencias de salida. SpeechSynthesizer acepta como parámetros:

  • El objeto SpeechConfig que creó en el paso anterior.
  • Un objeto AudioConfig que especifica cómo se deben manejar los resultados de la salida.
  1. Cree una instancia de AudioConfig para escribir automáticamente la salida en un archivo .wav mediante la función estática fromWavFileOutput():

    public static void main(String[] args) {
        SpeechConfig speechConfig = SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
        AudioConfig audioConfig = AudioConfig.fromWavFileOutput("path/to/write/file.wav");
    }
    
  2. Cree una instancia SpeechSynthesizer. Pase el objeto speechConfig y el objeto audioConfig como parámetros. Para sintetizar la voz y escribir en un archivo, ejecute SpeakText() con una cadena de texto.

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

Al ejecutar el programa, crea un archivo .wav sintetizado, que se escribe en la ubicación especificada. Este resultado es un buen ejemplo del uso más básico. A continuación, puede personalizar la salida y controlar la respuesta de la salida como una secuencia en memoria para trabajar con escenarios personalizados.

Síntesis a la salida de altavoz

Es posible que quiera obtener más información sobre el procesamiento de texto a voz y los resultados. Por ejemplo, puede que quiera saber cuándo se inicia y detiene el sintetizador, o que desee conocer otros eventos que se han encontrado durante la síntesis.

Para generar voz sintetizada en el dispositivo de salida activo actual, como un altavoz, cree una instancia AudioConfig mediante la función estática fromDefaultSpeakerOutput(). Este es un ejemplo:

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

Obtención de un resultado en forma de secuencia en memoria

Puede usar los datos de audio resultantes como una transmisión en memoria en vez de escribirlos directamente en un archivo. Con la transmisión en memoria, puede crear comportamientos personalizados:

  • Abstraer la matriz de bytes resultante como una secuencia que permita la búsqueda para los servicios de bajada personalizados
  • Integrar el resultado con otros servicios o API
  • Modificar los datos de audio, escribir encabezados .wav personalizados y hacer tareas relacionadas.

Puede realizar este cambio en el ejemplo anterior. En primer lugar, quite el bloqueo de AudioConfig, porque a partir de este momento administra el comportamiento de la salida de forma manual, ya que así obtiene mayor control. Luego, pase null para AudioConfig en el constructor SpeechSynthesizer.

Nota:

Al usar null para AudioConfig, en lugar de omitirlo como lo hizo en el ejemplo de salida del altavoz anterior, el audio no se reproduce de manera predeterminada en el dispositivo de salida activo actual.

Guarde el resultado en una variable SpeechSynthesisResult. La función SpeechSynthesisResult.getAudioData() devuelve una instancia de byte [] de los datos de salida. Puede trabajar manualmente con esta instancia de byte [], o bien puede usar la clase AudioDataStream para administrar la secuencia en memoria.

En este ejemplo, se usa la función estática AudioDataStream.fromResult() para obtener una secuencia del resultado:

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

A partir de aquí, se puede implementar cualquier comportamiento personalizado mediante el objeto stream resultante.

Personalización del formato de audio

Puede personalizar los atributos de salida de audio, incluidos:

  • Tipo de archivo de audio
  • Frecuencia de muestreo
  • Profundidad en bits

Para cambiar el formato de audio se usa la función setSpeechSynthesisOutputFormat() en el objeto SpeechConfig. Esta función espera una instancia enum de tipo SpeechSynthesisOutputFormat. Use el enum para seleccionar el formato de salida. Para ver los formatos disponibles, consulte la lista de formatos de audio.

Hay varias opciones para los distintos tipos de archivo, por lo que puede elegir la que cumpla con sus requisitos. Por definición, los formatos sin procesar, como Raw24Khz16BitMonoPcm, no incluyen encabezados de audio. Use formatos sin procesar solo en una de estas situaciones:

  • Sabe que la implementación de bajada puede descodificar una secuencia de bits sin procesar.
  • Tiene previsto compilar manualmente encabezados en función de factores como la profundidad de bits, la frecuencia de muestreo y el número de canales.

En este ejemplo, se especifica el formato RIFF de alta fidelidad Riff24Khz16BitMonoPcm, para lo que se establece SpeechSynthesisOutputFormat en el objeto SpeechConfig. Al igual que en el ejemplo de la sección anterior, se usa AudioDataStream para obtener una secuencia en memoria del resultado y, después, escribirla en un archivo.

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

Al ejecutar el programa, escribe un archivo .wav en la ruta de acceso especificada.

Uso de SSML para personalizar las características de la voz

Puede usar SSML para ajustar el tono, la pronunciación, la velocidad del habla, el volumen y otros aspectos de la salida de texto a voz mediante el envío de solicitudes desde un lenguaje de definición de esquema XML. En esta sección, se muestra un ejemplo de cómo cambiar la voz. Para obtener más información, consulte el artículo de instrucciones de SSML.

Para empezar a usar SSML para la personalización, realice un cambio mínimo que cambie la voz.

  1. Cree un archivo XML para la configuración de SSML en el directorio raíz del proyecto.

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

    En este ejemplo, el archivo es ssml.xml. El elemento raíz siempre es <speak>. Ajustar el texto en un elemento <voice> permite cambiar la voz mediante el parámetro name. Hay una lista completa de voces neuronales admitidas, consulte Idiomas admitidos.

  2. Cambiar la solicitud de síntesis de voz para que haga referencia al archivo XML. La solicitud es principalmente la misma. En lugar de usar la función SpeakText(), se usa SpeakSsml(). Esta función espera una cadena XML, por lo que primero debe crear una función para cargar un archivo XML y devolverlo como una cadena:

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

    En este punto, el objeto del resultado es exactamente el mismo que el de los ejemplos anteriores:

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

Nota:

Para cambiar la voz sin usar SSML, establezca la propiedad en SpeechConfig mediante SpeechConfig.setSpeechSynthesisVoiceName("en-US-AvaMultilingualNeural");.

Suscripción a eventos del sintetizador

Es posible que quiera obtener más información sobre el procesamiento de texto a voz y los resultados. Por ejemplo, puede que quiera saber cuándo se inicia y detiene el sintetizador, o que desee conocer otros eventos que se han encontrado durante la síntesis.

Al usar SpeechSynthesizer para texto a voz, puede suscribirse a los eventos de esta tabla:

Evento Descripción Caso de uso
BookmarkReached Indica que se alcanzó un marcador. Para desencadenar un evento de marcador alcanzado, se requiere un elemento bookmark en SSML. Este evento informa del tiempo transcurrido del audio de salida entre el inicio de la síntesis y el elemento bookmark. La propiedad del evento Text es el valor de cadena que estableció en el atributo mark del marcador. Los elementos bookmark no se hablan. Puede usar el elemento bookmark para insertar marcadores personalizados en SSML para obtener el desplazamiento de cada marcador en la secuencia de audio. El elemento bookmark se puede usar para hacer referencia a una ubicación específica en el texto o la secuencia de etiquetas.
SynthesisCanceled Indica que se canceló la síntesis de voz. Puede confirmar cuándo se ha cancelado la síntesis.
SynthesisCompleted Indica que la síntesis de voz se ha completado. Puede confirmar cuándo se ha completado la síntesis.
SynthesisStarted Indica que se ha iniciado la síntesis de voz. Puede confirmar cuándo se ha iniciado la síntesis.
Synthesizing Indica que la síntesis de voz está en curso. Este evento se desencadena cada vez que el SDK recibe un fragmento de audio del servicio Voz. Puede confirmar cuándo está la síntesis en curso.
VisemeReceived Indica que se recibió un evento de visema. Los visemas se suelen usar para representar los principales planteamientos de la voz observada. Entre los planteamientos clave se incluye la posición de los labios, la mandíbula y la lengua al generar un fonema determinado. Puede usar los visemas para animar la cara de un personaje mientras se reproduce el audio de voz.
WordBoundary Indica que se recibió un límite de palabras. Este evento se genera al principio de cada palabra hablada, puntuación y frases nuevas. El evento informa del desplazamiento de tiempo de la palabra actual, en tics, desde el principio del audio de salida. Este evento notifica la posición de un carácter en la cadena de entrada o SSML inmediatamente antes de la palabra que se va a pronunciar. Este evento se suele usar para obtener posiciones relativas del texto y el audio correspondiente. Es posible que quiera conocer una palabra nueva y, después, tomar medidas en función del tiempo. Por ejemplo, puede obtener información que pueda ayudarle a decidir cuándo y durante cuánto tiempo se resaltan las palabras mientras se dicen.

Nota:

Los eventos se generan cuando los datos de audio de salida están disponibles, lo que es más rápido que la reproducción en un dispositivo de salida. El autor de la llamada debe sincronizar correctamente el streaming y el tiempo real.

Este es un ejemplo que muestra cómo suscribirse a eventos para la síntesis de voz. Puede seguir las instrucciones del inicio rápido, pero reemplace el contenido de ese archivo SpeechSynthesis.java por el siguiente código 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);
    }
}

Puede encontrar más muestras de texto a voz en GitHub.

Uso de un punto de conexión personalizado

El punto de conexión personalizado es técnicamente idéntico al punto de conexión estándar que se usa en las solicitudes de texto a voz.

Una diferencia es que EndpointId debe especificarse para usar la voz personalizada a través del SDK de Voz. Puede empezar con el inicio rápido de texto a voz y, a continuación, actualizar el código con EndpointId y SpeechSynthesisVoiceName.

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

Para usar una voz personalizada mediante el lenguaje de marcado de síntesis de voz (SSML), especifique el nombre del modelo como nombre de voz. En este ejemplo se usa la voz YourCustomVoiceName.

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

Ejecutar y usar un contenedor

Los contenedores de voz proporcionan API de punto de conexión de consulta basadas en websocket a las que se accede a través del SDK de Voz y la CLI de Voz. De forma predeterminada, el SDK de Voz y la CLI de Voz usan el servicio de Voz público. Para usar el contenedor, deberá cambiar el método de inicialización. Use una dirección URL de host de contenedor en lugar de la clave y la región.

Para obtener más información sobre los contenedores, consulta Instalar y ejecutar contenedores de voz con Docker.

Documentación de referencia | Paquete (npm) | Ejemplos adicionales en GitHub | Código fuente de la biblioteca

En esta guía paso a paso aprenderá modelos de diseño comunes para realizar la síntesis de texto a voz.

Para obtener más información sobre las siguientes áreas, consulte ¿Qué es el texto a voz?

  • Obtención de respuestas como secuencias en memoria
  • Personalización de la frecuencia de muestreo y la velocidad de bits de salida
  • Envío de solicitudes de síntesis mediante el lenguaje de marcado de síntesis de voz (SSML)
  • Uso de voces neuronales
  • Suscripción a eventos y actuación sobre los resultados.

Selección del idioma y la voz de síntesis

La característica de texto a voz en el servicio de Voz admite más de 400 voces y más de 140 idiomas y variantes. Puede obtener la lista completa o probarlos en la Galería de voces.

Especifique el idioma o la voz de SpeechConfig para que coincida con el texto de entrada y usar la voz que prefiera:

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();

Todas las voces neuronales son multilingües y fluidas en su propio idioma y en inglés. Por ejemplo, si el texto de entrada en inglés es «I'm excited to try text to speech» (estoy encantado de probar texto a voz) y establece es-ES-ElviraNeural, el texto se hablará en inglés con acento español.

Si la voz no habla el idioma del texto de entrada, el servicio de Voz no crea audio sintetizado. Para obtener una lista completa de las voces neuronales admitidas, consulte Compatibilidad de idioma y voz con el servicio voz.

Nota:

La voz predeterminada es la primera voz devuelta por la configuración regional desde la API de lista de voz.

La voz que habla se determina en orden de prioridad de la siguiente manera:

  • Si no establece SpeechSynthesisVoiceName o SpeechSynthesisLanguage, habla la voz predeterminada para en-US.
  • Si solo establece SpeechSynthesisLanguage, habla la voz predeterminada para la configuración regional especificada.
  • Si se establecen SpeechSynthesisVoiceName y SpeechSynthesisLanguage, se omitirá la configuración SpeechSynthesisLanguage. Habla la voz que especifique mediante SpeechSynthesisVoiceName.
  • Si el elemento de voz se establece a través del lenguaje de marcado de síntesis de voz (SSML), se omiten los valores SpeechSynthesisVoiceName y SpeechSynthesisLanguage.

Síntesis de texto a voz

Para generar voz sintetizada en el dispositivo de salida activo actual, como un altavoz, cree una instancia AudioConfig mediante la función estática fromDefaultSpeakerOutput(). Este es un ejemplo:

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

Cuando ejecute el programa, se reproducirá un audio sintetizado desde el hablante. Este resultado es un buen ejemplo del uso más básico. A continuación, puede examinar cómo personalizar la salida y controlar la respuesta de la salida como una secuencia en memoria para trabajar con escenarios personalizados.

Obtención de un resultado en forma de secuencia en memoria

Puede usar los datos de audio resultantes como una transmisión en memoria en vez de escribirlos directamente en un archivo. Con la transmisión en memoria, puede crear comportamientos personalizados:

  • Abstraer la matriz de bytes resultante como una secuencia que permita la búsqueda para los servicios de bajada personalizados
  • Integrar el resultado con otros servicios o API
  • Modificar los datos de audio, escribir encabezados .wav personalizados y hacer tareas relacionadas

Puede realizar este cambio en el ejemplo anterior. Quite el bloqueo de AudioConfig, porque a partir de este momento administrará el comportamiento de la salida de forma manual, ya que así obtiene mayor control. Luego, pase null para AudioConfig en el constructor SpeechSynthesizer.

Nota:

Al usar null para AudioConfig, en lugar de omitirlo como lo hizo en el ejemplo de salida del altavoz anterior, el audio no se reproduce de manera predeterminada en el dispositivo de salida activo actual.

Guarde el resultado en una variable SpeechSynthesisResult. La propiedad SpeechSynthesisResult.audioData devuelve un valor ArrayBuffer de los datos de salida, el tipo de secuencia de explorador predeterminado. Para el código del lado servidor, convierta ArrayBuffer en una secuencia de búfer.

El código siguiente funciona para el código del lado cliente:

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

Puede implementar cualquier comportamiento personalizado mediante el objeto ArrayBuffer resultante. ArrayBuffer es un tipo común que se recibe en un explorador y se reproduce desde este formato.

En el caso de cualquier código basado en servidor, si necesita trabajar con los datos como una secuencia, debe convertir el objeto ArrayBuffer en una secuencia:

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

Personalización del formato de audio

Puede personalizar los atributos de salida de audio, incluidos:

  • Tipo de archivo de audio
  • Frecuencia de muestreo
  • Profundidad en bits

Para cambiar el formato de audio, se usa la propiedad speechSynthesisOutputFormat en el objeto SpeechConfig. Esta propiedad espera una instancia enum de tipo SpeechSynthesisOutputFormat. Use el enum para seleccionar el formato de salida. Para ver los formatos disponibles, consulte la lista de formatos de audio.

Hay varias opciones para los distintos tipos de archivo, por lo que puede elegir la que cumpla con sus requisitos. Por definición, los formatos sin procesar, como Raw24Khz16BitMonoPcm, no incluyen encabezados de audio. Use formatos sin procesar solo en una de estas situaciones:

  • Sabe que la implementación de bajada puede descodificar una secuencia de bits sin procesar.
  • Tiene previsto compilar manualmente encabezados en función de factores como la profundidad de bits, la frecuencia de muestreo y el número de canales.

En este ejemplo, se especifica el formato RIFF de alta fidelidad Riff24Khz16BitMonoPcm, para lo que se establece speechSynthesisOutputFormat en el objeto SpeechConfig. De forma similar al ejemplo de la sección anterior, obtenga los datos de ArrayBuffer de audio e interactúe con ellos.

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

Uso de SSML para personalizar las características de la voz

Puede usar SSML para ajustar el tono, la pronunciación, la velocidad del habla, el volumen y otros aspectos de la salida de texto a voz mediante el envío de solicitudes desde un lenguaje de definición de esquema XML. En esta sección, se muestra un ejemplo de cómo cambiar la voz. Para obtener más información, consulte Información general del Lenguaje de marcado de síntesis de voz.

Para empezar a usar SSML para la personalización, realice un cambio mínimo que cambie la voz.

  1. Cree un archivo XML para la configuración de SSML en el directorio raíz del proyecto.

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

    En este ejemplo, es ssml.xml. El elemento raíz siempre es <speak>. Ajustar el texto en un elemento <voice> permite cambiar la voz mediante el parámetro name. Hay una lista completa de voces neuronales admitidas, consulte Idiomas admitidos.

  2. Cambiar la solicitud de síntesis de voz para que haga referencia al archivo XML. La solicitud es básicamente la misma, pero en lugar de usar la función speakTextAsync(), se usa speakSsmlAsync(). Esta función espera una cadena XML. Cree una función para cargar un archivo XML y devolverlo como una cadena:

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

    Para más información sobre readFileSync, consulte Node.js file system (Sistema de archivos de Node.js).

    El objeto del resultado es exactamente el mismo que el de los ejemplos anteriores:

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

Nota:

Para cambiar la voz sin usar SSML, puede establecer la propiedad en SpeechConfig mediante SpeechConfig.speechSynthesisVoiceName = "en-US-AvaMultilingualNeural";.

Suscripción a eventos del sintetizador

Es posible que quiera obtener más información sobre el procesamiento de texto a voz y los resultados. Por ejemplo, puede que quiera saber cuándo se inicia y detiene el sintetizador, o que desee conocer otros eventos que se han encontrado durante la síntesis.

Al usar SpeechSynthesizer para texto a voz, puede suscribirse a los eventos de esta tabla:

Evento Descripción Caso de uso
BookmarkReached Indica que se alcanzó un marcador. Para desencadenar un evento de marcador alcanzado, se requiere un elemento bookmark en SSML. Este evento informa del tiempo transcurrido del audio de salida entre el inicio de la síntesis y el elemento bookmark. La propiedad del evento Text es el valor de cadena que estableció en el atributo mark del marcador. Los elementos bookmark no se hablan. Puede usar el elemento bookmark para insertar marcadores personalizados en SSML para obtener el desplazamiento de cada marcador en la secuencia de audio. El elemento bookmark se puede usar para hacer referencia a una ubicación específica en el texto o la secuencia de etiquetas.
SynthesisCanceled Indica que se canceló la síntesis de voz. Puede confirmar cuándo se ha cancelado la síntesis.
SynthesisCompleted Indica que la síntesis de voz se ha completado. Puede confirmar cuándo se ha completado la síntesis.
SynthesisStarted Indica que se ha iniciado la síntesis de voz. Puede confirmar cuándo se ha iniciado la síntesis.
Synthesizing Indica que la síntesis de voz está en curso. Este evento se desencadena cada vez que el SDK recibe un fragmento de audio del servicio Voz. Puede confirmar cuándo está la síntesis en curso.
VisemeReceived Indica que se recibió un evento de visema. Los visemas se suelen usar para representar los principales planteamientos de la voz observada. Entre los planteamientos clave se incluye la posición de los labios, la mandíbula y la lengua al generar un fonema determinado. Puede usar los visemas para animar la cara de un personaje mientras se reproduce el audio de voz.
WordBoundary Indica que se recibió un límite de palabras. Este evento se genera al principio de cada palabra hablada, puntuación y frases nuevas. El evento informa del desplazamiento de tiempo de la palabra actual, en tics, desde el principio del audio de salida. Este evento notifica la posición de un carácter en la cadena de entrada o SSML inmediatamente antes de la palabra que se va a pronunciar. Este evento se suele usar para obtener posiciones relativas del texto y el audio correspondiente. Es posible que quiera conocer una palabra nueva y, después, tomar medidas en función del tiempo. Por ejemplo, puede obtener información que pueda ayudarle a decidir cuándo y durante cuánto tiempo se resaltan las palabras mientras se dicen.

Nota:

Los eventos se generan cuando los datos de audio de salida están disponibles, lo que es más rápido que la reproducción en un dispositivo de salida. El autor de la llamada debe sincronizar correctamente el streaming y el tiempo real.

Este es un ejemplo que muestra cómo suscribirse a eventos para la síntesis de voz. Puede seguir las instrucciones del inicio rápido, pero reemplace el contenido de ese archivo SpeechSynthesis.js por el siguiente código 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;
    });
}());

Puede encontrar más muestras de texto a voz en GitHub.

Ejecutar y usar un contenedor

Los contenedores de voz proporcionan API de punto de conexión de consulta basadas en websocket a las que se accede a través del SDK de Voz y la CLI de Voz. De forma predeterminada, el SDK de Voz y la CLI de Voz usan el servicio de Voz público. Para usar el contenedor, deberá cambiar el método de inicialización. Use una dirección URL de host de contenedor en lugar de la clave y la región.

Para obtener más información sobre los contenedores, consulta Instalar y ejecutar contenedores de voz con Docker.

Documentación de referencia | Paquete (Download) | Ejemplos adicionales en GitHub

En esta guía paso a paso aprenderá modelos de diseño comunes para realizar la síntesis de texto a voz.

Para obtener más información sobre las siguientes áreas, consulte ¿Qué es el texto a voz?

  • Obtención de respuestas como secuencias en memoria
  • Personalización de la frecuencia de muestreo y la velocidad de bits de salida
  • Envío de solicitudes de síntesis mediante el lenguaje de marcado de síntesis de voz (SSML)
  • Uso de voces neuronales
  • Suscripción a eventos y actuación sobre los resultados.

Requisitos previos

Instalación del SDK de Voz y ejemplos

El repositorio Azure-Samples/cognitive-services-speech-sdk contiene ejemplos escritos en Objective-C para iOS y Mac. Seleccione un vínculo para ver las instrucciones de instalación de cada ejemplo:

Uso de un punto de conexión personalizado

El punto de conexión personalizado es técnicamente idéntico al punto de conexión estándar que se usa en las solicitudes de texto a voz.

Una diferencia es que EndpointId debe especificarse para usar la voz personalizada a través del SDK de Voz. Puede empezar con el inicio rápido de texto a voz y, a continuación, actualizar el código con EndpointId y SpeechSynthesisVoiceName.

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

Para usar una voz personalizada mediante el lenguaje de marcado de síntesis de voz (SSML), especifique el nombre del modelo como nombre de voz. En este ejemplo se usa la voz YourCustomVoiceName.

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

Ejecutar y usar un contenedor

Los contenedores de voz proporcionan API de punto de conexión de consulta basadas en websocket a las que se accede a través del SDK de Voz y la CLI de Voz. De forma predeterminada, el SDK de Voz y la CLI de Voz usan el servicio de Voz público. Para usar el contenedor, deberá cambiar el método de inicialización. Use una dirección URL de host de contenedor en lugar de la clave y la región.

Para obtener más información sobre los contenedores, consulta Instalar y ejecutar contenedores de voz con Docker.

Documentación de referencia | Paquete (Download) | Ejemplos adicionales en GitHub

En esta guía paso a paso aprenderá modelos de diseño comunes para realizar la síntesis de texto a voz.

Para obtener más información sobre las siguientes áreas, consulte ¿Qué es el texto a voz?

  • Obtención de respuestas como secuencias en memoria
  • Personalización de la frecuencia de muestreo y la velocidad de bits de salida
  • Envío de solicitudes de síntesis mediante el lenguaje de marcado de síntesis de voz (SSML)
  • Uso de voces neuronales
  • Suscripción a eventos y actuación sobre los resultados.

Requisitos previos

Instalación del SDK de Voz y ejemplos

El repositorio Azure-Samples/cognitive-services-speech-sdk contiene ejemplos escritos en Swift para iOS y Mac. Seleccione un vínculo para ver las instrucciones de instalación de cada ejemplo:

Ejecutar y usar un contenedor

Los contenedores de voz proporcionan API de punto de conexión de consulta basadas en websocket a las que se accede a través del SDK de Voz y la CLI de Voz. De forma predeterminada, el SDK de Voz y la CLI de Voz usan el servicio de Voz público. Para usar el contenedor, deberá cambiar el método de inicialización. Use una dirección URL de host de contenedor en lugar de la clave y la región.

Para obtener más información sobre los contenedores, consulta Instalar y ejecutar contenedores de voz con Docker.

Documentación de referencia | Paquete (PyPi) | Ejemplos adicionales en GitHub

En esta guía paso a paso aprenderá modelos de diseño comunes para realizar la síntesis de texto a voz.

Para obtener más información sobre las siguientes áreas, consulte ¿Qué es el texto a voz?

  • Obtención de respuestas como secuencias en memoria
  • Personalización de la frecuencia de muestreo y la velocidad de bits de salida
  • Envío de solicitudes de síntesis mediante el lenguaje de marcado de síntesis de voz (SSML)
  • Uso de voces neuronales
  • Suscripción a eventos y actuación sobre los resultados.

Selección del idioma y la voz de síntesis

La característica de texto a voz en el servicio de Voz admite más de 400 voces y más de 140 idiomas y variantes. Puede obtener la lista completa o probarlos en la Galería de voces.

Especifique el idioma o la voz de SpeechConfig para que coincida con el texto de entrada y usar la voz que prefiera:

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

Todas las voces neuronales son multilingües y fluidas en su propio idioma y en inglés. Por ejemplo, si el texto de entrada en inglés es «I'm excited to try text to speech» (estoy encantado de probar texto a voz) y establece es-ES-ElviraNeural, el texto se hablará en inglés con acento español.

Si la voz no habla el idioma del texto de entrada, el servicio de Voz no crea audio sintetizado. Para obtener una lista completa de las voces neuronales admitidas, consulte Compatibilidad de idioma y voz con el servicio voz.

Nota:

La voz predeterminada es la primera voz devuelta por la configuración regional desde la API de lista de voz.

La voz que habla se determina en orden de prioridad de la siguiente manera:

  • Si no establece SpeechSynthesisVoiceName o SpeechSynthesisLanguage, habla la voz predeterminada para en-US.
  • Si solo establece SpeechSynthesisLanguage, habla la voz predeterminada para la configuración regional especificada.
  • Si se establecen SpeechSynthesisVoiceName y SpeechSynthesisLanguage, se omitirá la configuración SpeechSynthesisLanguage. Habla la voz que especifique mediante SpeechSynthesisVoiceName.
  • Si el elemento de voz se establece a través del lenguaje de marcado de síntesis de voz (SSML), se omiten los valores SpeechSynthesisVoiceName y SpeechSynthesisLanguage.

Síntesis de voz en un archivo

Cree un objeto SpeechSynthesizer. Este objeto ejecuta conversiones de texto a voz y envía la salida a altavoces, archivos u otras secuencias de salida. SpeechSynthesizer acepta como parámetros:

  • El objeto SpeechConfig que creó en el paso anterior.
  • Un objeto AudioOutputConfig que especifica cómo se deben manejar los resultados de la salida.
  1. Cree una instancia de AudioOutputConfig para escribir automáticamente la salida en un archivo .wav mediante el parámetro de constructor filename:

    audio_config = speechsdk.audio.AudioOutputConfig(filename="path/to/write/file.wav")
    
  2. Cree una instancia de SpeechSynthesizer y pase los objetos speech_config y audio_config como parámetros. Para sintetizar la voz y escribir en un archivo, ejecute speak_text_async() con una cadena de texto.

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

Al ejecutar el programa, crea un archivo .wav sintetizado, que se escribe en la ubicación especificada. Este resultado es un buen ejemplo del uso más básico. A continuación, puede personalizar la salida y controlar la respuesta de la salida como una secuencia en memoria para trabajar con escenarios personalizados.

Síntesis a la salida de altavoz

Para generar voz sintetizada en el dispositivo de salida activo actual, como un altavoz, establezca el parámetro use_default_speaker al crear la instancia AudioOutputConfig. Este es un ejemplo:

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

Obtención de un resultado en forma de secuencia en memoria

Puede usar los datos de audio resultantes como una transmisión en memoria en vez de escribirlos directamente en un archivo. Con la transmisión en memoria, puede crear comportamientos personalizados:

  • Abstraer la matriz de bytes resultante como una secuencia que permita la búsqueda para los servicios de bajada personalizados
  • Integrar el resultado con otros servicios o API
  • Modificar los datos de audio, escribir encabezados .wav personalizados y hacer tareas relacionadas.

Puede realizar este cambio en el ejemplo anterior. En primer lugar, quite AudioConfig, porque a partir de este momento administra el comportamiento de la salida de manera manual, ya que así obtiene mayor control. Pase None para AudioConfig en el constructor SpeechSynthesizer.

Nota:

Al usar None para AudioConfig, en lugar de omitirlo como lo hizo en el ejemplo de salida del altavoz anterior, el audio no se reproduce de manera predeterminada en el dispositivo de salida activo actual.

Guarde el resultado en una variable SpeechSynthesisResult. La propiedad audio_data contiene un objeto bytes de los datos de salida. Puede trabajar con este objeto manualmente, o bien puede usar la clase AudioDataStream para administrar la secuencia en memoria.

En este ejemplo, se usa el constructor AudioDataStream para obtener una secuencia del resultado:

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)

A partir de aquí, se puede implementar cualquier comportamiento personalizado mediante el objeto stream resultante.

Personalización del formato de audio

Puede personalizar los atributos de salida de audio, incluidos:

  • Tipo de archivo de audio
  • Frecuencia de muestreo
  • Profundidad en bits

Para cambiar el formato de audio se usa la función set_speech_synthesis_output_format() en el objeto SpeechConfig. Esta función espera una instancia enum de tipo SpeechSynthesisOutputFormat. Use el enum para seleccionar el formato de salida. Para ver los formatos disponibles, consulte la lista de formatos de audio.

Hay varias opciones para los distintos tipos de archivo, por lo que puede elegir la que cumpla con sus requisitos. Por definición, los formatos sin procesar, como Raw24Khz16BitMonoPcm, no incluyen encabezados de audio. Use formatos sin procesar solo en una de estas situaciones:

  • Sabe que la implementación de bajada puede descodificar una secuencia de bits sin procesar.
  • Tiene previsto compilar manualmente encabezados en función de factores como la profundidad de bits, la frecuencia de muestreo y el número de canales.

En este ejemplo, se especifica el formato RIFF de alta fidelidad Riff24Khz16BitMonoPcm, para lo que se establece SpeechSynthesisOutputFormat en el objeto SpeechConfig. Al igual que en el ejemplo de la sección anterior, se usa AudioDataStream para obtener una secuencia en memoria del resultado y, después, escribirla en un archivo.

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

Al ejecutar el programa, escribe un archivo .wav en la ruta de acceso especificada.

Uso de SSML para personalizar las características de la voz

Puede usar SSML para ajustar el tono, la pronunciación, la velocidad del habla, el volumen y otros aspectos de la salida de texto a voz mediante el envío de solicitudes desde un lenguaje de definición de esquema XML. En esta sección, se muestra un ejemplo de cómo cambiar la voz. Para obtener más información, consulte Información general del Lenguaje de marcado de síntesis de voz.

Para empezar a usar SSML para la personalización, realice un cambio mínimo que cambie la voz.

  1. Cree un archivo XML para la configuración de SSML en el directorio raíz del proyecto.

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

    En este ejemplo, el archivo es ssml.xml. El elemento raíz siempre es <speak>. Ajustar el texto en un elemento <voice> permite cambiar la voz mediante el parámetro name. Hay una lista completa de voces neuronales admitidas, consulte Idiomas admitidos.

  2. Cambiar la solicitud de síntesis de voz para que haga referencia al archivo XML. La solicitud es principalmente la misma. En lugar de usar la función speak_text_async(), se usa speak_ssml_async(). Esta función espera una cadena XML. En primer lugar, lea la configuración de SSML como una cadena. Desde aquí, el objeto del resultado es exactamente el mismo que el de los ejemplos anteriores.

    Nota:

    Si ssml_string contiene  al principio de la cadena, debe quitar el formato de BOM o el servicio devolverá un error. Para ello, establezca el parámetro encoding como sigue: 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")
    

Nota

Para cambiar la voz sin usar SSML, puede establecer la propiedad en SpeechConfig mediante speech_config.speech_synthesis_voice_name = "en-US-AvaMultilingualNeural".

Suscripción a eventos del sintetizador

Es posible que quiera obtener más información sobre el procesamiento de texto a voz y los resultados. Por ejemplo, puede que quiera saber cuándo se inicia y detiene el sintetizador, o que desee conocer otros eventos que se han encontrado durante la síntesis.

Al usar SpeechSynthesizer para texto a voz, puede suscribirse a los eventos de esta tabla:

Evento Descripción Caso de uso
BookmarkReached Indica que se alcanzó un marcador. Para desencadenar un evento de marcador alcanzado, se requiere un elemento bookmark en SSML. Este evento informa del tiempo transcurrido del audio de salida entre el inicio de la síntesis y el elemento bookmark. La propiedad del evento Text es el valor de cadena que estableció en el atributo mark del marcador. Los elementos bookmark no se hablan. Puede usar el elemento bookmark para insertar marcadores personalizados en SSML para obtener el desplazamiento de cada marcador en la secuencia de audio. El elemento bookmark se puede usar para hacer referencia a una ubicación específica en el texto o la secuencia de etiquetas.
SynthesisCanceled Indica que se canceló la síntesis de voz. Puede confirmar cuándo se ha cancelado la síntesis.
SynthesisCompleted Indica que la síntesis de voz se ha completado. Puede confirmar cuándo se ha completado la síntesis.
SynthesisStarted Indica que se ha iniciado la síntesis de voz. Puede confirmar cuándo se ha iniciado la síntesis.
Synthesizing Indica que la síntesis de voz está en curso. Este evento se desencadena cada vez que el SDK recibe un fragmento de audio del servicio Voz. Puede confirmar cuándo está la síntesis en curso.
VisemeReceived Indica que se recibió un evento de visema. Los visemas se suelen usar para representar los principales planteamientos de la voz observada. Entre los planteamientos clave se incluye la posición de los labios, la mandíbula y la lengua al generar un fonema determinado. Puede usar los visemas para animar la cara de un personaje mientras se reproduce el audio de voz.
WordBoundary Indica que se recibió un límite de palabras. Este evento se genera al principio de cada palabra hablada, puntuación y frases nuevas. El evento informa del desplazamiento de tiempo de la palabra actual, en tics, desde el principio del audio de salida. Este evento notifica la posición de un carácter en la cadena de entrada o SSML inmediatamente antes de la palabra que se va a pronunciar. Este evento se suele usar para obtener posiciones relativas del texto y el audio correspondiente. Es posible que quiera conocer una palabra nueva y, después, tomar medidas en función del tiempo. Por ejemplo, puede obtener información que pueda ayudarle a decidir cuándo y durante cuánto tiempo se resaltan las palabras mientras se dicen.

Nota:

Los eventos se generan cuando los datos de audio de salida están disponibles, lo que es más rápido que la reproducción en un dispositivo de salida. El autor de la llamada debe sincronizar correctamente el streaming y el tiempo real.

Este es un ejemplo que muestra cómo suscribirse a eventos para la síntesis de voz. Puede seguir las instrucciones del inicio rápido, pero reemplace el contenido de ese archivo speech-synthesis.py por el siguiente código 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?")

Puede encontrar más muestras de texto a voz en GitHub.

Uso de un punto de conexión personalizado

El punto de conexión personalizado es técnicamente idéntico al punto de conexión estándar que se usa en las solicitudes de texto a voz.

Una diferencia es que endpoint_id debe especificarse para usar la voz personalizada a través del SDK de Voz. Puede empezar con el inicio rápido de texto a voz y, a continuación, actualizar el código con endpoint_id y 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"

Para usar una voz personalizada mediante el lenguaje de marcado de síntesis de voz (SSML), especifique el nombre del modelo como nombre de voz. En este ejemplo se usa la voz YourCustomVoiceName.

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

Ejecutar y usar un contenedor

Los contenedores de voz proporcionan API de punto de conexión de consulta basadas en websocket a las que se accede a través del SDK de Voz y la CLI de Voz. De forma predeterminada, el SDK de Voz y la CLI de Voz usan el servicio de Voz público. Para usar el contenedor, deberá cambiar el método de inicialización. Use una dirección URL de host de contenedor en lugar de la clave y la región.

Para obtener más información sobre los contenedores, consulta Instalar y ejecutar contenedores de voz con Docker.

Referencia de la API de REST en la conversión de voz en texto | Referencia de la API de REST en la conversión de voz en texto para audios breves | Ejemplos adicionales sobre GitHub

En esta guía paso a paso aprenderá modelos de diseño comunes para realizar la síntesis de texto a voz.

Para obtener más información sobre las siguientes áreas, consulte ¿Qué es el texto a voz?

  • Obtención de respuestas como secuencias en memoria
  • Personalización de la frecuencia de muestreo y la velocidad de bits de salida
  • Envío de solicitudes de síntesis mediante el lenguaje de marcado de síntesis de voz (SSML)
  • Uso de voces neuronales
  • Suscripción a eventos y actuación sobre los resultados.

Requisitos previos

Conversión de texto en voz

En el símbolo del sistema, ejecute el siguiente comando. Inserte estos valores en el comando:

  • Su clave del recurso de Voz
  • Su región del recurso de Voz

Es posible que también quiera cambiar estos valores:

  • El valor del encabezado X-Microsoft-OutputFormat, que controla el formato de la salida de audio. Puede encontrar una lista de formatos de salida de audio compatibles en la referencia de la API REST de texto a voz.
  • Voz de salida. Si desea obtener una lista de las voces disponibles para el punto de conexión del servicio de Voz, consulte API de lista de Voice.
  • Archivo de salida. En este ejemplo, la respuesta del servidor se dirige a un archivo denominado 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

En esta guía paso a paso aprenderá modelos de diseño comunes para realizar la síntesis de texto a voz.

Para obtener más información sobre las siguientes áreas, consulte ¿Qué es el texto a voz?

  • Obtención de respuestas como secuencias en memoria
  • Personalización de la frecuencia de muestreo y la velocidad de bits de salida
  • Envío de solicitudes de síntesis mediante el lenguaje de marcado de síntesis de voz (SSML)
  • Uso de voces neuronales
  • Suscripción a eventos y actuación sobre los resultados.

Requisitos previos

Descargar e instalar

Siga estos pasos y consulte el inicio rápido de la CLI de Voz para conocer los otros requisitos de la plataforma.

  1. Ejecute el siguiente comando de la CLI de .NET para instalar la CLI de Voz:

    dotnet tool install --global Microsoft.CognitiveServices.Speech.CLI
    
  2. Configure la clave de recurso de Voz y la región mediante la ejecución de los siguientes comandos. Reemplace SUBSCRIPTION-KEY por la clave del recurso de Voz y REGION por la región del recurso de Voz.

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

Síntesis de voz en un altavoz

Ahora está listo para ejecutar la CLI de Voz para sintetizar voz a partir de texto.

  • En una ventana de consola, cambie al directorio que contiene el archivo binario de la CLI de Voz. Luego, ejecute el siguiente comando:

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

La CLI de Voz crea un lenguaje natural en inglés a través del altavoz del equipo.

Síntesis de voz en un archivo

  • Ejecute el comando siguiente para cambiar la salida del altavoz a un archivo .wav:

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

La CLI de Voz genera lenguaje natural en inglés en el archivo de audio greetings.wav.

Ejecutar y usar un contenedor

Los contenedores de voz proporcionan API de punto de conexión de consulta basadas en websocket a las que se accede a través del SDK de Voz y la CLI de Voz. De forma predeterminada, el SDK de Voz y la CLI de Voz usan el servicio de Voz público. Para usar el contenedor, deberá cambiar el método de inicialización. Use una dirección URL de host de contenedor en lugar de la clave y la región.

Para obtener más información sobre los contenedores, consulta Instalar y ejecutar contenedores de voz con Docker.

Pasos siguientes