Comment synthétiser la parole à partir de texte

Documentation de référence | Package (NuGet) | Exemples supplémentaires sur GitHub

Dans ce guide pratique, vous allez découvrir des modèles de conception courants qui permettent d’utiliser la synthèse vocale.

Pour plus d’informations sur les domaines suivants, consultez Qu’est-ce que la synthèse vocale ?

  • Obtention de réponses en tant que flux en mémoire.
  • Personnalisation du taux d’échantillonnage de sortie et de la vitesse de transmission.
  • Envoi de demandes de synthèse à l’aide de SSML (Speech Synthesis Markup Language).
  • Utilisation de voix neurales.
  • Abonnement aux événements et exploitation des résultats.

Sélectionner la langue et la voix de synthèse

La fonctionnalité de synthèse vocale du service Speech prend en charge plus de 400 voix ainsi que plus de 140 langues et variantes. Vous pouvez en obtenir la liste complète ou les tester dans la Galerie de voix.

Spécifiez la langue ou la voix de SpeechConfig en fonction de votre texte d’entrée, puis utilisez la voix spécifiée. L’extrait de code suivant montre comment fonctionne cette technique :

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

Toutes les voix neuronales sont multilingues et parlent couramment leur propre langue et l’anglais. Par exemple, si le texte d’entrée en anglais est « I'm excited to try text to speech, » et que vous avez sélectionné es-ES-ElviraNeural, le texte est lu en anglais avec un accent espagnol.

Si la voix ne s’exprime pas dans la langue correspondant au texte entré, le service Speech ne créé pas d’audio synthétisées. Pour obtenir la liste complète des voix neuronales prises en charge, consultez Prise en charge des langues et des voix pour le service Speech.

Remarque

La voix par défaut est la première voix retournée par les paramètres régionaux depuis l’API de la liste des voix.

La voix qui parle est déterminée par ordre de priorité comme suit :

  • Si vous ne définissez pas SpeechSynthesisVoiceName ou SpeechSynthesisLanguage, la voix par défaut en-US est utilisée.
  • Si vous définissez uniquement SpeechSynthesisLanguage, la voix par défaut des paramètres régionaux spécifiés est utilisée.
  • Si SpeechSynthesisVoiceName et SpeechSynthesisLanguage sont tous deux définis, le paramètre SpeechSynthesisLanguage est ignoré. La voix que vous spécifiez en utilisant SpeechSynthesisVoiceName parle.
  • Si l’élément voix est défini en utilisant SSML (Speech Synthesis Markup Language), les paramètres SpeechSynthesisVoiceName et SpeechSynthesisLanguage sont ignorés.

Synthétiser la voix dans un fichier

Créez un objet SpeechSynthesizer. Cet objet affiché dans les extraits de code suivants exécute des conversions de synthèse vocale et des sorties vers des haut-parleurs, des fichiers ou d’autres flux de sortie. SpeechSynthesizer accepte comme paramètres :

  • L’objet SpeechConfig que vous avez créé à l’étape précédente.
  • Un objet AudioConfig qui spécifie comment les résultats de sortie doivent être gérés.
  1. Créez une instance AudioConfig pour écrire automatiquement la sortie dans un fichier .wav en utilisant la fonction FromWavFileOutput(). Instanciez-le avec une instruction using.

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

    Une instruction using dans ce contexte élimine automatiquement les ressources non managées et fait sortir l’objet de l’étendue après l’élimination.

  2. Instanciez une instance SpeechSynthesizer avec une autre instruction using. Transmettez votre objet speechConfig et l’objet audioConfig en tant que paramètres. Pour synthétiser la parole et écrire dans un fichier, exécutez SpeakTextAsync() avec une chaîne de texte.

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

Lorsque vous exécutez le programme, il crée un fichier .wav synthétisé, qui est écrit à l’emplacement que vous spécifiez. Ce résultat est un bon exemple de l’utilisation la plus basique. Ensuite, vous pouvez personnaliser la sortie et gérer la réponse de sortie sous forme de flux en mémoire pour travailler sur des scénarios personnalisés.

Synthétiser vers la sortie du haut-parleur

Pour générer la synthèse vocale vers l’appareil de sortie actif actuel tel qu’un haut-parleur, omettez le paramètre AudioConfig quand vous créez l’instance SpeechSynthesizer. Voici un exemple :

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

Obtenir le résultat sous forme de flux en mémoire

Vous pouvez utiliser les données audio obtenues sous forme de flux en mémoire plutôt que directement écrites dans un fichier. Avec le flux en mémoire, vous pouvez créer un comportement personnalisé :

  • Résumer le tableau d’octets obtenu sous forme de flux pouvant faire l’objet de recherches pour des services en aval personnalisés.
  • Intégrer le résultat à d’autres API ou services.
  • Modifier les données audio, écrire des en-têtes .wav personnalisés et effectuer les tâches associées.

Vous pouvez apporter cette modification à l’exemple précédent. Tout d’abord, supprimez le bloc AudioConfig, car vous aller gérer le comportement de sortie manuellement à partir de ce point pour un contrôle accru. Transmettez null pour AudioConfig dans le constructeur SpeechSynthesizer.

Remarque

Le fait de transmettre null pour AudioConfig, au lieu de l’omettre comme dans l’exemple de sortie de haut-parleur précédent, ne reproduit pas par défaut l’audio sur l’appareil de sortie actuellement actif.

Enregistrez le résultat dans une variable SpeechSynthesisResult. La propriété AudioData contient une instance byte [] pour les données de sortie. Vous pouvez utiliser cette instance byte [] manuellement ou utiliser la classe AudioDataStream pour gérer le flux en mémoire.

Dans cet exemple, vous allez utiliser la fonction statique AudioDataStream.FromResult() pour obtenir un flux à partir du résultat :

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

À ce stade, vous pouvez implémenter tout comportement personnalisé à partir de l’objet stream obtenu.

Personnaliser le format audio

Vous pouvez personnaliser les attributs de sortie audio, notamment :

  • Le type de fichier audio
  • Échantillonnage
  • Profondeur de bits

Pour changer de format audio, utilisez la fonction SetSpeechSynthesisOutputFormat() sur l’objet SpeechConfig. Cette fonction attend une instance enum de type SpeechSynthesisOutputFormat. Utilisez pour enum sélectionner le format de sortie. Pour connaître les formats disponibles, consultez la liste des formats audio.

Il existe diverses options pour les différents types de fichiers, ce qui permet de répondre à vos besoins. Par définition, les formats bruts comme Raw24Khz16BitMonoPcm n’incluent pas d’en-têtes audio. Utilisez les formats bruts uniquement dans les situations suivantes :

  • Vous savez que votre implémentation en aval peut décoder un flux binaire brut.
  • Vous envisagez de générer manuellement des en-têtes en fonction de facteurs tels que la profondeur de bit, le taux d’échantillonnage et le nombre de canaux.

Cet exemple spécifie le format RIFF haute fidélité Riff24Khz16BitMonoPcm en définissant SpeechSynthesisOutputFormat sur l’objet SpeechConfig. Comme dans l’exemple de la section précédente, vous allez utiliser AudioDataStream pour obtenir un flux en mémoire du résultat, puis l’écrire dans un fichier.

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

Lorsque vous exécutez le programme, il écrit un fichier .wav dans le chemin d’accès spécifié.

Utiliser SSML pour personnaliser les caractéristiques vocales

Vous pouvez utiliser SSML pour ajuster la tonalité, la prononciation, la vitesse d’élocution, le volume et d’autres aspects de sortie de la synthèse vocale en soumettant vos demandes à partir d’un schéma XML. Cette section présente un exemple de modification de voix. Pour plus d’informations, consultez Vue d’ensemble de Speech Synthesis Markup Language.

Pour commencer à utiliser SSML pour la personnalisation, vous allez apporter une modification mineure qui change la voix.

  1. Créez un fichier XML pour la configuration SSML dans le répertoire racine de votre projet.

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

    Dans cet exemple, le fichier est ssml.xml. L’élément racine est toujours <speak>. L’inclusion du texte dans un élément <voice> vous permet de modifier la voix à l’aide du paramètre name. Pour une liste complète des voix neuronales prises en charge, consultez Langues prises en charge.

  2. Changez la requête de synthèse vocale de sorte qu’elle fasse référence à votre fichier XML. La demande est presque totalement identique, sauf qu’au lieu d’utiliser la fonction SpeakTextAsync(), vous allez utiliser SpeakSsmlAsync(). Cette fonction attend une chaîne XML. Tout d’abord, chargez votre configuration SSSML sous forme de chaîne en utilisant File.ReadAllText(). À ce stade, l’objet obtenu est exactement le même que dans les exemples précédents.

    Remarque

    Si vous utilisez Visual Studio, il est probable que la configuration de votre build ne trouvera pas par défaut votre fichier XML. Cliquez avec le bouton de droite sur le fichier XML et sélectionnez Propriétés. Changez Action de compilation pour Contenu. Changez Copier dans le répertoire de sortie à Toujours copier.

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

Remarque

Pour modifier la voix sans utiliser SSML, vous pouvez définir la propriété sur SpeechConfig à l’aide de SpeechConfig.SpeechSynthesisVoiceName = "en-US-AvaMultilingualNeural";.

S’abonner aux événements de synthétiseur

Vous souhaiterez peut-être obtenir plus d’informations sur le traitement et les résultats de la synthèse vocale. Par exemple, vous souhaiterez peut-être savoir quand le synthétiseur démarre et s’arrête ou connaître les autres événements rencontrés pendant la synthèse.

Lors de l’utilisation du SpeechSynthesizer pour la synthèse vocale, vous pouvez vous abonner aux événements indiqués dans le tableau suivant :

Événement Description Cas d’utilisation
BookmarkReached Signale qu’un signet a été atteint. Pour déclencher un événement de signet atteint, un élément bookmark est requis dans le SSML. Cet événement signale le temps écoulé du contenu audio de sortie entre le début de la synthèse et l’élément bookmark. La propriété Text de l’événement est la valeur de chaîne que vous définissez dans l’attribut mark du signet. Les éléments bookmark ne sont pas énoncés. Vous pouvez utiliser l’élément bookmark pour insérer des marqueurs personnalisés en SSML afin d’obtenir le décalage de chaque marqueur dans le flux audio. L’élément bookmark peut être utilisé pour référencer un emplacement spécifique dans le texte ou la séquence de balises.
SynthesisCanceled Signale que la synthèse vocale a été annulée. Vous pouvez confirmer que la synthèse est annulée.
SynthesisCompleted Signale que la synthèse vocale est terminée. Vous pouvez confirmer que la synthèse est terminée.
SynthesisStarted Signale que la synthèse vocale est commencée. Vous pouvez confirmer que la synthèse est commencée.
Synthesizing Signale que la synthèse vocale est en cours. Cet événement se déclenche chaque fois que le SDK reçoit un segment audio du service Speech. Vous pouvez confirmer que la synthèse est en cours.
VisemeReceived Signale qu’un événement de visème a été reçu. Les visèmes sont souvent utilisées pour représenter les poses clés dans la parole observée. Les poses clés incluent la position des lèvres, de la mâchoire et de la langue dans la production d’un phonème particulier. Vous pouvez utiliser des visèmes pour animer le visage d’un personnage au fur et à mesure de la lecture audio.
WordBoundary Signale qu’une limite de mot a été reçue. Cet événement est déclenché au début de chaque nouveau mot prononcé, ponctuation et phrase. L’événement signale le décalage de temps du mot actuel, en ticks , à partir du début de l’audio de sortie. Cet événement signale également la position du caractère dans le texte d’entrée, ou SSML, juste avant le mot sur le point d’être prononcé. Cet événement est couramment utilisé pour obtenir les positions relatives du texte et de l’audio correspondant. Vous souhaiterez peut-être avoir des informations sur un nouveau mot, puis prendre des mesures en fonction du minutage. Par exemple, vous pouvez obtenir des informations qui peuvent vous aider à décider quand et pendant combien de temps mettre en surbrillance les mots à mesure qu’ils sont prononcés.

Remarque

Les événements sont déclenchés à mesure que les données audio de sortie deviennent disponibles, ce qui est plus rapide que la lecture sur un appareil de sortie. L’appelant doit synchroniser de manière appropriée le streaming et le temps réel.

Voici un exemple qui montre comment s’abonner aux événements pour la synthèse vocale. Vous pouvez suivre les instructions du guide de démarrage rapide, mais remplacez le contenu du fichier Program.cs par le code C# suivant :

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

Vous trouverez plus d’exemples de synthèse vocale sur GitHub.

Utiliser un point de terminaison personnalisé

D’un point de vue fonctionnel, le point de terminaison personnalisé est identique au point de terminaison standard utilisé pour les demandes de synthèse vocale.

La différence est que le EndpointId doit être spécifié pour utiliser votre voix personnalisée via le Kit de développement logiciel (SDK) Speech. Vous pouvez commencer par le guide de démarrage rapide de synthèse vocale, puis mettre à jour le code avec EndpointId et SpeechSynthesisVoiceName.

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

Pour utiliser une voix personnalisée via le langage SSML (Speech Synthesis Markup Language), spécifiez le nom du modèle comme nom de la voix. Cet exemple utilise la voix 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>

Exécuter et utiliser un conteneur

Les conteneurs Speech fournissent des API de point de terminaison de requête basées sur WebSocket, accessibles via le Kit de développement logiciel (SDK) Speech et l’interface CLI Speech. Par défaut, le kit de développement logiciel (SDK) Speech et l’interface CLI Speech utilisent le service Speech public. Pour utiliser le conteneur, vous devez changer la méthode d’initialisation. Utilisez une URL d’hôte de conteneur plutôt qu’une clé et une région.

Pour plus d’informations sur les conteneurs, consultez Installer et exécuter des conteneurs Speech avec Docker.

Documentation de référence | Package (NuGet) | Exemples supplémentaires sur GitHub

Dans ce guide pratique, vous allez découvrir des modèles de conception courants qui permettent d’utiliser la synthèse vocale.

Pour plus d’informations sur les domaines suivants, consultez Qu’est-ce que la synthèse vocale ?

  • Obtention de réponses en tant que flux en mémoire.
  • Personnalisation du taux d’échantillonnage de sortie et de la vitesse de transmission.
  • Envoi de demandes de synthèse à l’aide de SSML (Speech Synthesis Markup Language).
  • Utilisation de voix neurales.
  • Abonnement aux événements et exploitation des résultats.

Sélectionner la langue et la voix de synthèse

La fonctionnalité de synthèse vocale du service Speech prend en charge plus de 400 voix ainsi que plus de 140 langues et variantes. Consultez la liste complète des paramètres régionaux de synthèse vocale pris en charge ou essayez-les dans la Galerie de voix.

Spécifiez la langue ou la voix de la classe SpeechConfig en fonction de votre texte d’entrée, puis utilisez la voix spécifiée. L’extrait de code suivant montre comment fonctionne cette technique :

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

Toutes les voix neuronales sont multilingues et parlent couramment leur propre langue et l’anglais. Par exemple, si le texte d’entrée en anglais est « I'm excited to try text to speech, » et que vous avez défini es-ES-ElviraNeural, le texte est lu en anglais avec un accent espagnol.

Si la voix ne s’exprime pas dans la langue correspondant au texte entré, le service Speech ne créé pas d’audio synthétisées. Pour obtenir la liste complète des voix neuronales prises en charge, consultez Prise en charge des langues et des voix pour le service Speech.

Remarque

La voix par défaut est la première voix retournée par les paramètres régionaux depuis l’API de la liste des voix.

La voix qui parle est déterminée par ordre de priorité comme suit :

  • Si vous ne définissez pas SpeechSynthesisVoiceName ou SpeechSynthesisLanguage, la voix par défaut en-US est utilisée.
  • Si vous définissez uniquement SpeechSynthesisLanguage, la voix par défaut des paramètres régionaux spécifiés est utilisée.
  • Si SpeechSynthesisVoiceName et SpeechSynthesisLanguage sont tous deux définis, le paramètre SpeechSynthesisLanguage est ignoré. La voix que vous spécifiez en utilisant SpeechSynthesisVoiceName parle.
  • Si l’élément voix est défini en utilisant SSML (Speech Synthesis Markup Language), les paramètres SpeechSynthesisVoiceName et SpeechSynthesisLanguage sont ignorés.

Synthétiser la voix dans un fichier

Créez un objet SpeechSynthesizer. Cet objet affiché dans les extraits de code suivants exécute des conversions de synthèse vocale et des sorties vers des haut-parleurs, des fichiers ou d’autres flux de sortie. SpeechSynthesizer accepte comme paramètres :

  • L’objet SpeechConfig que vous avez créé à l’étape précédente.
  • Un objet AudioConfig qui spécifie comment les résultats de sortie doivent être gérés.
  1. Créez une instance AudioConfig pour écrire automatiquement la sortie dans un fichier .wav en utilisant la fonction FromWavFileOutput() :

    void synthesizeSpeech()
    {
        auto speechConfig = SpeechConfig::FromSubscription("YourSpeechKey", "YourSpeechRegion");
        auto audioConfig = AudioConfig::FromWavFileOutput("path/to/write/file.wav");
    }
    
  2. Instanciez une instance SpeechSynthesizer. Transmettez votre objet speechConfig et l’objet audioConfig en tant que paramètres. Pour synthétiser la parole et écrire dans un fichier, exécutez SpeakTextAsync() avec une chaîne de texte.

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

Lorsque vous exécutez le programme, il crée un fichier .wav synthétisé, qui est écrit à l’emplacement que vous spécifiez. Ce résultat est un bon exemple de l’utilisation la plus basique. Ensuite, vous pouvez personnaliser la sortie et gérer la réponse de sortie sous forme de flux en mémoire pour travailler sur des scénarios personnalisés.

Synthétiser vers la sortie du haut-parleur

Pour générer la synthèse vocale vers l’appareil de sortie actif actuel tel qu’un haut-parleur, omettez le paramètre AudioConfig lorsque vous créez l’instance SpeechSynthesizer. Voici un exemple :

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

Obtenir le résultat sous forme de flux en mémoire

Vous pouvez utiliser les données audio obtenues sous forme de flux en mémoire plutôt que directement écrites dans un fichier. Avec le flux en mémoire, vous pouvez créer un comportement personnalisé :

  • Résumer le tableau d’octets obtenu sous forme de flux pouvant faire l’objet de recherches pour des services en aval personnalisés.
  • Intégrer le résultat à d’autres API ou services.
  • Modifier les données audio, écrire des en-têtes .wav personnalisés et effectuer les tâches associées.

Vous pouvez apporter cette modification à l’exemple précédent. Tout d’abord, supprimez le bloc AudioConfig, car vous aller gérer le comportement de sortie manuellement à partir de ce point pour un contrôle accru. Transmettez NULL pour AudioConfig dans le constructeur SpeechSynthesizer.

Remarque

Le fait de transmettre NULL pour AudioConfig, au lieu de l’omettre comme dans l’exemple de sortie de haut-parleur précédent, ne reproduit pas par défaut l’audio sur l’appareil de sortie actuellement actif.

Enregistrez le résultat dans une variable SpeechSynthesisResult. Le getter GetAudioData retourne une instance byte [] pour les données de sortie. Vous pouvez utiliser cette instance byte [] manuellement ou utiliser la classe AudioDataStream pour gérer le flux en mémoire.

Dans cet exemple, utilisez la fonction statique AudioDataStream.FromResult() pour obtenir un flux à partir du résultat :

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

À ce stade, vous pouvez implémenter tout comportement personnalisé à partir de l’objet stream obtenu.

Personnaliser le format audio

Vous pouvez personnaliser les attributs de sortie audio, notamment :

  • Le type de fichier audio
  • Échantillonnage
  • Profondeur de bits

Pour changer de format audio, utilisez la fonction SetSpeechSynthesisOutputFormat() sur l’objet SpeechConfig. Cette fonction attend une instance enum de type SpeechSynthesisOutputFormat. Utilisez pour enum sélectionner le format de sortie. Pour connaître les formats disponibles, consultez la liste des formats audio.

Il existe diverses options pour les différents types de fichiers, ce qui permet de répondre à vos besoins. Par définition, les formats bruts comme Raw24Khz16BitMonoPcm n’incluent pas d’en-têtes audio. Utilisez les formats bruts uniquement dans les situations suivantes :

  • Vous savez que votre implémentation en aval peut décoder un flux binaire brut.
  • Vous envisagez de générer manuellement des en-têtes en fonction de facteurs tels que la profondeur de bit, le taux d’échantillonnage et le nombre de canaux.

Ce exemple spécifie le format RIFF haute fidélité Riff24Khz16BitMonoPcm en définissant SpeechSynthesisOutputFormat sur l’objet SpeechConfig. Comme dans l’exemple de la section précédente, vous allez utiliser AudioDataStream pour obtenir un flux en mémoire du résultat, puis l’écrire dans un fichier.

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

Lorsque vous exécutez le programme, il écrit un fichier .wav dans le chemin d’accès spécifié.

Utiliser SSML pour personnaliser les caractéristiques vocales

Vous pouvez utiliser SSML pour ajuster la tonalité, la prononciation, la vitesse d’élocution, le volume et d’autres aspects de sortie de la synthèse vocale en soumettant vos demandes à partir d’un schéma XML. Cette section présente un exemple de modification de voix. Pour plus d’informations, consultez Vue d’ensemble de Speech Synthesis Markup Language.

Pour commencer à utiliser SSML pour la personnalisation, apportez une modification mineure qui change la voix.

  1. Créez un fichier XML pour la configuration SSML dans le répertoire racine de votre projet.

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

    Dans cet exemple, le fichier est ssml.xml. L’élément racine est toujours <speak>. L’inclusion du texte dans un élément <voice> vous permet de modifier la voix à l’aide du paramètre name. Pour une liste complète des voix neuronales prises en charge, consultez Langues prises en charge.

  2. Changez la requête de synthèse vocale de sorte qu’elle fasse référence à votre fichier XML. La requête est essentiellement la même. Au lieu d’utiliser la fonction SpeakTextAsync(), utilisez SpeakSsmlAsync(). Cette fonction attend une chaîne XML. Tout d’abord, chargez votre configuration SSML sous forme de chaîne. À ce stade, l’objet obtenu est exactement le même que dans les exemples précédents.

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

Remarque

Pour modifier la voix sans utiliser SSML, vous pouvez définir la propriété sur SpeechConfig à l’aide de SpeechConfig.SetSpeechSynthesisVoiceName("en-US-AndrewMultilingualNeural").

S’abonner aux événements de synthétiseur

Vous souhaiterez peut-être obtenir plus d’informations sur le traitement et les résultats de la synthèse vocale. Par exemple, vous souhaiterez peut-être savoir quand le synthétiseur démarre et s’arrête ou connaître les autres événements rencontrés pendant la synthèse.

Lors de l’utilisation du SpeechSynthesizer pour la synthèse vocale, vous pouvez vous abonner aux événements indiqués dans le tableau suivant :

Événement Description Cas d’utilisation
BookmarkReached Signale qu’un signet a été atteint. Pour déclencher un événement de signet atteint, un élément bookmark est requis dans le SSML. Cet événement signale le temps écoulé du contenu audio de sortie entre le début de la synthèse et l’élément bookmark. La propriété Text de l’événement est la valeur de chaîne que vous définissez dans l’attribut mark du signet. Les éléments bookmark ne sont pas énoncés. Vous pouvez utiliser l’élément bookmark pour insérer des marqueurs personnalisés en SSML afin d’obtenir le décalage de chaque marqueur dans le flux audio. L’élément bookmark peut être utilisé pour référencer un emplacement spécifique dans le texte ou la séquence de balises.
SynthesisCanceled Signale que la synthèse vocale a été annulée. Vous pouvez confirmer que la synthèse est annulée.
SynthesisCompleted Signale que la synthèse vocale est terminée. Vous pouvez confirmer que la synthèse est terminée.
SynthesisStarted Signale que la synthèse vocale est commencée. Vous pouvez confirmer que la synthèse est commencée.
Synthesizing Signale que la synthèse vocale est en cours. Cet événement se déclenche chaque fois que le SDK reçoit un segment audio du service Speech. Vous pouvez confirmer que la synthèse est en cours.
VisemeReceived Signale qu’un événement de visème a été reçu. Les visèmes sont souvent utilisées pour représenter les poses clés dans la parole observée. Les poses clés incluent la position des lèvres, de la mâchoire et de la langue dans la production d’un phonème particulier. Vous pouvez utiliser des visèmes pour animer le visage d’un personnage au fur et à mesure de la lecture audio.
WordBoundary Signale qu’une limite de mot a été reçue. Cet événement est déclenché au début de chaque nouveau mot prononcé, ponctuation et phrase. L’événement signale le décalage de temps du mot actuel, en ticks , à partir du début de l’audio de sortie. Cet événement signale également la position du caractère dans le texte d’entrée, ou SSML, juste avant le mot sur le point d’être prononcé. Cet événement est couramment utilisé pour obtenir les positions relatives du texte et de l’audio correspondant. Vous souhaiterez peut-être avoir des informations sur un nouveau mot, puis prendre des mesures en fonction du minutage. Par exemple, vous pouvez obtenir des informations qui peuvent vous aider à décider quand et pendant combien de temps mettre en surbrillance les mots à mesure qu’ils sont prononcés.

Remarque

Les événements sont déclenchés à mesure que les données audio de sortie deviennent disponibles, ce qui est plus rapide que la lecture sur un appareil de sortie. L’appelant doit synchroniser de manière appropriée le streaming et le temps réel.

Voici un exemple qui montre comment s’abonner aux événements pour la synthèse vocale. Vous pouvez suivre les instructions du guide de démarrage rapide, mais remplacez le contenu du fichier main.cpp par le code suivant :

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

Vous trouverez plus d’exemples de synthèse vocale sur GitHub.

Utiliser un point de terminaison personnalisé

D’un point de vue fonctionnel, le point de terminaison personnalisé est identique au point de terminaison standard utilisé pour les demandes de synthèse vocale.

La différence est que le EndpointId doit être spécifié pour utiliser votre voix personnalisée via le Kit de développement logiciel (SDK) Speech. Vous pouvez commencer par le guide de démarrage rapide de synthèse vocale, puis mettre à jour le code avec EndpointId et SpeechSynthesisVoiceName.

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

Pour utiliser une voix personnalisée via le langage SSML (Speech Synthesis Markup Language), spécifiez le nom du modèle comme nom de la voix. Cet exemple utilise la voix 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>

Exécuter et utiliser un conteneur

Les conteneurs Speech fournissent des API de point de terminaison de requête basées sur WebSocket, accessibles via le Kit de développement logiciel (SDK) Speech et l’interface CLI Speech. Par défaut, le kit de développement logiciel (SDK) Speech et l’interface CLI Speech utilisent le service Speech public. Pour utiliser le conteneur, vous devez changer la méthode d’initialisation. Utilisez une URL d’hôte de conteneur plutôt qu’une clé et une région.

Pour plus d’informations sur les conteneurs, consultez Installer et exécuter des conteneurs Speech avec Docker.

Documentation de référence | Package (Go) | Exemples supplémentaires sur GitHub

Dans ce guide pratique, vous allez découvrir des modèles de conception courants qui permettent d’utiliser la synthèse vocale.

Pour plus d’informations sur les domaines suivants, consultez Qu’est-ce que la synthèse vocale ?

  • Obtention de réponses en tant que flux en mémoire.
  • Personnalisation du taux d’échantillonnage de sortie et de la vitesse de transmission.
  • Envoi de demandes de synthèse à l’aide de SSML (Speech Synthesis Markup Language).
  • Utilisation de voix neurales.
  • Abonnement aux événements et exploitation des résultats.

Prérequis

Installer le Kit de développement logiciel (SDK) Speech

Avant de pouvoir faire quoi que ce soit, vous devez installer le kit SDK Speech pour Go.

Synthèse vocale vers un haut-parleur

Utilisez l’exemple de code suivant pour exécuter la synthèse vocale sur votre appareil de sortie audio par défaut. Remplacez les variables subscription et region par votre clé de voix et votre emplacement/région. L’exécution du script dicte votre texte d’entrée sur le haut-parleur par défaut.

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

Exécutez les commandes suivantes pour créer un fichier go.mod lié aux composants hébergés sur GitHub :

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

Maintenant, générez et exécutez le code :

go build
go run quickstart

Pour plus d’informations sur les classes, consultez les documents de référence SpeechConfig et SpeechSynthesizer.

Synthèse vocale vers un flux en mémoire

Vous pouvez utiliser les données audio obtenues sous forme de flux en mémoire plutôt que directement écrites dans un fichier. Avec le flux en mémoire, vous pouvez créer un comportement personnalisé :

  • Résumer le tableau d’octets obtenu sous forme de flux pouvant faire l’objet de recherches pour des services en aval personnalisés.
  • Intégrer le résultat à d’autres API ou services.
  • Modifier les données audio, écrire des en-têtes .wav personnalisés et effectuer les tâches associées.

Vous pouvez apporter cette modification à l’exemple précédent. Supprimez le bloc AudioConfig, car vous allez gérer le comportement de sortie manuellement à partir de ce point pour un contrôle accru. Transmettez ensuite nil pour AudioConfig dans le constructeur SpeechSynthesizer.

Notes

Le fait de transmettre nil pour AudioConfig, au lieu de l’omettre comme dans l’exemple de sortie de haut-parleur précédent, n’aura pas pour effet de lire par défaut l’audio sur l’appareil de sortie actuellement actif.

Enregistrez le résultat dans une variable SpeechSynthesisResult. La propriété AudioData retourne une instance []byte pour les données de sortie. Vous pouvez utiliser cette instance de []byte manuellement ou utiliser la classe AudioDataStream pour gérer le flux en mémoire. Dans cet exemple, vous allez utiliser la fonction statique NewAudioDataStreamFromSpeechSynthesisResult() pour obtenir un flux à partir du résultat.

Remplacez les variables subscription et region par votre clé de voix et votre localisation/région :

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

Exécutez les commandes suivantes pour créer un fichier go.mod lié aux composants hébergés sur GitHub :

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

Maintenant, générez et exécutez le code :

go build
go run quickstart

Pour plus d’informations sur les classes, consultez les documents de référence SpeechConfig et SpeechSynthesizer.

Sélectionner la langue et la voix de synthèse

La fonctionnalité de synthèse vocale du service Speech prend en charge plus de 400 voix ainsi que plus de 140 langues et variantes. Vous pouvez en obtenir la liste complète ou les tester dans la Galerie de voix.

Spécifiez la langue ou la voix de SpeechConfig en fonction de votre texte d’entrée, puis utilisez la voix souhaitée :

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

Toutes les voix neuronales sont multilingues et parlent couramment leur propre langue et l’anglais. Par exemple, si le texte d’entrée en anglais est « I'm excited to try text to speech, » et que vous avez défini es-ES-ElviraNeural, le texte est lu en anglais avec un accent espagnol.

Si la voix ne s’exprime pas dans la langue correspondant au texte entré, le service Speech ne créé pas d’audio synthétisées. Pour obtenir la liste complète des voix neuronales prises en charge, consultez Prise en charge des langues et des voix pour le service Speech.

Remarque

La voix par défaut est la première voix retournée par les paramètres régionaux depuis l’API de la liste des voix.

La voix qui parle est déterminée par ordre de priorité comme suit :

  • Si vous ne définissez pas SpeechSynthesisVoiceName ou SpeechSynthesisLanguage, la voix par défaut en-US est utilisée.
  • Si vous définissez uniquement SpeechSynthesisLanguage, la voix par défaut des paramètres régionaux spécifiés est utilisée.
  • Si SpeechSynthesisVoiceName et SpeechSynthesisLanguage sont tous deux définis, le paramètre SpeechSynthesisLanguage est ignoré. La voix que vous spécifiez en utilisant SpeechSynthesisVoiceName parle.
  • Si l’élément voix est défini en utilisant SSML (Speech Synthesis Markup Language), les paramètres SpeechSynthesisVoiceName et SpeechSynthesisLanguage sont ignorés.

Utiliser SSML pour personnaliser les caractéristiques vocales

Vous pouvez utiliser le langage SSML (Speech Synthesis Markup Language) pour ajuster la tonalité, la prononciation, la vitesse d’élocution, le volume et d’autres éléments de sortie de la synthèse vocale en soumettant vos demandes à partir d’un schéma XML. Cette section présente un exemple de modification de voix. Pour plus d’informations, consultez Vue d’ensemble de Speech Synthesis Markup Language.

Pour commencer à utiliser SSML pour la personnalisation, vous allez apporter une modification mineure qui change la voix.

Tout d’abord, créez un fichier XML pour la configuration SSML dans le répertoire racine de votre projet. Dans cet exemple, il s’agit de ssml.xml. L’élément racine est toujours <speak>. L’inclusion du texte dans un élément <voice> vous permet de modifier la voix à l’aide du paramètre name. Pour une liste complète des voix neuronales prises en charge, consultez Langues prises en charge.

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

Ensuite, vous devez changer la demande de synthèse vocale de sorte qu’elle fasse référence à votre fichier XML. La demande est presque totalement identique, sauf qu’au lieu d’utiliser la fonction SpeakTextAsync(), vous allez utiliser SpeakSsmlAsync(). Sachant que cette fonction attend une chaîne XML, vous commencez par charger votre configuration SSML sous forme de chaîne. À ce stade, l’objet obtenu est exactement le même que dans les exemples précédents.

Remarque

Pour définir la voix sans utiliser SSML, vous pouvez définir la propriété sur SpeechConfig en utilisant speechConfig.SetSpeechSynthesisVoiceName("en-US-AvaMultilingualNeural").

S’abonner aux événements de synthétiseur

Vous souhaiterez peut-être obtenir plus d’informations sur le traitement et les résultats de la synthèse vocale. Par exemple, vous souhaiterez peut-être savoir quand le synthétiseur démarre et s’arrête ou connaître les autres événements rencontrés pendant la synthèse.

Lors de l’utilisation du SpeechSynthesizer pour la synthèse vocale, vous pouvez vous abonner aux événements indiqués dans le tableau suivant :

Événement Description Cas d’utilisation
BookmarkReached Signale qu’un signet a été atteint. Pour déclencher un événement de signet atteint, un élément bookmark est requis dans le SSML. Cet événement signale le temps écoulé du contenu audio de sortie entre le début de la synthèse et l’élément bookmark. La propriété Text de l’événement est la valeur de chaîne que vous définissez dans l’attribut mark du signet. Les éléments bookmark ne sont pas énoncés. Vous pouvez utiliser l’élément bookmark pour insérer des marqueurs personnalisés en SSML afin d’obtenir le décalage de chaque marqueur dans le flux audio. L’élément bookmark peut être utilisé pour référencer un emplacement spécifique dans le texte ou la séquence de balises.
SynthesisCanceled Signale que la synthèse vocale a été annulée. Vous pouvez confirmer que la synthèse est annulée.
SynthesisCompleted Signale que la synthèse vocale est terminée. Vous pouvez confirmer que la synthèse est terminée.
SynthesisStarted Signale que la synthèse vocale est commencée. Vous pouvez confirmer que la synthèse est commencée.
Synthesizing Signale que la synthèse vocale est en cours. Cet événement se déclenche chaque fois que le SDK reçoit un segment audio du service Speech. Vous pouvez confirmer que la synthèse est en cours.
VisemeReceived Signale qu’un événement de visème a été reçu. Les visèmes sont souvent utilisées pour représenter les poses clés dans la parole observée. Les poses clés incluent la position des lèvres, de la mâchoire et de la langue dans la production d’un phonème particulier. Vous pouvez utiliser des visèmes pour animer le visage d’un personnage au fur et à mesure de la lecture audio.
WordBoundary Signale qu’une limite de mot a été reçue. Cet événement est déclenché au début de chaque nouveau mot prononcé, ponctuation et phrase. L’événement signale le décalage de temps du mot actuel, en ticks , à partir du début de l’audio de sortie. Cet événement signale également la position du caractère dans le texte d’entrée, ou SSML, juste avant le mot sur le point d’être prononcé. Cet événement est couramment utilisé pour obtenir les positions relatives du texte et de l’audio correspondant. Vous souhaiterez peut-être avoir des informations sur un nouveau mot, puis prendre des mesures en fonction du minutage. Par exemple, vous pouvez obtenir des informations qui peuvent vous aider à décider quand et pendant combien de temps mettre en surbrillance les mots à mesure qu’ils sont prononcés.

Remarque

Les événements sont déclenchés à mesure que les données audio de sortie deviennent disponibles, ce qui est plus rapide que la lecture sur un appareil de sortie. L’appelant doit synchroniser de manière appropriée le streaming et le temps réel.

Voici un exemple qui montre comment s’abonner aux événements pour la synthèse vocale. Vous pouvez suivre les instructions du guide de démarrage rapide, mais remplacez le contenu du fichier speech-synthesis.go par le code Go suivant :

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

Vous trouverez plus d’exemples de synthèse vocale sur GitHub.

Exécuter et utiliser un conteneur

Les conteneurs Speech fournissent des API de point de terminaison de requête basées sur WebSocket, accessibles via le Kit de développement logiciel (SDK) Speech et l’interface CLI Speech. Par défaut, le kit de développement logiciel (SDK) Speech et l’interface CLI Speech utilisent le service Speech public. Pour utiliser le conteneur, vous devez changer la méthode d’initialisation. Utilisez une URL d’hôte de conteneur plutôt qu’une clé et une région.

Pour plus d’informations sur les conteneurs, consultez Installer et exécuter des conteneurs Speech avec Docker.

Documentation de référence | Exemples supplémentaires sur GitHub

Dans ce guide pratique, vous allez découvrir des modèles de conception courants qui permettent d’utiliser la synthèse vocale.

Pour plus d’informations sur les domaines suivants, consultez Qu’est-ce que la synthèse vocale ?

  • Obtention de réponses en tant que flux en mémoire.
  • Personnalisation du taux d’échantillonnage de sortie et de la vitesse de transmission.
  • Envoi de demandes de synthèse à l’aide de SSML (Speech Synthesis Markup Language).
  • Utilisation de voix neurales.
  • Abonnement aux événements et exploitation des résultats.

Sélectionner la langue et la voix de synthèse

La fonctionnalité de synthèse vocale du service Speech prend en charge plus de 400 voix ainsi que plus de 140 langues et variantes. Vous pouvez en obtenir la liste complète ou les tester dans la Galerie de voix.

Spécifiez la langue ou la voix de SpeechConfig en fonction de votre texte d’entrée, puis utilisez la voix spécifiée. L’extrait de code suivant montre comment fonctionne cette technique :

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

Toutes les voix neuronales sont multilingues et parlent couramment leur propre langue et l’anglais. Par exemple, si le texte d’entrée en anglais est « I'm excited to try text to speech, » et que vous avez défini es-ES-ElviraNeural, le texte est lu en anglais avec un accent espagnol.

Si la voix ne s’exprime pas dans la langue correspondant au texte entré, le service Speech ne créé pas d’audio synthétisées. Pour obtenir la liste complète des voix neuronales prises en charge, consultez Prise en charge des langues et des voix pour le service Speech.

Remarque

La voix par défaut est la première voix retournée par les paramètres régionaux depuis l’API de la liste des voix.

La voix qui parle est déterminée par ordre de priorité comme suit :

  • Si vous ne définissez pas SpeechSynthesisVoiceName ou SpeechSynthesisLanguage, la voix par défaut en-US est utilisée.
  • Si vous définissez uniquement SpeechSynthesisLanguage, la voix par défaut des paramètres régionaux spécifiés est utilisée.
  • Si SpeechSynthesisVoiceName et SpeechSynthesisLanguage sont tous deux définis, le paramètre SpeechSynthesisLanguage est ignoré. La voix que vous spécifiez en utilisant SpeechSynthesisVoiceName parle.
  • Si l’élément voix est défini en utilisant SSML (Speech Synthesis Markup Language), les paramètres SpeechSynthesisVoiceName et SpeechSynthesisLanguage sont ignorés.

Synthétiser la voix dans un fichier

Créez un objet SpeechSynthesizer. Cet objet exécute des conversions de synthèse vocale et des sorties vers des haut-parleurs, des fichiers ou d’autres flux de sortie. SpeechSynthesizer accepte comme paramètres :

  • L’objet SpeechConfig que vous avez créé à l’étape précédente.
  • Un objet AudioConfig qui spécifie comment les résultats de sortie doivent être gérés.
  1. Créez une instance AudioConfig pour écrire automatiquement la sortie dans un fichier .wav en utilisant la fonction statique fromWavFileOutput() :

    public static void main(String[] args) {
        SpeechConfig speechConfig = SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
        AudioConfig audioConfig = AudioConfig.fromWavFileOutput("path/to/write/file.wav");
    }
    
  2. Instanciez une instance SpeechSynthesizer. Transmettez votre objet speechConfig et l’objet audioConfig en tant que paramètres. Pour synthétiser la parole et écrire dans un fichier, exécutez SpeakText() avec une chaîne de texte.

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

Lorsque vous exécutez le programme, il crée un fichier .wav synthétisé, qui est écrit à l’emplacement que vous spécifiez. Ce résultat est un bon exemple de l’utilisation la plus basique. Ensuite, vous pouvez personnaliser la sortie et gérer la réponse de sortie sous forme de flux en mémoire pour travailler sur des scénarios personnalisés.

Synthétiser vers la sortie du haut-parleur

Vous souhaiterez peut-être obtenir plus d’informations sur le traitement et les résultats de la synthèse vocale. Par exemple, vous souhaiterez peut-être savoir quand le synthétiseur démarre et s’arrête ou connaître les autres événements rencontrés pendant la synthèse.

Pour générer la synthèse vocale vers l’appareil de sortie actif actuel tel qu’un haut-parleur, instanciez AudioConfig en utilisant la fonction statique fromDefaultSpeakerOutput(). Voici un exemple :

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

Obtenir le résultat sous forme de flux en mémoire

Vous pouvez utiliser les données audio obtenues sous forme de flux en mémoire plutôt que directement écrites dans un fichier. Avec le flux en mémoire, vous pouvez créer un comportement personnalisé :

  • Résumer le tableau d’octets obtenu sous forme de flux pouvant faire l’objet de recherches pour des services en aval personnalisés.
  • Intégrer le résultat à d’autres API ou services.
  • Modifier les données audio, écrire des en-têtes .wav personnalisés et effectuer les tâches associées.

Vous pouvez apporter cette modification à l’exemple précédent. Tout d’abord, supprimez le bloc AudioConfig, car vous aller gérer le comportement de sortie manuellement à partir de ce point pour un contrôle accru. Transmettez ensuite null pour AudioConfig dans le constructeur SpeechSynthesizer.

Remarque

Le fait de transmettre null pour AudioConfig, au lieu de l’omettre comme dans l’exemple de sortie de haut-parleur précédent, ne reproduit pas par défaut l’audio sur l’appareil de sortie actuellement actif.

Enregistrez le résultat dans une variable SpeechSynthesisResult. La fonction SpeechSynthesisResult.getAudioData() retourne une instance de byte [] des données de sortie. Vous pouvez utiliser cette instance de byte [] manuellement ou utiliser la classe AudioDataStream pour gérer le flux en mémoire.

Dans cet exemple, utilisez la fonction statique AudioDataStream.fromResult() pour obtenir un flux à partir du résultat :

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

À ce stade, vous pouvez implémenter tout comportement personnalisé à partir de l’objet stream obtenu.

Personnaliser le format audio

Vous pouvez personnaliser les attributs de sortie audio, notamment :

  • Le type de fichier audio
  • Échantillonnage
  • Profondeur de bits

Pour changer de format audio, utilisez la fonction setSpeechSynthesisOutputFormat() sur l’objet SpeechConfig. Cette fonction attend une instance enum de type SpeechSynthesisOutputFormat. Utilisez pour enum sélectionner le format de sortie. Pour connaître les formats disponibles, consultez la liste des formats audio.

Il existe diverses options pour les différents types de fichiers, ce qui permet de répondre à vos besoins. Par définition, les formats bruts comme Raw24Khz16BitMonoPcm n’incluent pas d’en-têtes audio. Utilisez les formats bruts uniquement dans les situations suivantes :

  • Vous savez que votre implémentation en aval peut décoder un flux binaire brut.
  • Vous envisagez de générer manuellement des en-têtes en fonction de facteurs tels que la profondeur de bit, le taux d’échantillonnage et le nombre de canaux.

Ce exemple spécifie le format RIFF haute fidélité Riff24Khz16BitMonoPcm en définissant SpeechSynthesisOutputFormat sur l’objet SpeechConfig. Comme dans l’exemple de la section précédente, vous allez utiliser AudioDataStream pour obtenir un flux en mémoire du résultat, puis l’écrire dans un fichier.

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

Lorsque vous exécutez le programme, il écrit un fichier .wav dans le chemin d’accès spécifié.

Utiliser SSML pour personnaliser les caractéristiques vocales

Vous pouvez utiliser SSML pour ajuster la tonalité, la prononciation, la vitesse d’élocution, le volume et d’autres aspects de sortie de la synthèse vocale en soumettant vos demandes à partir d’un schéma XML. Cette section présente un exemple de modification de voix. Pour plus d’informations, consultez l’article d’instructions de SSML.

Pour commencer à utiliser SSML pour la personnalisation, vous allez apporter une modification mineure qui change la voix.

  1. Créez un fichier XML pour la configuration SSML dans le répertoire racine de votre projet.

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

    Dans cet exemple, le fichier est ssml.xml. L’élément racine est toujours <speak>. L’inclusion du texte dans un élément <voice> vous permet de modifier la voix à l’aide du paramètre name. Pour une liste complète des voix neuronales prises en charge, consultez Langues prises en charge.

  2. Changez la requête de synthèse vocale de sorte qu’elle fasse référence à votre fichier XML. La requête est essentiellement la même. Au lieu d’utiliser la fonction SpeakText(), utilisez SpeakSsml(). Sachant que cette fonction attend une chaîne XML, vous devez d’abord créer une fonction pour charger un fichier XML et le retourner sous forme de chaîne :

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

    À ce stade, l’objet obtenu est exactement le même que dans les exemples précédents.

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

Remarque

Pour modifier la voix sans utiliser SSML, définissez propriété sur SpeechConfig en utilisant SpeechConfig.setSpeechSynthesisVoiceName("en-US-AvaMultilingualNeural");.

S’abonner aux événements de synthétiseur

Vous souhaiterez peut-être obtenir plus d’informations sur le traitement et les résultats de la synthèse vocale. Par exemple, vous souhaiterez peut-être savoir quand le synthétiseur démarre et s’arrête ou connaître les autres événements rencontrés pendant la synthèse.

Lors de l’utilisation du SpeechSynthesizer pour la synthèse vocale, vous pouvez vous abonner aux événements indiqués dans le tableau suivant :

Événement Description Cas d’utilisation
BookmarkReached Signale qu’un signet a été atteint. Pour déclencher un événement de signet atteint, un élément bookmark est requis dans le SSML. Cet événement signale le temps écoulé du contenu audio de sortie entre le début de la synthèse et l’élément bookmark. La propriété Text de l’événement est la valeur de chaîne que vous définissez dans l’attribut mark du signet. Les éléments bookmark ne sont pas énoncés. Vous pouvez utiliser l’élément bookmark pour insérer des marqueurs personnalisés en SSML afin d’obtenir le décalage de chaque marqueur dans le flux audio. L’élément bookmark peut être utilisé pour référencer un emplacement spécifique dans le texte ou la séquence de balises.
SynthesisCanceled Signale que la synthèse vocale a été annulée. Vous pouvez confirmer que la synthèse est annulée.
SynthesisCompleted Signale que la synthèse vocale est terminée. Vous pouvez confirmer que la synthèse est terminée.
SynthesisStarted Signale que la synthèse vocale est commencée. Vous pouvez confirmer que la synthèse est commencée.
Synthesizing Signale que la synthèse vocale est en cours. Cet événement se déclenche chaque fois que le SDK reçoit un segment audio du service Speech. Vous pouvez confirmer que la synthèse est en cours.
VisemeReceived Signale qu’un événement de visème a été reçu. Les visèmes sont souvent utilisées pour représenter les poses clés dans la parole observée. Les poses clés incluent la position des lèvres, de la mâchoire et de la langue dans la production d’un phonème particulier. Vous pouvez utiliser des visèmes pour animer le visage d’un personnage au fur et à mesure de la lecture audio.
WordBoundary Signale qu’une limite de mot a été reçue. Cet événement est déclenché au début de chaque nouveau mot prononcé, ponctuation et phrase. L’événement signale le décalage de temps du mot actuel, en ticks , à partir du début de l’audio de sortie. Cet événement signale également la position du caractère dans le texte d’entrée, ou SSML, juste avant le mot sur le point d’être prononcé. Cet événement est couramment utilisé pour obtenir les positions relatives du texte et de l’audio correspondant. Vous souhaiterez peut-être avoir des informations sur un nouveau mot, puis prendre des mesures en fonction du minutage. Par exemple, vous pouvez obtenir des informations qui peuvent vous aider à décider quand et pendant combien de temps mettre en surbrillance les mots à mesure qu’ils sont prononcés.

Remarque

Les événements sont déclenchés à mesure que les données audio de sortie deviennent disponibles, ce qui est plus rapide que la lecture sur un appareil de sortie. L’appelant doit synchroniser de manière appropriée le streaming et le temps réel.

Voici un exemple qui montre comment s’abonner aux événements pour la synthèse vocale. Vous pouvez suivre les instructions du guide de démarrage rapide, mais remplacez le contenu du fichier SpeechSynthesis.java par le code Java suivant :

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

Vous trouverez plus d’exemples de synthèse vocale sur GitHub.

Utiliser un point de terminaison personnalisé

D’un point de vue fonctionnel, le point de terminaison personnalisé est identique au point de terminaison standard utilisé pour les demandes de synthèse vocale.

La différence est que le EndpointId doit être spécifié pour utiliser votre voix personnalisée via le Kit de développement logiciel (SDK) Speech. Vous pouvez commencer par le guide de démarrage rapide de synthèse vocale, puis mettre à jour le code avec EndpointId et SpeechSynthesisVoiceName.

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

Pour utiliser une voix personnalisée via le langage SSML (Speech Synthesis Markup Language), spécifiez le nom du modèle comme nom de la voix. Cet exemple utilise la voix 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>

Exécuter et utiliser un conteneur

Les conteneurs Speech fournissent des API de point de terminaison de requête basées sur WebSocket, accessibles via le Kit de développement logiciel (SDK) Speech et l’interface CLI Speech. Par défaut, le kit de développement logiciel (SDK) Speech et l’interface CLI Speech utilisent le service Speech public. Pour utiliser le conteneur, vous devez changer la méthode d’initialisation. Utilisez une URL d’hôte de conteneur plutôt qu’une clé et une région.

Pour plus d’informations sur les conteneurs, consultez Installer et exécuter des conteneurs Speech avec Docker.

Documentation de référence | Package (npm) | Exemples supplémentaires sur GitHub | Code source de la bibliothèque

Dans ce guide pratique, vous allez découvrir des modèles de conception courants qui permettent d’utiliser la synthèse vocale.

Pour plus d’informations sur les domaines suivants, consultez Qu’est-ce que la synthèse vocale ?

  • Obtention de réponses en tant que flux en mémoire.
  • Personnalisation du taux d’échantillonnage de sortie et de la vitesse de transmission.
  • Envoi de demandes de synthèse à l’aide de SSML (Speech Synthesis Markup Language).
  • Utilisation de voix neurales.
  • Abonnement aux événements et exploitation des résultats.

Sélectionner la langue et la voix de synthèse

La fonctionnalité de synthèse vocale du service Speech prend en charge plus de 400 voix ainsi que plus de 140 langues et variantes. Vous pouvez en obtenir la liste complète ou les tester dans la Galerie de voix.

Spécifiez la langue ou la voix de SpeechConfig en fonction de votre texte d’entrée, puis utilisez la voix souhaitée :

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

Toutes les voix neuronales sont multilingues et parlent couramment leur propre langue et l’anglais. Par exemple, si le texte d’entrée en anglais est « I'm excited to try text to speech, » et que vous avez défini es-ES-ElviraNeural, le texte est lu en anglais avec un accent espagnol.

Si la voix ne s’exprime pas dans la langue correspondant au texte entré, le service Speech ne créé pas d’audio synthétisées. Pour obtenir la liste complète des voix neuronales prises en charge, consultez Prise en charge des langues et des voix pour le service Speech.

Remarque

La voix par défaut est la première voix retournée par les paramètres régionaux depuis l’API de la liste des voix.

La voix qui parle est déterminée par ordre de priorité comme suit :

  • Si vous ne définissez pas SpeechSynthesisVoiceName ou SpeechSynthesisLanguage, la voix par défaut en-US est utilisée.
  • Si vous définissez uniquement SpeechSynthesisLanguage, la voix par défaut des paramètres régionaux spécifiés est utilisée.
  • Si SpeechSynthesisVoiceName et SpeechSynthesisLanguage sont tous deux définis, le paramètre SpeechSynthesisLanguage est ignoré. La voix que vous spécifiez en utilisant SpeechSynthesisVoiceName parle.
  • Si l’élément voix est défini en utilisant SSML (Speech Synthesis Markup Language), les paramètres SpeechSynthesisVoiceName et SpeechSynthesisLanguage sont ignorés.

Synthétiser du texte

Pour générer la synthèse vocale vers l’appareil de sortie actif actuel tel qu’un haut-parleur, instanciez AudioConfig en utilisant la fonction statique fromDefaultSpeakerOutput(). Voici un exemple :

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

Lorsque vous exécutez le programme, l’audio synthétisé est lu sur le haut-parleur. Ce résultat est un bon exemple de l’utilisation la plus basique. Ensuite, vous pouvez personnaliser la sortie et la gestion de la réponse de sortie sous forme de flux en mémoire pour travailler sur des scénarios personnalisés.

Obtenir le résultat sous forme de flux en mémoire

Vous pouvez utiliser les données audio obtenues sous forme de flux en mémoire plutôt que directement écrites dans un fichier. Avec le flux en mémoire, vous pouvez créer un comportement personnalisé :

  • Résumer le tableau d’octets obtenu sous forme de flux pouvant faire l’objet de recherches pour des services en aval personnalisés.
  • Intégrer le résultat à d’autres API ou services.
  • Modifiez les données audio, écrivez des en-têtes .wav personnalisés et effectuez les tâches associées.

Vous pouvez apporter cette modification à l’exemple précédent. Supprimez le bloc AudioConfig, car vous allez gérer le comportement de sortie manuellement à partir de ce point pour un contrôle accru. Transmettez ensuite null pour AudioConfig dans le constructeur SpeechSynthesizer.

Remarque

Le fait de transmettre null pour AudioConfig, au lieu de l’omettre comme dans l’exemple de sortie de haut-parleur précédent, ne reproduit pas par défaut l’audio sur l’appareil de sortie actuellement actif.

Enregistrez le résultat dans une variable SpeechSynthesisResult. La propriété SpeechSynthesisResult.audioData retourne une valeur ArrayBuffer des données de sortie, le type de flux de navigateur par défaut. Pour le code côté serveur, convertissez ArrayBuffer en un flux de mémoire tampon.

Le code suivant fonctionne pour le côté client :

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

Vous pouvez implémenter un comportement personnalisé à partir de l’objet ArrayBuffer obtenu. ArrayBuffer est un type qu’il est courant de recevoir dans un navigateur et de lire dans ce format.

Pour le code serveur, si vous devez utiliser les données sous forme de flux, convertissez l’objet ArrayBuffer en flux :

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

Personnaliser le format audio

Vous pouvez personnaliser les attributs de sortie audio, notamment :

  • Le type de fichier audio
  • Échantillonnage
  • Profondeur de bits

Pour changer de format audio, utilisez la propriété speechSynthesisOutputFormat sur l’objet SpeechConfig. Cette propriété attend une instance enum de type SpeechSynthesisOutputFormat. Utilisez pour enum sélectionner le format de sortie. Pour connaître les formats disponibles, consultez la liste des formats audio.

Il existe diverses options pour les différents types de fichiers, ce qui permet de répondre à vos besoins. Par définition, les formats bruts comme Raw24Khz16BitMonoPcm n’incluent pas d’en-têtes audio. Utilisez les formats bruts uniquement dans les situations suivantes :

  • Vous savez que votre implémentation en aval peut décoder un flux binaire brut.
  • Vous envisagez de générer manuellement des en-têtes en fonction de facteurs tels que la profondeur de bit, le taux d’échantillonnage et le nombre de canaux.

Ce exemple spécifie le format RIFF haute fidélité Riff24Khz16BitMonoPcm en définissant speechSynthesisOutputFormat sur l’objet SpeechConfig. Comme dans l’exemple de la section précédente, récupérez les données ArrayBuffer audio et interagissez avec elles.

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

Utiliser SSML pour personnaliser les caractéristiques vocales

Vous pouvez utiliser SSML pour ajuster la tonalité, la prononciation, la vitesse d’élocution, le volume et d’autres aspects de sortie de la synthèse vocale en soumettant vos demandes à partir d’un schéma XML. Cette section présente un exemple de modification de voix. Pour plus d’informations, consultez Vue d’ensemble de Speech Synthesis Markup Language.

Pour commencer à utiliser SSML pour la personnalisation, vous allez apporter une modification mineure qui change la voix.

  1. Créez un fichier XML pour la configuration SSML dans le répertoire racine de votre projet.

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

    Dans cet exemple, il s’agit de ssml.xml. L’élément racine est toujours <speak>. L’inclusion du texte dans un élément <voice> vous permet de modifier la voix à l’aide du paramètre name. Pour une liste complète des voix neuronales prises en charge, consultez Langues prises en charge.

  2. Changez la requête de synthèse vocale de sorte qu’elle fasse référence à votre fichier XML. La demande est presque totalement identique, sauf qu’au lieu d’utiliser la fonction speakTextAsync(), vous allez utiliser speakSsmlAsync(). Cette fonction attend une chaîne XML. Créez une fonction pour charger un fichier XML et le retourner sous forme de chaîne :

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

    Pour plus d’informations sur readFileSync, consultez Système de fichiers Node.js.

    L’objet obtenu est exactement le même que dans les exemples précédents :

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

Remarque

Pour modifier la voix sans utiliser SSML, vous pouvez définir la propriété sur SpeechConfig à l’aide de SpeechConfig.speechSynthesisVoiceName = "en-US-AvaMultilingualNeural";.

S’abonner aux événements de synthétiseur

Vous souhaiterez peut-être obtenir plus d’informations sur le traitement et les résultats de la synthèse vocale. Par exemple, vous souhaiterez peut-être savoir quand le synthétiseur démarre et s’arrête ou connaître les autres événements rencontrés pendant la synthèse.

Lors de l’utilisation du SpeechSynthesizer pour la synthèse vocale, vous pouvez vous abonner aux événements indiqués dans le tableau suivant :

Événement Description Cas d’utilisation
BookmarkReached Signale qu’un signet a été atteint. Pour déclencher un événement de signet atteint, un élément bookmark est requis dans le SSML. Cet événement signale le temps écoulé du contenu audio de sortie entre le début de la synthèse et l’élément bookmark. La propriété Text de l’événement est la valeur de chaîne que vous définissez dans l’attribut mark du signet. Les éléments bookmark ne sont pas énoncés. Vous pouvez utiliser l’élément bookmark pour insérer des marqueurs personnalisés en SSML afin d’obtenir le décalage de chaque marqueur dans le flux audio. L’élément bookmark peut être utilisé pour référencer un emplacement spécifique dans le texte ou la séquence de balises.
SynthesisCanceled Signale que la synthèse vocale a été annulée. Vous pouvez confirmer que la synthèse est annulée.
SynthesisCompleted Signale que la synthèse vocale est terminée. Vous pouvez confirmer que la synthèse est terminée.
SynthesisStarted Signale que la synthèse vocale est commencée. Vous pouvez confirmer que la synthèse est commencée.
Synthesizing Signale que la synthèse vocale est en cours. Cet événement se déclenche chaque fois que le SDK reçoit un segment audio du service Speech. Vous pouvez confirmer que la synthèse est en cours.
VisemeReceived Signale qu’un événement de visème a été reçu. Les visèmes sont souvent utilisées pour représenter les poses clés dans la parole observée. Les poses clés incluent la position des lèvres, de la mâchoire et de la langue dans la production d’un phonème particulier. Vous pouvez utiliser des visèmes pour animer le visage d’un personnage au fur et à mesure de la lecture audio.
WordBoundary Signale qu’une limite de mot a été reçue. Cet événement est déclenché au début de chaque nouveau mot prononcé, ponctuation et phrase. L’événement signale le décalage de temps du mot actuel, en ticks , à partir du début de l’audio de sortie. Cet événement signale également la position du caractère dans le texte d’entrée, ou SSML, juste avant le mot sur le point d’être prononcé. Cet événement est couramment utilisé pour obtenir les positions relatives du texte et de l’audio correspondant. Vous souhaiterez peut-être avoir des informations sur un nouveau mot, puis prendre des mesures en fonction du minutage. Par exemple, vous pouvez obtenir des informations qui peuvent vous aider à décider quand et pendant combien de temps mettre en surbrillance les mots à mesure qu’ils sont prononcés.

Remarque

Les événements sont déclenchés à mesure que les données audio de sortie deviennent disponibles, ce qui est plus rapide que la lecture sur un appareil de sortie. L’appelant doit synchroniser de manière appropriée le streaming et le temps réel.

Voici un exemple qui montre comment s’abonner aux événements pour la synthèse vocale. Vous pouvez suivre les instructions du guide de démarrage rapide, mais remplacez le contenu du fichier SpeechSynthesis.js par le code JavaScript suivant.

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

Vous trouverez plus d’exemples de synthèse vocale sur GitHub.

Exécuter et utiliser un conteneur

Les conteneurs Speech fournissent des API de point de terminaison de requête basées sur WebSocket, accessibles via le Kit de développement logiciel (SDK) Speech et l’interface CLI Speech. Par défaut, le kit de développement logiciel (SDK) Speech et l’interface CLI Speech utilisent le service Speech public. Pour utiliser le conteneur, vous devez changer la méthode d’initialisation. Utilisez une URL d’hôte de conteneur plutôt qu’une clé et une région.

Pour plus d’informations sur les conteneurs, consultez Installer et exécuter des conteneurs Speech avec Docker.

Documentation de référence | Package (Télécharger) | Exemples supplémentaires sur GitHub

Dans ce guide pratique, vous allez découvrir des modèles de conception courants qui permettent d’utiliser la synthèse vocale.

Pour plus d’informations sur les domaines suivants, consultez Qu’est-ce que la synthèse vocale ?

  • Obtention de réponses en tant que flux en mémoire.
  • Personnalisation du taux d’échantillonnage de sortie et de la vitesse de transmission.
  • Envoi de demandes de synthèse à l’aide de SSML (Speech Synthesis Markup Language).
  • Utilisation de voix neurales.
  • Abonnement aux événements et exploitation des résultats.

Prérequis

Installer le Kit de développement logiciel (SDK) Speech et les exemples

Le référentiel Azure-Samples/cognitive-services-speech-sdk contient des exemples écrits en Objective-C pour iOS et Mac. Sélectionnez un lien pour afficher les instructions d’installation de chaque exemple :

Utiliser un point de terminaison personnalisé

D’un point de vue fonctionnel, le point de terminaison personnalisé est identique au point de terminaison standard utilisé pour les demandes de synthèse vocale.

La différence est que le EndpointId doit être spécifié pour utiliser votre voix personnalisée via le Kit de développement logiciel (SDK) Speech. Vous pouvez commencer par le guide de démarrage rapide de synthèse vocale, puis mettre à jour le code avec EndpointId et SpeechSynthesisVoiceName.

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

Pour utiliser une voix personnalisée via le langage SSML (Speech Synthesis Markup Language), spécifiez le nom du modèle comme nom de la voix. Cet exemple utilise la voix 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>

Exécuter et utiliser un conteneur

Les conteneurs Speech fournissent des API de point de terminaison de requête basées sur WebSocket, accessibles via le Kit de développement logiciel (SDK) Speech et l’interface CLI Speech. Par défaut, le kit de développement logiciel (SDK) Speech et l’interface CLI Speech utilisent le service Speech public. Pour utiliser le conteneur, vous devez changer la méthode d’initialisation. Utilisez une URL d’hôte de conteneur plutôt qu’une clé et une région.

Pour plus d’informations sur les conteneurs, consultez Installer et exécuter des conteneurs Speech avec Docker.

Documentation de référence | Package (Télécharger) | Exemples supplémentaires sur GitHub

Dans ce guide pratique, vous allez découvrir des modèles de conception courants qui permettent d’utiliser la synthèse vocale.

Pour plus d’informations sur les domaines suivants, consultez Qu’est-ce que la synthèse vocale ?

  • Obtention de réponses en tant que flux en mémoire.
  • Personnalisation du taux d’échantillonnage de sortie et de la vitesse de transmission.
  • Envoi de demandes de synthèse à l’aide de SSML (Speech Synthesis Markup Language).
  • Utilisation de voix neurales.
  • Abonnement aux événements et exploitation des résultats.

Prérequis

Installer le Kit de développement logiciel (SDK) Speech et les exemples

Le référentiel Azure-Samples/cognitive-services-speech-sdk contient des exemples écrits en Swift pour iOS et Mac. Sélectionnez un lien pour afficher les instructions d’installation de chaque exemple :

Exécuter et utiliser un conteneur

Les conteneurs Speech fournissent des API de point de terminaison de requête basées sur WebSocket, accessibles via le Kit de développement logiciel (SDK) Speech et l’interface CLI Speech. Par défaut, le kit de développement logiciel (SDK) Speech et l’interface CLI Speech utilisent le service Speech public. Pour utiliser le conteneur, vous devez changer la méthode d’initialisation. Utilisez une URL d’hôte de conteneur plutôt qu’une clé et une région.

Pour plus d’informations sur les conteneurs, consultez Installer et exécuter des conteneurs Speech avec Docker.

Documentation de référence | Package (PyPi) | Exemples supplémentaires sur GitHub

Dans ce guide pratique, vous allez découvrir des modèles de conception courants qui permettent d’utiliser la synthèse vocale.

Pour plus d’informations sur les domaines suivants, consultez Qu’est-ce que la synthèse vocale ?

  • Obtention de réponses en tant que flux en mémoire.
  • Personnalisation du taux d’échantillonnage de sortie et de la vitesse de transmission.
  • Envoi de demandes de synthèse à l’aide de SSML (Speech Synthesis Markup Language).
  • Utilisation de voix neurales.
  • Abonnement aux événements et exploitation des résultats.

Sélectionner la langue et la voix de synthèse

La fonctionnalité de synthèse vocale du service Speech prend en charge plus de 400 voix ainsi que plus de 140 langues et variantes. Vous pouvez en obtenir la liste complète ou les tester dans la Galerie de voix.

Spécifiez la langue ou la voix de SpeechConfig en fonction de votre texte d’entrée, puis utilisez la voix souhaitée :

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

Toutes les voix neuronales sont multilingues et parlent couramment leur propre langue et l’anglais. Par exemple, si le texte d’entrée en anglais est « I'm excited to try text to speech, » et que vous avez défini es-ES-ElviraNeural, le texte est lu en anglais avec un accent espagnol.

Si la voix ne s’exprime pas dans la langue correspondant au texte entré, le service Speech ne créé pas d’audio synthétisées. Pour obtenir la liste complète des voix neuronales prises en charge, consultez Prise en charge des langues et des voix pour le service Speech.

Remarque

La voix par défaut est la première voix retournée par les paramètres régionaux depuis l’API de la liste des voix.

La voix qui parle est déterminée par ordre de priorité comme suit :

  • Si vous ne définissez pas SpeechSynthesisVoiceName ou SpeechSynthesisLanguage, la voix par défaut en-US est utilisée.
  • Si vous définissez uniquement SpeechSynthesisLanguage, la voix par défaut des paramètres régionaux spécifiés est utilisée.
  • Si SpeechSynthesisVoiceName et SpeechSynthesisLanguage sont tous deux définis, le paramètre SpeechSynthesisLanguage est ignoré. La voix que vous spécifiez en utilisant SpeechSynthesisVoiceName parle.
  • Si l’élément voix est défini en utilisant SSML (Speech Synthesis Markup Language), les paramètres SpeechSynthesisVoiceName et SpeechSynthesisLanguage sont ignorés.

Synthétiser la voix dans un fichier

Créez un objet SpeechSynthesizer. Cet objet exécute des conversions de synthèse vocale et des sorties vers des haut-parleurs, des fichiers ou d’autres flux de sortie. SpeechSynthesizer accepte comme paramètres :

  • L’objet SpeechConfig que vous avez créé à l’étape précédente.
  • Un objet AudioOutputConfig qui spécifie comment les résultats de sortie doivent être gérés.
  1. Créez une instance AudioOutputConfig pour écrire automatiquement la sortie dans un fichier .wav en utilisant le paramètre de constructeur filename :

    audio_config = speechsdk.audio.AudioOutputConfig(filename="path/to/write/file.wav")
    
  2. Instanciez SpeechSynthesizer en transmettant votre objet speech_config et l’objet audio_config en tant que paramètres. Pour synthétiser la parole et écrire dans un fichier, exécutez speak_text_async() avec une chaîne de texte.

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

Lorsque vous exécutez le programme, il crée un fichier .wav synthétisé, qui est écrit à l’emplacement que vous spécifiez. Ce résultat est un bon exemple de l’utilisation la plus basique. Ensuite, vous pouvez personnaliser la sortie et gérer la réponse de sortie sous forme de flux en mémoire pour travailler sur des scénarios personnalisés.

Synthétiser vers la sortie du haut-parleur

Pour générer la synthèse vocale vers l’appareil de sortie actif actuel tel qu’un haut-parleur, définissez le paramètre use_default_speaker lorsque vous créez l’instance AudioOutputConfig. Voici un exemple :

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

Obtenir le résultat sous forme de flux en mémoire

Vous pouvez utiliser les données audio obtenues sous forme de flux en mémoire plutôt que directement écrites dans un fichier. Avec le flux en mémoire, vous pouvez créer un comportement personnalisé :

  • Résumer le tableau d’octets obtenu sous forme de flux pouvant faire l’objet de recherches pour des services en aval personnalisés.
  • Intégrer le résultat à d’autres API ou services.
  • Modifier les données audio, écrire des en-têtes .wav personnalisés et effectuer les tâches associées.

Vous pouvez apporter cette modification à l’exemple précédent. Tout d’abord, supprimez AudioConfig, car vous allez gérer le comportement de sortie manuellement à partir de ce point pour un contrôle accru. Transmettez None pour AudioConfig dans le constructeur SpeechSynthesizer.

Remarque

Le fait de transmettre None pour AudioConfig, au lieu de l’omettre comme dans l’exemple de sortie de haut-parleur précédent, ne reproduit pas par défaut l’audio sur l’appareil de sortie actuellement actif.

Enregistrez le résultat dans une variable SpeechSynthesisResult. La propriété audio_data contient un objet bytes des données de sortie. Vous pouvez utiliser cet objet manuellement ou utiliser la classe AudioDataStream pour gérer le flux en mémoire.

Dans cet exemple, utilisez le constructeur AudioDataStream pour obtenir un flux à partir du résultat :

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)

À ce stade, vous pouvez implémenter tout comportement personnalisé à partir de l’objet stream obtenu.

Personnaliser le format audio

Vous pouvez personnaliser les attributs de sortie audio, notamment :

  • Le type de fichier audio
  • Échantillonnage
  • Profondeur de bits

Pour changer de format audio, utilisez la fonction set_speech_synthesis_output_format() sur l’objet SpeechConfig. Cette fonction attend une instance enum de type SpeechSynthesisOutputFormat. Utilisez pour enum sélectionner le format de sortie. Pour connaître les formats disponibles, consultez la liste des formats audio.

Il existe diverses options pour les différents types de fichiers, ce qui permet de répondre à vos besoins. Par définition, les formats bruts comme Raw24Khz16BitMonoPcm n’incluent pas d’en-têtes audio. Utilisez les formats bruts uniquement dans les situations suivantes :

  • Vous savez que votre implémentation en aval peut décoder un flux binaire brut.
  • Vous envisagez de générer manuellement des en-têtes en fonction de facteurs tels que la profondeur de bit, le taux d’échantillonnage et le nombre de canaux.

Ce exemple spécifie le format RIFF haute fidélité Riff24Khz16BitMonoPcm en définissant SpeechSynthesisOutputFormat sur l’objet SpeechConfig. Comme dans l’exemple de la section précédente, vous allez utiliser AudioDataStream pour obtenir un flux en mémoire du résultat, puis l’écrire dans un fichier.

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

Lorsque vous exécutez le programme, il écrit un fichier .wav dans le chemin d’accès spécifié.

Utiliser SSML pour personnaliser les caractéristiques vocales

Vous pouvez utiliser SSML pour ajuster la tonalité, la prononciation, la vitesse d’élocution, le volume et d’autres aspects de sortie de la synthèse vocale en soumettant vos demandes à partir d’un schéma XML. Cette section présente un exemple de modification de voix. Pour plus d’informations, consultez Vue d’ensemble de Speech Synthesis Markup Language.

Pour commencer à utiliser SSML pour la personnalisation, apportez une modification mineure qui change la voix.

  1. Créez un fichier XML pour la configuration SSML dans le répertoire racine de votre projet.

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

    Dans cet exemple, le fichier est ssml.xml. L’élément racine est toujours <speak>. L’inclusion du texte dans un élément <voice> vous permet de modifier la voix à l’aide du paramètre name. Pour une liste complète des voix neuronales prises en charge, consultez Langues prises en charge.

  2. Changez la requête de synthèse vocale de sorte qu’elle fasse référence à votre fichier XML. La requête est essentiellement la même. Au lieu d’utiliser la fonction speak_text_async(), utilisez speak_ssml_async(). Cette fonction attend une chaîne XML. Commencez par lire votre configuration SSML sous forme de chaîne. À ce stade, l’objet obtenu est exactement le même que dans les exemples précédents.

    Remarque

    Si votre ssml_string contient  en début de chaîne, vous devez éliminer le format BOM ou le service retourne une erreur. Pour cela, vous devez définir le paramètre encoding comme suit : 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")
    

Notes

Pour modifier la voix sans utiliser SSML, vous pouvez définir la propriété sur SpeechConfig à l’aide de speech_config.speech_synthesis_voice_name = "en-US-AvaMultilingualNeural".

S’abonner aux événements de synthétiseur

Vous souhaiterez peut-être obtenir plus d’informations sur le traitement et les résultats de la synthèse vocale. Par exemple, vous souhaiterez peut-être savoir quand le synthétiseur démarre et s’arrête ou connaître les autres événements rencontrés pendant la synthèse.

Lors de l’utilisation du SpeechSynthesizer pour la synthèse vocale, vous pouvez vous abonner aux événements indiqués dans le tableau suivant :

Événement Description Cas d’utilisation
BookmarkReached Signale qu’un signet a été atteint. Pour déclencher un événement de signet atteint, un élément bookmark est requis dans le SSML. Cet événement signale le temps écoulé du contenu audio de sortie entre le début de la synthèse et l’élément bookmark. La propriété Text de l’événement est la valeur de chaîne que vous définissez dans l’attribut mark du signet. Les éléments bookmark ne sont pas énoncés. Vous pouvez utiliser l’élément bookmark pour insérer des marqueurs personnalisés en SSML afin d’obtenir le décalage de chaque marqueur dans le flux audio. L’élément bookmark peut être utilisé pour référencer un emplacement spécifique dans le texte ou la séquence de balises.
SynthesisCanceled Signale que la synthèse vocale a été annulée. Vous pouvez confirmer que la synthèse est annulée.
SynthesisCompleted Signale que la synthèse vocale est terminée. Vous pouvez confirmer que la synthèse est terminée.
SynthesisStarted Signale que la synthèse vocale est commencée. Vous pouvez confirmer que la synthèse est commencée.
Synthesizing Signale que la synthèse vocale est en cours. Cet événement se déclenche chaque fois que le SDK reçoit un segment audio du service Speech. Vous pouvez confirmer que la synthèse est en cours.
VisemeReceived Signale qu’un événement de visème a été reçu. Les visèmes sont souvent utilisées pour représenter les poses clés dans la parole observée. Les poses clés incluent la position des lèvres, de la mâchoire et de la langue dans la production d’un phonème particulier. Vous pouvez utiliser des visèmes pour animer le visage d’un personnage au fur et à mesure de la lecture audio.
WordBoundary Signale qu’une limite de mot a été reçue. Cet événement est déclenché au début de chaque nouveau mot prononcé, ponctuation et phrase. L’événement signale le décalage de temps du mot actuel, en ticks , à partir du début de l’audio de sortie. Cet événement signale également la position du caractère dans le texte d’entrée, ou SSML, juste avant le mot sur le point d’être prononcé. Cet événement est couramment utilisé pour obtenir les positions relatives du texte et de l’audio correspondant. Vous souhaiterez peut-être avoir des informations sur un nouveau mot, puis prendre des mesures en fonction du minutage. Par exemple, vous pouvez obtenir des informations qui peuvent vous aider à décider quand et pendant combien de temps mettre en surbrillance les mots à mesure qu’ils sont prononcés.

Remarque

Les événements sont déclenchés à mesure que les données audio de sortie deviennent disponibles, ce qui est plus rapide que la lecture sur un appareil de sortie. L’appelant doit synchroniser de manière appropriée le streaming et le temps réel.

Voici un exemple qui montre comment s’abonner aux événements pour la synthèse vocale. Vous pouvez suivre les instructions du guide de démarrage rapide, mais remplacez le contenu du fichier speech-synthesis.py par le code Python suivant :

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

Vous trouverez plus d’exemples de synthèse vocale sur GitHub.

Utiliser un point de terminaison personnalisé

D’un point de vue fonctionnel, le point de terminaison personnalisé est identique au point de terminaison standard utilisé pour les demandes de synthèse vocale.

La différence est que le endpoint_id doit être spécifié pour utiliser votre voix personnalisée via le Kit de développement logiciel (SDK) Speech. Vous pouvez commencer par le guide de démarrage rapide de synthèse vocale, puis mettre à jour le code avec endpoint_id et 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"

Pour utiliser une voix personnalisée via le langage SSML (Speech Synthesis Markup Language), spécifiez le nom du modèle comme nom de la voix. Cet exemple utilise la voix 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>

Exécuter et utiliser un conteneur

Les conteneurs Speech fournissent des API de point de terminaison de requête basées sur WebSocket, accessibles via le Kit de développement logiciel (SDK) Speech et l’interface CLI Speech. Par défaut, le kit de développement logiciel (SDK) Speech et l’interface CLI Speech utilisent le service Speech public. Pour utiliser le conteneur, vous devez changer la méthode d’initialisation. Utilisez une URL d’hôte de conteneur plutôt qu’une clé et une région.

Pour plus d’informations sur les conteneurs, consultez Installer et exécuter des conteneurs Speech avec Docker.

Informations de référence sur l’API REST de reconnaissance vocale | Informations de référence sur l’API REST de reconnaissance vocale pour audio court | Exemples supplémentaires sur GitHub

Dans ce guide pratique, vous allez découvrir des modèles de conception courants qui permettent d’utiliser la synthèse vocale.

Pour plus d’informations sur les domaines suivants, consultez Qu’est-ce que la synthèse vocale ?

  • Obtention de réponses en tant que flux en mémoire.
  • Personnalisation du taux d’échantillonnage de sortie et de la vitesse de transmission.
  • Envoi de demandes de synthèse à l’aide de SSML (Speech Synthesis Markup Language).
  • Utilisation de voix neurales.
  • Abonnement aux événements et exploitation des résultats.

Prérequis

Convertir du texte en parole

Depuis une invite de commandes, exécutez la commande suivante. Insérez ces valeurs dans la commande :

  • Clé de votre ressource Speech
  • Région de votre ressource Speech

Vous pouvez également changer les valeurs suivantes :

  • La valeur d’en-tête X-Microsoft-OutputFormat, qui contrôle le format de sortie audio. Vous trouverez la liste des formats de sortie audio pris en charge dans les informations de référence sur l’API REST de synthèse vocale.
  • La voix de sortie. Pour obtenir la liste des voix disponibles pour votre point de terminaison de service Speech, consultez l’API de liste vocale.
  • Fichier de sortie. Dans cet exemple, nous dirigeons la réponse du serveur vers un fichier nommé 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

Dans ce guide pratique, vous allez découvrir des modèles de conception courants qui permettent d’utiliser la synthèse vocale.

Pour plus d’informations sur les domaines suivants, consultez Qu’est-ce que la synthèse vocale ?

  • Obtention de réponses en tant que flux en mémoire.
  • Personnalisation du taux d’échantillonnage de sortie et de la vitesse de transmission.
  • Envoi de demandes de synthèse à l’aide de SSML (Speech Synthesis Markup Language).
  • Utilisation de voix neurales.
  • Abonnement aux événements et exploitation des résultats.

Prérequis

Télécharger et installer

Suivez ces étapes et consultez le guide de démarrage rapide de l’interface CLI Speech pour connaître les autres conditions requises pour votre plateforme.

  1. Exécutez la commande CLI .NET suivante pour installer l’interface CLI Speech :

    dotnet tool install --global Microsoft.CognitiveServices.Speech.CLI
    
  2. Exécutez les commandes suivantes pour configurer la clé et la région de votre ressource Speech. Remplacez SUBSCRIPTION-KEY par la clé de la ressource Speech et remplacez REGION par la région de la ressource Speech.

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

Synthétiser la voix vers un haut-parleur

Vous êtes maintenant prêt à exécuter l’interface CLI Speech pour synthétiser la voix à partir du texte.

  • Dans une fenêtre de console, accédez au répertoire qui contient le fichier binaire Speech CLI. Exécutez ensuite la commande suivante :

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

L’interface CLI Speech génère un langage naturel en anglais par le biais du haut-parleur de l’ordinateur.

Synthétiser la voix dans un fichier

  • Exécutez la commande suivante pour convertir la sortie de votre haut-parleur en fichier .wav :

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

L’interface CLI Speech génère un langage naturel en anglais dans le fichier audio greetings.wav.

Exécuter et utiliser un conteneur

Les conteneurs Speech fournissent des API de point de terminaison de requête basées sur WebSocket, accessibles via le Kit de développement logiciel (SDK) Speech et l’interface CLI Speech. Par défaut, le kit de développement logiciel (SDK) Speech et l’interface CLI Speech utilisent le service Speech public. Pour utiliser le conteneur, vous devez changer la méthode d’initialisation. Utilisez une URL d’hôte de conteneur plutôt qu’une clé et une région.

Pour plus d’informations sur les conteneurs, consultez Installer et exécuter des conteneurs Speech avec Docker.

Étapes suivantes